diff --git a/.gitignore b/.gitignore index 58eafaf68d..48aa29b69e 100644 --- a/.gitignore +++ b/.gitignore @@ -96,3 +96,5 @@ tools/appliance/box/ .pydevproject systemvm/.pydevproject test/.pydevprojec +plugins/hypervisors/kvm/.pydevproject +scripts/.pydevproject diff --git a/.java-version b/.java-version new file mode 100644 index 0000000000..d3bdbdf1fd --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +1.7 diff --git a/.python-version b/.python-version new file mode 100644 index 0000000000..564383308e --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +cloudstack diff --git a/.travis.yml b/.travis.yml index 200f1999ce..34220fe05b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,27 +15,35 @@ # specific language governing permissions and limitations # under the License. sudo: required +dist: trusty language: java cache: directories: - $HOME/.cache jdk: - oraclejdk7 +python: + - "2.7" +cache: + directories: + - $HOME/.m2 + timeout: 1000 notifications: email: false env: global: - REGRESSION_CYCLE=4 - REGRESSION_INDEX=6 + - PATH=$HOME/.local/bin:$PATH matrix: - - TESTS="smoke/test_affinity_groups smoke/test_primary_storage" - - TESTS="smoke/test_deploy_vms_with_varied_deploymentplanners smoke/test_disk_offerings smoke/test_global_settings smoke/test_multipleips_per_nic" - - TESTS="smoke/test_portable_publicip smoke/test_privategw_acl smoke/test_public_ip_range smoke/test_pvlan smoke/test_regions smoke/test_network" - - TESTS="smoke/test_reset_vm_on_reboot smoke/test_resource_detail smoke/test_routers smoke/test_guest_vlan_range smoke/test_iso smoke/test_non_contigiousvlan" - - TESTS="smoke/test_secondary_storage smoke/test_service_offerings smoke/test_ssvm smoke/test_templates smoke/test_over_provisioning" + - TESTS="smoke/test_affinity_groups smoke/test_affinity_groups_projects smoke/test_dynamicroles smoke/test_deploy_vgpu_enabled_vm smoke/test_deploy_vm_iso smoke/test_deploy_vm_root_resize smoke/test_deploy_vm_with_userdata smoke/test_deploy_vms_with_varied_deploymentplanners smoke/test_disk_offerings smoke/test_global_settings smoke/test_guest_vlan_range" + - TESTS="smoke/test_hosts smoke/test_internal_lb smoke/test_iso smoke/test_list_ids_parameter smoke/test_loadbalance smoke/test_login smoke/test_multipleips_per_nic smoke/test_network smoke/test_network_acl smoke/test_nic smoke/test_nic_adapter_type smoke/test_non_contigiousvlan" + - TESTS="smoke/test_outofbandmanagement smoke/test_over_provisioning smoke/test_password_server smoke/test_portable_publicip smoke/test_primary_storage smoke/test_privategw_acl smoke/test_public_ip_range smoke/test_pvlan smoke/test_regions smoke/test_reset_vm_on_reboot smoke/test_resource_detail" + - TESTS="smoke/test_router_dhcphosts smoke/test_routers smoke/test_routers_iptables_default_policy smoke/test_routers_network_ops smoke/test_staticroles smoke/test_scale_vm smoke/test_secondary_storage smoke/test_service_offerings smoke/test_snapshots smoke/test_ssvm smoke/test_templates" + - TESTS="smoke/test_usage_events smoke/test_vm_life_cycle smoke/test_vm_snapshots smoke/test_volumes smoke/test_vpc_redundant smoke/test_vpc_router_nics smoke/test_vpc_vpn smoke/misc/test_deploy_vm smoke/misc/test_vm_ha smoke/misc/test_escalations_templates smoke/misc/test_vm_sync" - - TESTS="smoke/test_volumes smoke/test_vpc_vpn smoke/misc/test_deploy_vm smoke/test_vm_life_cycle component/test_mm_max_limits" - - TESTS="component/test_acl_isolatednetwork_delete component/test_mm_domain_limits component/test_acl_listsnapshot" + - TESTS="component/test_mm_max_limits component/test_acl_isolatednetwork_delete" + - TESTS="component/test_mm_domain_limits component/test_acl_listsnapshot" - TESTS="component/test_acl_listvm component/test_acl_sharednetwork_deployVM-impersonation component/test_acl_sharednetwork" - TESTS="component/test_snapshots component/test_acl_listvolume" before_install: travis_wait 30 ./tools/travis/before_install.sh @@ -43,7 +51,7 @@ install: ./tools/travis/install.sh before_script: travis_wait 30 ./tools/travis/before_script.sh script: - travis_wait 30 sleep 30 - - ./tools/travis/script.sh $TESTS + - ./tools/travis/script.sh ${TESTS} after_success: ./tools/travis/after_success.sh after_failure: ./tools/travis/after_failure.sh after_script: ./tools/travis/after_script.sh diff --git a/INSTALL.md b/INSTALL.md index 9924ba91f5..8a83fb0f72 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -38,6 +38,23 @@ Start the MySQL service: $ service mysqld start +### Using jenv and/or pyenv for Version Management + +CloudStack is built using Java and Python. To make selection of these tools versions more consistent and ease installation for developers, optional support for [jenv](http://www.jenv.be/) and [pyenv](https://github.com/yyuu/pyenv) with [virtualenv]|(https://github.com/yyuu/pyenv-virtualenv) is provided. jenv installation instructions are available here and pyenv installation instructions are available here. For users of [oh-my-zsh](http://ohmyz.sh/) there is a pyenv plugin available to trigger configuration of pyenv in a shell session. + +Following installation, execute the following commands to configure jenv and pyenv for use with CloudStack development: + +''' + # pyenv install 2.7.11 # Install Python 2.7.11 + # pyenv virtualenv 2.7.11 cloudstack # Create a cloidstack virtualenv using Python 2.7.11 + # pip install -r /requirements.txt # Install cloudstack Python dependencies + # jenv add # Add Java7 to jenv +''' + +*N.B.* If you are running Linux, you may need to install additional packages to allow pyenv to build Python. + +Following these steps, jenv and pyenv will use .java-version and .python-version files in the root of the CloudStack source tree to switch to the correct Java version and the cloudstack Python virtualenv for CloudStack development. + ## Getting the Source Code You may get the source code from the repository hosted on Apache: diff --git a/agent/pom.xml b/agent/pom.xml index 96bfd4d9a5..9ff0c5e23c 100644 --- a/agent/pom.xml +++ b/agent/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/agent/src/com/cloud/agent/AgentShell.java b/agent/src/com/cloud/agent/AgentShell.java index 961c106017..5e0da68c6d 100644 --- a/agent/src/com/cloud/agent/AgentShell.java +++ b/agent/src/com/cloud/agent/AgentShell.java @@ -409,12 +409,7 @@ public void start() { /* By default we only search for log4j.xml */ LogUtils.initLog4j("log4j-cloud.xml"); - /* - By default we disable IPv6 for now to maintain backwards - compatibility. At a later point in time we can change this - behavior to prefer IPv6 over IPv4. - */ - boolean ipv6disabled = true; + boolean ipv6disabled = false; String ipv6 = getProperty(null, "ipv6disabled"); if (ipv6 != null) { ipv6disabled = Boolean.parseBoolean(ipv6); diff --git a/api/pom.xml b/api/pom.xml index 160629c219..6b9c98f9c1 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/api/src/com/cloud/agent/api/to/NfsTO.java b/api/src/com/cloud/agent/api/to/NfsTO.java index 51d1aadef2..1cf7218ea1 100644 --- a/api/src/com/cloud/agent/api/to/NfsTO.java +++ b/api/src/com/cloud/agent/api/to/NfsTO.java @@ -24,6 +24,7 @@ public class NfsTO implements DataStoreTO { private DataStoreRole _role; private String uuid; private static final String pathSeparator = "/"; + private Integer nfsVersion; public NfsTO() { @@ -71,4 +72,12 @@ public void setUuid(String uuid) { public String getPathSeparator() { return pathSeparator; } + + public Integer getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(Integer nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 7349c1f541..3cc4eac81f 100644 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -66,6 +66,8 @@ import com.cloud.vm.Nic; import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.VirtualMachine; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; import org.apache.cloudstack.config.Configuration; import org.apache.cloudstack.usage.Usage; @@ -166,6 +168,14 @@ public class EventTypes { public static final String EVENT_GLOBAL_LOAD_BALANCER_DELETE = "GLOBAL.LB.DELETE"; public static final String EVENT_GLOBAL_LOAD_BALANCER_UPDATE = "GLOBAL.LB.UPDATE"; + // Role events + public static final String EVENT_ROLE_CREATE = "ROLE.CREATE"; + public static final String EVENT_ROLE_UPDATE = "ROLE.UPDATE"; + public static final String EVENT_ROLE_DELETE = "ROLE.DELETE"; + public static final String EVENT_ROLE_PERMISSION_CREATE = "ROLE.PERMISSION.CREATE"; + public static final String EVENT_ROLE_PERMISSION_UPDATE = "ROLE.PERMISSION.UPDATE"; + public static final String EVENT_ROLE_PERMISSION_DELETE = "ROLE.PERMISSION.DELETE"; + // Account events public static final String EVENT_ACCOUNT_ENABLE = "ACCOUNT.ENABLE"; public static final String EVENT_ACCOUNT_DISABLE = "ACCOUNT.DISABLE"; @@ -299,6 +309,14 @@ public class EventTypes { // Host public static final String EVENT_HOST_RECONNECT = "HOST.RECONNECT"; + // Host Out-of-band management + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE = "HOST.OOBM.ENABLE"; + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE = "HOST.OOBM.DISABLE"; + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_CONFIGURE = "HOST.OOBM.CONFIGURE"; + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_ACTION = "HOST.OOBM.ACTION"; + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_CHANGE_PASSWORD = "HOST.OOBM.CHANGEPASSWORD"; + public static final String EVENT_HOST_OUTOFBAND_MANAGEMENT_POWERSTATE_TRANSITION = "HOST.OOBM.POWERSTATE.TRANSITION"; + // Maintenance public static final String EVENT_MAINTENANCE_CANCEL = "MAINT.CANCEL"; public static final String EVENT_MAINTENANCE_CANCEL_PRIMARY_STORAGE = "MAINT.CANCEL.PS"; @@ -605,6 +623,14 @@ public class EventTypes { entityEventDetails.put(EVENT_LB_CERT_ASSIGN, LoadBalancer.class); entityEventDetails.put(EVENT_LB_CERT_REMOVE, LoadBalancer.class); + // Role events + entityEventDetails.put(EVENT_ROLE_CREATE, Role.class); + entityEventDetails.put(EVENT_ROLE_UPDATE, Role.class); + entityEventDetails.put(EVENT_ROLE_DELETE, Role.class); + entityEventDetails.put(EVENT_ROLE_PERMISSION_CREATE, RolePermission.class); + entityEventDetails.put(EVENT_ROLE_PERMISSION_UPDATE, RolePermission.class); + entityEventDetails.put(EVENT_ROLE_PERMISSION_DELETE, RolePermission.class); + // Account events entityEventDetails.put(EVENT_ACCOUNT_ENABLE, Account.class); entityEventDetails.put(EVENT_ACCOUNT_DISABLE, Account.class); @@ -727,6 +753,14 @@ public class EventTypes { // Host entityEventDetails.put(EVENT_HOST_RECONNECT, Host.class); + // Host Out-of-band management + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE, Host.class); + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE, Host.class); + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_CONFIGURE, Host.class); + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_ACTION, Host.class); + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_CHANGE_PASSWORD, Host.class); + entityEventDetails.put(EVENT_HOST_OUTOFBAND_MANAGEMENT_POWERSTATE_TRANSITION, Host.class); + // Maintenance entityEventDetails.put(EVENT_MAINTENANCE_CANCEL, Host.class); entityEventDetails.put(EVENT_MAINTENANCE_CANCEL_PRIMARY_STORAGE, Host.class); diff --git a/api/src/com/cloud/resource/ResourceService.java b/api/src/com/cloud/resource/ResourceService.java index 7461455aae..7050b97e0f 100644 --- a/api/src/com/cloud/resource/ResourceService.java +++ b/api/src/com/cloud/resource/ResourceService.java @@ -18,6 +18,7 @@ import java.util.List; +import com.cloud.dc.DataCenter; import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd; import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd; import org.apache.cloudstack.api.command.admin.host.AddHostCmd; @@ -92,6 +93,8 @@ public interface ResourceService { Cluster getCluster(Long clusterId); + DataCenter getZone(Long zoneId); + List getSupportedHypervisorTypes(long zoneId, boolean forVirtualRouter, Long podId); boolean releaseHostReservation(Long hostId); diff --git a/api/src/com/cloud/user/Account.java b/api/src/com/cloud/user/Account.java index b912e515bf..58cedcd574 100644 --- a/api/src/com/cloud/user/Account.java +++ b/api/src/com/cloud/user/Account.java @@ -46,6 +46,8 @@ public enum State { public short getType(); + public Long getRoleId(); + public State getState(); public Date getRemoved(); diff --git a/api/src/com/cloud/user/AccountService.java b/api/src/com/cloud/user/AccountService.java index 7cc1e3089c..959a710d6d 100644 --- a/api/src/com/cloud/user/AccountService.java +++ b/api/src/com/cloud/user/AccountService.java @@ -57,9 +57,9 @@ public interface AccountService { * @return the user if created successfully, null otherwise */ UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, - short accountType, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID); + short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID); - UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long domainId, String networkDomain, + UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID, User.Source source); /** diff --git a/api/src/com/cloud/vm/VmStats.java b/api/src/com/cloud/vm/VmStats.java index 2b7943883e..1c23c01ed8 100644 --- a/api/src/com/cloud/vm/VmStats.java +++ b/api/src/com/cloud/vm/VmStats.java @@ -32,4 +32,10 @@ public interface VmStats { public double getDiskWriteKBs(); + public double getMemoryKBs(); + + public double getIntFreeMemoryKBs(); + + public double getTargetMemoryKBs(); + } diff --git a/api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java b/api/src/org/apache/cloudstack/acl/Role.java similarity index 75% rename from api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java rename to api/src/org/apache/cloudstack/acl/Role.java index dad660b90f..b05d886fdb 100644 --- a/api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java +++ b/api/src/org/apache/cloudstack/acl/Role.java @@ -14,13 +14,14 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.agent.api.storage; -import com.cloud.agent.api.Answer; +package org.apache.cloudstack.acl; -public class PrepareOVAPackingAnswer extends Answer { - public PrepareOVAPackingAnswer(PrepareOVAPackingCommand cmd, boolean result, String details) { - super(cmd, result, details); - } +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; +public interface Role extends InternalIdentity, Identity { + String getName(); + RoleType getRoleType(); + String getDescription(); } diff --git a/api/src/org/apache/cloudstack/acl/RolePermission.java b/api/src/org/apache/cloudstack/acl/RolePermission.java new file mode 100644 index 0000000000..0157a66825 --- /dev/null +++ b/api/src/org/apache/cloudstack/acl/RolePermission.java @@ -0,0 +1,31 @@ +// 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.acl; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface RolePermission extends InternalIdentity, Identity { + enum Permission {ALLOW, DENY} + + long getRoleId(); + Rule getRule(); + Permission getPermission(); + String getDescription(); + long getSortOrder(); +} diff --git a/api/src/org/apache/cloudstack/acl/RoleService.java b/api/src/org/apache/cloudstack/acl/RoleService.java new file mode 100644 index 0000000000..59eef51e78 --- /dev/null +++ b/api/src/org/apache/cloudstack/acl/RoleService.java @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.acl; + +import org.apache.cloudstack.framework.config.ConfigKey; + +import java.util.List; + +public interface RoleService { + + ConfigKey EnableDynamicApiChecker = new ConfigKey<>("Advanced", Boolean.class, "dynamic.apichecker.enabled", "false", + "If set to true, this enables the dynamic role-based api access checker and disables the default static role-based api access checker.", + true); + + boolean isEnabled(); + Role findRole(final Long id); + Role createRole(final String name, final RoleType roleType, final String description); + boolean updateRole(final Role role, final String name, final RoleType roleType, final String description); + boolean deleteRole(final Role role); + + RolePermission findRolePermission(final Long id); + RolePermission findRolePermissionByUuid(final String uuid); + + RolePermission createRolePermission(final Role role, final Rule rule, final RolePermission.Permission permission, final String description); + /** + * updateRolePermission updates the order/position of an role permission + * @param role The role whose permissions needs to be re-ordered + * @param newOrder The new list of ordered role permissions + */ + boolean updateRolePermission(final Role role, final List newOrder); + boolean deleteRolePermission(final RolePermission rolePermission); + + List listRoles(); + List findRolesByName(final String name); + List findRolesByType(final RoleType roleType); + List findAllPermissionsBy(final Long roleId); +} diff --git a/api/src/org/apache/cloudstack/acl/RoleType.java b/api/src/org/apache/cloudstack/acl/RoleType.java index 90e3d1ef60..a8a64a58df 100644 --- a/api/src/org/apache/cloudstack/acl/RoleType.java +++ b/api/src/org/apache/cloudstack/acl/RoleType.java @@ -16,18 +16,90 @@ // under the License. package org.apache.cloudstack.acl; +import com.cloud.user.Account; +import com.google.common.base.Enums; +import com.google.common.base.Strings; + // Enum for default roles in CloudStack public enum RoleType { - Admin(1), ResourceAdmin(2), DomainAdmin(4), User(8), Unknown(0); + Admin(1L, Account.ACCOUNT_TYPE_ADMIN, 1), + ResourceAdmin(2L, Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN, 2), + DomainAdmin(3L, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, 4), + User(4L, Account.ACCOUNT_TYPE_NORMAL, 8), + Unknown(-1L, (short) -1, 0); + private long id; + private short accountType; private int mask; - private RoleType(int mask) { + RoleType(final long id, final short accountType, final int mask) { + this.id = id; + this.accountType = accountType; this.mask = mask; } - public int getValue() { + public long getId() { + return id; + } + + public short getAccountType() { + return accountType; + } + + public int getMask() { return mask; } -} + public static RoleType fromString(final String name) { + if (!Strings.isNullOrEmpty(name) + && Enums.getIfPresent(RoleType.class, name).isPresent()) { + return RoleType.valueOf(name); + } + throw new IllegalStateException("Illegal RoleType name provided"); + } + + public static RoleType fromMask(int mask) { + for (RoleType roleType : RoleType.values()) { + if (roleType.getMask() == mask) { + return roleType; + } + } + return Unknown; + } + + public static RoleType getByAccountType(final short accountType) { + RoleType roleType = RoleType.Unknown; + switch (accountType) { + case Account.ACCOUNT_TYPE_ADMIN: + roleType = RoleType.Admin; + break; + case Account.ACCOUNT_TYPE_DOMAIN_ADMIN: + roleType = RoleType.DomainAdmin; + break; + case Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN: + roleType = RoleType.ResourceAdmin; + break; + case Account.ACCOUNT_TYPE_NORMAL: + roleType = RoleType.User; + break; + } + return roleType; + } + + public static Long getRoleByAccountType(final Long roleId, final Short accountType) { + if (roleId == null && accountType != null) { + RoleType defaultRoleType = RoleType.getByAccountType(accountType); + if (defaultRoleType != null && defaultRoleType != RoleType.Unknown) { + return defaultRoleType.getId(); + } + } + return roleId; + } + + public static Short getAccountTypeByRole(final Role role, final Short accountType) { + if (role != null && role.getId() > 0L) { + return role.getRoleType().getAccountType(); + } + return accountType; + } +} diff --git a/api/src/org/apache/cloudstack/acl/Rule.java b/api/src/org/apache/cloudstack/acl/Rule.java new file mode 100644 index 0000000000..27920107fd --- /dev/null +++ b/api/src/org/apache/cloudstack/acl/Rule.java @@ -0,0 +1,54 @@ +// 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.acl; + +import com.cloud.exception.InvalidParameterValueException; +import com.google.common.base.Strings; + +import java.util.regex.Pattern; + +public final class Rule { + private final String rule; + private final static Pattern ALLOWED_PATTERN = Pattern.compile("^[a-zA-Z0-9*]+$"); + + public Rule(final String rule) { + validate(rule); + this.rule = rule; + } + + public boolean matches(final String commandName) { + return !Strings.isNullOrEmpty(commandName) + && commandName.toLowerCase().matches(rule.toLowerCase().replace("*", "\\w*")); + } + + public String getRuleString() { + return rule; + } + + @Override + public String toString() { + return rule; + } + + private static boolean validate(final String rule) { + if (Strings.isNullOrEmpty(rule) || !ALLOWED_PATTERN.matcher(rule).matches()) { + throw new InvalidParameterValueException("Only API names and wildcards are allowed, invalid rule provided: " + rule); + } + return true; + } +} diff --git a/api/src/org/apache/cloudstack/alert/AlertService.java b/api/src/org/apache/cloudstack/alert/AlertService.java index 2b827eb003..ad711ecea4 100644 --- a/api/src/org/apache/cloudstack/alert/AlertService.java +++ b/api/src/org/apache/cloudstack/alert/AlertService.java @@ -66,6 +66,7 @@ private AlertType(short type, String name, boolean isDefault) { public static final AlertType ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED = new AlertType((short)26, "ALERT.RESOURCE.EXCEED", true); public static final AlertType ALERT_TYPE_SYNC = new AlertType((short)27, "ALERT.TYPE.SYNC", true); public static final AlertType ALERT_TYPE_UPLOAD_FAILED = new AlertType((short)28, "ALERT.UPLOAD.FAILED", true); + public static final AlertType ALERT_TYPE_OOBM_AUTH_ERROR = new AlertType((short)29, "ALERT.OOBM.AUTHERROR", true); public short getType() { return type; diff --git a/api/src/com/cloud/exception/MissingParameterValueException.java b/api/src/org/apache/cloudstack/api/ApiArgValidator.java similarity index 76% rename from api/src/com/cloud/exception/MissingParameterValueException.java rename to api/src/org/apache/cloudstack/api/ApiArgValidator.java index 4bcaa567c5..bd2294c601 100644 --- a/api/src/com/cloud/exception/MissingParameterValueException.java +++ b/api/src/org/apache/cloudstack/api/ApiArgValidator.java @@ -14,13 +14,10 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.exception; -import com.cloud.utils.exception.CloudRuntimeException; +package org.apache.cloudstack.api; -public class MissingParameterValueException extends CloudRuntimeException { - - public MissingParameterValueException(String message) { - super(message); - } -} \ No newline at end of file +public enum ApiArgValidator { + NotNullOrEmpty, // does Strings.isNullOrEmpty check + PositiveNumber, // does != null and > 0 check +} diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index ef4ff9a0fe..1d0b4a3756 100644 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -21,6 +21,7 @@ public class ApiConstants { public static final String ACCOUNTS = "accounts"; public static final String ACCOUNT_TYPE = "accounttype"; public static final String ACCOUNT_ID = "accountid"; + public static final String ADDRESS = "address"; public static final String ALGORITHM = "algorithm"; public static final String ALLOCATED_ONLY = "allocatedonly"; public static final String API_KEY = "apikey"; @@ -76,6 +77,7 @@ public class ApiConstants { public static final String DEVICE_ID = "deviceid"; public static final String DISK_OFFERING_ID = "diskofferingid"; public static final String DISK_SIZE = "disksize"; + public static final String DRIVER = "driver"; public static final String ROOT_DISK_SIZE = "rootdisksize"; public static final String DISPLAY_NAME = "displayname"; public static final String DISPLAY_NETWORK = "displaynetwork"; @@ -177,6 +179,8 @@ public class ApiConstants { public static final String OS_TYPE_ID = "ostypeid"; public static final String OS_DISPLAY_NAME = "osdisplayname"; public static final String OS_NAME_FOR_HYPERVISOR = "osnameforhypervisor"; + public static final String OUTOFBANDMANAGEMENT_POWERSTATE = "outofbandmanagementpowerstate"; + public static final String OUTOFBANDMANAGEMENT_ENABLED = "outofbandmanagementenabled"; public static final String PARAMS = "params"; public static final String PARENT_DOMAIN_ID = "parentdomainid"; public static final String PASSWORD = "password"; @@ -193,6 +197,7 @@ public class ApiConstants { public static final String PORTABLE_IP_ADDRESS = "portableipaddress"; public static final String PORT_FORWARDING_SERVICE_ID = "portforwardingserviceid"; public static final String POST_URL = "postURL"; + public static final String POWER_STATE = "powerstate"; public static final String PRIVATE_INTERFACE = "privateinterface"; public static final String PRIVATE_IP = "privateip"; public static final String PRIVATE_PORT = "privateport"; @@ -358,6 +363,12 @@ public class ApiConstants { public static final String PROJECT_IDS = "projectids"; public static final String PROJECT = "project"; public static final String ROLE = "role"; + public static final String ROLE_ID = "roleid"; + public static final String ROLE_TYPE = "roletype"; + public static final String ROLE_NAME = "rolename"; + public static final String PERMISSION = "permission"; + public static final String RULE = "rule"; + public static final String RULE_ORDER = "ruleorder"; public static final String USER = "user"; public static final String ACTIVE_ONLY = "activeonly"; public static final String TOKEN = "token"; @@ -551,6 +562,7 @@ public class ApiConstants { public static final String VM_SNAPSHOT_DESCRIPTION = "description"; public static final String VM_SNAPSHOT_DISPLAYNAME = "name"; public static final String VM_SNAPSHOT_ID = "vmsnapshotid"; + public static final String VM_SNAPSHOT_IDS = "vmsnapshotids"; public static final String VM_SNAPSHOT_DISK_IDS = "vmsnapshotdiskids"; public static final String VM_SNAPSHOT_MEMORY = "snapshotmemory"; public static final String VM_SNAPSHOT_QUIESCEVM = "quiescevm"; diff --git a/api/src/org/apache/cloudstack/api/ApiServerService.java b/api/src/org/apache/cloudstack/api/ApiServerService.java index 61474080d7..aeeb7b613c 100644 --- a/api/src/org/apache/cloudstack/api/ApiServerService.java +++ b/api/src/org/apache/cloudstack/api/ApiServerService.java @@ -16,10 +16,12 @@ // under the License. package org.apache.cloudstack.api; -import com.cloud.exception.CloudAuthenticationException; -import javax.servlet.http.HttpSession; -import java.util.Map; import java.net.InetAddress; +import java.util.Map; + +import javax.servlet.http.HttpSession; + +import com.cloud.exception.CloudAuthenticationException; public interface ApiServerService { public boolean verifyRequest(Map requestParameters, Long userId) throws ServerApiException; @@ -27,7 +29,7 @@ public interface ApiServerService { public Long fetchDomainId(String domainUUID); public ResponseObject loginUser(HttpSession session, String username, String password, Long domainId, String domainPath, InetAddress loginIpAddress, - Map requestParameters) throws CloudAuthenticationException; + Map requestParameters) throws CloudAuthenticationException; public void logoutUser(long userId); @@ -40,4 +42,8 @@ public ResponseObject loginUser(HttpSession session, String username, String pas public String handleRequest(Map params, String responseType, StringBuilder auditTrailSb) throws ServerApiException; public Class getCmdClass(String cmdName); + + public String getJSONContentType(); + + public boolean isSecureSessionCookieEnabled(); } diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index 360b277d89..5be75196d3 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -30,6 +30,7 @@ import javax.inject.Inject; import com.cloud.utils.HttpUtils; +import org.apache.cloudstack.acl.RoleService; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.RoleType; @@ -85,6 +86,7 @@ public abstract class BaseCmd { private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName()); + public static final String RESPONSE_SUFFIX = "response"; public static final String RESPONSE_TYPE_XML = HttpUtils.RESPONSE_TYPE_XML; public static final String RESPONSE_TYPE_JSON = HttpUtils.RESPONSE_TYPE_JSON; public static final String USER_ERROR_MESSAGE = "Internal error executing command, please contact your system administrator"; @@ -104,12 +106,13 @@ public static enum CommandType { @Parameter(name = "response", type = CommandType.STRING) private String responseType; - @Inject public ConfigurationService _configService; @Inject public AccountService _accountService; @Inject + public RoleService roleService; + @Inject public UserVmService _userVmService; @Inject public ManagementService _mgr; @@ -323,7 +326,7 @@ public List getParamFields() { if (allowedRoles.length > 0) { roleIsAllowed = false; for (final RoleType allowedRole : allowedRoles) { - if (allowedRole.getValue() == caller.getType()) { + if (allowedRole.getAccountType() == caller.getType()) { roleIsAllowed = true; break; } diff --git a/api/src/org/apache/cloudstack/api/BaseResponse.java b/api/src/org/apache/cloudstack/api/BaseResponse.java index 05de218763..45016c1a2a 100644 --- a/api/src/org/apache/cloudstack/api/BaseResponse.java +++ b/api/src/org/apache/cloudstack/api/BaseResponse.java @@ -24,23 +24,38 @@ public abstract class BaseResponse implements ResponseObject { private transient String responseName; private transient String objectName; + @SerializedName(ApiConstants.JOB_ID) + @Param(description = "the UUID of the latest async job acting on this object") + protected String jobId; + + @SerializedName(ApiConstants.JOB_STATUS) + @Param(description = "the current status of the latest async job acting on this object") + private Integer jobStatus; + + public BaseResponse() { + } + + public BaseResponse(final String objectName) { + this.objectName = objectName; + } + @Override - public String getResponseName() { + public final String getResponseName() { return responseName; } @Override - public void setResponseName(String responseName) { + public final void setResponseName(String responseName) { this.responseName = responseName; } @Override - public String getObjectName() { + public final String getObjectName() { return objectName; } @Override - public void setObjectName(String objectName) { + public final void setObjectName(String objectName) { this.objectName = objectName; } @@ -49,14 +64,6 @@ public String getObjectId() { return null; } - @SerializedName(ApiConstants.JOB_ID) - @Param(description = "the UUID of the latest async job acting on this object") - protected String jobId; - - @SerializedName(ApiConstants.JOB_STATUS) - @Param(description = "the current status of the latest async job acting on this object") - private Integer jobStatus; - @Override public String getJobId() { return jobId; diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/NoSuchLdapUserException.java b/api/src/org/apache/cloudstack/api/BaseResponseWithTagInformation.java old mode 100644 new mode 100755 similarity index 56% rename from plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/NoSuchLdapUserException.java rename to api/src/org/apache/cloudstack/api/BaseResponseWithTagInformation.java index d9bf13f6e4..3d694a3141 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/NoSuchLdapUserException.java +++ b/api/src/org/apache/cloudstack/api/BaseResponseWithTagInformation.java @@ -14,18 +14,27 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.ldap; +package org.apache.cloudstack.api; -public class NoSuchLdapUserException extends Exception { - private static final long serialVersionUID = 6782938919658010900L; - private final String username; +import java.util.Set; - public NoSuchLdapUserException(final String username) { - super("No such user: " + username); - this.username = username; +import org.apache.cloudstack.api.response.ResourceTagResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public abstract class BaseResponseWithTagInformation extends BaseResponse { + + @SerializedName(ApiConstants.TAGS) + @Param(description = "the list of resource tags associated", responseObject = ResourceTagResponse.class) + protected Set tags; + + public void addTag(ResourceTagResponse tag) { + this.tags.add(tag); } - public String getUsername() { - return username; + public Set getTags(){ + return this.tags; } + } diff --git a/api/src/org/apache/cloudstack/api/Parameter.java b/api/src/org/apache/cloudstack/api/Parameter.java index 7ee6897af2..fa6075dc97 100644 --- a/api/src/org/apache/cloudstack/api/Parameter.java +++ b/api/src/org/apache/cloudstack/api/Parameter.java @@ -49,4 +49,6 @@ String since() default ""; RoleType[] authorized() default {}; + + ApiArgValidator[] validations() default {}; } diff --git a/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java b/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java index b55ce71498..2e1fbd6f86 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java @@ -22,6 +22,7 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -31,6 +32,7 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.RoleResponse; import org.apache.cloudstack.context.CallContext; import com.cloud.user.Account; @@ -55,10 +57,12 @@ public class CreateAccountCmd extends BaseCmd { @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, - required = true, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") private Short accountType; + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.") + private Long roleId; + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Creates the user under the specified domain.") private Long domainId; @@ -106,7 +110,11 @@ public String getAccountName() { } public Short getAccountType() { - return accountType; + return RoleType.getAccountTypeByRole(roleService.findRole(roleId), accountType); + } + + public Long getRoleId() { + return RoleType.getRoleByAccountType(roleId, accountType); } public Long getDomainId() { @@ -178,7 +186,7 @@ public void execute() { validateParams(); CallContext.current().setEventDetails("Account Name: " + getAccountName() + ", Domain Id:" + getDomainId()); UserAccount userAccount = - _accountService.createUserAccount(getUsername(), getPassword(), getFirstName(), getLastName(), getEmail(), getTimeZone(), getAccountName(), getAccountType(), + _accountService.createUserAccount(getUsername(), getPassword(), getFirstName(), getLastName(), getEmail(), getTimeZone(), getAccountName(), getAccountType(), getRoleId(), getDomainId(), getNetworkDomain(), getDetails(), getAccountUUID(), getUserUUID()); if (userAccount != null) { AccountResponse response = _responseGenerator.createUserAccountResponse(ResponseView.Full, userAccount); @@ -196,5 +204,8 @@ private void validateParams() { if(StringUtils.isEmpty(getPassword())) { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Empty passwords are not allowed"); } + if (getAccountType() == null && (getRoleId() == null || getRoleId() < 1L)) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Neither account type and role ID are not provided"); + } } } diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java new file mode 100644 index 0000000000..994573d179 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java @@ -0,0 +1,105 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.RoleResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = CreateRoleCmd.APINAME, description = "Creates a role", responseObject = RoleResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class CreateRoleCmd extends BaseCmd { + public static final String APINAME = "createRole"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, + description = "creates a role with this unique name", validations = {ApiArgValidator.NotNullOrEmpty}) + private String roleName; + + @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, + description = "The type of the role, valid options are: Admin, ResourceAdmin, DomainAdmin, User", + validations = {ApiArgValidator.NotNullOrEmpty}) + private String roleType; + + @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "The description of the role") + private String roleDescription; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getRoleName() { + return roleName; + } + + public RoleType getRoleType() { + return RoleType.fromString(roleType); + } + + public String getRoleDescription() { + return roleDescription; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final Role role) { + final RoleResponse response = new RoleResponse(); + response.setId(role.getUuid()); + response.setRoleName(role.getName()); + response.setRoleType(role.getRoleType()); + response.setResponseName(getCommandName()); + response.setObjectName("role"); + setResponseObject(response); + } + + @Override + public void execute() { + CallContext.current().setEventDetails("Role: " + getRoleName() + ", type:" + getRoleType() + ", description: " + getRoleDescription()); + final Role role = roleService.createRole(getRoleName(), getRoleType(), getRoleDescription()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create role"); + } + setupResponse(role); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRolePermissionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRolePermissionCmd.java new file mode 100644 index 0000000000..aeb3f4ee11 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/CreateRolePermissionCmd.java @@ -0,0 +1,124 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.acl.Rule; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.RolePermissionResponse; +import org.apache.cloudstack.api.response.RoleResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = CreateRolePermissionCmd.APINAME, description = "Adds a API permission to a role", responseObject = RolePermissionResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class CreateRolePermissionCmd extends BaseCmd { + public static final String APINAME = "createRolePermission"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, required = true, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + @Parameter(name = ApiConstants.RULE, type = CommandType.STRING, required = true, description = "The API name or wildcard rule such as list*", + validations = {ApiArgValidator.NotNullOrEmpty}) + private String rule; + + @Parameter(name = ApiConstants.PERMISSION, type = CommandType.STRING, required = true, description = "The rule permission, allow or deny. Default: deny.") + private String permission; + + @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "The description of the role permission") + private String description; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + public Rule getRule() { + return new Rule(rule); + } + + public RolePermission.Permission getPermission() { + if (Strings.isNullOrEmpty(permission)) { + return null; + } + return RolePermission.Permission.valueOf(permission.toUpperCase()); + } + + public String getDescription() { + return description; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final RolePermission rolePermission, final Role role) { + final RolePermissionResponse response = new RolePermissionResponse(); + response.setId(rolePermission.getUuid()); + response.setRoleId(role.getUuid()); + response.setRule(rolePermission.getRule()); + response.setRulePermission(rolePermission.getPermission()); + response.setDescription(rolePermission.getDescription()); + response.setResponseName(getCommandName()); + response.setObjectName("rolepermission"); + setResponseObject(response); + } + + @Override + public void execute() { + final Role role = roleService.findRole(getRoleId()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided"); + } + CallContext.current().setEventDetails("Role id: " + role.getId() + ", rule:" + getRule() + ", permission: " + getPermission() + ", description: " + getDescription()); + final RolePermission rolePermission = roleService.createRolePermission(role, getRule(), getPermission(), getDescription()); + if (rolePermission == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create role permission"); + } + setupResponse(rolePermission, role); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRoleCmd.java new file mode 100644 index 0000000000..bd4a7cdacb --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRoleCmd.java @@ -0,0 +1,83 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.RoleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = DeleteRoleCmd.APINAME, description = "Deletes a role", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class DeleteRoleCmd extends BaseCmd { + public static final String APINAME = "deleteRole"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, required = true, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + Role role = roleService.findRole(getRoleId()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Cannot find the role with provided id"); + } + CallContext.current().setEventDetails("Role id: " + role.getId()); + boolean result = roleService.deleteRole(role); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRolePermissionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRolePermissionCmd.java new file mode 100644 index 0000000000..9c7dc7c986 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/DeleteRolePermissionCmd.java @@ -0,0 +1,83 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.RolePermissionResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = DeleteRolePermissionCmd.APINAME, description = "Deletes a role permission", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class DeleteRolePermissionCmd extends BaseCmd { + public static final String APINAME = "deleteRolePermission"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, required = true, entityType = RolePermissionResponse.class, + description = "ID of the role permission", validations = {ApiArgValidator.PositiveNumber}) + private Long rolePermissionId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRolePermissionId() { + return rolePermissionId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + RolePermission rolePermission = roleService.findRolePermission(getRolePermissionId()); + if (rolePermission == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role permission id provided"); + } + CallContext.current().setEventDetails("Role permission id: " + rolePermission.getId()); + boolean result = roleService.deleteRolePermission(rolePermission); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolePermissionsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolePermissionsCmd.java new file mode 100644 index 0000000000..f20abf4014 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolePermissionsCmd.java @@ -0,0 +1,106 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +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.ListResponse; +import org.apache.cloudstack.api.response.RolePermissionResponse; +import org.apache.cloudstack.api.response.RoleResponse; + +import java.util.ArrayList; +import java.util.List; + + +@APICommand(name = ListRolePermissionsCmd.APINAME, description = "Lists role permissions", responseObject = RolePermissionResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class ListRolePermissionsCmd extends BaseCmd { + public static final String APINAME = "listRolePermissions"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final List rolePermissions, final Long roleId) { + final Role roleProvided = roleService.findRole(roleId); + final ListResponse response = new ListResponse<>(); + final List rolePermissionResponses = new ArrayList<>(); + for (final RolePermission rolePermission : rolePermissions) { + final RolePermissionResponse rolePermissionResponse = new RolePermissionResponse(); + Role role = roleProvided; + if (role == null) { + role = roleService.findRole(rolePermission.getRoleId()); + } + rolePermissionResponse.setRoleId(role.getUuid()); + rolePermissionResponse.setRoleName(role.getName()); + rolePermissionResponse.setId(rolePermission.getUuid()); + rolePermissionResponse.setRule(rolePermission.getRule()); + rolePermissionResponse.setRulePermission(rolePermission.getPermission()); + rolePermissionResponse.setDescription(rolePermission.getDescription()); + rolePermissionResponse.setObjectName("rolepermission"); + rolePermissionResponses.add(rolePermissionResponse); + } + response.setResponses(rolePermissionResponses); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException { + final List rolePermissions = roleService.findAllPermissionsBy(getRoleId()); + setupResponse(rolePermissions, getRoleId()); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java new file mode 100644 index 0000000000..5cf870bfc0 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java @@ -0,0 +1,128 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.RoleResponse; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@APICommand(name = ListRolesCmd.APINAME, description = "Lists dynamic roles in CloudStack", responseObject = RoleResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin}) +public class ListRolesCmd extends BaseCmd { + public static final String APINAME = "listRoles"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "List role by role ID.") + private Long id; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "List role by role name.") + private String roleName; + + @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "List role by role type, valid options are: Admin, ResourceAdmin, DomainAdmin, User.") + private String roleType; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + public String getName() { + return roleName; + } + + public RoleType getRoleType() { + if (!Strings.isNullOrEmpty(roleType)) { + return RoleType.valueOf(roleType); + } + return null; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + private void setupResponse(final List roles) { + final ListResponse response = new ListResponse<>(); + final List roleResponses = new ArrayList<>(); + for (final Role role : roles) { + if (role == null) { + continue; + } + final RoleResponse roleResponse = new RoleResponse(); + roleResponse.setId(role.getUuid()); + roleResponse.setRoleName(role.getName()); + roleResponse.setRoleType(role.getRoleType()); + roleResponse.setDescription(role.getDescription()); + roleResponse.setObjectName("role"); + roleResponses.add(roleResponse); + } + response.setResponses(roleResponses); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final List roles; + if (getId() != null && getId() > 0L) { + roles = Collections.singletonList(roleService.findRole(getId())); + } else if (!Strings.isNullOrEmpty(getName())) { + roles = roleService.findRolesByName(getName()); + } else if (getRoleType() != null){ + roles = roleService.findRolesByType(getRoleType()); + } else { + roles = roleService.listRoles(); + } + setupResponse(roles); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java new file mode 100644 index 0000000000..e17fc6f571 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java @@ -0,0 +1,108 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.response.RoleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +@APICommand(name = UpdateRoleCmd.APINAME, description = "Updates a role", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class UpdateRoleCmd extends BaseCmd { + public static final String APINAME = "updateRole"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, required = true, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + @Parameter(name = ApiConstants.NAME, type = BaseCmd.CommandType.STRING, description = "creates a role with this unique name") + private String roleName; + + @Parameter(name = ApiConstants.TYPE, type = BaseCmd.CommandType.STRING, description = "The type of the role, valid options are: Admin, ResourceAdmin, DomainAdmin, User") + private String roleType; + + @Parameter(name = ApiConstants.DESCRIPTION, type = BaseCmd.CommandType.STRING, description = "The description of the role") + private String roleDescription; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + public String getRoleName() { + return roleName; + } + + public RoleType getRoleType() { + if (!Strings.isNullOrEmpty(roleType)) { + return RoleType.fromString(roleType); + } + return null; + } + + public String getRoleDescription() { + return roleDescription; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + Role role = roleService.findRole(getRoleId()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided"); + } + CallContext.current().setEventDetails("Role: " + getRoleName() + ", type:" + getRoleType() + ", description: " + getRoleDescription()); + boolean result = roleService.updateRole(role, getRoleName(), getRoleType(), getRoleDescription()); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java new file mode 100644 index 0000000000..055265c5cc --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/acl/UpdateRolePermissionCmd.java @@ -0,0 +1,104 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.acl; + +import com.cloud.user.Account; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +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; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.RolePermissionResponse; +import org.apache.cloudstack.api.response.RoleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; + +import java.util.ArrayList; +import java.util.List; + +@APICommand(name = UpdateRolePermissionCmd.APINAME, description = "Updates a role permission order", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", + authorized = {RoleType.Admin}) +public class UpdateRolePermissionCmd extends BaseCmd { + public static final String APINAME = "updateRolePermission"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, required = true, entityType = RoleResponse.class, + description = "ID of the role", validations = {ApiArgValidator.PositiveNumber}) + private Long roleId; + + @Parameter(name = ApiConstants.RULE_ORDER, type = CommandType.LIST, collectionType = CommandType.UUID, required = true, entityType = RolePermissionResponse.class, + description = "The parent role permission uuid, use 0 to move this rule at the top of the list") + private List rulePermissionOrder; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getRoleId() { + return roleId; + } + + public List getRulePermissionOrder() { + return rulePermissionOrder; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + final Role role = roleService.findRole(getRoleId()); + if (role == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided"); + } + CallContext.current().setEventDetails("Reordering permissions for role id: " + role.getId()); + final List rolePermissionsOrder = new ArrayList<>(); + for (Long rolePermissionId : getRulePermissionOrder()) { + final RolePermission rolePermission = roleService.findRolePermission(rolePermissionId); + if (rolePermission == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Provided role permission(s) do not exist"); + } + rolePermissionsOrder.add(rolePermission); + } + boolean result = roleService.updateRolePermission(role, rolePermissionsOrder); + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setSuccess(result); + setResponseObject(response); + } +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java index 0124d5997b..45f790fb70 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.config; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.RoleService; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -81,6 +83,10 @@ public String getCfgName() { return cfgName; } + public void setCfgName(final String cfgName) { + this.cfgName = cfgName; + } + public String getValue() { return value; } @@ -117,6 +123,12 @@ public long getEntityOwnerId() { @Override public void execute() { + if (Strings.isNullOrEmpty(getCfgName())) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Empty configuration name provided"); + } + if (getCfgName().equalsIgnoreCase(RoleService.EnableDynamicApiChecker.key())) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Restricted configuration update not allowed"); + } Configuration cfg = _configService.updateConfiguration(this); if (cfg != null) { ConfigurationResponse response = _responseGenerator.createConfigurationResponse(cfg); diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java index d7aa18bbfe..424fc05aed 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java @@ -81,9 +81,19 @@ public class ListHostsCmd extends BaseListCmd { description = "lists hosts in the same cluster as this VM and flag hosts with enough CPU/RAm to host this VM") private Long virtualMachineId; + @Parameter(name = ApiConstants.OUTOFBANDMANAGEMENT_ENABLED, + type = CommandType.BOOLEAN, + description = "list hosts for which out-of-band management is enabled") + private Boolean outOfBandManagementEnabled; + + @Parameter(name = ApiConstants.OUTOFBANDMANAGEMENT_POWERSTATE, + type = CommandType.STRING, + description = "list hosts by its out-of-band management interface's power state. Its value can be one of [On, Off, Unknown]") + private String outOfBandManagementPowerState; + @Parameter(name = ApiConstants.RESOURCE_STATE, type = CommandType.STRING, - description = "list hosts by resource state. Resource state represents current state determined by admin of host, valule can be one of [Enabled, Disabled, Unmanaged, PrepareForMaintenance, ErrorInMaintenance, Maintenance, Error]") + description = "list hosts by resource state. Resource state represents current state determined by admin of host, value can be one of [Enabled, Disabled, Unmanaged, PrepareForMaintenance, ErrorInMaintenance, Maintenance, Error]") private String resourceState; @Parameter(name = ApiConstants.DETAILS, @@ -165,6 +175,15 @@ public String getResourceState() { return resourceState; } + + public Boolean isOutOfBandManagementEnabled() { + return outOfBandManagementEnabled; + } + + public String getHostOutOfBandManagementPowerState() { + return outOfBandManagementPowerState; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java new file mode 100644 index 0000000000..ea2e3cdb76 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ChangeOutOfBandManagementPasswordCmd.java @@ -0,0 +1,112 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import com.google.common.base.Strings; +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.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = ChangeOutOfBandManagementPasswordCmd.APINAME, description = "Changes out-of-band management interface password on the host and updates the interface configuration in CloudStack if the operation succeeds, else reverts the old password", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = true, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class ChangeOutOfBandManagementPasswordCmd extends BaseAsyncCmd { + public static final String APINAME = "changeOutOfBandManagementPassword"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, required = true, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the host") + private Long hostId; + + @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "the new host management interface password of maximum length 16, if none is provided a random password would be used") + private String password; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Host host = _resourceService.getHost(getHostId()); + if (host == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); + } + + CallContext.current().setEventDetails("Host Id: " + host.getId() + " Password: " + getPassword().charAt(0) + "****"); + CallContext.current().putContextParameter(Host.class, host.getUuid()); + + final OutOfBandManagementResponse response = outOfBandManagementService.changeOutOfBandManagementPassword(host, getPassword()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + public Long getHostId() { + return hostId; + } + + public String getPassword() { + if (Strings.isNullOrEmpty(password)) { + password = _mgr.generateRandomPassword(); + } + return password; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_CHANGE_PASSWORD; + } + + @Override + public String getEventDescription() { + return "change out-of-band management password for host: " + getHostId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java new file mode 100644 index 0000000000..db224108df --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/ConfigureOutOfBandManagementCmd.java @@ -0,0 +1,125 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +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; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = ConfigureOutOfBandManagementCmd.APINAME, description = "Configures a host's out-of-band management interface", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = true, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class ConfigureOutOfBandManagementCmd extends BaseCmd { + public static final String APINAME = "configureOutOfBandManagement"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, required = true, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the host") + private Long hostId; + + @Parameter(name = ApiConstants.DRIVER, type = CommandType.STRING, required = true, description = "the host management interface driver, for example: ipmitool") + private String driver; + + @Parameter(name = ApiConstants.ADDRESS, type = CommandType.STRING, required = true, description = "the host management interface IP address") + private String address; + + @Parameter(name = ApiConstants.PORT, type = CommandType.STRING, required = true, description = "the host management interface port") + private String port; + + @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, required = true, description = "the host management interface user") + private String username; + + @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, required = true, description = "the host management interface password") + private String password; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Host host = _resourceService.getHost(getHostId()); + if (host == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); + } + CallContext.current().putContextParameter(Host.class, host.getUuid()); + final OutOfBandManagementResponse response = outOfBandManagementService.configureOutOfBandManagement(host, getHostPMOptions()); + response.setId(host.getUuid()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + public Long getHostId() { + return hostId; + } + + public final ImmutableMap getHostPMOptions() { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + if (!Strings.isNullOrEmpty(driver)) { + builder.put(OutOfBandManagement.Option.DRIVER, driver); + } + if (!Strings.isNullOrEmpty(address)) { + builder.put(OutOfBandManagement.Option.ADDRESS, address); + } + if (!Strings.isNullOrEmpty(port)) { + builder.put(OutOfBandManagement.Option.PORT, port); + } + if (!Strings.isNullOrEmpty(username)) { + builder.put(OutOfBandManagement.Option.USERNAME, username); + } + if (!Strings.isNullOrEmpty(password)) { + builder.put(OutOfBandManagement.Option.PASSWORD, password); + } + return builder.build(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForClusterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForClusterCmd.java new file mode 100644 index 0000000000..67d84d5096 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForClusterCmd.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.org.Cluster; +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.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ClusterResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = DisableOutOfBandManagementForClusterCmd.APINAME, description = "Disables out-of-band management for a cluster", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class DisableOutOfBandManagementForClusterCmd extends BaseAsyncCmd { + public static final String APINAME = "disableOutOfBandManagementForCluster"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.CLUSTER_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ClusterResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the cluster") + private Long clusterId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Cluster cluster = _resourceService.getCluster(getClusterId()); + if (cluster == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find cluster by ID: " + getClusterId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.disableOutOfBandManagement(cluster); + + CallContext.current().setEventDetails("Cluster Id:" + cluster.getId() + " out-of-band management enabled: false"); + CallContext.current().putContextParameter(Cluster.class, cluster.getUuid()); + + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getClusterId() { + return clusterId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE; + } + + @Override + public String getEventDescription() { + return "disable out-of-band management password for cluster: " + getClusterId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java new file mode 100644 index 0000000000..009d0d3fd1 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForHostCmd.java @@ -0,0 +1,104 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +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.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = DisableOutOfBandManagementForHostCmd.APINAME, description = "Disables out-of-band management for a host", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class DisableOutOfBandManagementForHostCmd extends BaseAsyncCmd { + public static final String APINAME = "disableOutOfBandManagementForHost"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = HostResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the host") + private Long hostId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Host host = _resourceService.getHost(getHostId()); + if (host == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.disableOutOfBandManagement(host); + + CallContext.current().setEventDetails("Host Id:" + host.getId() + " out-of-band management enabled: false"); + CallContext.current().putContextParameter(Host.class, host.getUuid()); + + response.setId(host.getUuid()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getHostId() { + return hostId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE; + } + + @Override + public String getEventDescription() { + return "disable out-of-band management password for host: " + getHostId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForZoneCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForZoneCmd.java new file mode 100644 index 0000000000..82e92a75ea --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/DisableOutOfBandManagementForZoneCmd.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.dc.DataCenter; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +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.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = DisableOutOfBandManagementForZoneCmd.APINAME, description = "Disables out-of-band management for a zone", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class DisableOutOfBandManagementForZoneCmd extends BaseAsyncCmd { + public static final String APINAME = "disableOutOfBandManagementForZone"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ZoneResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the zone") + private Long zoneId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final DataCenter zone = _resourceService.getZone(getZoneId()); + if (zone == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find zone by ID: " + getZoneId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.disableOutOfBandManagement(zone); + + CallContext.current().setEventDetails("Zone Id:" + zone.getId() + " out-of-band management enabled: false"); + CallContext.current().putContextParameter(DataCenter.class, zone.getUuid()); + + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getZoneId() { + return zoneId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE; + } + + @Override + public String getEventDescription() { + return "disable out-of-band management password for zone: " + getZoneId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForClusterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForClusterCmd.java new file mode 100644 index 0000000000..64279c3a6d --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForClusterCmd.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.org.Cluster; +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.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ClusterResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = EnableOutOfBandManagementForClusterCmd.APINAME, description = "Enables out-of-band management for a cluster", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class EnableOutOfBandManagementForClusterCmd extends BaseAsyncCmd { + public static final String APINAME = "enableOutOfBandManagementForCluster"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.CLUSTER_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ClusterResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the cluster") + private Long clusterId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Cluster cluster = _resourceService.getCluster(getClusterId()); + if (cluster == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find cluster by ID: " + getClusterId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.enableOutOfBandManagement(cluster); + + CallContext.current().setEventDetails("Cluster Id:" + cluster.getId() + " out-of-band management enabled: true"); + CallContext.current().putContextParameter(Cluster.class, cluster.getUuid()); + + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getClusterId() { + return clusterId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE; + } + + @Override + public String getEventDescription() { + return "enable out-of-band management password for cluster: " + getClusterId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForHostCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForHostCmd.java new file mode 100644 index 0000000000..746725602d --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForHostCmd.java @@ -0,0 +1,104 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +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.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = EnableOutOfBandManagementForHostCmd.APINAME, description = "Enables out-of-band management for a host", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class EnableOutOfBandManagementForHostCmd extends BaseAsyncCmd { + public static final String APINAME = "enableOutOfBandManagementForHost"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = HostResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the host") + private Long hostId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Host host = _resourceService.getHost(getHostId()); + if (host == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.enableOutOfBandManagement(host); + + CallContext.current().setEventDetails("Host Id:" + host.getId() + " out-of-band management enabled: true"); + CallContext.current().putContextParameter(Host.class, host.getUuid()); + + response.setId(host.getUuid()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getHostId() { + return hostId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE; + } + + @Override + public String getEventDescription() { + return "enable out-of-band management password for host: " + getHostId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForZoneCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForZoneCmd.java new file mode 100644 index 0000000000..cae2181330 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/EnableOutOfBandManagementForZoneCmd.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.dc.DataCenter; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +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.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = EnableOutOfBandManagementForZoneCmd.APINAME, description = "Enables out-of-band management for a zone", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class EnableOutOfBandManagementForZoneCmd extends BaseAsyncCmd { + public static final String APINAME = "enableOutOfBandManagementForZone"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, required = true, entityType = ZoneResponse.class, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the zone") + private Long zoneId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + final public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final DataCenter zone = _resourceService.getZone(getZoneId()); + if (zone == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find zone by ID: " + getZoneId()); + } + + OutOfBandManagementResponse response = outOfBandManagementService.enableOutOfBandManagement(zone); + + CallContext.current().setEventDetails("Zone Id:" + zone.getId() + " out-of-band management enabled: true"); + CallContext.current().putContextParameter(DataCenter.class, zone.getUuid()); + + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + final public Long getZoneId() { + return zoneId; + } + + @Override + final public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE; + } + + @Override + public String getEventDescription() { + return "enable out-of-band management password for zone: " + getZoneId(); + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java new file mode 100644 index 0000000000..8d6bdd350d --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/outofbandmanagement/IssueOutOfBandManagementPowerActionCmd.java @@ -0,0 +1,124 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.outofbandmanagement; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiCommandJobType; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement.PowerOperation; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; + +import javax.inject.Inject; + +@APICommand(name = IssueOutOfBandManagementPowerActionCmd.APINAME, description = "Initiates the specified power action to the host's out-of-band management interface", + responseObject = OutOfBandManagementResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.9.0", authorized = {RoleType.Admin}) +public class IssueOutOfBandManagementPowerActionCmd extends BaseAsyncCmd { + public static final String APINAME = "issueOutOfBandManagementPowerAction"; + + @Inject + private OutOfBandManagementService outOfBandManagementService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, required = true, + validations = {ApiArgValidator.PositiveNumber}, description = "the ID of the host") + private Long hostId; + + @Parameter(name = ApiConstants.TIMEOUT, type = CommandType.LONG, description = "optional operation timeout in seconds that overrides the global or cluster-level out-of-band management timeout setting") + 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") + private String powerAction; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + final Host host = _resourceService.getHost(getHostId()); + if (host == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unable to find host by ID: " + getHostId()); + } + final PowerOperation powerOperation = PowerOperation.valueOf(getPowerAction()); + + CallContext.current().setEventDetails("Host Id: " + host.getId() + " Action: " + powerOperation.toString()); + CallContext.current().putContextParameter(Host.class, host.getUuid()); + + final OutOfBandManagementResponse response = outOfBandManagementService.executeOutOfBandManagementPowerOperation(host, powerOperation, getActionTimeout()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + public Long getHostId() { + return hostId; + } + + public Long getActionTimeout() { + return actionTimeout; + } + + public String getPowerAction() { + return powerAction; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ACTION; + } + + @Override + public String getEventDescription() { + return "issue out-out-band management power action: " + getPowerAction() + " on host: " + getHostId(); + } + + @Override + public ApiCommandJobType getInstanceType() { + return ApiCommandJobType.Host; + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java index 6b673cf632..839d64dcf9 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/AddImageStoreCmd.java @@ -49,7 +49,7 @@ public class AddImageStoreCmd extends BaseCmd { @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name for the image store") private String name; - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, description = "the URL for the image store") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, length = 2048, description = "the URL for the image store") private String url; @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, description = "the Zone ID for the image store") diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateSecondaryStagingStoreCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateSecondaryStagingStoreCmd.java index cfe4383578..194179d769 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateSecondaryStagingStoreCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateSecondaryStagingStoreCmd.java @@ -45,7 +45,7 @@ public class CreateSecondaryStagingStoreCmd extends BaseCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, description = "the URL for the staging store") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, length = 2048, description = "the URL for the staging store") private String url; @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, description = "the Zone ID for the staging store") diff --git a/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java index f1d3fe975f..32000c6364 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java @@ -75,7 +75,12 @@ public class MigrateVirtualMachineWithVolumeCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.MIGRATE_TO, type = CommandType.MAP, required = false, - description = "Map of pool to which each volume should be migrated (volume/pool pair)") + description = "Storage to pool mapping. This parameter specifies the mapping between a volume and a pool where you want to migrate that volume. Format of this " + + "parameter: migrateto[volume-index].volume=&migrateto[volume-index].pool=Where, [volume-index] indicates the index to identify the volume that you " + + "want to migrate, volume= indicates the UUID of the volume that you want to migrate, and pool= indicates the UUID of the pool where you want to " + + "migrate the volume. Example: migrateto[0].volume=<71f43cd6-69b0-4d3b-9fbc-67f50963d60b>&migrateto[0].pool=&" + + "migrateto[1].volume=<88de0173-55c0-4c1c-a269-83d0279eeedf>&migrateto[1].pool=<95d6e97c-6766-4d67-9a30-c449c15011d1>&migrateto[2].volume=" + + "<1b331390-59f2-4796-9993-bf11c6e76225>&migrateto[2].pool=<41fdb564-9d3b-447d-88ed-7628f7640cbc>") private Map migrateVolumeTo; ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java index 24486a3c79..9c526563d4 100644 --- a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java @@ -47,6 +47,7 @@ public void execute() { Map capabilities = _mgr.listCapabilities(this); CapabilitiesResponse response = new CapabilitiesResponse(); response.setSecurityGroupsEnabled((Boolean)capabilities.get("securityGroupsEnabled")); + response.setDynamicRolesEnabled(roleService.isEnabled()); response.setCloudStackVersion((String)capabilities.get("cloudStackVersion")); response.setUserPublicTemplateEnabled((Boolean)capabilities.get("userPublicTemplateEnabled")); response.setSupportELB((String)capabilities.get("supportELB")); diff --git a/api/src/org/apache/cloudstack/api/command/user/iso/ExtractIsoCmd.java b/api/src/org/apache/cloudstack/api/command/user/iso/ExtractIsoCmd.java index 85f6008598..a400a014b6 100644 --- a/api/src/org/apache/cloudstack/api/command/user/iso/ExtractIsoCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/iso/ExtractIsoCmd.java @@ -49,7 +49,7 @@ public class ExtractIsoCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = TemplateResponse.class, required = true, description = "the ID of the ISO file") private Long id; - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, description = "the URL to which the ISO would be extracted") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, length = 2048, description = "the URL to which the ISO would be extracted") private String url; @Parameter(name = ApiConstants.ZONE_ID, diff --git a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java index a1cb4780c7..599aac1fd0 100644 --- a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java @@ -78,7 +78,7 @@ public class RegisterIsoCmd extends BaseCmd { description = "the ID of the OS type that best represents the OS of this ISO. If the ISO is bootable this parameter needs to be passed") private Long osTypeId; - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, description = "the URL to where the ISO is currently being hosted") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, length = 2048, description = "the URL to where the ISO is currently being hosted") private String url; @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, diff --git a/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java b/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java index 47a6876d09..97bb187dd5 100644 --- a/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/snapshot/ListSnapshotsCmd.java @@ -48,6 +48,9 @@ public class ListSnapshotsCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = SnapshotResponse.class, description = "lists snapshot by snapshot ID") private Long id; + @Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=SnapshotResponse.class, description="the IDs of the snapshots, mutually exclusive with id", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.INTERVAL_TYPE, type = CommandType.STRING, description = "valid values are HOURLY, DAILY, WEEKLY, and MONTHLY.") private String intervalType; @@ -120,4 +123,8 @@ public void execute() { setResponseObject(response); } + + public List getIds() { + return ids; + } } diff --git a/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java index b8fbb02ad2..4708aff6ff 100644 --- a/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/snapshot/RevertSnapshotCmd.java @@ -36,7 +36,7 @@ import com.cloud.storage.Snapshot; import com.cloud.user.Account; -@APICommand(name = "revertSnapshot", description = "revert a volume snapshot.", responseObject = SnapshotResponse.class, entityType = {Snapshot.class}, +@APICommand(name = "revertSnapshot", description = "This is supposed to revert a volume snapshot. This command is only supported with KVM so far", responseObject = SnapshotResponse.class, entityType = {Snapshot.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class RevertSnapshotCmd extends BaseAsyncCmd { public static final Logger s_logger = Logger.getLogger(RevertSnapshotCmd.class.getName()); diff --git a/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java index c8d6ce338c..59c4abe002 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java @@ -113,6 +113,7 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.URL, type = CommandType.STRING, + length = 2048, description = "Optional, only for baremetal hypervisor. The directory name where template stored on CIFS server") private String url; diff --git a/api/src/org/apache/cloudstack/api/command/user/template/ExtractTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/ExtractTemplateCmd.java index c88b5e334b..48d3e1405a 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/ExtractTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/ExtractTemplateCmd.java @@ -49,7 +49,7 @@ public class ExtractTemplateCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = TemplateResponse.class, required = true, description = "the ID of the template") private Long id; - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, description = "the url to which the ISO would be extracted") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, length = 2048, description = "the url to which the ISO would be extracted") private String url; @Parameter(name = ApiConstants.ZONE_ID, diff --git a/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java index 7a2a15834a..772ca2749e 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/ListTemplatesCmd.java @@ -18,6 +18,7 @@ import org.apache.log4j.Logger; +import java.util.List; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandJobType; import org.apache.cloudstack.api.ApiConstants; @@ -50,6 +51,9 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "the template ID") private Long id; + @Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=TemplateResponse.class, description="the IDs of the templates, mutually exclusive with id", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the template name") private String templateName; @@ -132,4 +136,8 @@ public void execute() { response.setResponseName(getCommandName()); setResponseObject(response); } + + public List getIds() { + return ids; + } } diff --git a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java index 8de30f690e..8ff0b6b449 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java @@ -104,6 +104,7 @@ public class RegisterTemplateCmd extends BaseCmd { @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, + length = 2048, description = "the URL of where the template is hosted. Possible URL include http:// and https://") private String url; diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java index 7769ff8573..da0ce2a2ff 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java @@ -16,25 +16,14 @@ // under the License. package org.apache.cloudstack.api.command.user.vm; -import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenter.NetworkType; -import com.cloud.event.EventTypes; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InsufficientServerCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.network.Network; -import com.cloud.network.Network.IpAddresses; -import com.cloud.offering.DiskOffering; -import com.cloud.offering.ServiceOffering; -import com.cloud.template.VirtualMachineTemplate; -import com.cloud.user.Account; -import com.cloud.uservm.UserVm; -import com.cloud.utils.net.NetUtils; -import com.cloud.vm.VirtualMachine; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ACL; @@ -59,17 +48,23 @@ import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.Network; +import com.cloud.network.Network.IpAddresses; +import com.cloud.uservm.UserVm; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.VirtualMachine; @APICommand(name = "deployVirtualMachine", description = "Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = true) -public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd { +public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityGroupAction { public static final Logger s_logger = Logger.getLogger(DeployVMCmd.class.getName()); private static final String s_name = "deployvirtualmachineresponse"; @@ -257,26 +252,12 @@ public boolean isDisplay() { return displayVm; } - public List getSecurityGroupIdList() { - if (securityGroupNameList != null && securityGroupIdList != null) { - throw new InvalidParameterValueException("securitygroupids parameter is mutually exclusive with securitygroupnames parameter"); - } + public List getSecurityGroupNameList() { + return securityGroupNameList; + } - //transform group names to ids here - if (securityGroupNameList != null) { - List securityGroupIds = new ArrayList(); - for (String groupName : securityGroupNameList) { - Long groupId = _responseGenerator.getSecurityGroupId(groupName, getEntityOwnerId()); - if (groupId == null) { - throw new InvalidParameterValueException("Unable to find group by name " + groupName); - } else { - securityGroupIds.add(groupId); - } - } - return securityGroupIds; - } else { - return securityGroupIdList; - } + public List getSecurityGroupIdList() { + return securityGroupIdList; } public Long getServiceOfferingId() { @@ -328,7 +309,7 @@ public boolean getStartVm() { return startVm == null ? true : startVm; } - private Map getIpToNetworkMap() { + public Map getIpToNetworkMap() { if ((networkIds != null || ipAddress != null || getIp6Address() != null) && ipToNetworkList != null) { throw new InvalidParameterValueException("NetworkIds and ipAddress can't be specified along with ipToNetworkMap parameter"); } @@ -363,6 +344,10 @@ private Map getIpToNetworkMap() { return ipToNetworkMap; } + public String getIpAddress() { + return ipAddress; + } + public String getIp6Address() { if (ip6Address == null) { return null; @@ -392,6 +377,11 @@ public List getAffinityGroupIdList() { } } + public String getKeyboard() { + // TODO Auto-generated method stub + return keyboard; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -478,129 +468,11 @@ public void execute() { } } - // this is an opportunity to verify that parameters that came in via the Details Map are OK - // for example, minIops and maxIops should either both be specified or neither be specified and, - // if specified, minIops should be <= maxIops - private void verifyDetails() { - Map map = getDetails(); - - if (map != null) { - String minIops = (String)map.get("minIops"); - String maxIops = (String)map.get("maxIops"); - - verifyMinAndMaxIops(minIops, maxIops); - - minIops = (String)map.get("minIopsDo"); - maxIops = (String)map.get("maxIopsDo"); - - verifyMinAndMaxIops(minIops, maxIops); - } - } - - private void verifyMinAndMaxIops(String minIops, String maxIops) { - if ((minIops != null && maxIops == null) || (minIops == null && maxIops != null)) { - throw new InvalidParameterValueException("Either 'Min IOPS' and 'Max IOPS' must both be specified or neither be specified."); - } - - long lMinIops; - - try { - if (minIops != null) { - lMinIops = Long.parseLong(minIops); - } - else { - lMinIops = 0; - } - } - catch (NumberFormatException ex) { - throw new InvalidParameterValueException("'Min IOPS' must be a whole number."); - } - - long lMaxIops; - - try { - if (maxIops != null) { - lMaxIops = Long.parseLong(maxIops); - } - else { - lMaxIops = 0; - } - } - catch (NumberFormatException ex) { - throw new InvalidParameterValueException("'Max IOPS' must be a whole number."); - } - - if (lMinIops > lMaxIops) { - throw new InvalidParameterValueException("'Min IOPS' must be less than or equal to 'Max IOPS'."); - } - } @Override public void create() throws ResourceAllocationException { try { - //Verify that all objects exist before passing them to the service - Account owner = _accountService.getActiveAccountById(getEntityOwnerId()); - - verifyDetails(); - - DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Unable to find zone by id=" + zoneId); - } - - ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId); - if (serviceOffering == null) { - throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId); - } - - VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId); - // Make sure a valid template ID was specified - if (template == null) { - throw new InvalidParameterValueException("Unable to find the template " + templateId); - } - - DiskOffering diskOffering = null; - if (diskOfferingId != null) { - diskOffering = _entityMgr.findById(DiskOffering.class, diskOfferingId); - if (diskOffering == null) { - throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId); - } - } - - if (!zone.isLocalStorageEnabled()) { - if (serviceOffering.getUseLocalStorage()) { - throw new InvalidParameterValueException("Zone is not configured to use local storage but service offering " + serviceOffering.getName() + " uses it"); - } - if (diskOffering != null && diskOffering.getUseLocalStorage()) { - throw new InvalidParameterValueException("Zone is not configured to use local storage but disk offering " + diskOffering.getName() + " uses it"); - } - } - - UserVm vm = null; - IpAddresses addrs = new IpAddresses(ipAddress, getIp6Address()); - if (zone.getNetworkType() == NetworkType.Basic) { - if (getNetworkIds() != null) { - throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); - } else { - vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name, displayName, diskOfferingId, - size, group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList(), - getDetails(), getCustomId()); - } - } else { - if (zone.isSecurityGroupEnabled()) { - vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(), owner, name, - displayName, diskOfferingId, size, group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, - getAffinityGroupIdList(), getDetails(), getCustomId()); - - } else { - if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) { - throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); - } - vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName, diskOfferingId, size, group, - getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList(), getDetails(), - getCustomId()); - } - } + UserVm vm = _userVmService.createVirtualMachine(this); if (vm != null) { setEntityId(vm.getId()); diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java index e4c2f7d633..661100b533 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/ScaleVMCmd.java @@ -16,6 +16,9 @@ // under the License. package org.apache.cloudstack.api.command.user.vm; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -78,8 +81,22 @@ public Long getServiceOfferingId() { return serviceOfferingId; } + //instead of reading a map directly we are using collections. + //it is because details.values() cannot be cast to a map. + //it gives a exception public Map getDetails() { - return details; + Map customparameterMap = new HashMap(); + if (details != null && details.size() != 0) { + Collection parameterCollection = details.values(); + Iterator iter = parameterCollection.iterator(); + while (iter.hasNext()) { + HashMap value = (HashMap)iter.next(); + for (String key : value.keySet()) { + customparameterMap.put(key, value.get(key)); + } + } + } + return customparameterMap; } ///////////////////////////////////////////////////// @@ -142,4 +159,4 @@ public void execute() { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to scale vm"); } } -} +} \ No newline at end of file diff --git a/api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java b/api/src/org/apache/cloudstack/api/command/user/vm/SecurityGroupAction.java similarity index 75% rename from api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java rename to api/src/org/apache/cloudstack/api/command/user/vm/SecurityGroupAction.java index 60d74f6c86..87a829e467 100644 --- a/api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/SecurityGroupAction.java @@ -14,13 +14,12 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package com.cloud.agent.api.storage; +package org.apache.cloudstack.api.command.user.vm; -import com.cloud.agent.api.Answer; - -public class CreateVolumeOVAAnswer extends Answer { - public CreateVolumeOVAAnswer(CreateVolumeOVACommand cmd, boolean result, String details) { - super(cmd, result, details); - } +import java.util.List; +public interface SecurityGroupAction { + List getSecurityGroupIdList(); + List getSecurityGroupNameList(); + long getEntityOwnerId(); } diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java index 458122d6d7..4508f7e471 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java @@ -16,7 +16,9 @@ // under the License. package org.apache.cloudstack.api.command.user.vm; -import org.apache.log4j.Logger; +import java.util.Collection; +import java.util.List; +import java.util.Map; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; @@ -29,8 +31,10 @@ import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.GuestOSResponse; +import org.apache.cloudstack.api.response.SecurityGroupResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; @@ -38,14 +42,11 @@ import com.cloud.uservm.UserVm; import com.cloud.vm.VirtualMachine; -import java.util.Collection; -import java.util.Map; - @APICommand(name = "updateVirtualMachine", description="Updates properties of a virtual machine. The VM has to be stopped and restarted for the " + "new properties to take effect. UpdateVirtualMachine does not first check whether the VM is stopped. " + "Therefore, stop the VM manually before issuing this call.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = true) -public class UpdateVMCmd extends BaseCustomIdCmd { +public class UpdateVMCmd extends BaseCustomIdCmd implements SecurityGroupAction { public static final Logger s_logger = Logger.getLogger(UpdateVMCmd.class.getName()); private static final String s_name = "updatevirtualmachineresponse"; @@ -96,6 +97,25 @@ public class UpdateVMCmd extends BaseCustomIdCmd { @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, description = "Details in key/value pairs.") protected Map details; + @ACL + @Parameter(name = ApiConstants.SECURITY_GROUP_IDS, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = SecurityGroupResponse.class, + description = "list of security group ids to be applied on the virtual machine.") + private List securityGroupIdList; + + @ACL + @Parameter(name = ApiConstants.SECURITY_GROUP_NAMES, + type = CommandType.LIST, + collectionType = CommandType.STRING, + entityType = SecurityGroupResponse.class, + description = "comma separated list of security groups names that going to be applied to the virtual machine. " + + "Should be passed only when vm is created from a zone with Basic Network support. " + + "Mutually exclusive with securitygroupids parameter" + ) + private List securityGroupNameList; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -145,7 +165,15 @@ public Map getDetails() { return (Map) (paramsCollection.toArray())[0]; } -///////////////////////////////////////////////////// + public List getSecurityGroupIdList() { + return securityGroupIdList; + } + + public List getSecurityGroupNameList() { + return securityGroupNameList; + } + + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java index bc9c1c8596..b10555556b 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpgradeVMCmd.java @@ -16,6 +16,9 @@ // under the License. package org.apache.cloudstack.api.command.user.vm; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import org.apache.log4j.Logger; @@ -77,7 +80,18 @@ public Long getServiceOfferingId() { } public Map getDetails() { - return details; + Map customparameterMap = new HashMap(); + if (details != null && details.size() != 0) { + Collection parameterCollection = details.values(); + Iterator iter = parameterCollection.iterator(); + while (iter.hasNext()) { + HashMap value = (HashMap)iter.next(); + for (String key : value.keySet()) { + customparameterMap.put(key, value.get(key)); + } + } + } + return customparameterMap; } ///////////////////////////////////////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java index c9bc2430d2..ad5126e468 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vmsnapshot/ListVMSnapshotCmd.java @@ -39,6 +39,9 @@ public class ListVMSnapshotCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.VM_SNAPSHOT_ID, type = CommandType.UUID, entityType = VMSnapshotResponse.class, description = "The ID of the VM snapshot") private Long id; + @Parameter(name=ApiConstants.VM_SNAPSHOT_IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=VMSnapshotResponse.class, description="the IDs of the vm snapshots, mutually exclusive with vmsnapshotid", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.STATE, type = CommandType.STRING, description = "state of the virtual machine snapshot") private String state; @@ -84,4 +87,8 @@ public String getCommandName() { return s_name; } + public List getIds() { + return ids; + } + } diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ExtractVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ExtractVolumeCmd.java index 049396c370..fc536d3f03 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/ExtractVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ExtractVolumeCmd.java @@ -54,7 +54,7 @@ public class ExtractVolumeCmd extends BaseAsyncCmd { required=true, description="the ID of the volume") private Long id; - @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, description = "the url to which the volume would be extracted") + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = false, length = 2048, description = "the url to which the volume would be extracted") private String url; @Parameter(name = ApiConstants.ZONE_ID, diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java index cc218f7197..059def7c16 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java @@ -18,6 +18,7 @@ import org.apache.log4j.Logger; +import java.util.List; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandJobType; @@ -53,6 +54,9 @@ public class ListVolumesCmd extends BaseListTaggedResourcesCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = VolumeResponse.class, description = "the ID of the disk volume") private Long id; + @Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=VolumeResponse.class, description="the IDs of the volumes, mutually exclusive with id", since = "4.9") + private List ids; + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name of the disk volume") private String volumeName; @@ -153,4 +157,8 @@ public void execute() { response.setResponseName(getCommandName()); setResponseObject(response); } + + public List getIds() { + return ids; + } } diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java index c360c146d6..2174961675 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java @@ -62,6 +62,7 @@ public class UploadVolumeCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, + length = 2048, description = "the URL of where the volume is hosted. Possible URL include http:// and https://") private String url; diff --git a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java index 0fb496cc04..e1131092f0 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpn/CreateVpnCustomerGatewayCmd.java @@ -51,7 +51,7 @@ public class CreateVpnCustomerGatewayCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.STRING, required = true, description = "guest cidr list of the customer gateway") private String peerCidrList; - @Parameter(name = ApiConstants.IPSEC_PSK, type = CommandType.STRING, required = true, description = "IPsec Preshared-Key of the customer gateway") + @Parameter(name = ApiConstants.IPSEC_PSK, type = CommandType.STRING, required = true, description = "IPsec Preshared-Key of the customer gateway. Cannot contain newline or double quotes.") private String ipsecPsk; @Parameter(name = ApiConstants.IKE_POLICY, type = CommandType.STRING, required = true, description = "IKE policy of the customer gateway") diff --git a/api/src/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java index 3b188b85ca..bb5914111b 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpn/UpdateVpnCustomerGatewayCmd.java @@ -57,7 +57,7 @@ public class UpdateVpnCustomerGatewayCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.STRING, required = true, description = "guest cidr of the customer gateway") private String guestCidrList; - @Parameter(name = ApiConstants.IPSEC_PSK, type = CommandType.STRING, required = true, description = "IPsec Preshared-Key of the customer gateway") + @Parameter(name = ApiConstants.IPSEC_PSK, type = CommandType.STRING, required = true, description = "IPsec Preshared-Key of the customer gateway. Cannot contain newline or double quotes.") private String ipsecPsk; @Parameter(name = ApiConstants.IKE_POLICY, type = CommandType.STRING, required = true, description = "IKE policy of the customer gateway") diff --git a/api/src/org/apache/cloudstack/api/response/AccountResponse.java b/api/src/org/apache/cloudstack/api/response/AccountResponse.java index 2e50c51858..7b48a1ea8a 100644 --- a/api/src/org/apache/cloudstack/api/response/AccountResponse.java +++ b/api/src/org/apache/cloudstack/api/response/AccountResponse.java @@ -21,6 +21,7 @@ import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; @@ -43,6 +44,18 @@ public class AccountResponse extends BaseResponse implements ResourceLimitAndCou @Param(description = "account type (admin, domain-admin, user)") private Short accountType; + @SerializedName(ApiConstants.ROLE_ID) + @Param(description = "the ID of the role") + private String roleId; + + @SerializedName(ApiConstants.ROLE_TYPE) + @Param(description = "the type of the role (Admin, ResourceAdmin, DomainAdmin, User)") + private String roleType; + + @SerializedName(ApiConstants.ROLE_NAME) + @Param(description = "the name of the role") + private String roleName; + @SerializedName(ApiConstants.DOMAIN_ID) @Param(description = "id of the Domain the account belongs too") private String domainId; @@ -260,6 +273,20 @@ public void setAccountType(Short accountType) { this.accountType = accountType; } + public void setRoleId(String roleId) { + this.roleId = roleId; + } + + public void setRoleType(RoleType roleType) { + if (roleType != null) { + this.roleType = roleType.name(); + } + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + public void setDomainId(String domainId) { this.domainId = domainId; } diff --git a/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java b/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java deleted file mode 100644 index 0725d40983..0000000000 --- a/api/src/org/apache/cloudstack/api/response/AddIpToVmNicResponse.java +++ /dev/null @@ -1,88 +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.api.response; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; - -import com.cloud.serializer.Param; - -@SuppressWarnings("unused") -public class AddIpToVmNicResponse extends BaseResponse { - @SerializedName(ApiConstants.ID) - @Param(description = "the ID of the secondary private IP addr") - private Long id; - - @SerializedName(ApiConstants.IP_ADDRESS) - @Param(description = "Secondary IP address") - private String ipAddr; - - @SerializedName(ApiConstants.NIC_ID) - @Param(description = "the ID of the nic") - private Long nicId; - - @SerializedName(ApiConstants.NETWORK_ID) - @Param(description = "the ID of the network") - private Long nwId; - - @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) - @Param(description = "the ID of the vm") - private Long vmId; - - public Long getId() { - return id; - } - - public String getIpAddr() { - return ipAddr; - } - - public void setIpAddr(String ipAddr) { - this.ipAddr = ipAddr; - } - - public Long getNicId() { - return nicId; - } - - public void setNicId(Long nicId) { - this.nicId = nicId; - } - - public Long getNwId() { - return nwId; - } - - public void setNwId(Long nwId) { - this.nwId = nwId; - } - - public Long getVmId() { - return vmId; - } - - public void setVmId(Long vmId) { - this.vmId = vmId; - } - - public Long setId(Long id) { - return id; - } - -} diff --git a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java index 623a0a231f..bcdad468fa 100644 --- a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java +++ b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java @@ -28,6 +28,10 @@ public class CapabilitiesResponse extends BaseResponse { @Param(description = "true if security groups support is enabled, false otherwise") private boolean securityGroupsEnabled; + @SerializedName("dynamicrolesenabled") + @Param(description = "true if dynamic role-based api checker is enabled, false otherwise") + private boolean dynamicRolesEnabled; + @SerializedName("cloudstackversion") @Param(description = "version of the cloud stack") private String cloudStackVersion; @@ -84,6 +88,10 @@ public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) { this.securityGroupsEnabled = securityGroupsEnabled; } + public void setDynamicRolesEnabled(boolean dynamicRolesEnabled) { + this.dynamicRolesEnabled = dynamicRolesEnabled; + } + public void setCloudStackVersion(String cloudStackVersion) { this.cloudStackVersion = cloudStackVersion; } diff --git a/api/src/org/apache/cloudstack/api/response/ClusterResponse.java b/api/src/org/apache/cloudstack/api/response/ClusterResponse.java index df01e09595..754baa2677 100644 --- a/api/src/org/apache/cloudstack/api/response/ClusterResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ClusterResponse.java @@ -17,7 +17,9 @@ package org.apache.cloudstack.api.response; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import com.google.gson.annotations.SerializedName; @@ -86,6 +88,10 @@ public class ClusterResponse extends BaseResponse { @Param(description = "Ovm3 VIP to use for pooling and/or clustering") private String ovm3vip; + @SerializedName(ApiConstants.RESOURCE_DETAILS) + @Param(description = "Meta data associated with the zone (key/value pairs)") + private Map resourceDetails; + public String getId() { return id; } @@ -197,4 +203,11 @@ public void setOvm3Vip(String ovm3vip) { public String getOvm3Vip() { return ovm3vip; } + + public void setResourceDetails(Map details) { + if (details == null) { + return; + } + this.resourceDetails = new HashMap<>(details); + } } diff --git a/api/src/org/apache/cloudstack/api/response/HostResponse.java b/api/src/org/apache/cloudstack/api/response/HostResponse.java index c6697fbe30..ab9c8c3767 100644 --- a/api/src/org/apache/cloudstack/api/response/HostResponse.java +++ b/api/src/org/apache/cloudstack/api/response/HostResponse.java @@ -24,6 +24,7 @@ import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; import java.util.Date; import java.util.HashMap; @@ -200,6 +201,10 @@ public class HostResponse extends BaseResponse { @Param(description = "true if this host is suitable(has enough capacity and satisfies all conditions like hosttags, max guests vm limit etc) to migrate a VM to it , false otherwise") private Boolean suitableForMigration; + @SerializedName("outofbandmanagement") + @Param(description = "the host out-of-band management information") + private OutOfBandManagementResponse outOfBandManagementResponse; + @SerializedName("resourcestate") @Param(description = "the resource state of the host") private String resourceState; @@ -403,6 +408,14 @@ public void setSuitableForMigration(Boolean suitableForMigration) { this.suitableForMigration = suitableForMigration; } + public OutOfBandManagementResponse getOutOfBandManagementResponse() { + return outOfBandManagementResponse; + } + + public void setOutOfBandManagementResponse(final OutOfBandManagement outOfBandManagementConfig) { + this.outOfBandManagementResponse = new OutOfBandManagementResponse(outOfBandManagementConfig); + } + public String getResourceState() { return resourceState; } diff --git a/api/src/org/apache/cloudstack/api/response/OutOfBandManagementResponse.java b/api/src/org/apache/cloudstack/api/response/OutOfBandManagementResponse.java new file mode 100644 index 0000000000..19594d2950 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/OutOfBandManagementResponse.java @@ -0,0 +1,189 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; + +import com.cloud.host.Host; +import com.cloud.serializer.Param; +import com.google.common.base.Strings; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; + +@EntityReference(value = Host.class) +public class OutOfBandManagementResponse extends BaseResponse { + @SerializedName(ApiConstants.HOST_ID) + @Param(description = "the ID of the host") + private String id; + + @SerializedName(ApiConstants.POWER_STATE) + @Param(description = "the out-of-band management interface powerState of the host") + private OutOfBandManagement.PowerState powerState; + + @SerializedName(ApiConstants.ENABLED) + @Param(description = "true if out-of-band management is enabled for the host") + private Boolean enabled; + + @SerializedName(ApiConstants.DRIVER) + @Param(description = "the out-of-band management driver for the host") + private String driver; + + @SerializedName(ApiConstants.ADDRESS) + @Param(description = "the out-of-band management interface address") + private String ipAddress; + + @SerializedName(ApiConstants.PORT) + @Param(description = "the out-of-band management interface port") + private String port; + + @SerializedName(ApiConstants.USERNAME) + @Param(description = "the out-of-band management interface username") + private String username; + + @SerializedName(ApiConstants.PASSWORD) + @Param(description = "the out-of-band management interface password") + private String password; + + @SerializedName(ApiConstants.ACTION) + @Param(description = "the out-of-band management action (if issued)") + private String outOfBandManagementAction; + + @SerializedName(ApiConstants.DESCRIPTION) + @Param(description = "the operation result description") + private String resultDescription; + + @SerializedName(ApiConstants.STATUS) + @Param(description = "the operation result") + private Boolean success; + + public OutOfBandManagementResponse() { + super("outofbandmanagement"); + } + + public OutOfBandManagementResponse(final OutOfBandManagement outOfBandManagementConfig) { + this(); + if (outOfBandManagementConfig == null) { + this.setEnabled(false); + this.setPowerState(OutOfBandManagement.PowerState.Disabled); + return; + } + this.setEnabled(outOfBandManagementConfig.isEnabled()); + if (outOfBandManagementConfig.getPowerState() != null) { + this.setPowerState(outOfBandManagementConfig.getPowerState()); + } else { + this.setPowerState(OutOfBandManagement.PowerState.Unknown); + } + this.setDriver(outOfBandManagementConfig.getDriver()); + this.setIpAddress(outOfBandManagementConfig.getAddress()); + if (outOfBandManagementConfig.getPort() != null) { + this.setPort(String.valueOf(outOfBandManagementConfig.getPort())); + } + this.setUsername(outOfBandManagementConfig.getUsername()); + if (!Strings.isNullOrEmpty(outOfBandManagementConfig.getPassword())) { + this.setPassword(outOfBandManagementConfig.getPassword().substring(0, 1) + "****"); + } + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public OutOfBandManagement.PowerState getPowerState() { + return powerState; + } + + public void setPowerState(OutOfBandManagement.PowerState powerState) { + this.powerState = powerState; + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public String getDriver() { + return driver; + } + + public void setDriver(String driver) { + this.driver = driver; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getOutOfBandManagementAction() { + return outOfBandManagementAction; + } + + public void setOutOfBandManagementAction(String outOfBandManagementAction) { + this.outOfBandManagementAction = outOfBandManagementAction; + } + + public String getResultDescription() { + return resultDescription; + } + + public void setResultDescription(String resultDescription) { + this.resultDescription = resultDescription; + } + + public Boolean getSuccess() { + return success; + } + + public void setSuccess(Boolean success) { + this.success = success; + } +} diff --git a/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java b/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java index ae61347b48..4432556053 100644 --- a/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ResourceTagResponse.java @@ -114,6 +114,10 @@ public String getKey() { return this.key; } + public String getValue() { + return this.value; + } + @Override public int hashCode() { final int prime = 31; diff --git a/api/src/org/apache/cloudstack/api/response/RolePermissionResponse.java b/api/src/org/apache/cloudstack/api/response/RolePermissionResponse.java new file mode 100644 index 0000000000..ac1c5298c1 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/RolePermissionResponse.java @@ -0,0 +1,101 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.Rule; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +@EntityReference(value = RolePermission.class) +public class RolePermissionResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) + @Param(description = "the ID of the role permission") + private String id; + + @SerializedName(ApiConstants.ROLE_ID) + @Param(description = "the ID of the role to which the role permission belongs") + private String roleId; + + @SerializedName(ApiConstants.ROLE_NAME) + @Param(description = "the name of the role to which the role permission belongs") + private String roleName; + + @SerializedName(ApiConstants.RULE) + @Param(description = "the api name or wildcard rule") + private String rule; + + @SerializedName(ApiConstants.PERMISSION) + @Param(description = "the permission type of the api name or wildcard rule, allow/deny") + private String rulePermission; + + @SerializedName(ApiConstants.DESCRIPTION) + @Param(description = "the description of the role permission") + private String ruleDescription; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getRoleId() { + return roleId; + } + + public void setRoleId(String roleId) { + this.roleId = roleId; + } + + public String getRoleName() { + return roleName; + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + + public String getRule() { + return rule; + } + + public void setRule(Rule rule) { + if (rule != null) { + this.rule = rule.getRuleString(); + } + } + + public String getRulePermission() { + return rulePermission; + } + + public void setRulePermission(RolePermission.Permission rulePermission) { + if (rulePermission != null) { + this.rulePermission = rulePermission.name().toLowerCase(); + } + } + + public void setDescription(String description) { + this.ruleDescription = description; + } +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/response/NicDetailResponse.java b/api/src/org/apache/cloudstack/api/response/RoleResponse.java similarity index 55% rename from api/src/org/apache/cloudstack/api/response/NicDetailResponse.java rename to api/src/org/apache/cloudstack/api/response/RoleResponse.java index 152d101d31..fd4bf28e61 100644 --- a/api/src/org/apache/cloudstack/api/response/NicDetailResponse.java +++ b/api/src/org/apache/cloudstack/api/response/RoleResponse.java @@ -14,63 +14,50 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. + package org.apache.cloudstack.api.response; +import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; - +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; -import com.cloud.serializer.Param; - -@SuppressWarnings("unused") -public class NicDetailResponse extends BaseResponse { +@EntityReference(value = Role.class) +public class RoleResponse extends BaseResponse { @SerializedName(ApiConstants.ID) - @Param(description = "ID of the nic") + @Param(description = "the ID of the role") private String id; @SerializedName(ApiConstants.NAME) - @Param(description = "name of the nic detail") - private String name; - - @SerializedName(ApiConstants.VALUE) - @Param(description = "value of the nic detail") - private String value; + @Param(description = "the name of the role") + private String roleName; - @SerializedName(ApiConstants.DISPLAY_NIC) - @Param(description = "an optional field whether to the display the nic to the end user or not.") - private Boolean displayNic; + @SerializedName(ApiConstants.TYPE) + @Param(description = "the type of the role") + private String roleType; - public String getId() { - return id; - } + @SerializedName(ApiConstants.DESCRIPTION) + @Param(description = "the description of the role") + private String roleDescription; public void setId(String id) { this.id = id; } - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public String getName() { - - return name; - } - - public void setName(String name) { - this.name = name; + public void setRoleName(String roleName) { + this.roleName = roleName; } - public Boolean getDisplayNic() { - return displayNic; + public void setRoleType(RoleType roleType) { + if (roleType != null) { + this.roleType = roleType.name(); + } } - public void setDisplayNic(Boolean displayNic) { - this.displayNic = displayNic; + public void setDescription(String description) { + this.roleDescription = description; } } diff --git a/api/src/org/apache/cloudstack/api/response/TemplateResponse.java b/api/src/org/apache/cloudstack/api/response/TemplateResponse.java index 3e21043e33..237f181d4d 100644 --- a/api/src/org/apache/cloudstack/api/response/TemplateResponse.java +++ b/api/src/org/apache/cloudstack/api/response/TemplateResponse.java @@ -21,19 +21,18 @@ import java.util.Map; import java.util.Set; -import com.google.gson.annotations.SerializedName; - import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.BaseResponseWithTagInformation; import org.apache.cloudstack.api.EntityReference; import com.cloud.serializer.Param; import com.cloud.storage.Storage.ImageFormat; import com.cloud.template.VirtualMachineTemplate; +import com.google.gson.annotations.SerializedName; @EntityReference(value = VirtualMachineTemplate.class) @SuppressWarnings("unused") -public class TemplateResponse extends BaseResponse implements ControlledViewEntityResponse { +public class TemplateResponse extends BaseResponseWithTagInformation implements ControlledViewEntityResponse { @SerializedName(ApiConstants.ID) @Param(description = "the template ID") private String id; @@ -170,15 +169,6 @@ public class TemplateResponse extends BaseResponse implements ControlledViewEnti @Param(description = "additional key/value details tied with template") private Map details; - // To avoid breaking backwards compatibility, we still treat a template at different zones as different templates, so not embedding - // template_zone information in this TemplateZoneResponse set. - // @SerializedName("zones") @Param(description="list of zones associated with tempate", responseObject = TemplateZoneResponse.class) - // private Set zones; - - @SerializedName(ApiConstants.TAGS) - @Param(description = "the list of resource tags associated with tempate", responseObject = ResourceTagResponse.class) - private Set tags; - @SerializedName(ApiConstants.SSHKEY_ENABLED) @Param(description = "true if template is sshkey enabled, false otherwise") private Boolean sshKeyEnabled; @@ -188,7 +178,6 @@ public class TemplateResponse extends BaseResponse implements ControlledViewEnti private Boolean isDynamicallyScalable; public TemplateResponse() { - // zones = new LinkedHashSet(); tags = new LinkedHashSet(); } @@ -346,10 +335,6 @@ public void setTags(Set tags) { this.tags = tags; } - public void addTag(ResourceTagResponse tag) { - this.tags.add(tag); - } - public void setSshKeyEnabled(boolean sshKeyEnabled) { this.sshKeyEnabled = sshKeyEnabled; } @@ -361,4 +346,5 @@ public void setDynamicallyScalable(boolean isDynamicallyScalable) { public String getZoneId() { return zoneId; } + } diff --git a/api/src/org/apache/cloudstack/api/response/TemplateZoneResponse.java b/api/src/org/apache/cloudstack/api/response/TemplateZoneResponse.java deleted file mode 100644 index f2e7725de0..0000000000 --- a/api/src/org/apache/cloudstack/api/response/TemplateZoneResponse.java +++ /dev/null @@ -1,134 +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.api.response; - -import java.util.Date; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; - -import com.cloud.serializer.Param; - -public class TemplateZoneResponse extends BaseResponse { - @SerializedName(ApiConstants.ZONE_ID) - @Param(description = "the ID of the zone for the template") - private String zoneId; - - @SerializedName(ApiConstants.ZONE_NAME) - @Param(description = "the name of the zone for the template") - private String zoneName; - - @SerializedName(ApiConstants.STATUS) - @Param(description = "the status of the template") - private String status; - - @SerializedName(ApiConstants.IS_READY) - // propName="ready" (FIXME: this used to be part of Param annotation, do we need it?) - @Param(description = "true if the template is ready to be deployed from, false otherwise.") - private boolean isReady; - - @SerializedName(ApiConstants.CREATED) - @Param(description = "the date this template was created") - private Date created; - - public TemplateZoneResponse() { - super(); - } - - public TemplateZoneResponse(String zoneId, String zoneName) { - super(); - this.zoneId = zoneId; - this.zoneName = zoneName; - } - - public String getZoneId() { - return zoneId; - } - - public void setZoneId(String zoneId) { - this.zoneId = zoneId; - } - - public String getZoneName() { - return zoneName; - } - - public void setZoneName(String zoneName) { - this.zoneName = zoneName; - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public boolean isReady() { - return isReady; - } - - public void setReady(boolean isReady) { - this.isReady = isReady; - } - - public Date getCreated() { - return created; - } - - public void setCreated(Date created) { - this.created = created; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - String oid = this.getZoneId(); - result = prime * result + ((oid == null) ? 0 : oid.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - TemplateZoneResponse other = (TemplateZoneResponse)obj; - String oid = this.getZoneId(); - if (oid == null) { - if (other.getZoneId() != null) { - return false; - } - } else if (!oid.equals(other.getZoneId())) { - return false; - } else if (this.getZoneName().equals(other.getZoneName())) { - return false; - } - return true; - } - -} diff --git a/api/src/org/apache/cloudstack/api/response/UpgradeVmResponse.java b/api/src/org/apache/cloudstack/api/response/UpgradeVmResponse.java deleted file mode 100644 index c42b64bc72..0000000000 --- a/api/src/org/apache/cloudstack/api/response/UpgradeVmResponse.java +++ /dev/null @@ -1,323 +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.api.response; - -import java.util.Date; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; - -import com.cloud.serializer.Param; - -public class UpgradeVmResponse extends BaseResponse { - @SerializedName("id") - private String id; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Date getCreated() { - return created; - } - - public void setCreated(Date created) { - this.created = created; - } - - public String getIpAddress() { - return ipAddress; - } - - public void setIpAddress(String ipAddress) { - this.ipAddress = ipAddress; - } - - public String getState() { - return state; - } - - public void setState(String state) { - this.state = state; - } - - public String getAccount() { - return account; - } - - public void setAccount(String account) { - this.account = account; - } - - public String getDomainId() { - return domainId; - } - - public void setDomainId(String domainId) { - this.domainId = domainId; - } - - public String getDomain() { - return domain; - } - - public void setDomain(String domain) { - this.domain = domain; - } - - public boolean isHaEnable() { - return haEnable; - } - - public void setHaEnable(boolean haEnable) { - this.haEnable = haEnable; - } - - public String getZoneId() { - return zoneId; - } - - public void setZoneId(String zoneId) { - this.zoneId = zoneId; - } - - public String getDisplayName() { - return displayName; - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - public String getZoneName() { - return zoneName; - } - - public void setZoneName(String zoneName) { - this.zoneName = zoneName; - } - - public String getHostId() { - return hostId; - } - - public void setHostId(String hostId) { - this.hostId = hostId; - } - - public String getHostName() { - return hostName; - } - - public void setHostName(String hostName) { - this.hostName = hostName; - } - - public String getTemplateId() { - return templateId; - } - - public void setTemplateId(String templateId) { - this.templateId = templateId; - } - - public String getTemplateName() { - return templateName; - } - - public void setTemplateName(String templateName) { - this.templateName = templateName; - } - - public String getTemplateDisplayText() { - return templateDisplayText; - } - - public void setTemplateDisplayText(String templateDisplayText) { - this.templateDisplayText = templateDisplayText; - } - - public boolean isPasswordEnabled() { - return passwordEnabled; - } - - public void setPasswordEnabled(boolean passwordEnabled) { - this.passwordEnabled = passwordEnabled; - } - - public String getServiceOfferingId() { - return serviceOfferingId; - } - - public void setServiceOfferingId(String serviceOfferingId) { - this.serviceOfferingId = serviceOfferingId; - } - - public String getServiceOfferingName() { - return serviceOfferingName; - } - - public void setServiceOfferingName(String serviceOfferingName) { - this.serviceOfferingName = serviceOfferingName; - } - - public long getCpuSpeed() { - return cpuSpeed; - } - - public void setCpuSpeed(long cpuSpeed) { - this.cpuSpeed = cpuSpeed; - } - - public long getMemory() { - return memory; - } - - public void setMemory(long memory) { - this.memory = memory; - } - - public long getCpuUsed() { - return cpuUsed; - } - - public void setCpuUsed(long cpuUsed) { - this.cpuUsed = cpuUsed; - } - - public long getNetworkKbsRead() { - return networkKbsRead; - } - - public void setNetworkKbsRead(long networkKbsRead) { - this.networkKbsRead = networkKbsRead; - } - - public long getNetworkKbsWrite() { - return networkKbsWrite; - } - - public void setNetworkKbsWrite(long networkKbsWrite) { - this.networkKbsWrite = networkKbsWrite; - } - - public String isId() { - return id; - } - - @SerializedName("name") - @Param(description = "the ID of the virtual machine") - private String name; - - @SerializedName("created") - @Param(description = "the date when this virtual machine was created") - private Date created; - - @SerializedName("ipaddress") - @Param(description = "the ip address of the virtual machine") - private String ipAddress; - - @SerializedName("state") - @Param(description = "the state of the virtual machine") - private String state; - - @SerializedName("account") - @Param(description = "the account associated with the virtual machine") - private String account; - - @SerializedName("domainid") - @Param(description = "the ID of the domain in which the virtual machine exists") - private String domainId; - - @SerializedName("domain") - @Param(description = "the name of the domain in which the virtual machine exists") - private String domain; - - @SerializedName("haenable") - @Param(description = "true if high-availability is enabled, false otherwise") - private boolean haEnable; - - @SerializedName("zoneid") - @Param(description = "the ID of the availablility zone for the virtual machine") - private String zoneId; - - @SerializedName("displayname") - @Param(description = "user generated name. The name of the virtual machine is returned if no displayname exists.") - private String displayName; - - @SerializedName(ApiConstants.ZONE_NAME) - @Param(description = "the name of the availability zone for the virtual machine") - private String zoneName; - - @SerializedName("hostid") - @Param(description = "the ID of the host for the virtual machine") - private String hostId; - - @SerializedName("hostname") - @Param(description = "the name of the host for the virtual machine") - private String hostName; - - @SerializedName("templateid") - @Param(description = "the ID of the template for the virtual machine. A -1 is returned if the virtual machine was created from an ISO file.") - private String templateId; - - @SerializedName("templatename") - @Param(description = "the name of the template for the virtual machine") - private String templateName; - - @SerializedName("templatedisplaytext") - @Param(description = " an alternate display text of the template for the virtual machine") - private String templateDisplayText; - - @SerializedName("passwordenabled") - @Param(description = "true if the password rest feature is enabled, false otherwise") - private boolean passwordEnabled; - - @SerializedName("serviceofferingid") - @Param(description = "the ID of the service offering of the virtual machine") - private String serviceOfferingId; - - @SerializedName("serviceofferingname") - @Param(description = "the name of the service offering of the virtual machine") - private String serviceOfferingName; - - @SerializedName("cpunumber") - @Param(description = "the number of cpu this virtual machine is running with") - private long cpuSpeed; - - @SerializedName("memory") - @Param(description = "the memory allocated for the virtual machine") - private long memory; - - @SerializedName("cpuused") - @Param(description = "the amount of the vm's CPU currently used") - private long cpuUsed; - - @SerializedName("networkkbsread") - @Param(description = "the incoming network traffic on the vm") - private long networkKbsRead; - - @SerializedName("networkkbswrite") - @Param(description = "the outgoing network traffic on the host") - private long networkKbsWrite; -} diff --git a/api/src/org/apache/cloudstack/api/response/UserResponse.java b/api/src/org/apache/cloudstack/api/response/UserResponse.java index 36611ae738..cc986b38a1 100644 --- a/api/src/org/apache/cloudstack/api/response/UserResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserResponse.java @@ -20,6 +20,7 @@ import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; @@ -65,6 +66,18 @@ public class UserResponse extends BaseResponse { @Param(description = "the account type of the user") private Short accountType; + @SerializedName(ApiConstants.ROLE_ID) + @Param(description = "the ID of the role") + private String roleId; + + @SerializedName(ApiConstants.ROLE_TYPE) + @Param(description = "the type of the role") + private String roleType; + + @SerializedName(ApiConstants.ROLE_NAME) + @Param(description = "the name of the role") + private String roleName; + @SerializedName("domainid") @Param(description = "the domain ID of the user") private String domainId; @@ -174,6 +187,20 @@ public void setAccountType(Short accountType) { this.accountType = accountType; } + public void setRoleId(String roleId) { + this.roleId = roleId; + } + + public void setRoleType(RoleType roleType) { + if (roleType != null) { + this.roleType = roleType.name(); + } + } + + public void setRoleName(String roleName) { + this.roleName = roleName; + } + public String getDomainId() { return domainId; } diff --git a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java index e8d1a9ed89..b681d4f70d 100644 --- a/api/src/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserVmResponse.java @@ -24,7 +24,7 @@ import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.BaseResponseWithTagInformation; import org.apache.cloudstack.api.EntityReference; import com.cloud.network.router.VirtualRouter; @@ -35,7 +35,7 @@ @SuppressWarnings("unused") @EntityReference(value = {VirtualMachine.class, UserVm.class, VirtualRouter.class}) -public class UserVmResponse extends BaseResponse implements ControlledEntityResponse { +public class UserVmResponse extends BaseResponseWithTagInformation implements ControlledEntityResponse { @SerializedName(ApiConstants.ID) @Param(description = "the ID of the virtual machine") private String id; @@ -196,6 +196,18 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp @Param(description = "the write (bytes) of disk on the vm") private Long diskKbsWrite; + @SerializedName("memorykbs") + @Param(description = "the memory used by the vm") + private Long memoryKBs; + + @SerializedName("memoryintfreekbs") + @Param(description = "the internal memory thats free in vm") + private Long memoryIntFreeKBs; + + @SerializedName("memorytargetkbs") + @Param(description = "the target memory in vm") + private Long memoryTargetKBs; + @SerializedName("diskioread") @Param(description = "the read (io) of disk on the vm") private Long diskIORead; @@ -244,10 +256,6 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp @Param(description = "instance name of the user vm; this parameter is returned to the ROOT admin only", since = "3.0.1") private String instanceName; - @SerializedName(ApiConstants.TAGS) - @Param(description = "the list of resource tags associated with vm", responseObject = ResourceTagResponse.class) - private Set tags; - transient Set tagIds; @SerializedName(ApiConstants.DETAILS) @@ -466,6 +474,18 @@ public Long getDiskKbsWrite() { return diskKbsWrite; } + public Long getMemoryKBs() { + return memoryKBs; + } + + public Long getMemoryIntFreeKBs() { + return memoryIntFreeKBs; + } + + public Long getMemoryTargetKBs() { + return memoryTargetKBs; + } + public Long getDiskIORead() { return diskIORead; } @@ -514,10 +534,6 @@ public String getInstanceName() { return instanceName; } - public Set getTags() { - return tags; - } - public String getKeyPairName() { return keyPairName; } @@ -645,6 +661,18 @@ public void setDiskIORead(Long diskIORead) { this.diskIORead = diskIORead; } + public void setMemoryKBs(Long memoryKBs) { + this.memoryKBs = memoryKBs; + } + + public void setMemoryIntFreeKBs(Long memoryIntFreeKBs) { + this.memoryIntFreeKBs = memoryIntFreeKBs; + } + + public void setMemoryTargetKBs(Long memoryTargetKBs) { + this.memoryTargetKBs = memoryTargetKBs; + } + public void setDiskIOWrite(Long diskIOWrite) { this.diskIOWrite = diskIOWrite; } @@ -758,10 +786,6 @@ public void setTags(Set tags) { this.tags = tags; } - public void addTag(ResourceTagResponse tag) { - this.tags.add(tag); - } - public void setKeyPairName(String keyPairName) { this.keyPairName = keyPairName; } diff --git a/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.java deleted file mode 100644 index 957fb48708..0000000000 --- a/api/src/org/apache/cloudstack/api/response/VolumeDetailResponse.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 org.apache.cloudstack.api.response; - -import com.google.gson.annotations.SerializedName; - -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; - -import com.cloud.serializer.Param; - -@SuppressWarnings("unused") -public class VolumeDetailResponse extends BaseResponse { - @SerializedName(ApiConstants.ID) - @Param(description = "ID of the volume") - private String id; - - @SerializedName(ApiConstants.NAME) - @Param(description = "name of the volume detail") - private String name; - - @SerializedName(ApiConstants.VALUE) - @Param(description = "value of the volume detail") - private String value; - - @SerializedName(ApiConstants.DISPLAY_VOLUME) - @Param(description = "an optional field whether to the display the volume to the end user or not.") - private Boolean displayVm; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public String getName() { - - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Boolean getDisplayVm() { - return displayVm; - } - - public void setDisplayVm(Boolean displayVm) { - this.displayVm = displayVm; - } -} diff --git a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java index eeb4af9c9e..a934563e9f 100644 --- a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java @@ -22,7 +22,7 @@ import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.BaseResponseWithTagInformation; import org.apache.cloudstack.api.EntityReference; import com.cloud.serializer.Param; @@ -31,7 +31,7 @@ @EntityReference(value = Volume.class) @SuppressWarnings("unused") -public class VolumeResponse extends BaseResponse implements ControlledViewEntityResponse { +public class VolumeResponse extends BaseResponseWithTagInformation implements ControlledViewEntityResponse { @SerializedName(ApiConstants.ID) @Param(description = "ID of the disk volume") private String id; @@ -212,10 +212,6 @@ public class VolumeResponse extends BaseResponse implements ControlledViewEntity @Param(description = "the status of the volume") private String status; - @SerializedName(ApiConstants.TAGS) - @Param(description = "the list of resource tags associated with volume", responseObject = ResourceTagResponse.class) - private Set tags; - @SerializedName(ApiConstants.DISPLAY_VOLUME) @Param(description = "an optional field whether to the display the volume to the end user or not.", authorized = {RoleType.Admin}) private Boolean displayVolume; @@ -439,14 +435,6 @@ public void setProjectName(String projectName) { this.projectName = projectName; } - public void setTags(Set tags) { - this.tags = tags; - } - - public void addTag(ResourceTagResponse tag) { - this.tags.add(tag); - } - public void setDisplayVolume(Boolean displayVm) { this.displayVolume = displayVm; } @@ -522,4 +510,8 @@ public String getTemplateDisplayText() { public void setTemplateDisplayText(String templateDisplayText) { this.templateDisplayText = templateDisplayText; } + + public void setTags(Set tags) { + this.tags = tags; + } } diff --git a/api/src/org/apache/cloudstack/api/response/ZoneResponse.java b/api/src/org/apache/cloudstack/api/response/ZoneResponse.java index 7aee448f6e..4266077e81 100644 --- a/api/src/org/apache/cloudstack/api/response/ZoneResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ZoneResponse.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.api.response; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -233,6 +234,9 @@ public void addTag(ResourceTagResponse tag) { } public void setResourceDetails(Map details) { - this.resourceDetails = details; + if (details == null) { + return; + } + this.resourceDetails = new HashMap<>(details); } } diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagement.java b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagement.java new file mode 100644 index 0000000000..1a22328e02 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagement.java @@ -0,0 +1,150 @@ +// 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.outofbandmanagement; + +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; +import com.cloud.utils.fsm.StateObject; +import org.apache.cloudstack.api.InternalIdentity; +import org.apache.cloudstack.utils.identity.ManagementServerNode; + +import java.util.Set; + +public interface OutOfBandManagement extends StateObject, InternalIdentity { + + PowerState getState(); + + Long getHostId(); + + boolean isEnabled(); + + PowerState getPowerState(); + + String getDriver(); + + String getAddress(); + + Integer getPort(); + + String getUsername(); + + String getPassword(); + + Long getManagementServerId(); + + void setEnabled(boolean enabled); + + void setDriver(String driver); + + void setAddress(String address); + + void setPort(Integer port); + + void setUsername(String username); + + void setPassword(String password); + + enum Option { + DRIVER, + ADDRESS, + PORT, + USERNAME, + PASSWORD + } + + enum PowerOperation { + ON, + OFF, + CYCLE, + RESET, + SOFT, + STATUS, + } + + enum PowerState { + On, + Off, + Unknown, + Disabled; + + public enum Event { + On("Chassis Power is On"), + Off("Chassis Power is Off"), + AuthError("Authentication error happened"), + Unknown("An unknown error happened"), + Enabled("Out-of-band management enabled"), + Disabled("Out-of-band management disabled"); + + private String description; + Event(String description) { + this.description = description; + } + public String toString() { + return String.format("%s(%s)", super.toString(), this.getDescription()); + } + public String getDescription() { + return description; + } + public Long getServerId() { + // TODO: change in future if we've better claim & ownership + // Right now the first one to update the db wins + // and mgmt server id would eventually become consistent + return ManagementServerNode.getManagementServerId(); + } + } + + public Event toEvent() { + if (this.equals(On)) { + return Event.On; + } else if (this.equals(Off)) { + return Event.Off; + } else if (this.equals(Disabled)) { + return Event.Disabled; + } + return Event.Unknown; + } + + private static final StateMachine2 FSM = new StateMachine2(); + static { + FSM.addInitialTransition(Event.On, On); + FSM.addInitialTransition(Event.Off, Off); + FSM.addInitialTransition(Event.Unknown, Unknown); + FSM.addInitialTransition(Event.AuthError, Unknown); + FSM.addInitialTransition(Event.Disabled, Disabled); + + FSM.addTransitionFromStates(Event.On, On, On, Off, Unknown, Disabled); + FSM.addTransitionFromStates(Event.Off, Off, On, Off, Unknown, Disabled); + FSM.addTransitionFromStates(Event.Unknown, Unknown, On, Off, Unknown, Disabled); + FSM.addTransitionFromStates(Event.AuthError, Unknown, On, Off, Disabled); + FSM.addTransitionFromStates(Event.Disabled, Disabled, On, Off, Unknown); + } + + public static StateMachine2 getStateMachine() { + return FSM; + } + + public PowerState getNextPowerState(Event e) throws NoTransitionException { + return FSM.getNextState(this, e); + } + + public Set getPossibleEvents() { + return FSM.getPossibleEvents(this); + } + + } +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementDriver.java b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementDriver.java new file mode 100644 index 0000000000..38489631f2 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementDriver.java @@ -0,0 +1,25 @@ +// 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.outofbandmanagement; + +import com.cloud.utils.component.Adapter; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverCommand; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; + +public interface OutOfBandManagementDriver extends Adapter { + OutOfBandManagementDriverResponse execute(OutOfBandManagementDriverCommand cmd); +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementService.java b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementService.java new file mode 100644 index 0000000000..699b2c6a99 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementService.java @@ -0,0 +1,55 @@ +// 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.outofbandmanagement; + +import com.cloud.dc.DataCenter; +import com.cloud.host.Host; +import com.cloud.org.Cluster; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.api.response.OutOfBandManagementResponse; +import org.apache.cloudstack.framework.config.ConfigKey; + +import java.util.List; + +public interface OutOfBandManagementService { + + ConfigKey ActionTimeout = new ConfigKey("Advanced", Long.class, "outofbandmanagement.action.timeout", "60", + "The out of band management action timeout in seconds, configurable by cluster", true, ConfigKey.Scope.Cluster); + + ConfigKey SyncThreadInterval = new ConfigKey("Advanced", Long.class, "outofbandmanagement.sync.interval", "300000", + "The interval (in milliseconds) when the out-of-band management background sync are retrieved", true, ConfigKey.Scope.Global); + + ConfigKey SyncThreadPoolSize = new ConfigKey("Advanced", Integer.class, "outofbandmanagement.sync.poolsize", "50", + "The out of band management background sync thread pool size", true, ConfigKey.Scope.Global); + + long getId(); + boolean isOutOfBandManagementEnabled(Host host); + void submitBackgroundPowerSyncTask(Host host); + boolean transitionPowerStateToDisabled(List hosts); + + OutOfBandManagementResponse enableOutOfBandManagement(DataCenter zone); + OutOfBandManagementResponse enableOutOfBandManagement(Cluster cluster); + OutOfBandManagementResponse enableOutOfBandManagement(Host host); + + OutOfBandManagementResponse disableOutOfBandManagement(DataCenter zone); + OutOfBandManagementResponse disableOutOfBandManagement(Cluster cluster); + OutOfBandManagementResponse disableOutOfBandManagement(Host host); + + OutOfBandManagementResponse configureOutOfBandManagement(Host host, ImmutableMap options); + OutOfBandManagementResponse executeOutOfBandManagementPowerOperation(Host host, OutOfBandManagement.PowerOperation operation, Long timeout); + OutOfBandManagementResponse changeOutOfBandManagementPassword(Host host, String password); +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverChangePasswordCommand.java b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverChangePasswordCommand.java new file mode 100644 index 0000000000..943339e74e --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverChangePasswordCommand.java @@ -0,0 +1,34 @@ +// 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.outofbandmanagement.driver; + +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; + +public final class OutOfBandManagementDriverChangePasswordCommand extends OutOfBandManagementDriverCommand { + private final String newPassword; + + public OutOfBandManagementDriverChangePasswordCommand(final ImmutableMap options, final Long timeout, final String newPassword) { + super(options, timeout); + this.newPassword = newPassword; + } + + public final String getNewPassword() { + return newPassword; + } + +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverCommand.java b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverCommand.java new file mode 100644 index 0000000000..999b10c612 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverCommand.java @@ -0,0 +1,43 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.outofbandmanagement.driver; + +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.joda.time.Duration; + +public abstract class OutOfBandManagementDriverCommand { + private final ImmutableMap options; + private final Duration timeout; + + public OutOfBandManagementDriverCommand(final ImmutableMap options, final Long timeoutSeconds) { + this.options = options; + if (timeoutSeconds != null && timeoutSeconds > 0) { + this.timeout = new Duration(timeoutSeconds * 1000); + } else { + this.timeout = Duration.ZERO; + } + } + + public final ImmutableMap getOptions() { + return options; + } + + public final Duration getTimeout() { + return timeout; + } +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverPowerCommand.java b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverPowerCommand.java new file mode 100644 index 0000000000..406be3b044 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverPowerCommand.java @@ -0,0 +1,33 @@ +// 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.outofbandmanagement.driver; + +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; + +public final class OutOfBandManagementDriverPowerCommand extends OutOfBandManagementDriverCommand { + private final OutOfBandManagement.PowerOperation powerOperation; + + public OutOfBandManagementDriverPowerCommand(final ImmutableMap options, final Long timeout, final OutOfBandManagement.PowerOperation powerOperation) { + super(options, timeout); + this.powerOperation = powerOperation; + } + + public final OutOfBandManagement.PowerOperation getPowerOperation() { + return powerOperation; + } +} diff --git a/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverResponse.java b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverResponse.java new file mode 100644 index 0000000000..78a25daee2 --- /dev/null +++ b/api/src/org/apache/cloudstack/outofbandmanagement/driver/OutOfBandManagementDriverResponse.java @@ -0,0 +1,85 @@ +// 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.outofbandmanagement.driver; + +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; + +public class OutOfBandManagementDriverResponse { + private String result; + private String error; + private boolean success = false; + private boolean hasAuthFailure = false; + private OutOfBandManagement.PowerState powerState; + + public OutOfBandManagementDriverResponse(String result, String error, boolean success) { + this.result = result; + this.error = error; + this.success = success; + } + + public OutOfBandManagement.PowerState.Event toEvent() { + if (hasAuthFailure()) { + return OutOfBandManagement.PowerState.Event.AuthError; + } + + if (!isSuccess() || powerState == null) { + return OutOfBandManagement.PowerState.Event.Unknown; + } + + return powerState.toEvent(); + } + + public boolean isSuccess() { + return success; + } + + public String getResult() { + return result; + } + + public String getError() { + return error; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public void setResult(String result) { + this.result = result; + } + + public void setError(String error) { + this.error = error; + } + + public OutOfBandManagement.PowerState getPowerState() { + return powerState; + } + + public void setPowerState(OutOfBandManagement.PowerState powerState) { + this.powerState = powerState; + } + + public boolean hasAuthFailure() { + return hasAuthFailure; + } + + public void setAuthFailure(boolean hasAuthFailure) { + this.hasAuthFailure = hasAuthFailure; + } +} diff --git a/api/test/org/apache/cloudstack/acl/RoleTypeTest.java b/api/test/org/apache/cloudstack/acl/RoleTypeTest.java new file mode 100644 index 0000000000..611b761014 --- /dev/null +++ b/api/test/org/apache/cloudstack/acl/RoleTypeTest.java @@ -0,0 +1,100 @@ +// 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.acl; + +import com.cloud.user.Account; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Arrays; + +public class RoleTypeTest { + + @Test + public void testValidRoleTypeFromString() { + for (RoleType roleType : RoleType.values()) { + Assert.assertEquals(RoleType.fromString(roleType.name()), roleType); + } + } + + @Test + public void testInvalidRoleTypeFromString() { + for (String roleType : Arrays.asList(null, "", "admin", "12345%&^*")) { + try { + RoleType.fromString(roleType); + Assert.fail("Invalid roletype provided, exception was expected"); + } catch (IllegalStateException e) { + Assert.assertEquals(e.getMessage(), "Illegal RoleType name provided"); + } + } + } + + @Test + public void testDefaultRoleMaskByValue() { + Assert.assertEquals(RoleType.fromMask(1), RoleType.Admin); + Assert.assertEquals(RoleType.fromMask(2), RoleType.ResourceAdmin); + Assert.assertEquals(RoleType.fromMask(4), RoleType.DomainAdmin); + Assert.assertEquals(RoleType.fromMask(8), RoleType.User); + Assert.assertEquals(RoleType.fromMask(0), RoleType.Unknown); + } + + @Test + public void testGetByAccountType() { + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_NORMAL), RoleType.User); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_ADMIN), RoleType.Admin); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_DOMAIN_ADMIN), RoleType.DomainAdmin); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN), RoleType.ResourceAdmin); + Assert.assertEquals(RoleType.getByAccountType(Account.ACCOUNT_TYPE_PROJECT), RoleType.Unknown); + } + + @Test + public void testGetRoleByAccountTypeWhenRoleIdIsProvided() { + Assert.assertEquals(RoleType.getRoleByAccountType(123L, Account.ACCOUNT_TYPE_ADMIN), Long.valueOf(123L)); + Assert.assertEquals(RoleType.getRoleByAccountType(1234L, null), Long.valueOf(1234L)); + } + + @Test + public void testGetRoleByAccountTypeForDefaultAccountTypes() { + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_ADMIN), (Long) RoleType.Admin.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_NORMAL), (Long) RoleType.User.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_DOMAIN_ADMIN), (Long) RoleType.DomainAdmin.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN), (Long) RoleType.ResourceAdmin.getId()); + Assert.assertEquals(RoleType.getRoleByAccountType(null, Account.ACCOUNT_TYPE_PROJECT), null); + } + + @Test + public void testGetAccountTypeByRoleWhenRoleIsNull() { + for (Short accountType: Arrays.asList( + Account.ACCOUNT_TYPE_NORMAL, + Account.ACCOUNT_TYPE_ADMIN, + Account.ACCOUNT_TYPE_DOMAIN_ADMIN, + Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN, + Account.ACCOUNT_TYPE_PROJECT, + (short) 12345)) { + Assert.assertEquals(RoleType.getAccountTypeByRole(null, accountType), accountType); + } + } + + @Test + public void testGetAccountTypeByRole() { + Role role = Mockito.mock(Role.class); + Mockito.when(role.getRoleType()).thenReturn(RoleType.Admin); + Mockito.when(role.getId()).thenReturn(100L); + Assert.assertEquals(RoleType.getAccountTypeByRole(role, null), (Short) RoleType.Admin.getAccountType()); + } +} \ No newline at end of file diff --git a/api/test/org/apache/cloudstack/acl/RuleTest.java b/api/test/org/apache/cloudstack/acl/RuleTest.java new file mode 100644 index 0000000000..08bd775bd0 --- /dev/null +++ b/api/test/org/apache/cloudstack/acl/RuleTest.java @@ -0,0 +1,98 @@ +// 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.acl; + +import com.cloud.exception.InvalidParameterValueException; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; + +public class RuleTest { + + @Test + public void testToString() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertEquals(rule.toString(), "someString"); + } + + @Test + public void testMatchesEmpty() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertFalse(rule.matches("")); + } + + @Test + public void testMatchesNull() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertFalse(rule.matches(null)); + } + + @Test + public void testMatchesSpace() throws Exception { + Rule rule = new Rule("someString"); + Assert.assertFalse(rule.matches(" ")); + } + + @Test + public void testMatchesAPI() throws Exception { + Rule rule = new Rule("someApi"); + Assert.assertTrue(rule.matches("someApi")); + } + + @Test + public void testMatchesWildcardSuffix() throws Exception { + Rule rule = new Rule("list*"); + Assert.assertTrue(rule.matches("listHosts")); + } + + @Test + public void testMatchesWildcardPrefix() throws Exception { + Rule rule = new Rule("*User"); + Assert.assertTrue(rule.matches("createUser")); + } + + @Test + public void testMatchesWildcardMiddle() throws Exception { + Rule rule = new Rule("list*s"); + Assert.assertTrue(rule.matches("listClusters")); + } + + @Test + public void testValidateRuleWithValidData() throws Exception { + for (String rule : Arrays.asList("a", "1", "someApi", "someApi321", "123SomeApi", + "prefix*", "*middle*", "*Suffix", + "*", "**", "f***", "m0nk3yMa**g1c*")) { + Assert.assertEquals(new Rule(rule).toString(), rule); + } + } + + @Test + public void testValidateRuleWithInvalidData() throws Exception { + for (String rule : Arrays.asList(null, "", " ", " ", "\n", "\t", "\r", "\"", "\'", + "^someApi$", "^someApi", "some$", "some-Api;", "some,Api", + "^", "$", "^$", ".*", "\\w+", "r**l3rd0@Kr3", "j@s1n|+|0ȷ", + "[a-z0-9-]+", "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$")) { + try { + new Rule(rule); + Assert.fail("Invalid rule, exception was expected"); + } catch (InvalidParameterValueException e) { + Assert.assertTrue(e.getMessage().startsWith("Only API names and wildcards are allowed")); + } + } + } +} \ No newline at end of file diff --git a/api/test/org/apache/cloudstack/api/command/admin/account/CreateAccountCmdTest.java b/api/test/org/apache/cloudstack/api/command/admin/account/CreateAccountCmdTest.java index c0a046de43..b50b2269c1 100644 --- a/api/test/org/apache/cloudstack/api/command/admin/account/CreateAccountCmdTest.java +++ b/api/test/org/apache/cloudstack/api/command/admin/account/CreateAccountCmdTest.java @@ -18,6 +18,7 @@ */ package org.apache.cloudstack.api.command.admin.account; +import org.apache.cloudstack.acl.RoleService; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.context.CallContext; @@ -41,10 +42,13 @@ public class CreateAccountCmdTest { @Mock private AccountService accountService; + @Mock + private RoleService roleService; @InjectMocks private CreateAccountCmd createAccountCmd = new CreateAccountCmd(); + private long roleId = 1L; private short accountType = 1; private Long domainId = 1L; @@ -69,7 +73,7 @@ public void testExecuteWithNotBlankPassword() { } catch (ServerApiException e) { Assert.assertTrue("Received exception as the mock accountService createUserAccount returns null user", true); } - Mockito.verify(accountService, Mockito.times(1)).createUserAccount(null, "Test", null, null, null, null, null, accountType, domainId, null, null, null, null); + Mockito.verify(accountService, Mockito.times(1)).createUserAccount(null, "Test", null, null, null, null, null, accountType, roleId, domainId, null, null, null, null); } @Test @@ -82,7 +86,7 @@ public void testExecuteWithNullPassword() { Assert.assertEquals(ApiErrorCode.PARAM_ERROR, e.getErrorCode()); Assert.assertEquals("Empty passwords are not allowed", e.getMessage()); } - Mockito.verify(accountService, Mockito.never()).createUserAccount(null, null, null, null, null, null, null, accountType, domainId, null, null, null, null); + Mockito.verify(accountService, Mockito.never()).createUserAccount(null, null, null, null, null, null, null, accountType, roleId, domainId, null, null, null, null); } @Test @@ -95,6 +99,6 @@ public void testExecuteWithEmptyPassword() { Assert.assertEquals(ApiErrorCode.PARAM_ERROR, e.getErrorCode()); Assert.assertEquals("Empty passwords are not allowed", e.getMessage()); } - Mockito.verify(accountService, Mockito.never()).createUserAccount(null, null, null, null, null, null, null, accountType, domainId, null, null, null, null); + Mockito.verify(accountService, Mockito.never()).createUserAccount(null, null, null, null, null, null, null, accountType, roleId, domainId, null, null, null, null); } } diff --git a/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java index 63c4a03243..65b9330664 100644 --- a/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java +++ b/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java @@ -19,6 +19,7 @@ import junit.framework.Assert; import junit.framework.TestCase; +import org.apache.cloudstack.acl.RoleService; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -48,22 +49,46 @@ public void setUp() { updateCfgCmd = new UpdateCfgCmd(); } + @Test + public void testExecuteForEmptyCfgName() { + updateCfgCmd._configService = configService; + + try { + updateCfgCmd.execute(); + } catch (ServerApiException exception) { + Assert.assertEquals("Empty configuration name provided", exception.getDescription()); + } + } + + @Test + public void testExecuteForRestrictedCfg() { + updateCfgCmd._configService = configService; + updateCfgCmd.setCfgName(RoleService.EnableDynamicApiChecker.key()); + + try { + updateCfgCmd.execute(); + } catch (ServerApiException exception) { + Assert.assertEquals("Restricted configuration update not allowed", exception.getDescription()); + } + } + @Test public void testExecuteForEmptyResult() { updateCfgCmd._configService = configService; + updateCfgCmd.setCfgName("some.cfg"); try { updateCfgCmd.execute(); } catch (ServerApiException exception) { Assert.assertEquals("Failed to update config", exception.getDescription()); } - } @Test public void testExecuteForNullResult() { updateCfgCmd._configService = configService; + updateCfgCmd.setCfgName("some.cfg"); try { Mockito.when(configService.updateConfiguration(updateCfgCmd)).thenReturn(null); @@ -88,6 +113,7 @@ public void testCreateSuccess() { Configuration cfg = Mockito.mock(Configuration.class); updateCfgCmd._configService = configService; updateCfgCmd._responseGenerator = responseGenerator; + updateCfgCmd.setCfgName("some.cfg"); try { Mockito.when(configService.updateConfiguration(updateCfgCmd)).thenReturn(cfg); diff --git a/build/replace.properties b/build/replace.properties index 3983b1031c..9e0b65c690 100644 --- a/build/replace.properties +++ b/build/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql AGENTLOGDIR=logs AGENTLOG=logs/agent.log MSMNTDIR=/mnt diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index fbdedda5c2..8b8ad1a957 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -876,6 +876,7 @@ label.metrics.num.cpu.cores=Cores label.metrics.property=Property label.metrics.scope=Scope label.metrics.state=State +label.metrics.outofbandmanagementpowerstate=Power State label.metrics.storagepool=Storage Pool label.metrics.vm.name=VM Name label.migrate.instance.to.host=Migrate instance to another host @@ -1004,6 +1005,25 @@ label.pods=Pods label.port.forwarding.policies=Port forwarding policies label.port.forwarding=Port Forwarding label.port.range=Port Range +label.powerstate=Power State +label.outofbandmanagement=Out-of-band Management +label.outofbandmanagement.action.issue=Issue Out-of-band Management Power Action +label.outofbandmanagement.action=Action +label.outofbandmanagement.address=Address +label.outofbandmanagement.changepassword=Change Out-of-band Management Password +label.outofbandmanagement.configure=Configure Out-of-band Management +label.outofbandmanagement.driver=Driver +label.outofbandmanagement.disable=Disable Out-of-band Management +label.outofbandmanagement.enable=Enable Out-of-band Management +label.outofbandmanagement.password=Password +label.outofbandmanagement.port=Port +label.outofbandmanagement.username=Username +message.outofbandmanagement.changepassword=Change Out-of-band Management password +message.outofbandmanagement.configure=Configure Out-of-band Management +message.outofbandmanagement.disable=Disable Out-of-band Management +message.outofbandmanagement.enable=Enable Out-of-band Management +message.outofbandmanagement.issue=Issue Out-of-band Management Power Action +message.outofbandmanagement.action.maintenance=Warning host is in maintenance mode label.PreSetup=PreSetup label.prev=Prev label.previous=Previous @@ -1095,9 +1115,17 @@ label.retry.interval=Retry Interval label.review=Review label.revoke.project.invite=Revoke invitation label.role=Role +label.roles=Roles +label.roletype=Role Type +label.add.role=Add Role +label.edit.role=Edit Role +label.delete.role=Delete Role +message.role.ordering.fail=Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again. label.root.certificate=Root certificate label.root.disk.controller=Root disk controller label.root.disk.offering=Root Disk Offering +label.permission=Permission +label.rule=Rule label.rules=Rules label.running.vms=Running VMs label.s3.access_key=Access Key diff --git a/client/WEB-INF/classes/resources/messages_ar.properties b/client/WEB-INF/classes/resources/messages_ar.properties index 3ba58ecf14..d1832c456a 100644 --- a/client/WEB-INF/classes/resources/messages_ar.properties +++ b/client/WEB-INF/classes/resources/messages_ar.properties @@ -48,7 +48,7 @@ label.CIDR.list=\u0642\u0627\u0626\u0645\u0629 CIDR label.CIDR.of.destination.network=CIDR \u0627\u0644\u062e\u0627\u0635 \u0628\u0627\u0644\u0634\u0628\u0643\u0629 \u0627\u0644\u0645\u0648\u062c\u0647\u0629. label.clean.up=\u062a\u0646\u0638\u064a\u0641 label.clear.list=\u0645\u0633\u062d \u0627\u0644\u0642\u0627\u0626\u0645\u0629 -label.configuration=\u0627\u0644\u062a\u0643\u0648\u064a\u0646 +label.configuration=\u062a\u0631\u062a\u064a\u0628 label.configure.network.ACLs=\u0636\u0628\u0637 \u0634\u0628\u0643\u0629 ACLs label.configure=\u0642\u0645 \u0628\u062a\u0643\u0648\u064a\u0646 label.configure.vpc=\u062a\u0643\u0648\u064a\u0646 VPC diff --git a/client/WEB-INF/classes/resources/messages_de_DE.properties b/client/WEB-INF/classes/resources/messages_de_DE.properties index d51598eeb6..3fb4126e00 100644 --- a/client/WEB-INF/classes/resources/messages_de_DE.properties +++ b/client/WEB-INF/classes/resources/messages_de_DE.properties @@ -728,7 +728,7 @@ label.general.alerts=Allgemeine Alarme label.generating.url=Generieren der URL label.globo.dns.configuration=GloboDNS-Konfiguration label.globo.dns=GloboDNS -label.gluster.volume=Volumen +label.gluster.volume=Volume label.go.step.2=Gehe zu Schritt 2 label.go.step.3=Weiter zu Schritt 3 label.go.step.4=Weiter mit Schritt 4 diff --git a/client/WEB-INF/classes/resources/messages_es.properties b/client/WEB-INF/classes/resources/messages_es.properties index 33fee1f846..4c76d2a18f 100644 --- a/client/WEB-INF/classes/resources/messages_es.properties +++ b/client/WEB-INF/classes/resources/messages_es.properties @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -changed.item.properties=Propiedades del elemento cambiadas +changed.item.properties=Propiedades del elemento cambiados confirm.enable.s3=Por favor, complete la siguiente informaci\u00f3n para habilitar el soporte del Almacenamiento Secundario sobre S3 confirm.enable.swift=Por favor, complete la siguiente informaci\u00f3n para habilitar el soporte para Swift error.could.not.change.your.password.because.ldap.is.enabled=Error, no se puede cambiar la contrase\u00f1a porque LDAP esta activado @@ -28,23 +28,23 @@ error.mgmt.server.inaccessible=El Servidor de Gesti\u00f3n es inaccesible. Por f error.password.not.match=Los campos de contrase\u00f1a no coinciden error.please.specify.physical.network.tags=Las Ofertas de Red no est\u00e1n disponibles hasta que se especifique los tags para esta red f\u00edsica. error.session.expired=Su sesi\u00f3n ha caducado. -error.something.went.wrong.please.correct.the.following=Algo sali\u00f3 mal, por favor corrija lo siguiente +error.something.went.wrong.please.correct.the.following=Algo sali\u00f3 mal, pro favor corrija lo siguiente error.unable.to.reach.management.server=No podemos conectar con el Management Server -error.unresolved.internet.name=Su nombre de Internet no se puede resolver. -force.delete.domain.warning=Advertencia\: Si elige esta opci\u00f3n se realizar\u00e1 la supresi\u00f3n de todos los dominios secundarios, todas las cuentas asociadas y sus recursos. -force.delete=Forzar Borrado -force.remove=Forzar la Remoci\u00f3n -force.remove.host.warning=Advertencia\: Si elige esta opci\u00f3n, CloudStack detendra por la fuerza todas las m\u00e1quinas virtuales en ejecuci\u00f3n antes de remover este servidor del cl\u00faster. -force.stop=Forzar la Detenci\u00f3n -force.stop.instance.warning=Advertencia\: Forzar la dertenci\u00f3n de esta instancia deber\u00ed\u00ada ser su \u00faltima opci\u00f3n. Puede conducir a la p\u00e9rdida de datos, as\u00ed\u00ad como un comportamiento inconsistente del estado de la m\u00e1quina virtual. +error.unresolved.internet.name=El nombre de Internet no se puede resolver. +force.delete.domain.warning=Advertencia\: Si elige esta opci\u00f3n, la supresi\u00f3n de todos los dominios secundarios y todas las cuentas asociadas y sus recursos. +force.delete=Forzar el borrado +force.remove=Forzar el retiro +force.remove.host.warning=Advertencia\: Si elige esta opci\u00f3n, CloudStack para detener la fuerza todas las m\u00e1quinas virtuales en ejecuci\u00f3n antes de retirar este host del cl\u00faster. +force.stop=Forzar la detenci\u00f3n +force.stop.instance.warning=Advertencia\: Forzar la dertenci\u00f3n de esta instancia deber\u00ed\u00ada ser su \u00faltima opci\u00f3n. Puede conducir a la p\u00e9rdida de datos, as\u00ed\u00ad como un comportamiento incoherente del Estado de la m\u00e1quina virtual. hint.no.host.tags=No se encontraron las etiquetas de servidor hint.no.storage.tags=No se encontraron las etiquetas de almacenamiento hint.type.part.host.tag=El tipo esta en parte de la etiqueta de servidor hint.type.part.storage.tag=El tipo est\u00e1 en parte de la etiqueta de almacenamiento ICMP.code=C\u00f3digo ICMP ICMP.type=Tipo ICMP -image.directory=Directorio de Im\u00e1genes -inline=Inline +image.directory=Directorio de im\u00e1genes +inline=alineado instances.actions.reboot.label=Reiniciar Instancia label.about=Acerca de label.about.app=Acerca de CloudStack @@ -52,9 +52,9 @@ label.accept.project.invitation=Aceptar invitaci\u00f3n al proyecto label.account.and.security.group=Cuenta, Grupo de seguridad label.account=Cuenta label.account.details=Detalles de la Cuenta -label.account.id=ID de la Cuenta +label.account.id=ID de la cuenta label.account.lower=cuenta -label.account.name=Nombre de la Cuenta +label.account.name=Nombre de cuenta label.accounts=Cuentas label.account.specific=espec\u00edficas de la cuenta label.account.type=Tipo de Cuenta @@ -66,119 +66,119 @@ label.acl.replaced=ACL reemplazada label.acquire.new.ip=Adquirir nueva IP label.acquire.new.secondary.ip=Adquirir nuevo IP secundario label.action=Acci\u00f3n -label.action.attach.disk=Conectar Disco -label.action.attach.disk.processing=Conectando Disco.... +label.action.attach.disk=Conecte el disco +label.action.attach.disk.processing=Conectando el disco.... label.action.attach.iso=Conectar ISO label.action.attach.iso.processing=Conectando el ISO.... -label.action.cancel.maintenance.mode=Cancelar el Modo de Mantenimiento -label.action.cancel.maintenance.mode.processing=Cancelando el Modo de Mantenimiento.... -label.action.change.password=Cambiar la Contrase\u00f1a +label.action.cancel.maintenance.mode=Cancelar el modo de mantenimiento +label.action.cancel.maintenance.mode.processing=Cancelando el modo de mantenimiento.... +label.action.change.password=Cambiar la contrase\u00f1a label.action.change.service=Cambiar el Servicio -label.action.change.service.processing=Cambiando el Servicio.... +label.action.change.service.processing=Cambiando el servicio.... label.action.configure.samlauthorization=Configurar Autorizaci\u00f3n SAML SSO label.action.copy.ISO=Copiar ISO label.action.copy.ISO.processing=Copiando ISO.... -label.action.copy.template=Copiar el Template -label.action.copy.template.processing=Copiando Template.... -label.action.create.template=Crear Template -label.action.create.template.from.vm=Crear Template desde VM -label.action.create.template.from.volume=Crear Template desde Volumen -label.action.create.template.processing=Creando Template.... +label.action.copy.template=Copiear la plantilla +label.action.copy.template.processing=Copiando Plantilla.... +label.action.create.template=Crear plantilla +label.action.create.template.from.vm=Crear plantilla de VM +label.action.create.template.from.volume=Crear plantilla de volumen +label.action.create.template.processing=Creaci\u00f3n de plantillas .... label.action.create.vm=Crear VM -label.action.create.vm.processing=Creando VM.... -label.action.create.volume=Crear Volumen -label.action.create.volume.processing=Creando Volumen.... +label.action.create.vm.processing=Creaci\u00f3n de m\u00e1quina virtual .... +label.action.create.volume=Crear volumen +label.action.create.volume.processing=Crear volumen .... label.action.delete.account=Eliminar cuenta -label.action.delete.account.processing=Eliminando cuenta.... -label.action.delete.cluster.processing=Removiendo Cluster.... -label.action.delete.cluster=Remover Cluster -label.action.delete.disk.offering=Borrar Oferta de Disco -label.action.delete.disk.offering.processing=Borrar Oferta de Disco.... -label.action.delete.domain.processing=Removiendo el Dominio .... -label.action.delete.domain=Remover Dominio -label.action.delete.firewall.processing=Eliminando el Firewall .... -label.action.delete.firewall=Remover regla de firewall -label.action.delete.ingress.rule.processing=Removiendo Regla de ingreso.... -label.action.delete.ingress.rule=Remover Regla de ingreso -label.action.delete.IP.range.processing=Remover Rango de IP.... -label.action.delete.IP.range=Remover Rango de IP -label.action.delete.ISO=Borrar ISO -label.action.delete.ISO.processing=Borrar ISO.... -label.action.delete.load.balancer.processing=Removiendo Load Balancer.... -label.action.delete.load.balancer=Remover regla de load balancer +label.action.delete.account.processing=Eliminar cuentas .... +label.action.delete.cluster=Borrar Grupo +label.action.delete.cluster.processing=Borrar Grupo .... +label.action.delete.disk.offering=Borrar disco Ofrenda +label.action.delete.disk.offering.processing=Borrar disco ofrece .... +label.action.delete.domain=Eliminar de dominio +label.action.delete.domain.processing=Eliminaci\u00f3n de dominio .... +label.action.delete.firewall=Eliminar servidor de seguridad +label.action.delete.firewall.processing=Eliminaci\u00f3n de firewall .... +label.action.delete.ingress.rule=Borrar ingreso Regla +label.action.delete.ingress.rule.processing=Eliminaci\u00f3n de ingreso regla .... +label.action.delete.IP.range=Eliminar Rango de IP +label.action.delete.IP.range.processing=Eliminar Rango de IP .... +label.action.delete.ISO=Eliminar ISO +label.action.delete.ISO.processing=Eliminaci\u00f3n de la norma ISO .... +label.action.delete.load.balancer=Eliminar equilibrador de carga +label.action.delete.load.balancer.processing=Eliminaci\u00f3n del equilibrador de carga .... label.action.delete.network=Eliminar Red -label.action.delete.network.processing=Borrando Red.... +label.action.delete.network.processing=Eliminaci\u00f3n de red .... label.action.delete.nexusVswitch=Eliminar Nexus 1000v label.action.delete.nic=Quitar NIC label.action.delete.physical.network=Eliminar red f\u00edsica label.action.delete.pod=Eliminar Pod -label.action.delete.pod.processing=Eliminando Pod.... -label.action.delete.primary.storage=Eliminar Almacenamiento Primario -label.action.delete.primary.storage.processing=Eliminando Almacenamiento Primario.... -label.action.delete.secondary.storage=Eliminar Almacenamiento Secundario -label.action.delete.secondary.storage.processing=Eliminando Almacenamiento Secundario .... +label.action.delete.pod.processing=Eliminar Pod .... +label.action.delete.primary.storage=Almacenamiento primario Eliminar +label.action.delete.primary.storage.processing=Eliminaci\u00f3n de almacenamiento primaria .... +label.action.delete.secondary.storage.processing=Eliminaci\u00f3n de almacenamiento secundario .... +label.action.delete.secondary.storage=secundaria almacenamiento Eliminar label.action.delete.security.group=Borrar Grupo de Seguridad label.action.delete.security.group.processing=Eliminar grupo de seguridad .... label.action.delete.service.offering=Eliminar Oferta de Servicio -label.action.delete.service.offering.processing=Eliminando Oferta de Servicio .... +label.action.delete.service.offering.processing=Eliminaci\u00f3n de Oferta de Servicio .... label.action.delete.snapshot=Eliminar instant\u00e1nea -label.action.delete.snapshot.processing=Borrando instant\u00e1nea .... +label.action.delete.snapshot.processing=Eliminar instant\u00e1nea .... label.action.delete.system.service.offering=Eliminar Oferta de Servicio de Sistema -label.action.delete.template=Eliminar Template -label.action.delete.template.processing=Borrando Template.... +label.action.delete.template=Eliminar plantilla +label.action.delete.template.processing=Eliminar plantilla .... label.action.delete.user=Eliminar usuario -label.action.delete.user.processing=Eliminando Usuario.... +label.action.delete.user.processing=Eliminar usuario .... label.action.delete.volume=Eliminar volumen -label.action.delete.volume.processing=Eliminando volumen .... +label.action.delete.volume.processing=Eliminar volumen .... label.action.delete.zone=Eliminar Zona -label.action.delete.zone.processing=Eliminando Zona.... +label.action.delete.zone.processing=Eliminaci\u00f3n de la Zona .... label.action.destroy.instance=Destruye Instancia -label.action.destroy.instance.processing=Destruyendo Instancia.... +label.action.destroy.instance.processing=Destrucci\u00f3n Instancia .... label.action.destroy.systemvm=destruir el sistema VM -label.action.destroy.systemvm.processing=Destruyendo VM de Sistema.... -label.action.detach.disk=Desconectar Disco -label.action.detach.disk.processing=Desconectando Disco .... -label.action.detach.iso.processing=Desconectando ISO.... +label.action.destroy.systemvm.processing=Destrucci\u00f3n del sistema VM .... +label.action.detach.disk.processing=Extracci\u00f3n disco .... +label.action.detach.disk=Separar disco +label.action.detach.iso.processing=Extracci\u00f3n ISO .... label.action.detach.iso=Separar ISO label.action.disable.account=Desactivar cuenta -label.action.disable.account.processing=Deshabilitando cuenta.... -label.action.disable.cluster=Deshabilitar Cl\u00faster -label.action.disable.cluster.processing=Deshabilitando el Cluster.... +label.action.disable.account.processing=Deshabilitar cuenta .... +label.action.disable.cluster=Deshabilitar cl\u00faster +label.action.disable.cluster.processing=Desactivaci\u00f3n de Cluster Server .... label.action.disable.nexusVswitch=Deshabilitar Nexus 1000v label.action.disable.physical.network=Desactivar la red f\u00edsica label.action.disable.pod=Deshabilitar Pod -label.action.disable.pod.processing=Deshabilitando el Pod.... +label.action.disable.pod.processing=Deshabilitar Pod .... label.action.disable.static.NAT=Deshabilitar NAT est\u00e1tica -label.action.disable.static.NAT.processing=Deshabilitando el NAT Est\u00e1tico.... +label.action.disable.static.NAT.processing=Deshabilitar NAT est\u00e1tica .... label.action.disable.user=Deshabilitar usuario -label.action.disable.user.processing=Deshabilitando Usuario.... +label.action.disable.user.processing=Desactivaci\u00f3n de usuario .... label.action.disable.zone=Deshabilitar la zona -label.action.disable.zone.processing=Deshabilitando Zona.... +label.action.disable.zone.processing=Desactivaci\u00f3n de la zona .... label.action.download.ISO=ISO Descargar -label.action.download.template=Descargar Template +label.action.download.template=Descargar plantilla label.action.download.volume=Descargar Volumen -label.action.download.volume.processing=Descargando Volumen.... +label.action.download.volume.processing=Volumen Descargar .... label.action.edit.account=Editar cuenta -label.action.edit.disk.offering=Editar Oferta de Disco +label.action.edit.disk.offering=Editar disco Ofrenda label.action.edit.domain=Editar Dominio -label.action.edit.global.setting=Editar la Configuraci\u00f3n Global -label.action.edit.host=Editar Servidor +label.action.edit.global.setting=Editar Mundial Marco +label.action.edit.host=edici\u00f3n Anfitri\u00f3n label.action.edit.instance=Editar Instancia label.action.edit.ISO=Editar ISO label.action.edit.network=Edici\u00f3n de redes label.action.edit.network.offering=Editar Red ofrece label.action.edit.network.processing=Editando Red.... label.action.edit.pod=Editar Pod -label.action.edit.primary.storage=Editar Almacenamiento Primario +label.action.edit.primary.storage=Editar Almacenamiento primario label.action.edit.resource.limits=Editar l\u00edmites de recursos label.action.edit.service.offering=Editar Oferta de Servicio -label.action.edit.template=Editar Template +label.action.edit.template=Editar plantilla label.action.edit.user=Editar usuario label.action.edit.zone=Edici\u00f3n Zona label.action.enable.account=Habilitar cuenta label.action.enable.account.processing=cuenta de Habilitaci\u00f3n .... -label.action.enable.cluster=Habilitar Cl\u00faster -label.action.enable.cluster.processing=Habilitando el Cl\u00faster .... +label.action.enable.cluster=Habilitar cl\u00faster +label.action.enable.cluster.processing=Habilitar cl\u00faster .... label.action.enable.maintenance.mode=Activar el modo de mantenimiento label.action.enable.maintenance.mode.processing=Habilitaci\u00f3n del modo de mantenimiento .... label.action.enable.nexusVswitch=Habilitar Nexus 1000v @@ -200,8 +200,8 @@ label.action.generate.keys.processing=Generar claves .... label.action.list.nexusVswitch=Listar Nexus 1000v label.action.lock.account=Bloqueo de cuenta label.action.lock.account.processing=Bloqueo de cuenta .... -label.action.manage.cluster=Gestionar Cl\u00faster -label.action.manage.cluster.processing=Gestionando Cl\u00faster.... +label.action.manage.cluster=gestionar racimo +label.action.manage.cluster.processing=La gesti\u00f3n de cl\u00fasteres .... label.action.migrate.instance=Migrar Instancia label.action.migrate.instance.processing=Migrar Instancia .... label.action.migrate.router=migrar Router @@ -216,19 +216,19 @@ label.action.reboot.systemvm.processing=reinicio del sistema VM .... label.action.reboot.systemvm=Reiniciar sistema VM label.action.recurring.snapshot=recurrente instant\u00e1neas label.action.register.iso=Registrar ISO -label.action.register.template=Registrar template desde una URL +label.action.register.template=Registrar plantilla desde una URL label.action.release.ip=estreno IP label.action.release.ip.processing=Liberar IP .... -label.action.remove.host.processing=Removiendo el Servidor.... -label.action.remove.host=Quitar el Servidor +label.action.remove.host.processing=Extracci\u00f3n de host .... +label.action.remove.host=Quitar host label.action.reset.password.processing=Restablecimiento de la contrase\u00f1a .... label.action.reset.password=Restablecer contrase\u00f1a label.action.resize.volume=Cambiar el tama\u00f1o del Volumen -label.action.resize.volume.processing=Cambiando el tama\u00f1o del Volumen.... +label.action.resize.volume.processing=Cambiar el tama\u00f1o del Volumen.... label.action.resource.limits=Recursos l\u00edmites label.action.restore.instance.processing=Restaurar Instancia .... label.action.restore.instance=Restaurar Instancia -label.action.revert.snapshot.processing=Revertiendo a Snapshot... +label.action.revert.snapshot.processing=Volviendo a Snapshot... label.action.revert.snapshot=Revertir a Snapshot label.actions=Acciones label.action.start.instance=Iniciar Instancia @@ -239,27 +239,27 @@ label.action.start.systemvm=Inicio del sistema VM label.action.start.systemvm.processing=A partir del sistema VM .... label.action.stop.instance=Detener Instancia label.action.stop.instance.processing=Detener Instancia .... -label.action.stop.router=Parar el Router -label.action.stop.router.processing=Parando el Router.... -label.action.stop.systemvm=Parar VM del Sistema -label.action.stop.systemvm.processing=Deteniendo VM de Sistema.... -label.action.take.snapshot.processing=Tomando instant\u00e1nea.... +label.action.stop.router=Detener router +label.action.stop.router.processing=Detener router .... +label.action.stop.systemvm=parada del sistema VM +label.action.stop.systemvm.processing=Detener sistema VM .... +label.action.take.snapshot.processing=Tomar instant\u00e1neas .... label.action.take.snapshot=Tomar instant\u00e1nea -label.action.unmanage.cluster=Dejar de Gestionar Cl\u00faster -label.action.unmanage.cluster.processing=Dejando de Gestionar Cl\u00faster .... +label.action.unmanage.cluster.processing=Unmanaging Grupo .... +label.action.unmanage.cluster=Unmanage racimo label.action.update.OS.preference=Actualizar OS Preferencia label.action.update.OS.preference.processing=Actualizaci\u00f3n de sistema operativo preferencia .... label.action.update.resource.count=Actualizaci\u00f3n de recursos Conde label.action.update.resource.count.processing=Actualizaci\u00f3n de Conde de recursos .... label.action.vmsnapshot.create=Tomar instant\u00e1nea de VM -label.action.vmsnapshot.delete=Borrar Instant\u00e1nea de VM -label.action.vmsnapshot.revert=Volver VM a la instant\u00e1nea +label.action.vmsnapshot.delete=Borrar Instantanea de VM +label.action.vmsnapshot.revert=Volver VM a la instantanea label.activate.project=Activar Proyecto label.active.sessions=Sesiones activas label.add.account=A\u00f1adir cuenta label.add.accounts=Agregar cuentas label.add.accounts.to=Agregar cuentas a -label.add.account.to.project=Agregar cuenta al proyecto +label.add.account.to.project=Agregar cuenta al projecto label.add.ACL=Agregar ACL label.add.acl.list=Agregar Lista ACL label.add.affinity.group=Agregar un nuevo grupo de afinidad @@ -272,10 +272,10 @@ label.add.by=A\u00f1adir por label.add.by.cidr=A\u00f1adir Por CIDR label.add.by.group=A\u00f1adir Por el Grupo de label.add.ciscoASA1000v=Agregar un Recurso CiscoASA1000v -label.add.cluster=A\u00f1adir Cl\u00faster +label.add.cluster=A\u00f1adir Grupo label.add.compute.offering=Agregar oferta de computo label.add.direct.iprange=A\u00f1adir Direct IP Gama -label.add.disk.offering=A\u00f1adir Oferta de Disco +label.add.disk.offering=A\u00f1adir disco Ofrenda label.add.domain=Agregar dominio label.added.brocade.vcs.switch=Nuevo Switch VCS Brocade agregado label.added.network.offering=Oferta de Red agregada @@ -288,9 +288,9 @@ label.add.firewall=Agregar Servidor de seguridad label.add.globo.dns=Agregar GloboDNS label.add.gslb=Agregar GSLB label.add.guest.network=Agregar red de invitado -label.add.host=Agregar Servidor +label.add.host=Agregar host label.adding=Agregar -label.adding.cluster=Agregando Cl\u00faster +label.adding.cluster=Adici\u00f3n de cl\u00faster label.adding.failed=No se pudo agregar label.adding.pod=Agregar Pod label.adding.processing=A\u00f1adir .... @@ -301,7 +301,7 @@ label.adding.zone=Agregar la zona label.add.intermediate.certificate=Agregar certificado de entidad intermedia label.add.internal.lb=Agregar LB Interno label.add.ip.range=A\u00f1adir Rango de IP -label.add.isolated.guest.network=Agregar red Aislada para Guest +label.add.isolated.guest.network=Agregar red Aislado para Guest label.add.isolated.guest.network.with.sourcenat=Agregar Red Aislada para Guest con SourceNat label.add.isolated.network=Agregar Red Aislada label.additional.networks=Redes adicional @@ -331,20 +331,20 @@ label.add.physical.network=Agregar red f\u00edsica label.add.pod=A\u00f1adir Pod label.add.portable.ip.range=Agregar un Rango IP Port\u00e1til label.add.port.forwarding.rule=Agregar regla port forwarding -label.add.primary.storage=A\u00f1adir Almacenamiento Primario +label.add.primary.storage=A\u00f1adir Almacenamiento primario label.add.private.gateway=Agregar Gateway Privado label.add.region=Agregar Regi\u00f3n label.add.resources=Agregar Recursos label.add.route=Agregar ruta label.add.rule=Agregar regla -label.add.secondary.storage=Agregar Almacenamiento Secundario +label.add.secondary.storage=A\u00f1adir secundaria almacenamiento label.add.security.group=Agregar grupo de seguridad label.add.service.offering=A\u00f1adir Servicio de Oferta label.add.SRX.device=Agregar dispositivo SRX label.add.static.nat.rule=Agregar regla NAT est\u00e1tica label.add.static.route=Agregar ruta est\u00e1tica label.add.system.service.offering=Agregar Oferta de Servicio del Sistema -label.add.template=A\u00f1adir Template +label.add.template=A\u00f1adir plantilla label.add.to.group=Agregar al grupo label.add.ucs.manager=Agregar UCS Manager label.add.user=Agregar usuario @@ -373,7 +373,7 @@ label.advanced.search=B\u00fasqueda Avanzada label.affinity=Afinidad label.affinity.group=Grupo de Afinidad label.affinity.groups=Grupos de Afinidades -label.agent.password=Contrase\u00f1a del Agente +label.agent.password=Password de Agente label.agent.port=Puerto del Agente label.agent.state=Estado del Agente label.agent.username=Usuario de Agente @@ -395,7 +395,7 @@ label.apply=Aplicar label.app.name=CloudStack label.archive.alerts=Archivar alertas label.archive=Archivar -label.archive.events=Archivar eventos +label.archive.events=Archivar sucesos label.assign=Asignar label.assigned.vms=VMs Asignadas label.assign.instance.another=Asignar la instancias a otra Cuenta @@ -423,13 +423,13 @@ label.baremetal.pxe.device=Agregar Proveedor PXE para Baremetal label.baremetal.pxe.devices=Dispositivo Baremetal para PXE label.baremetal.pxe.provider=Proveedor PXE para Baremetal label.baremetal.rack.configuration=Configuraci\u00f3n del Rack Baremetal -label.basic=B\u00e1sic0 +label.basic=B\u00e1sica label.basic.mode=Modo b\u00e1sico -label.bigswitch.bcf.details=Detalles del BigSwitch BCF +label.bigswitch.bcf.details=Detalles del Controlador BigSwitch BCF label.bigswitch.bcf.nat=BigSwitch BCF con NAT habilitado label.bigswitch.controller.address=Direcci\u00f3n del Controlador BigSwitch BCF -label.blade.id=ID de Blade -label.blades=Blades +label.blade.id=ID de Hoja +label.blades=Hojas label.bootable=arranque label.broadcast.domain.range=Rango del dominio de Broadcast label.broadcast.domain.type=Tipo de dominio de difusi\u00f3n @@ -443,9 +443,9 @@ label.by.alert.type=Por tipo de alerta label.by.availability=Por Disponibilidad label.by.date.end=Por fecha (finalizaci\u00f3n) label.by.date.start=Por fecha (inicio) -label.by.domain=Por Dominio +label.by.domain=Por dominio label.by.end.date=Por Fecha de finalizaci\u00f3n -label.by.event.type=Por tipo de evento +label.by.event.type=Por tipo de suceso label.by.level=por Nivel label.by.pod=Por Pod label.by.role=por funci\u00f3n @@ -484,10 +484,10 @@ label.clear.list=Limpiar lista label.close=Cerrar label.cloud.console=Cloud Management Console label.cloud.managed=Cloud.com Gestionado -label.cluster=Cl\u00faster -label.cluster.name=Nombre del Cl\u00faster -label.clusters=Clusters -label.cluster.type=Tipo de Cl\u00faster +label.cluster=Grupo +label.cluster.name=Nombre del Cluster +label.clusters=Cluster +label.cluster.type=Tipo de Cluster Server label.clvm=CLVM label.code=C\u00f3digo label.community=Comunidad @@ -502,7 +502,7 @@ label.configure.network.ACLs=Configurar ACLs de la Red label.configure.sticky.policy=Configurar pol\u00edtica de Sticky label.configure.vpc=Configurar VPC label.confirmation=Confirmation -label.confirm.password=Confirmar la contrase\u00f1a +label.confirm.password=Confirmar password label.congratulations=Felicitaciones \! label.conserve.mode=Conservar modo label.console.proxy=Consola proxy @@ -531,9 +531,9 @@ label.cross.zones=Cruz Zonas label.custom=A Medida label.custom.disk.iops=IOPS personalizadas label.custom.disk.offering=Oferta de Disco Personalizada -label.custom.disk.size=Tama\u00f1o de Disco Personalizado +label.custom.disk.size=Personal Disk Size label.daily=diario -label.data.disk.offering=Oferta para Disco de Datos +label.data.disk.offering=Datos Disco Offering label.date=Fecha label.day=D\u00eda label.day.of.month=D\u00eda del mes @@ -546,9 +546,9 @@ label.dedicated=Dedicado label.dedicate=Dedicar label.dedicated.vlan.vni.ranges=Rangos VLAN/VNI Dedicados label.dedicate.host=Servidor Dedicado -label.dedicate.pod=Dedicar Pod +label.dedicate.pod=Pod Dedicado label.dedicate.vlan.vni.range=Dedicar Rango VLAN/VNI -label.dedicate.zone=Dedicar Zona +label.dedicate.zone=Zona Dedicada label.default.egress.policy=Pol\u00edtica de salida por defecto label.default=Por Defecto label.default.use=Usar por defecto @@ -601,7 +601,7 @@ label.direct.attached.public.ip=IP P\u00fablica Conectada en forma Directa label.direct.ips=IPs de la Red Compartida label.disable.autoscale=Deshabilitar Escalado Autom\u00e1tico label.disabled=personas de movilidad reducida -label.disable.host=Deshabilitar Servidor +label.disable.host=Deshabitar Servidor label.disable.network.offering=Deshabitar oferta de red label.disable.provider=Deshabilitar proveedor label.disable.vnmc.provider=Deshabitar proveedor VNMC @@ -610,14 +610,14 @@ label.disable.vpn=Deshabilitar VPN label.disabling.vpn.access=Desactivaci\u00f3n de VPN de acceso label.disassociate.profile.blade=Remover asociaci\u00f3n entre Perfil y Blade label.disbale.vnmc.device=Deshabitar dispositivo VNMC -label.disk.allocated=Disco Asignado +label.disk.allocated=disco asignado label.disk.bytes.read.rate=Lectura de Disco (BPS) label.disk.bytes.write.rate=Escritura a Disco (BPS) label.disk.iops.max=IOPS m\u00e1ximas label.disk.iops.min=IOPS m\u00ednimas label.disk.iops.read.rate=Lectura de Disco (IOPS) label.disk.iops.total=Total de IOPS -label.disk.iops.write.rate=Escritura a Disco (IOPS) +label.disk.iops.write.rate=Escritura de Disco (IOPS) label.disk.offering.details=Detalles de oferta de disco label.disk.offering=disco Ofrenda label.diskoffering=oferta de disco @@ -639,10 +639,10 @@ label.dns=DNS label.DNS.domain.for.guest.networks=Dominio DNS para las Redes Guest label.domain.admin=Administrador de dominio label.domain.details=Detalles del Dominio -label.domain=Dominio -label.domain.id=ID de Dominio +label.domain=dominio +label.domain.id=ID de dominio label.domain.lower=dominio -label.domain.name=Nombre de Dominio +label.domain.name=Nombre de dominio label.domain.router=Router de Dominio label.domain.suffix=DNS sufijo de dominio (es decir, xyz.com) label.done=Listo @@ -663,7 +663,7 @@ label.edit.secondary.ips=Editar IPs secundarios label.edit.tags=Editar etiquetas label.edit.traffic.type=Edite el tipo de trafico label.edit.vpc=Editar VPC -label.egress.default.policy=Regla de salida predeterminada +label.egress.default.policy=Directiva de salida predeterminada label.egress.rule=Regla de salida label.egress.rules=Reglas de salida label.elastic=El\u00e1stico @@ -673,7 +673,7 @@ label.email=correo electr\u00f3nico label.email.lower=email label.enable.autoscale=Habilitar Escalado Autom\u00e1tico label.enable.host=Habilitar Servidor -label.enable.network.offering=Habilitar oferta de red +label.enable.network.offering=Habilitar oferta de red label.enable.provider=Habilitar proveedor label.enable.s3=Habilitar Almacenamiento Secundario sobre S3 label.enable.swift=Habilitar Swift @@ -698,7 +698,7 @@ label.ESP.encryption=Encriptaci\u00f3n ESP label.ESP.hash=Hash label.ESP.lifetime=Tiempo de vida ESP (en segundos) label.ESP.policy=Pol\u00edtica ESP -label.esx.host=Servidor ESX / ESXi +label.esx.host=ESX / ESXi anfitri\u00f3n label.event.archived=Evento Archivado label.event.deleted=Evento Borrado label.event=Evento @@ -706,7 +706,7 @@ label.every=Cada label.example=Ejemplo label.expunge=Purgar label.external.link=Enlace externo -label.extractable=Extra\u00edble +label.extractable=extra\u00edble label.extractable.lower=extraible label.f5.details=Detalles F5 label.f5=F5 @@ -724,7 +724,7 @@ label.friday=Viernes label.full=completo label.full.path=Path completo label.gateway=puerta de enlace -label.general.alerts=Alertas Generales +label.general.alerts=General de Alertas label.generating.url=Generar URL label.globo.dns.configuration=Configuraci\u00f3n de GloboDNS label.globo.dns=GloboDNS @@ -774,18 +774,18 @@ label.health.check.interval.in.sec=Intervalo de Health Check (en seg) label.health.check.message.desc=Tu load balancer automaticamente har\u00e1 health checks en tus instancias cloudstack y solo pasar\u00e1 el tr\u00e1fico a las instancias que lo cumplan. label.health.check=Verificaci\u00f3n de Salud label.health.check.wizard=Wizard para Health Check -label.healthy.threshold=Umbral Saludable +label.healthy.threshold=Barrera de Salud label.help=Ayuda label.hide.ingress.rule=Ocultar el art\u00edculo ingreso label.hints=Sugerencias label.home=Inicio -label.host.alerts=Alertas de Servidor -label.host.MAC=MAC del Servidor -label.host.name=nombre de servidor -label.host=Servidores -label.hosts=Servidores +label.host.alerts=Host Alertas +label.host=Ej\u00e9rcitos +label.host.MAC=MAC del Host +label.host.name=nombre de host +label.hosts=Ej\u00e9rcitos label.host.tag=Etiqueta del Servidor -label.host.tags=Etiquetas del Servidor +label.host.tags=Etiquetas de Host label.hourly=por hora label.hvm=HVM label.hypervisor.capabilities=Capacidades del Hipervisor @@ -813,9 +813,9 @@ label.installWizard.addHostIntro.title=Agreguemos un servidor label.installWizard.addPodIntro.subtitle=\u00bfQue es un Pod? label.installWizard.addPodIntro.title=Agreguemos un Pod label.installWizard.addPrimaryStorageIntro.subtitle=\u00bfQu\u00e9 es el almacenamiento primario? -label.installWizard.addPrimaryStorageIntro.title=Agreguemos el almacenamiento primario -label.installWizard.addSecondaryStorageIntro.subtitle=Que es el almacenamiento secundario? -label.installWizard.addSecondaryStorageIntro.title=Agreguemos un almacenamiento secundario +label.installWizard.addPrimaryStorageIntro.title=Agreguemos almacenamiento primario +label.installWizard.addSecondaryStorageIntro.subtitle=Que es almacenamiento secundario? +label.installWizard.addSecondaryStorageIntro.title=A\u00f1adir almacenamiento secundario label.installWizard.addZoneIntro.subtitle=\u00bfQu\u00e9 es una zona? label.installWizard.addZoneIntro.title=Agreguemos una zona label.installWizard.addZone.title=Agregar zona @@ -828,7 +828,7 @@ label.instance.name=Nombre de instancia label.instance.port=Puerto de Instancia label.instance.scaled.up=Instancia escalada a lo requerido en la oferta label.instances=Instancias -label.instanciate.template.associate.profile.blade=Instanciar Template y asociar al Perfil del Blade +label.instanciate.template.associate.profile.blade=Instanciar Plantilla y asociar al Perfil del Blade label.intermediate.certificate=Entidad de Certificaci\u00f3n Intermedia {0} label.internal.dns.1=DNS interno una label.internal.dns.2=DNS interno 2 @@ -889,7 +889,7 @@ label.key=Llave label.kvm.traffic.label=Etiqueta de tr\u00e1fico KVM label.label=Etiqueta label.lang.arabic=\u00c1rabe -label.lang.brportugese=Portugu\u00e9s de Brasil +label.lang.brportugese=Portugues de Brasil label.lang.catalan=Catal\u00e1n label.lang.chinese=Chino (simplificado) label.lang.dutch=Holandes @@ -955,7 +955,7 @@ label.max.primary.storage=Primario M\u00e1x. (GiB) label.max.public.ips=IPs p\u00fablicas M\u00e1x. label.max.secondary.storage=Secundario M\u00e1x. (GiB) label.max.snapshots=Instant\u00e1neas M\u00e1x. -label.max.templates=Templates M\u00e1ximos +label.max.templates=Plantillas M\u00e1ximos label.max.vms=VMs de usuario M\u00e1x. label.max.volumes=Maxima cantidad de Volumes label.max.vpcs=VPCs M\u00e1x. @@ -972,16 +972,16 @@ label.menu.alerts=Alertas label.menu.all.accounts=Todas las cuentas label.menu.all.instances=todas las instancias label.menu.community.isos=Comunidad ISOs -label.menu.community.templates=Templates de la Comunidad +label.menu.community.templates=plantillas de la comunidad label.menu.configuration=Configuraci\u00f3n label.menu.dashboard=Interfaz label.menu.destroyed.instances=Destruir instancias -label.menu.disk.offerings=Ofertas de Disco -label.menu.domains=Dominios +label.menu.disk.offerings=disco ofertas +label.menu.domains=dominio label.menu.events=Eventos label.menu.featured.isos=destacados ISO -label.menu.featured.templates=Templates Destacados -label.menu.global.settings=Configuraci\u00f3n Global +label.menu.featured.templates=destacados plantillas +label.menu.global.settings=Configuraci\u00f3n global label.menu.infrastructure=Infraestructura label.menu.instances=Instancias label.menu.ipaddresses=Direcciones IP @@ -989,7 +989,7 @@ label.menu.isos=ISO label.menu.my.accounts=Mis cuentas label.menu.my.instances=Mi instancias label.menu.my.isos=Mi ISOs -label.menu.my.templates=Mis Templates +label.menu.my.templates=Mis plantillas label.menu.network.offerings=Red de ofertas label.menu.network=Red label.menu.physical.resources=Recursos F\u00edsicos @@ -1004,13 +1004,13 @@ label.menu.storage=Almacenamiento label.menu.system.service.offerings=Ofertas de Sistema label.menu.system=Sistema label.menu.system.vms=Sistema de m\u00e1quinas virtuales -label.menu.templates=Templates +label.menu.templates=plantillas label.menu.virtual.appliances=Virtual Appliances label.menu.virtual.resources=Virtual de Recursos label.menu.volumes=Vol\u00famenes label.menu.vpc.offerings=Ofertas de VPC label.metrics.allocated=Asignados -label.metrics.clusters=Clusters +label.metrics.clusters=Cluster label.metrics.cpu.allocated=Asignaci\u00f3n de CPU label.metrics.cpu.max.dev=Desviaci\u00f3n label.metrics.cpu.total=Total @@ -1027,7 +1027,7 @@ label.metrics.disk.unallocated=Sin asignar label.metrics.disk.usage=Uso del Disco label.metrics.disk.used=Usado label.metrics.disk.write=Escritura -label.metrics.hosts=Servidores +label.metrics.hosts=Ej\u00e9rcitos label.metrics.memory.allocated=Asignaci\u00f3n de Memoria label.metrics.memory.max.dev=Desviaci\u00f3n label.metrics.memory.total=Total @@ -1044,13 +1044,13 @@ label.metrics.scope=Alcance label.metrics.state=Estado label.metrics.storagepool=Pool de Almacenamiento label.metrics.vm.name=Nombre de la VM -label.migrate.instance.to.host=Migrar instancia a otro servidor. +label.migrate.instance.to.host=Migrar instancia a otro host. label.migrate.instance.to=Migraci\u00f3n de ejemplo para -label.migrate.instance.to.ps=Migrar instancia a otro almacenamiento primario +label.migrate.instance.to.ps=Migrar instancia a otro primary storage. label.migrate.lb.vm=Migrar LB VM label.migrate.router.to=Router para migrar label.migrate.systemvm.to=Migrar m\u00e1quina virtual del sistema para -label.migrate.to.host=Migrar al server +label.migrate.to.host=Migrar a host label.migrate.to.storage=Migrar a almacenamiento label.migrate.volume=Migrar Volumen label.migrate.volume.to.primary.storage=Migrar volumen a otro almacenamiento primario @@ -1062,14 +1062,14 @@ label.minutes.past.hour=minuto(s) despu\u00e9s de la hora label.mode=modo label.monday=lunes label.monthly=mensual -label.more.templates=M\u00e1s Templates +label.more.templates=plantillas \= M\u00e1s label.move.down.row=Mover abajo una fila label.move.to.bottom=Mover al fondo label.move.to.top=Mover al principio label.move.up.row=Mover una fila arriba label.my.account=Mi Cuenta label.my.network=Mi red -label.my.templates=Mis Templates +label.my.templates=Mis plantillas label.name.lower=Nombre label.name=Nombre label.name.optional=Nombre (Opcional) @@ -1087,7 +1087,7 @@ label.network.desc=Red de Desc label.network.details=Detalles de la Red label.network.device=De dispositivos de red label.network.device.type=Tipo de red de dispositivos -label.network.domain=Red de Dominio +label.network.domain=red de dominio label.network.domain.text=Dominio de Red label.network.id=ID de red label.networking.and.security=Redes y Seguridad @@ -1116,7 +1116,7 @@ label.next=Siguiente label.nexusVswitch=Nexus 1000v label.nfs=NFS label.nfs.server=servidor NFS -label.nfs.storage=Almacenamiento NFS +label.nfs.storage=NFS Almacenamiento label.nic.adapter.type=Tipo de adaptador NIC label.nicira.controller.address=Direcci\u00f3n de Controladora label.nicira.l2gatewayserviceuuid=UUID del Servicio L2 Gateway @@ -1137,18 +1137,18 @@ label.no.security.groups=No hay grupos disponibles de Seguridad label.not.found=No se ha encontrado label.no.thanks=No, gracias label.notifications=Notificaciones -label.number.of.clusters=Cantidad de Clusters +label.number.of.clusters=N\u00famero de Clusters label.number.of.cpu.sockets=Cantidad de Sockets de CPU -label.number.of.hosts=N\u00famero de Servidores +label.number.of.hosts=N\u00famero de Hosts label.number.of.pods=N\u00famero de Pods -label.number.of.system.vms=Cantidad de VM\\\\'s de Sistema +label.number.of.system.vms=N\u00famero de VM\\\\'s del Systema label.number.of.virtual.routers=N\u00famero de Routers Virtuales label.number.of.zones=N\u00famero de Zonas label.num.cpu.cores=n\u00famero de n\u00facleos de CPU label.numretries=N\u00famero de reintentos label.ocfs2=OCFS2 label.offer.ha=Oferta HA -label.of.month=del mes +label.of.month=de mes label.ok=Aceptar label.opendaylight.controller=Controlador OpenDaylight label.opendaylight.controllerdetail=Detalles del Controlador OpenDaylight @@ -1174,11 +1174,11 @@ label.owner.domain=Due\u00f1o del Dominio label.palo.alto.details=Detalles de Palo Alto label.PA.log.profile=Perfil de Palo Alto Log label.PA=Palo Alto -label.parent.domain=Dominio Padre +label.parent.domain=Padres de dominio label.passive=Pasivo label.password=Contrase\u00f1a -label.password.enabled=Contrase\u00f1a Activada -label.password.lower=contraseña +label.password.enabled=Contrase\u00f1a Activado +label.password.lower=contrase\u00f1a label.password.reset.confirm=La Contrase\u00f1a se ha cambiado a label.PA.threat.profile=Perf\u00edl de Amenazas Palo Alto label.path=Ruta @@ -1191,7 +1191,7 @@ label.PING.CIFS.password=PING CIFS contrase\u00f1a label.PING.CIFS.username=PING CIFS nombre de usuario label.PING.dir=PING Directorio label.ping.path=Camino de Ping -label.PING.storage.IP=PING a la IP del almacenamiento +label.PING.storage.IP=PING almacenamiento IP label.planner.mode=Modo planificaci\u00f3n label.please.complete.the.following.fields=Por favor complete los siguientes campos label.please.specify.netscaler.info=Por favor especifique la informaci\u00f3n del Netscaler @@ -1214,12 +1214,12 @@ label.port.range=rango de puertos label.PreSetup=PreSetup label.prev=Anterior label.previous=Previo -label.primary.allocated=Almacenamiento Primario Asignado +label.primary.allocated=primaria asignado de almacenamiento label.primary.network=Red Primaria label.primary.storage=Almacenamiento Primario -label.primary.storage.count=Almacenamiento Primario del Pool +label.primary.storage.count=Pool Almacenamiento Primario label.primary.storage.limits=L\u00edmite del Almacenamiento Primario (GiB) -label.primary.used=Almacenamiento Primario Usado +label.primary.used=Primaria Almacenado label.private.Gateway=Gateway Privado label.private.interface=Interfaz privada label.private.ip=direcci\u00f3n IP privada @@ -1232,11 +1232,11 @@ label.private.port=Puerto privado label.private.zone=Zona Privada label.profile=Perfil label.project.dashboard=Tablero del Proyecto -label.project.id=ID del Proyecto +label.project.id=ID proyecto label.project.invite=Invitar al proyecto label.project.name=Nombre del Proyecto -label.project=Proyecto -label.projects=Proyectos +label.project=proyecto +label.projects=proyectos label.project.view=Vista de Proyecto label.protocol.number=N\u00famero de Protocolo label.protocol=Protocolo @@ -1273,7 +1273,7 @@ label.quota.description=Descripci\u00f3n de Quota label.quota.email.body=Cuerpo label.quota.email.lastupdated=\u00daltima Modificaci\u00f3n label.quota.email.subject=Tema -label.quota.email.template=Template de E-Mail +label.quota.email.template=Plantilla de E-Mail label.quota.enddate=Fecha de F\u00edn label.quota.endquota=Quota Final label.quota.enforcequota=Forzar Quota @@ -1355,7 +1355,7 @@ label.replace.acl=Reemplazar ACL label.required=Requerido label.requires.upgrade=Requiere Actualizaci\u00f3n label.reserved.ip.range=Rango IP Reservado -label.reserved.system.gateway=Gateway de sistema reservado +label.reserved.system.gateway=System gateway reservado label.reserved.system.ip=Reservados sistema de PI label.reserved.system.netmask=M\u00e1scara de red reservada para el sistema label.reset.ssh.key.pair.on.vm=Resetear el Par de Claves SSH en la VM @@ -1382,7 +1382,7 @@ label.revoke.project.invite=Cancelar Invitaci\u00f3n label.role=Papel label.root.certificate=Certificado Ra\u00edz label.root.disk.controller=Controladora de disco ROOT -label.root.disk.offering=Ofertas de Discos Root +label.root.disk.offering=Root Disco Offering label.root.disk.size=Tama\u00f1o del disco Root (GB) label.router.vm.scaled.up=Router VM Escaladas label.routing=Enrutamiento @@ -1416,12 +1416,12 @@ label.secondary.ips=IPs secundarios label.secondary.isolated.vlan.id=VLAN ID de Secundaria Aislada label.secondary.staging.store=Almacenamiento Secundario Temporario label.secondary.staging.store.details=Detalles del Almacenamiento Secundario Temporario -label.secondary.storage=Almacenamiento Secundario +label.secondary.storage=Almacenamiento secundario label.secondary.storage.count=Pools del Almacenamiento Secundario label.secondary.storage.details=Detalles del Almacenamiento Secundario label.secondary.storage.limits=L\u00edmite del Almacenamiento Secundario (GiB) label.secondary.storage.vm=VM de almacenamiento secundario -label.secondary.used=Almacenamiento Secundario Usado +label.secondary.used=Secundaria Almacenado label.secret.key=clave secreta label.security.group=Grupo de Seguridad label.security.group.name=Nombre de grupo de seguridad @@ -1436,7 +1436,7 @@ label.select.offering=Elija oferta label.select.project=Elegir Proyecto label.select.region=Elegir Regi\u00f3n label.select=Seleccione -label.select.template=Elegir Template +label.select.template=Elegir Plantilla label.select.tier=Elija Tier label.select-view=Seleccione vista label.select.vm.for.static.nat=Seleccione VM para NAT est\u00e1tica @@ -1447,13 +1447,13 @@ label.service.offering.details=Detalles de la oferta de servicio label.service.offering=Oferta de Servicio label.services=Servicios label.service.state=Estado del servicio -label.session.expired=Su Sesi\u00f3n a Caducado +label.session.expired=Session Caducado label.set.default.NIC=Definir NIC por defecto -label.settings=Seteos +label.settings=Setos label.setup=Configuraci\u00f3n label.setup.network=Configurar Red label.setup.zone=Configurar Zona -label.set.up.zone.type=Configurar tipo de zona +label.set.up.zone.type=Definir tipo de zona label.shared=compartidas label.SharedMountPoint=SharedMountPoint label.show.advanced.settings=Mostrar setos avanzados @@ -1490,7 +1490,7 @@ label.ssh.key.pair=Par de Claves SSH label.ssh.key.pairs=Par de Claves SSH label.standard.us.keyboard=Teclado Standard (US) label.start.IP=IP inicial -label.start.lb.vm=Arrancar LB VM +label.start.lb.vm=Arrancar VM LB label.start.port=Iniciar Puerto label.start.reserved.system.IP=IP inicial reservada para el sistema label.start.vlan=VLAN inicial @@ -1508,7 +1508,7 @@ label.step.1.title=Paso 1\: Seleccione una plantilla label.step.2=Paso 2 label.step.2.title=Paso 2\: Oferta de Servicio label.step.3=Paso 3 -label.step.3.title=Paso 3\: Seleccione una Oferta de Disco +label.step.3.title=Paso 3\: Seleccione un disco Ofrenda label.step.4=Paso 4 label.step.4.title=Paso 4\: Red label.step.5=Paso 5 @@ -1516,13 +1516,13 @@ label.step.5.title=Paso 5\: Revisi\u00f3n label.stickiness.method=M\u00e9todo de Stickiness label.stickiness=Stickiness label.sticky.cookie-name=Nombre de Cookie -label.sticky.domain=Dominio +label.sticky.domain=dominio label.sticky.expire=Expira label.sticky.holdtime=Tiempo de Retenci\u00f3n label.sticky.indirect=Indirecto label.sticky.length=Longitud label.sticky.mode=modo -label.sticky.name=Nombre de Sticky +label.sticky.name=Nombre Pegajoso label.sticky.nocache=No Cache label.sticky.postonly=Solo Post label.sticky.prefix=Prefijo @@ -1533,9 +1533,9 @@ label.stop.lb.vm=Parar LB VM label.stopped.vms=Detenido m\u00e1quinas virtuales label.storage=Almacenamiento label.storage.pool=Pool de Almacenamiento -label.storage.tags=Etiquetas de Almacenamiento +label.storage.tags=Etiquetas de almacenamiento label.storage.traffic=Tr\u00e1fico de Almacenamiento -label.storage.type=Tipo de Almacenamiento +label.storage.type=Tipo de almacenamiento label.subdomain.access=Acceso al Subdominio label.submit=Enviar label.submitted.by=[Enviado por\: ] @@ -1564,8 +1564,8 @@ label.tags=Etiquetas label.tag.value=Valor de Etiqueta label.target.iqn=Objetivo IQN label.task.completed=Tarea finalizada. -label.template.limits=Templates L\u00edmites -label.template=Template +label.template.limits=Plantilla L\u00edmites +label.template=plantilla label.TFTP.dir=Directorio de TFTP label.tftp.root.directory=Directorio ra\u00edz de TFTP label.theme.default=Tema Por Defecto @@ -1585,7 +1585,7 @@ label.timezone=Zona horaria label.token=Token label.total.cpu=Total CPU label.total.CPU=Total CPU -label.total.hosts=Total de Servidores +label.total.hosts=Total de Hosts label.total.memory=Memoria Total label.total.of.ip=Direcciones IP totales label.total.of.vm=Total de m\u00e1quinas virtuales @@ -1606,21 +1606,21 @@ label.unavailable=no disponible label.unhealthy.threshold=Fuera del Umbral Saludable label.unlimited=Unlimited label.untagged=sin etiquetar -label.update.project.resources=Actualizar recursos del proyecto +label.update.project.resources=Actualizar recurso del proyecto label.update.ssl.cert= Certificado SSL label.update.ssl= Certificado SSL label.updating=Actualizar label.upgrade.required=La Actualizaci\u00f3n es necesaria -label.upgrade.router.newer.template=Actualizar Router para usar el Template M\u00e1s Nuevo +label.upgrade.router.newer.template=Actualizar Router para usar una Plantilla m\u00e1s Nueva label.upload.from.local=Subir desde Local label.upload=Subir -label.upload.template.from.local=Subir Template desde Local +label.upload.template.from.local=Subir Plantilla desde Local label.upload.volume.from.local=Subir un Volumen desde Local label.upload.volume.from.url=Subir un Volumen desde URL label.upload.volume=Subir volumen label.url=URL label.usage.interface=Interfaz de uso -label.usage.sanity.result=Resultado del Uso Correcto +label.usage.sanity.result=Resultado del Uso Sanitizado label.usage.server=Servidor de Uso label.usage.type=Tipo de Uso label.usage.unit=Unidad @@ -1636,11 +1636,11 @@ label.use.vm.ips=Usar las IP de la VM label.use.vm.ip=Usar VM IP\: label.value=Valor label.vcdcname=nombre -label.vcenter.cluster=Cl\u00faster de vCenter +label.vcenter.cluster=vCenter cl\u00faster label.vcenter.datacenter=vCenter de centros de datos label.vcenter.datastore=vCenter almac\u00e9n de datos -label.vcenter.host=Servidor vCenter -label.vcenter.password=Contrase\u00f1a de vCenter +label.vcenter.host=vCenter anfitri\u00f3n +label.vcenter.password=vCenter Contrase\u00f1a label.vcenter.username=vCenter Nombre de usuario label.vcenter=vcenter label.vcipaddress=Direcci\u00f3n IP de vCenter @@ -1661,7 +1661,7 @@ label.virtual.appliance.details=Detalles del Virtual appliance label.virtual.appliances=Virtual Appliances label.virtual.appliance=Virtual Appliance label.virtual.machine=M\u00e1quinas virtuales -label.virtual.machines=M\u00e1quinas virtuales +label.virtual.machines=Maquinas virtuales label.virtual.networking=Red Virtual label.virtual.network=Red Virtual label.virtual.routers.group.account=Routers Virtuales agrupados por cuenta @@ -1705,7 +1705,7 @@ label.vmware.traffic.label=Etiquetas de tr\u00e1fico para VMware label.vnet.id=ID de VLAN label.vnet=VLAN label.vnmc.devices=Dispositivo VNMC -label.vnmc=VNMC +label.vnmc=ID de VM label.volatile=Vol\u00e1til label.volgroup=Volume Group label.volume.details=Detalles del Volumen @@ -1765,22 +1765,22 @@ label.zones=Zona label.zone.type=Tipo de Zona label.zone.wide=Zona para todo el label.zoneWizard.trafficType.guest=Guest\: Tr\u00e1fico entre las m\u00e1quinas virtuales del usuario final -label.zoneWizard.trafficType.management=Management\: Tr\u00e1fico entre los recursos internos de CloudStack\\\\'s, incluyendo cualquier componente que se comunique con el Management Server, tales como servidores y las VMs de sistema de CloudStack +label.zoneWizard.trafficType.management=Management\: Tr\u00e1fico entre los recursos internos de CloudStack\\\\'s, incluyendo cualquier componente que se comunique con el Management Server, tales como hosts y las VMs de systema de CloudStack label.zoneWizard.trafficType.public=Public\: Tr\u00e1fico entre la internet y las m\u00e1quinas virtuales en el cloud. -label.zoneWizard.trafficType.storage=Almacenamiento\: Tr\u00e1fico entre los servidores de almacenamiento primario y secundario, tales como templates de VM e instant\u00e1neas +label.zoneWizard.trafficType.storage=Almacenamiento\: Tr\u00e1fico entre los servidores de almacenamiento primario y secundario, tales como plantillas de VM e instant\u00e1neas label.zone=Zona managed.state=Estado logr\u00f3 message.acquire.ip.nic=Por favor confirme que desea adquirir una IP secundaria nueva para esta NIC.
NOTA\: Las direcciones IP secundarios adquiridas deben ser configuradas manualmente desde la m\u00e1quina virtual. message.acquire.new.ip=Por favor confirme que usted quiere adquirir una nueva IP para esta red message.acquire.new.ip.vpc=Por favor confirme que usted desea adquirir una nueva IP para este VPC. message.acquire.public.ip=Por favor seleccione una zona de la que desea adquirir su nueva IP. -message.action.cancel.maintenance=El servidor ha cancelado con \u00e9xito su entrada al modo mantenimiento. Este proceso puede tardar hasta varios minutos. message.action.cancel.maintenance.mode=Por favor, confirme que desea cancelar el mantenimiento +message.action.cancel.maintenance=Su acogida ha sido cancelado con \u00e9xito para el mantenimiento. Este proceso puede tardar hasta varios minutos. message.action.change.service.warning.for.instance=Su instancia debe estar apagada antes de intentar el cambio de la oferta de servicio activa. message.action.change.service.warning.for.router=Su router debe estar apagado antes de intentar el cambio de la oferta de servicio activa. -message.action.delete.cluster=Por favor, confirme que desea eliminar este cl\u00faster. -message.action.delete.disk.offering=Por favor, confirme que desea eliminar esta oferta de disco. -message.action.delete.domain=Por favor, confirme que desea eliminar este dominio +message.action.delete.cluster=Por favor, confirme que desea eliminar del cl\u00faster +message.action.delete.disk.offering=Por favor, confirme que desea eliminar ofreciendo disco +message.action.delete.domain=Por favor, confirme que desea eliminar de dominio message.action.delete.external.firewall=Por favor, confirme que desea quitar este servidor de seguridad externo. Advertencia\: Si usted est\u00e1 planeando volver a agregar el servidor de seguridad externo mismo, debe restablecer los datos de uso en el dispositivo. message.action.delete.external.load.balancer=Por favor, confirme que desea eliminar este equilibrador de carga externa. Advertencia\: Si usted est\u00e1 planeando volver a agregar la misma equilibrador de carga externo, debe restablecer los datos de uso en el dispositivo. message.action.delete.ingress.rule=Por favor, confirme que desea eliminar la regla de ingreso @@ -1789,30 +1789,30 @@ message.action.delete.ISO=Por favor, confirme que desea eliminar la norma ISO message.action.delete.network=Por favor, confirme que desea eliminar de la red message.action.delete.nexusVswitch=Porfavor confirme que usted quiere eliminar el Nexus 1000v message.action.delete.nic=Por favor, confirme que desea remover esta NIC, lo que har\u00e1 que sea removida la red de esta VM. -message.action.delete.physical.network=Por favor confirme que desea borrar esta red f\u00edsica. +message.action.delete.physical.network=Por favor confirme que desea borrar esta red f\u00edsica message.action.delete.pod=Por favor, confirme que desea eliminar de la vaina message.action.delete.primary.storage=Por favor, confirme que desea eliminar el almacenamiento primario -message.action.delete.secondary.storage=Por favor, confirme que desea eliminar este almacenamiento secundario. +message.action.delete.secondary.storage=Por favor, confirme que desea eliminar de almacenamiento secundario message.action.delete.security.group=Por favor, confirme que desea eliminar el grupo de seguridad message.action.delete.service.offering=Por favor, confirme que desea eliminar oferta de servicios message.action.delete.snapshot=Por favor, confirme que desea eliminar instant\u00e1neas message.action.delete.system.service.offering=Por favor confirme que desea borrar esta oferta de servicio. -message.action.delete.template.for.all.zones=El template es utilizado por todas las zonas. Por favor, confirme que desea eliminarlo de todas las zonas. -message.action.delete.template=Por favor, confirme que desea eliminar este template. +message.action.delete.template.for.all.zones=La plantilla es utilizada por todas las zonas. Por favor, confirme que desea eliminar de todas las zonas. +message.action.delete.template=Por favor, confirme que desea eliminar la plantilla message.action.delete.volume=Por favor, confirme que desea eliminar el volumen message.action.delete.zone=Por favor, confirme que desea eliminar la zona message.action.destroy.instance=Por favor, confirme que desea destruir ejemplo message.action.destroy.systemvm=Por favor, confirme que desea destruir la m\u00e1quina virtual del sistema. -message.action.disable.cluster=Por favor, confirme que desea deshabilitar este cl\u00faster. +message.action.disable.cluster=Por favor, confirme que desea desactivar este grupo. message.action.disable.nexusVswitch=Por favor confirme que usted quiere deshabilitar este nexus 1000v message.action.disable.physical.network=Por favor confirmar que usted quiere deshabilitar esta red f\u00edsica message.action.disable.pod=Por favor, confirme que desea desactivar esta vaina. message.action.disable.static.NAT=Por favor, confirme que desea desactivar NAT est\u00e1tica message.action.disable.zone=Por favor, confirme que desea desactivar esta zona. -message.action.downloading.template=Descargando template. +message.action.downloading.template=Descargando plantilla. message.action.download.iso=Por favor confirme que usted quiere descargar esta ISO message.action.download.template=Por favor confirme que usted quiere descargar este template -message.action.enable.cluster=Por favor, confirme que desea habilitar este cl\u00faster. +message.action.enable.cluster=Por favor, confirme que desea habilitar este grupo. message.action.enable.maintenance=Su acogida ha sido preparado con \u00e9xito para el mantenimiento. Este proceso puede tardar hasta varios minutos o m\u00e1s dependiendo de c\u00f3mo las m\u00e1quinas virtuales se encuentran actualmente en este servidor. message.action.enable.nexusVswitch=por favor confirme que usted quiere habilitar este nexus 1000v message.action.enable.physical.network=Por favor confirmar que usted quiere habilitar esta red f\u00edsica @@ -1830,7 +1830,7 @@ message.action.reboot.systemvm=Por favor, confirme que desea reiniciar el sistem message.action.release.ip=Por favor, confirme que desea liberar IP message.action.remove.host=Por favor confirme que desea borrar este servidor. message.action.reset.password.off=Su ejemplo en la actualidad no es compatible con esta funci\u00f3n. -message.action.reset.password.warning=Su instancia debe ser detenida antes de intentar cambiar la contrase\u00f1a actual. +message.action.reset.password.warning=Su ejemplo debe ser detenido antes de intentar cambiar su contrase\u00f1a actual. message.action.restore.instance=Por favor, confirme que desea restaurar ejemplo message.action.revert.snapshot=Por favor confirme que desea revertir el volumen elegido a esta instant\u00e1nea. message.action.start.instance=Por favor, confirme que desea iniciar la instancia @@ -1846,13 +1846,13 @@ message.action.vmsnapshot.revert=Revertir instant\u00e1nea de VM message.activate.project=Usted esta seguro que quiere activar este proyecto? message.add.cluster=A\u00f1adir un hipervisor administradas por cl\u00faster de zona , la consola de message.add.cluster.zone=A\u00f1adir un hipervisor administradas por cl\u00faster de zona -message.add.disk.offering=Por favor, especifique los par\u00e1metros siguientes para agregar una nueva oferta de disco +message.add.disk.offering=Por favor, especifique los par\u00e1metros siguientes para agregar un nuevo disco que ofrece message.add.domain=por favor especifique el subdominio que usted quiere crear bajo este dominio message.added.new.nuage.vsp.controller=Nuevo Controlador Nuage Vsp agregado message.added.vpc.offering=Oferta VPC agregada message.add.firewall=A\u00f1adir un servidor de seguridad a la zona message.add.guest.network=Por favor confirme que desea agregar una red de guest -message.add.host=Por favor, especifique los par\u00e1metros siguientes para agregar un nuevo servidor +message.add.host=Por favor, especifique los par\u00e1metros siguientes para agregar un nuevo host message.adding.host=Agregando un servidor message.adding.Netscaler.device=Agregando un dispositivo NetScaler message.adding.Netscaler.provider=Agregando un proveedor NetScaler @@ -1872,7 +1872,7 @@ message.add.region=Por favor cargue la informaci\u00f3n requerida para agregar u message.add.secondary.storage=A\u00f1adir un nuevo almacenamiento de zona message.add.service.offering=Por favor, rellene los siguientes datos para agregar una nueva oferta de servicio. message.add.system.service.offering=Por favor complete los siguientes datos para agregar un nueva oferta de servicio. -message.add.template=Por favor ingrese los siguientes datos para crear el nuevo template +message.add.template=Por favor ingrese los siguientes datos para crear la nueva plantilla message.add.volume=Por favor, rellene los siguientes datos para agregar un nuevo volumen. message.add.VPN.gateway=Por favor confirme que usted quiere agregar un VPN Gateway message.admin.guide.read=Para VM basadas en VMware, lea por favor el cap\u00edtulo de escalado din\u00e1mico en la gu\u00eda de administraci\u00f3n.\u00bfDesea continuar? @@ -1885,7 +1885,7 @@ message.alert.state.detected=Estado de Alerta detectado message.allow.vpn.access=Por favor, introduzca un nombre de usuario y la contrase\u00f1a del usuario que desea permitir el acceso de VPN. message.apply.snapshot.policy=Ha actualizado su pol\u00edtica instant\u00e1nea actual. message.attach.iso.confirm=Por favor, confirme que desea conectar el ISO a la instancia virtual -message.attach.volume=Por favor, rellene los siguientes datos para conectar un nuevo volumen. Si est\u00e1 conectando un volumen de disco a una m\u00e1quina virtual basada en Windows, deber\u00e1 reiniciar la instancia para ver el disco conectado. +message.attach.volume=Por favor, rellene los siguientes datos para fijar un nuevo volumen. Si est\u00e1 colocando un volumen de disco a una m\u00e1quina virtual de Windows basado, usted tendr\u00e1 que reiniciar la instancia para ver el disco adjunto. message.basic.mode.desc=Seleccione este modelo de red si lo haces * no * desea habilitar cualquier soporte VLAN. Todas las instancias virtuales creados en virtud de este modelo de red se le asignar\u00e1 una direcci\u00f3n IP directamente desde la red y grupos de seguridad se utilizan para proporcionar la seguridad y la segregaci\u00f3n. message.change.ipaddress=Por favor confirme que desea cambiar la direcci\u00f3n IP de esta NIC en la VM. message.change.offering.confirm=Por favor, confirme que desea cambiar la oferta de servicio de la instancia virtual. @@ -1900,7 +1900,7 @@ message.configuring.guest.traffic=Configurando el tr\u00e1fico de guest message.configuring.physical.networks=Configurando las redes f\u00edsicas message.configuring.public.traffic=Configurando el tr\u00e1fico public message.configuring.storage.traffic=Configurando el tr\u00e1fico de almacenamiento -message.confirm.action.force.reconnect=Por favor confirme que desea forzar la reconexi\u00f3n de este servidor. +message.confirm.action.force.reconnect=Por favor confirme que desea forzar la reconexi\u00f3n de este servidor message.confirm.add.vnmc.provider=Por favor confirme que desea agregar el proveedor VNMC. message.confirm.archive.alert=Por favor confirme que desea archivar esta alerta. message.confirm.archive.event=Por favor confirme que desea archivar este evento. @@ -1910,30 +1910,30 @@ message.confirm.attach.disk=\u00bf Est\u00e1 seguro que desea conectar el disco? message.confirm.create.volume=\u00bfEst\u00e1 seguro que desea crear un volumen? message.confirm.current.guest.CIDR.unchanged=\u00bfDesea mantener el CIDR de la red guest actual sin cambios? message.confirm.dedicate.cluster.domain.account=\u00bfRealmente desea dedicar este cluster al dominio/cuenta? -message.confirm.dedicate.host.domain.account=\u00bfDesea dedicar estos servidores a un dominio/cuenta? -message.confirm.dedicate.pod.domain.account=\u00bfDesea dedicar este pod a un dominio/cuenta? +message.confirm.dedicate.host.domain.account=\u00bfDesea dedicar este hosts a un dominio/cuenta? +message.confirm.dedicate.pod.domain.account=\u00bfDesea dedicar este por a un dominio/cuenta? message.confirm.dedicate.zone=\u00bfRealmente quiere dedicar esta zona a un domino/cuenta? message.confirm.delete.acl.list=\u00bfEsta seguro que desea borrar esta lista de ACL? message.confirm.delete.alert=\u00bfEst\u00e1 seguro que desea borrar esta alerta? -message.confirm.delete.baremetal.rack.configuration=Por favor confirme que desea borrar la Configuraci\u00f3n del Rack Baremetal. -message.confirm.delete.BigSwitchBcf=Por favor confirme que desa borrar este Controlador BigSwitch BCF -message.confirm.delete.BrocadeVcs=Por favor confirme que desa borrar este Switch Brocade Vcs +message.confirm.delete.baremetal.rack.configuration=Por favor confirme que desea borrar la configuraci\u00f3n del Rack Baremetal. +message.confirm.delete.BigSwitchBcf=Por favo confirme que desa borrar este Controlador BigSwitch BCF +message.confirm.delete.BrocadeVcs=Por favo confirme que desa borrar este Switch Brocade Vcs message.confirm.delete.ciscoASA1000v=Por favor confirme que desea borrar CiscoASA1000v message.confirm.delete.ciscovnmc.resource=Por favor confirme que desea borrar el recurso CiscoVNMC message.confirm.delete.F5=Por favor confirme que ud quiere eliminar el F5 message.confirm.delete.internal.lb=Por favor confirme que desea borrar este LB Interno -message.confirm.delete.NetScaler=Por favor confirme que desa borrar este NetScaler -message.confirm.delete.NuageVsp=Por favor confirme que desa borrar este Nuage Virtualized Services Directory +message.confirm.delete.NetScaler=Por favo confirme que desa borrar este NetScaler +message.confirm.delete.NuageVsp=Por favo confirme que desa borrar este Nuage Virtualized Services Directory message.confirm.delete.PA=Por favor confirme que desa borrar este Palo Alto message.confirm.delete.secondary.staging.store=Por favor confirme que desea borrar el Almacenamiento Secundario Temporal. message.confirm.delete.SRX=Por favor confirme que desa borrar este SRX message.confirm.delete.ucs.manager=Por favor confirme que desea borrar el UCS Manager -message.confirm.destroy.router=Por favor confirme que desea destruir este router +message.confirm.destroy.router=Por favor confirme que desa borrar este router message.confirm.disable.host=Por favor confirme que desea deshabitar este servidor message.confirm.disable.network.offering=\u00bfEsta seguro que desea deshabilitar esta oferta de red? -message.confirm.disable.provider=Por favor confirme que desea deshabilitar este proveedor +message.confirm.disable.provider=Por favor confirme que desea deshabitar este proveedor message.confirm.disable.vnmc.provider=Por favor confirme que desea deshabitar el proveedor VNMC. -message.confirm.disable.vpc.offering=\u00bfEsta seguro que desea deshabilitar esta oferta de VPC? +message.confirm.disable.vpc.offering=\u00bfEsta seguro que desea deshabitar esta oferta de VPC? message.confirm.enable.host=Por favor confirme que desea habilitar este servidor message.confirm.enable.network.offering=\u00bfEsta seguro que desea habilitar esta oferta de red? message.confirm.enable.provider=Por favor confirme que desea habilitar este proveedor @@ -1942,7 +1942,7 @@ message.confirm.enable.vpc.offering=\u00bfEsta seguro que desea habilitar esta o message.confirm.join.project=por favor confirme que usted desea unirse a este proyecto. message.confirm.migrate.volume=\u00bfQuiere migrar este volumen? message.confirm.refresh.blades=Por favor confirme que desea refrescar los blades. -message.confirm.release.dedicated.cluster=\u00bfDesea liberar este cl\u00faster dedicado? +message.confirm.release.dedicated.cluster=\u00bf Desea liberar este cl\u00faster dedicado? message.confirm.release.dedicated.host=\u00bfDesea liberar este servidor dedicado? message.confirm.release.dedicated.pod=\u00bfDesea liberar el uso dedicado del pod? message.confirm.release.dedicated.zone=\u00bfDesea liberar esta zona dedicada? @@ -1961,17 +1961,17 @@ message.confirm.scale.up.system.vm=\u00bfDesea escalar esta VM de sistema? message.confirm.shutdown.provider=Por favor confirme que desea apagar ester proveedor message.confirm.start.lb.vm=Por favor confirme que desea iniciar esta VM de LB message.confirm.stop.lb.vm=Por favor confirme que desea parar esta VM de LB -message.confirm.upgrade.router.newer.template=Por favor confirme que desea actualizar el router con un template m\u00e1s nuevo -message.confirm.upgrade.routers.account.newtemplate=Por favor confirme que desea actualizar todos los routers de esta cuenta con un template nuevo -message.confirm.upgrade.routers.cluster.newtemplate=Por favor confirme que desea actualizar todos los routers de este cluster con un template nuevo -message.confirm.upgrade.routers.newtemplate=Por favor confirme que desea actualizar todos los routers de esta zona con un template m\u00e1s nuevo -message.confirm.upgrade.routers.pod.newtemplate=Por favor confirme que desea actualizar todos los routers de este pod con un template nuevo +message.confirm.upgrade.router.newer.template=Por favor confirme que desea actualizar el router con una plantilla nueva +message.confirm.upgrade.routers.account.newtemplate=Por favor confirme que desea actualizar todos los routers de esta cuenta con una plantilla nueva +message.confirm.upgrade.routers.cluster.newtemplate=Por favor confirme que desea actualizar todos los routers de este cluster con una plantilla nueva +message.confirm.upgrade.routers.newtemplate=Por favor confirme que desea actualizar todos los routers de esta zona con una plantilla nueva +message.confirm.upgrade.routers.pod.newtemplate=Por favor confirme que desea actualizar todos los routers de este pod con una plantilla nueva message.copy.iso.confirm=Por favor, confirme que desea copiar el ISO a -message.copy.template.confirm=\u00bfEsta seguro que desea copiar este template? -message.copy.template=Copiar template XXX desde la zona hacia +message.copy.template.confirm=\u00bfDesea copiar esta plantilla? +message.copy.template=Copia plantilla XXX de la zona message.create.template=Esta seguro que quiere crear un template? -message.create.template.vm=Crear VM desde el template -message.create.template.volume=Por favor, especifique la siguiente informaci\u00f3n antes de crear un template desde su volumen de disco\: . El tiempo de creaci\u00f3n del template puede demorar unos minutos o m\u00e1s, dependiendo del tama\u00f1o del volumen. +message.create.template.vm=Crear VM de la plantilla +message.create.template.volume=Por favor, especifique la siguiente informaci\u00f3n antes de crear una plantilla de su volumen de disco\: . Creaci\u00f3n de la plantilla puede oscilar entre varios minutos m\u00e1s, dependiendo del tama\u00f1o del volumen. message.creating.cluster=Creando cluster message.creating.guest.network=Creando red guest message.creating.physical.networks=Creando redes f\u00edsicas @@ -1993,14 +1993,14 @@ message.delete.VPN.customer.gateway=Por favor confirme que desea borrar esta VPN message.delete.VPN.gateway=Por favor confirme que usted quiere eliminar este VPN Gateway message.desc.add.new.lb.sticky.rule=Agregar nueva regla Sticky al LB message.desc.advanced.zone=Para topologia de redes m\u00e1s sofisticadas. Este modelo de red provee la mayor flexibilidad al definir la redes guest y proveyendo ofertas de redes personalizadas tales como firewall, VPN, o soporte de load balancer. -message.desc.basic.zone=Provee una red \u00fanica donde cada instancia de VM se le asigna una IP de esta red. El aislamiento de Guest puede proveerse por medio de productos en layer-3 tales como los security groups (filtrado de direcciones IP por origen). +message.desc.basic.zone=Provee una red \u00fanica donde cada instancia de VM es asignada una IP directamente desde la red. El aislamiento de Guest puede proveerse por medio de layer-3 tales como los security groups (filtrado de direcciones IP por origen). message.desc.cluster=Cada por debe contener uno o m\u00e1s clusters, ahora agregaremos el primero. Un cluster contiene un grupo de servidores. Los servidores en el cluster tiene el mismo hardware, ejecutan el mismo hipervisors, est\u00e1n en la misma subred, y utilizan el mismo almacenamiento compartido. Cada cluster consiste en uno o m\u00e1s servidores y uno o m\u00e1s servidores de almacenamiento primario. message.desc.created.ssh.key.pair=Par de Claves SSH creadas. message.desc.create.ssh.key.pair=Por favor completar los siguientes datos para crear o registrar un par de claves ssh.

1. Si la clave p\u00fablica esta definida, CloudStack la registrar\u00e1. Uds puede usarla por medio de la clave privada.

2. Si la clave p\u00fablica no esta definida, CloudStack crear\u00e1 un nuevo Par de Claves SSH. En este caso, por favor copie y grab\u00e9 la clave privada. CloudStack no la almacenar\u00e1.
-message.desc.host=Cada cluster debe contener por lo menos un servidor (computadora) para que la VMs Guest ejecuten all\u00ed, y se agregara el primero ahora. Para que un servidor funcione en CloudStack, se debe instalar el software del hypervisor, asignarle una IP al host en la red de Management y asegurarse que se conecte al servidores de management de CloudStack.

Indicar el nombre DNS del servidor o su direcci\u00f3n IP, el nombre del usuario (usualmente root), su contrase\u00f1a y las etiquetas necesarias para catalogar los servidores. -message.desc.primary.storage=Cada cl\u00faster debe contener uno o m\u00e1s servidores primarios de almacenamiento, y ahora se agregara el primero. El almacenamiento primario contiene los volumenes de disco para todas las VMSs ejecutandose en los servidores del cl\u00faster. Utilice cualquier protocolo standard que soporte el hipervisor. -message.desc.reset.ssh.key.pair=Por favor especifique el par de claves ssh que desea agregar a esta VM. Tenga en cuenta que la clave de root ser\u00e1 cambiada al realizar esta operaci\u00f3n si la opci\u00f3n de contrase\u00f1a esta habilitada. -message.desc.secondary.storage=Cada zona debe tener al menos un servidor de NFS secundario, y se agregar\u00e1 el primero ahora. El almacenamiento secundario guarda los templates de VM, las im\u00e1genes ISO, y las instant\u00e1neas de volumentes. Este server debe estar disponible a todos los servidores de la zona.

Complete con la direcci\u00f3n IP y el PATH exportado +message.desc.host=Cada cluster debe contener por lo menos un host (servidor) para que la VMs Guest ejecuten all\u00ed, y se agregara el primero ahora. Para que un host funcione en CloudStack, se debe instalar el software del hypervisor, asignarle una IP al host en la red de Management y asegurarse que se conecte al servidores de management de CloudStack.

Indicar el nombre DNS del host o su direcci\u00f3n IP, el nombre del usuario (usualmente root), su contrase\u00f1a y las etiquetas necesarias para catalogar los hosts. +message.desc.primary.storage=Cada cl\u00faster debe contener uno o m\u00e1s servidores primarios de almacenamiento, y ahora se agregara el primero. El almacenamiento primario contiene los volumenes de disco para todas las VMSs ejecutandose en los hosts del cl\u00faster. Utilice cualquier protocolo standard que soporte el hipervisor. +message.desc.reset.ssh.key.pair=Pro favor especifique el par de claves ssh que desea agregar a esta VM. Tenga en cuenta que la clave de root ser\u00e1 cambiada al realizar esta operaci\u00f3n si la opci\u00f3n de contrase\u00f1a esta habilitada. +message.desc.secondary.storage=Cada zona debe tener al menos un servidor de NFS secundario, y se agregar\u00e1 el primero ahora. El almacenamiento secundario guarda las plantillas de VM, las im\u00e1genes ISO, y las instantaneas de volumentes. Este server debe estar disponible a todos los hosts de la zona.

Complete con la direcci\u00f3n IP y el PATH exportado message.desc.zone=Una zona es la unidad organizacional m\u00e1s grande en CloudStack, y t\u00edpicamente se corresponde con un datacenter en particular. Las Zonas proveen aislaci\u00f3n f\u00edsica y redundancia. Una zona consiste de uno o m\u00e1s pode (cada uno conteniendo servidores y almacenamiento primario), junto con el almacenamiento secundario que es compartido entre todos los pods en la zona message.detach.disk=\u00bf Est\u00e1 seguro que desea desconectar este disco? message.detach.iso.confirm=Por favor, confirme que desea quitar el ISO de la instancia virtual @@ -2013,7 +2013,7 @@ message.disabling.network.offering=Deshabilitar oferta de red message.disabling.vpc.offering=Deshabilitando oferta VPC message.disallowed.characters=Caracteres no permitidos\: \\<\\,\\> message.download.ISO=Por favor haga click 00000para descargar el ISO -message.download.template=Por favor haga click 00000para descargar el template +message.download.template=Por favor haga click 00000para descargar la plantilla message.download.volume.confirm=Por favor confirme que desea descargar este volumen. message.download.volume=Por favor, haga clic 00000 para bajar el volumen message.edit.account=Editar ("-1" indica que no hay limite a la cantidad de recursos creados) @@ -2042,24 +2042,24 @@ message.host.dedicated=Servidor Dedicado message.host.dedication.released=Dedicaci\u00f3n de Servidor liberada message.installWizard.click.retry=Haz click en el bot\u00f3n para re-intentar el lanzamiento de la instancia. message.installWizard.copy.whatIsACluster=Un cluster provee una forma de agrupar los servidores. Todos los servidores que componen el cluster tienen un hardware id\u00e9ntico, ejecutan el mismo hipervisor, est\u00e1n en la misma subred y utilizan el mismo almacenamiento compartido. Las instancias de las VMs pueden migrarse en caliente desde un servidor a otro dentro del mismo cluster, sin interrupci\u00f3n del servicio del usuario. Un cluster es la tercera forma organizacional en una instalaci\u00f3n de CloudStack&\#8482; . Los ilustres est\u00e1n contenidos dentro de los podes, los podes estar contenidos en las zonas.

CloudStack&\#8482; permite m\u00faltiple clusters en una instalaci\u00f3n de cloud, pero para realizar una instalaci\u00f3n b\u00e1sica, solo necesitamos uno. -message.installWizard.copy.whatIsAHost=Un servidor es una sola computadora. Los Servidores proveen los recursos de computo necesarios para ejecutar las m\u00e1quinas virtuales. Cada servidor tiene un hipervisor instalado para gestionar las VMs guest (excepto en los servidores baremetal, los cuales son un caso especial que se explaya en la Gu\u00eda de Administraci\u00f3n Avanzada). Por ejemplo, un servidor Linux con KVM habilitado, un servidor con Citrix XenServer o un servidor con ESXi. En una instalaci\u00f3n B\u00e1sica, usaremos un solo servidor ejecutando XenServer o KVM.

El servidor es la m\u00ednima unidad organizacional de CloudStack&\#8482; .Los servidores est\u00e1n contenidos dentro de los ilustres, los ilustres en los pods, y estos \u00faltimos en las zonas. +message.installWizard.copy.whatIsAHost=Un servidor es una sola computadora. Los Servidores proveen los recursos de computo necesarios para ejecutar las m\u00e1quinas virtuales. Cada servidor tiene un hipervisor instalado para gestionar las VMs guest (excepto en los servidores baremetal, los cuales son un caso especial que se explaya en la Gu\u00eda de Administraci\u00f3n Avanzada). Por ejemplo, un servidor Linux con KVM habilitado, un servidor con Citrix XenServer o un servidor con ESXi. En una instalaci\u00f3n Basica, usaremos un solo servidor ejecutando XenServer o KVM.

El servidor es la m\u00ednima unidad organizacional de CloudStack&\#8482; .Los servidores est\u00e1n contenidos dentro de los ilustres, los ilustres en los pods, y estos \u00faltimos en las zonas. message.installWizard.copy.whatIsAPod=Un pod representa generalmente un solo rock. Los servidores en el mismo por estar en la misma subred.

El por es la segunda agrupaci\u00f3n organizacional dentro de CloudStack&\#8482; .Los Pods est\u00e1n contenidos dentro de la zona. Cada zona puede contener uno m\u00e1s pods. En la instalaci\u00f3n B\u00e1sica, solo se necesita tener un por en la zona. message.installWizard.copy.whatIsAZone=Una zona es la unidad organizacional m\u00e1s grande dentro de una instalaci\u00f3n de CloudStack&\#8482;. Una zona tipicamente se corresponde a un solo datacenter, sin embargo esta permitido contar con varias zonas dentro del mismo datacenter. El beneficio de organizar la infraestructura en zonas es que provee aislaci\u00f3n f\u00edsica y redundancia. Por ejemplo, cada zona puede tener su propia fuente de alimentaci\u00f3n y lo mismo con su salida de red, ademas de poder estar separadas geograficamente en grandes distancias (lo cual no es obligatorio). message.installWizard.copy.whatIsCloudStack=CloudStack&\#8482 es una plataforma de software que aglutina recursos computo para poder crear coludas de infraestructuras como Servicio (IaaS), tanto p\u00fablicas como privadas.\nCloudStack&\#8482 gestiona la red, el almacenamiento y los nodos de computo que conforma la infraestructura de cloud. Se puede usar CloudStack&\#8482 para desplegar, gestionar y configurar ambientes de cloud computan.

Extendiendose m\u00e1s all\u00e1 del manejo individual de m\u00e1quinas virtuales en hardware comotidizado, CloudStack&\#8482 provee una soluci\u00f3n llave en mano de un software de infraestructura de red para ofrecer datacenter virtuales como servicio, proveyendo todos los componentes esenciales para construir, desplegar y gestionar aplicaciones cloud multi-tier y multi-tenant. Se ofrecen dos versiones, la open source y la Premium, brindando la primera caracter\u00edsticas casi id\u00e9nticas. message.installWizard.copy.whatIsPrimaryStorage=La infraestrucutra cloud de CloudStack&\#8482 hace uso de dos tipos de almacenamiento, el primario y el secundario. Ambos pueden ser iSCSI, NFS o discos locales.

El Almacenamiento Primario se asocia a un cluster, y almacena los vol\u00famenes de discos de cada VM para todas las VMs en los servidores del cluster. El almacenamiento primario es t\u00edpicamente alojado cerca de los servidores. -message.installWizard.copy.whatIsSecondaryStorage=El almacenamiento secundario est\u00e1 asociado a una zona, y almacena lo siguiente\:
  • Templates - im\u00e1genes del sistema operativo que se pueden utilizar para arrancar VMs, pueden incluir informaci\u00f3n de configuraci\u00f3n adicional, como las aplicaciones instaladas
  • Im\u00e1genes ISO - im\u00e1genes del Sistema Operativo que pueden ser boteables o no boteables
  • Instant\u00e1neas de vol\u00famenes de disco - copias de datos guardadas de VM que se pueden utilizar para la recuperaci\u00f3n de datos o para crear nuevos templates
+message.installWizard.copy.whatIsSecondaryStorage=El almacenamiento secundario est\u00e1 asociado a una zona, y almacena lo siguiente\:
  • Plantillas - im\u00e1genes del sistema operativo que se pueden utilizar para arrancar VMs, pueden incluir informaci\u00f3n de configuraci\u00f3n adicional, como las aplicaciones instaladas
  • Im\u00e1genes ISO - im\u00e1genes del Sistema Operativo que pueden ser boteables o no boteables
  • Disco instant\u00e1neas de vol\u00famenes - copias de datos guardadas de VM que se pueden utilizar para la recuperaci\u00f3n de datos o para crear nuevas plantillas
message.installWizard.now.building=Ahora construyendo su nube... message.installWizard.tooltip.addCluster.name=Nombre del Cluster. Puede ser alfanum\u00e9rico .Este no es usado por CloudStack -message.installWizard.tooltip.addHost.hostname=El nombre DNS o direcci\u00f3n IP del servidor. -message.installWizard.tooltip.addHost.password=Esta es la contrase\u00f1a del usuario mencionado anteriormente (Desde su Instalaci\u00f3n XenServer) +message.installWizard.tooltip.addHost.hostname=El nombre DNS o direcci\u00f3n IP del host +message.installWizard.tooltip.addHost.password=Este es el password para el nombre de usuario mencionado anteriormente (Desde su Instalaci\u00f3n XenServer) message.installWizard.tooltip.addHost.username=Generalmente root message.installWizard.tooltip.addPod.name=Nombre del POD message.installWizard.tooltip.addPod.reservedSystemEndIp=Este es el rango de direcciones IP en la red privada que la CloudStack utiliza para administrar las VMs del Almacenamiento Secundario y consola Proxy. Estas direcciones IP se han tomado de la misma subred que los servidores inform\u00e1ticos. -message.installWizard.tooltip.addPod.reservedSystemGateway=El gateway para los servidores en ese pod. -message.installWizard.tooltip.addPod.reservedSystemNetmask=La m\u00e1scara de red en uso en la subred de los guest ser\u00e1. +message.installWizard.tooltip.addPod.reservedSystemGateway=El gateway ,puerta de enlace, para los host en ese pod. +message.installWizard.tooltip.addPod.reservedSystemNetmask=La m\u00e1scara de red en uso en la subred de los hu\u00e9spedes ser\u00e1. message.installWizard.tooltip.addPod.reservedSystemStartIp=Este es el rango de direcciones IP en la red privada que la CloudStack utiliza para administrar las VMs del Almacenamiento Secundario y consola Proxy. Estas direcciones IP se han tomado de la misma subred que los servidores inform\u00e1ticos. message.installWizard.tooltip.addPrimaryStorage.name=\ Nombre para el storage -message.installWizard.tooltip.addPrimaryStorage.path=(para NFS) En NFS este es el directorio exportado desde el servidor. Directorio (por SharedMountPoint). Con KVM este es el directorio de cada servidor en donde se monta el almacenamiento primario. Por ejemplo, "/mnt/primary". +message.installWizard.tooltip.addPrimaryStorage.path=(para NFS) En NFS este es el directorio exportado desde el servidor. Directorio (por SharedMountPoint). Con KVM este es el directorio de cada host en donde se monta el almacenamiento primario. Por ejemplo, "/mnt/primary". message.installWizard.tooltip.addPrimaryStorage.server=(para NFS, iSCSI, o PreSetup) La direcci\u00f3n IP o el nombre DNS del dispositivo de almacenamiento. message.installWizard.tooltip.addSecondaryStorage.nfsServer=Direcci\u00f3n IP del servidor NFS que contiene el secondary storage message.installWizard.tooltip.addSecondaryStorage.path=El path exportado, ubicado en el servidor especificado anteriormente @@ -2075,7 +2075,7 @@ message.installWizard.tooltip.configureGuestTraffic.guestNetmask=La m\u00e1scara message.installWizard.tooltip.configureGuestTraffic.guestStartIp=El rango de direcciones IP que estar\u00e1 disponible para los guest en esta zona. Si se utiliza una sola NIC, estas IPs estar\u00e1n en el mismo CIDR del pod. message.installWizard.tooltip.configureGuestTraffic.name=Nombre de su RED message.instance.scaled.up.confirm=\u00bfRealmente desea escalar la instancia? -message.instanceWizard.noTemplates=No tienes templates disponibles, por favor agregue uno compatible y re-inicie el asistente de creaci\u00f3n de instancias. +message.instanceWizard.noTemplates=No tienes plantillas disponibles, por favor agregue una plantilla compatible y reinicio el asistente de creaci\u00f3n de instancias. message.ip.address.changed=Su direcci\u00f3n IP pudo haber cambiado. Le gustar\u00eda actualizar el listado? Tenga en cuenta que en este caso el panel de detalles se cerrar\u00e1. message.iso.desc=Disco con la imagen contenedora de los datos o los medios bootables para el SO message.join.project=Ahora estas unido al proyecto. Por favor cambiar a la Vista de Proyecto para verlo. @@ -2086,23 +2086,23 @@ message.link.domain.to.ldap=Habilitar autosync para este dominio en LDAP message.listView.subselect.multi=(Ctrl/Cmd-click) message.lock.account=Por favor, confirme que desea bloquear esta cuenta. Al bloquear la cuenta, todos los usuarios de esta cuenta ya no ser\u00e1 capaz de gestionar sus recursos de la nube. Los recursos existentes todav\u00eda se puede acceder. message.migrate.instance.confirm=Por favor, confirme el anfitri\u00f3n desea migrar la instancia virtual. -message.migrate.instance.to.host=Por favor, confirmar que desea mover la instancia a otro servidor. +message.migrate.instance.to.host=Por favor, confirmar que desea mover la instancia a otro host. message.migrate.instance.to.ps=Por favor, confirmar que desea mover la instancia a otro primary storage. -message.migrate.router.confirm=Por favor, confirme el servidor que desea migrar el router\: -message.migrate.systemvm.confirm=Por favor, confirme el servidor al que desea migrar la m\u00e1quina virtual de sistema\: +message.migrate.router.confirm=Por favor, confirme el hu\u00e9sped que desea migrar el router\: +message.migrate.systemvm.confirm=Por favor, confirme el hu\u00e9sped que desea migrar la m\u00e1quina virtual de sistema\: message.migrate.volume=Por favor confirme que usted quiere migrar el volumen a otro almacenamiento primario message.network.addVM.desc=Por favor indique la red que desea agregar a esta VM. Una NIC nueva se agregar\u00e1 en esta red. message.network.addVMNIC=Por favor confirme que desea agregar una nueva NIC a la VM para esta red. message.network.remote.access.vpn.configuration=Se ha creado la configuraci\u00f3n de acceso remoto por VPN, pero fall\u00f3 su aplicaci\u00f3n. Por favor verifique la conectividad de todos los elementos de red y vuelva a intentarlo. message.new.user=Especifique lo siguiente para agregar un nuevo usuario a la cuenta message.no.affinity.groups=No hay ning\u00fan grupo de afinidad. Por favor continue con el paso siguiente. -message.no.host.available=No hay disponibles Servidores para la Migraci\u00f3n +message.no.host.available=No hay disponibles Hosts para la Migraci\u00f3n message.no.network.support.configuration.not.true=Usted no tiene ninguna zona que ha permitido a grupo de seguridad. Por lo tanto, no hay funciones de red adicionales. Por favor, contin\u00fae con el paso 5. message.no.network.support=El hipervisor seleccionado, vSphere, no tiene funciones de red adicionales. Por favor, contin\u00fae con el paso 5. message.no.projects.adminOnly=No tienes ning\u00fan proyecto.
Por favor dile a tu administrador que cree uno nuevo. -message.no.projects=No tienes ning\u00fan proyecto.
Por favor crea uno nuevo desde la secci\u00f3n de Proyectos. -message.number.clusters=

\# de Clusters

-message.number.hosts=

\# de Servidores

+message.no.projects=No tienes ning\u00fan proyecto.
Pro favor crear uno nuevo desde la secci\u00f3n de Proyectos. +message.number.clusters=

\# de Grupos

+message.number.hosts=

\# de Anfitri\u00f3n

message.number.pods=

\# de Las vainas

message.number.storage=

\# de Almacenamiento primario

message.number.zones=

\# de Zonas

@@ -2115,7 +2115,7 @@ message.please.confirm.remove.ssh.key.pair=Por favor confirme que usted quiere e message.please.proceed=Por favor proceda a el siguiente paso. message.please.select.a.configuration.for.your.zone=Por favor elija una configuraci\u00f3n para su zona. message.please.select.a.different.public.and.management.network.before.removing=Por favor elija una red public y de management diferente antes de remover -message.please.select.networks=Por favor seleccione la red para su m\u00e1quina virtual. +message.please.select.networks=Por favor seleccione la red para su maquina virtual. message.please.select.ssh.key.pair.use.with.this.vm=Por favor elija el par de claves ssh que desea usar en esta VM\: message.please.wait.while.zone.is.being.created=Por favor espere un momento la zona esta siendo creada, puede llegar a demorar unos minutos... message.pod.dedication.released=Dedicaci\u00f3n de Pod liberada @@ -2125,15 +2125,15 @@ message.public.traffic.in.advanced.zone=El tr\u00e1fico p\u00fablico se genera c message.public.traffic.in.basic.zone=El tr\u00e1fico p\u00fablico es generado cuando las VMs en el cloud acceden a Internet o proveen servicios a clientes sobre Internet. Direcciones IPs accesible p\u00fablicamente deben ser asignadas para este cometido. Cuando una instancia es creada, una IP de este conjunto de IPs Publicas es asignada a la instancia ademas de la direcci\u00f3n IP en la red guest. NAT est\u00e1tico 1-1 ser\u00e1 configurado en forma autom\u00e1tica entre la IP p\u00fablica y la IP guest. Los usuarios tambi\u00e9n pueden utilizar la interfaz de CLoudStack para adquirir IPs adicionales para implementar NAT est\u00e1tico entre las instancias y la IP p\u00fablica. message.question.are.you.sure.you.want.to.add=Est\u00e1 seguro que quiere agregar message.read.admin.guide.scaling.up=Por favor les la secci\u00f3n de escalado din\u00e1mico en la gu\u00eda de administraci\u00f3n antes de escalarlo. -message.recover.vm=Por favor confirmar que se quiere recuperar esta VM. +message.recover.vm=Confirme que quiere recuperar esta VM. message.redirecting.region=Redirigiendo a la regi\u00f3n... -message.reinstall.vm=NOTA\: Proceda con precauci\u00f3n. Esta acci\u00f3n har\u00e1 que la VM se vuelva a instalar usando el template. Los datos en el disco de base se perder\u00e1n. Los vol\u00famenes de datos adicionales no se modificar\u00e1n. +message.reinstall.vm=NOTA\: Proceda con precauci\u00f3n. Esta acci\u00f3n har\u00e1 que la VM se vuelva a instalar usando la plantilla. Los datos en el disco de base se perder\u00e1n. Los vol\u00famenes de datos adicionales no se modificar\u00e1n. message.removed.ssh.key.pair=Se removi\u00f3 un Par de Claves SSH message.remove.ldap=\u00bfQuiere borrar la configuraci\u00f3n LDAP? message.remove.region=\u00bfEsta seguro que desea remover esta regi\u00f3n del servidor de management? message.remove.vpc=Por favor confirme que usted quiere eliminar el VPC message.remove.vpn.access=Por favor, confirme que desea eliminar el acceso VPN desde el siguiente usuario -message.reset.password.warning.notPasswordEnabled=El Template de esta instancia fue creado sin la gesti\u00f3n de contrase\u00f1a habilitada +message.reset.password.warning.notPasswordEnabled=El Template de esta instancia fue creado sin gesti\u00f3n de contrase\u00f1a habilitada message.reset.password.warning.notStopped=Su instancia debe ser detenida antes de intentar cambiar la contrase\u00f1a actual. message.reset.VPN.connection=Por favor confirme que desea respetar la conexi\u00f3n de la VPN message.restart.mgmt.server=Por favor, reinicie el servidor de administraci\u00f3n (s) para la nueva configuraci\u00f3n surta efecto. @@ -2150,39 +2150,39 @@ message.select.iso=Por favor seleccione un ISO para su nueva instancia virtual message.select.item=Por favor, seleccionar un item . message.select.security.groups=Por favor elija los security group(s) para su nueva VM message.select.template=Por favor seleccione un template para su nueva instancia virtual -message.select.tier=Por favor elija un Tier -message.set.default.NIC.manual=Por favor ahora actualice manualmente la NIC por defecto en la VM. +message.select.tier=Por favo elija un Tier +message.set.default.NIC.manual=Por favor actualice manualmente la NIC por defecto en la VM. message.set.default.NIC=Por favor que desea que esta NIC sea la por defecto en esta VM. -message.setup.physical.network.during.zone.creation.basic=Cuando se esta agregando un zona b\u00e1sica, puedes setear un red f\u00edsica que se corresponda a una NIC del hipervisor. La red transporta varios tipos de tr\u00e1fico.

Puedes tambi\u00e9n arrastrar y soltar otro tipo de tr\u00e1ficos en la interfaz f\u00edsica. +message.setup.physical.network.during.zone.creation.basic=Cuando se esta agregando un zona b\u00e1sica, puedes sesear un red f\u00edsica que se corresponda a una NIC del hipervisor. La red transporta varios tipos de tr\u00e1fico.

Puedes tambi\u00e9n arrastrar y soltar otro tipo de tr\u00e1ficos en la interfaz f\u00edsica. message.setup.physical.network.during.zone.creation=Cuando se esta agregando una zona avanzada, se necesita setear una o m\u00e1s redes f\u00edsicas. Cada red se corresponder\u00e1 con una NIC del hipervisor. Cada red f\u00edsica puede transportar uno o m\u00e1s tipos de tr\u00e1fico, con ciertas restricciones en como ellos se combinan.

Arrastre y suelte uno o m\u00e1s tipos de tr\u00e1fico sobre cada red f\u00edsica. message.setup.successful=La configuraci\u00f3n de la cloud finalizo satisfactoriamente. message.snapshot.schedule=Puedes definir cronogramas de instant\u00e2neas recurrentes al seleccionar las opciones disponibles debajo y aplicando las pol\u00edticas deseadas message.specifiy.tag.key.value=Por favor especifique una etiqueta con clave y valor message.specify.url=Por favor especifique la URL -message.step.1.continue=Por favor seleccione un template o imagen ISO para continuar -message.step.1.desc=Por favor seleccione un template para la instancia virtual. Tambi\u00e9n puede optar por seleccionar un template en blanco desde el que se pueda instalar una imagen ISO. +message.step.1.continue=Por favor seleccione una plantilla o ISO para continuar +message.step.1.desc=Por favor seleccione una plantilla para la instancia virtual. Tambi\u00e9n puede optar por seleccionar una plantilla en blanco desde el que puede ser una imagen ISO instalado en. message.step.2.continue=Por favor seleccione una oferta de servicio para continuar message.step.3.continue=Por favor seleccione una oferta en disco para continuar message.step.4.continue=Por favor seleccione al menos una red social para continuar message.step.4.desc=Por favor, seleccione la red primaria que la instancia virtual estar\u00e1 conectado. -message.storage.traffic=Tr\u00e1fico entre los recursos internos de CloudStack\\\\'s, incluyendo cualquier componente que se comunique con el Management Server, tales como servidores y las VMs de sistema de CloudStack +message.storage.traffic=Tr\u00e1fico entre los recursos internos de CloudStack\\\\'s, incluyendo cualquier componente que se comunique con el Management Server, tales como hosts y las VMs de systema de CloudStack message.suspend.project=\u00bfEst\u00e1 seguro que desea suspender este proyecto? message.systems.vms.ready=VM de Sistema lista. -message.template.copying=El Template esta siendo copiado. +message.template.copying=La Plantilla esta siendo copiada. message.template.desc=La imagen de OS que puede usarse para iniciar una VM message.tier.required=El Tier es obligatorio. message.tooltip.dns.1=Nombre del servidor DNS que ser\u00e1 usado por las VMs en la zona. Las direcciones IP p\u00fablicas de la zona deber\u00e1n llegar a este servidor. -message.tooltip.dns.2=El nombre del segundo servidor DNS para ser usado por las VMs en esta zona. La direcci\u00f3n IP p\u00fablica para esta zona debe ser accesible desde este servidor. +message.tooltip.dns.2=El nombre del segundo servidor DNS para ser usado por las VMs en esta zona. La direcci\u00f3n IP p\u00fablica para esta zona debe ser accesible desde el servidor. message.tooltip.internal.dns.1=Nombre del servidor DNS que ser\u00e1 usado por las VMs internas de sistema de CloudStack en la zona. Las direcciones IP p\u00fablicas de la zona deber\u00e1n llegar a este servidor. message.tooltip.internal.dns.2=Nombre del servidor DNS que ser\u00e1 usado por las VMs internas de sistema de CloudStack en la zona. Las direcciones IP p\u00fablicas de la zona deber\u00e1n llegar a este servidor. message.tooltip.network.domain=Un subfijo DNS que crear\u00e1 un nombre de dominio personalizado para la red que es acceso da por las VMs guest. message.tooltip.pod.name=Un nombre para este pod. -message.tooltip.reserved.system.gateway=El gateway para los servidores en el pod. +message.tooltip.reserved.system.gateway=El gateway para los hosts en el pod. message.tooltip.reserved.system.netmask=El prefijo de red que define la subred del pod. Use notaci\u00f3n CIDR. message.tooltip.zone.name=Un nombre para la zona. -message.update.os.preference=Por favor seleccione un sistema operativo de preferencia para este servidor. Todas las instancias virtuales con preferencias similares ser\u00e1n los primeros asignados a este servidor antes de elegir otro. +message.update.os.preference=Por favor seleccione un sistema operativo de preferencia para este equipo. Todas las instancias virtuales con preferencias similares ser\u00e1n los primeros asignados a este equipo antes de elegir otro. message.update.resource.count=Por favor confirme que usted quiere actualizar los conteos para esta cuenta -message.update.ssl.failed=Fallo la actualizaci\u00f3n del Certificado SSL. +message.update.ssl.failed=Fallo la actualizaci\u00f3n del Certficado SSL. message.update.ssl=Por favor, env\u00ede una nueva X.509 compatible con certificado SSL que se actualizar\u00e1 a cada instancia virtual de la consola del servidor proxy\: message.update.ssl.succeeded=Actualizaci\u00f3n del Certificado SSL exitosa message.validate.accept=Por favor ingrese un valor con extensi\u00f3n v\u00e1lida. @@ -2190,36 +2190,36 @@ message.validate.creditcard=Por favor ingrese un n\u00famero de tarjeta de cr\u0 message.validate.date.ISO=Por favor ingrese una fecha (ISO) v\u00e1lida. message.validate.date=Por favor ingrese una fecha v\u00e1lida. message.validate.digits=Por favor ingrese solo n\u00fameros. -message.validate.email.address=Por favor ingrese un email v\u00e1lido. +message.validate.email.address=Por favor ingrese i+un email v\u00e1lido. message.validate.equalto=Por favor ingrese el mismo valor nuevamente. message.validate.fieldrequired=Este campo es obligatorio. message.validate.fixfield=Por favor corrija este campo. message.validate.instance.name=El nombre de la instancia no puede ser m\u00e1s largo que 63 caracteres. Solo se permiten letras ASCII tales como a~z, A~Z, n\u00fameros 0~9, los guiones est\u00e1n permitidos. Deben empezar con una letra y finalizar con una letra o un n\u00famero. message.validate.invalid.characters=Se han hallado caracteres no v\u00e1lidos. Por favor, corr\u00edjalos. message.validate.maxlength=Por favor ingrese no m\u00e1s que {0} caracteres. -message.validate.max=Por favor ingrese un valor menor o igual que {0}. +message.validate.max=Por favor ingrese un valor menor o igual que {0}. message.validate.minlength=Por favor ingrese al menos {0} caracteres. message.validate.number=Por favor ingrese un n\u00famero v\u00e1lido. message.validate.range.length=Por favor ingrese un valor entre {0} y {1} caracteres de longitud. message.validate.range=Por favor ingrese un valor entre {0} y {1}. message.validate.URL=Por favor ingrese una URL v\u00e1lida. message.virtual.network.desc=Una red dedicada virtualizados para su cuenta. El dominio de difusi\u00f3n est\u00e1 contenida dentro de una VLAN y todos los acceso a la red p\u00fablica se encamina a cabo por un router virtual. -message.vm.create.template.confirm=Crear el Template reiniciar\u00e1 autom\u00e1ticamente la m\u00e1quina virtual. +message.vm.create.template.confirm=Crear plantilla de la m\u00e1quina virtual se reiniciar\u00e1 autom\u00e1ticamente. message.vm.review.launch=Por favor verifique la siguiente informaci\u00f3n es correcta y confirme antes de lanzarla. message.vnmc.available.list=VNMC no esta disponible en esta lista de proveedores. message.vnmc.not.available.list=VNMC no esta disponible en esta lista de proveedores. -message.volume.create.template.confirm=Por favor, confirme que desea crear un template desde este volumen de disco. El tiempo de creaci\u00f3n del template puede demorar unos minutos o varios m\u00e1s, dependiendo del tama\u00f1o del volumen. -message.waiting.for.builtin.templates.to.load=Esperando que se carguen los templates incorporados... +message.volume.create.template.confirm=Por favor, confirme que desea crear una plantilla para este volumen de disco. Creaci\u00f3n de la plantilla puede oscilar entre varios minutos m\u00e1s, dependiendo del tama\u00f1o del volumen. +message.waiting.for.builtin.templates.to.load=Esperando por las plantillas incorporadas para cargar... message.XSTools61plus.update.failed=La actualizaci\u00f3n fall\u00f3, la versi\u00f3n original de XS es 6.1\\+. Error\: message.you.must.have.at.least.one.physical.network=Debes tener por lo menos una red f\u00edsica -message.your.cloudstack.is.ready=\u00a1Tu CloudStack esta listo\! +message.your.cloudstack.is.ready=Tu CloudStack esta listo\! message.Zone.creation.complete=Creci\u00f3n de la zona completada message.zone.creation.complete.would.you.like.to.enable.this.zone=Creci\u00f3n de la zona completada.\u00bfDesea habilitarla? message.zone.no.network.selection=La zona elegida no tiene ninguna red para seleccionar. message.zone.step.1.desc=Por favor seleccione un modelo de red para su zona. message.zone.step.2.desc=Por favor ingrese la siguiente informaci\u00f3n para agregar una nueva zona -message.zone.step.3.desc=Por favor ingrese la siguiente informaci\u00f3n para agregar un nuevo pod -message.zoneWizard.enable.local.storage=PRECAUCI\u00d3N\: Si habilita el almacenamiento local para esta zona, deber\u00e1 hacer lo siguiente dependiendo de donde se quieran iniciar VMs de sistema\:

1. Si las VMs de sistema deben ser iniciadas sobre el almacenamiento primario compartido, este debe agregarse a la zona despu\u00e9s de creada. Tambi\u00e9n puedes iniciar la zona en estado dshabilitado.

2. Si la VM de sistema necesita ser iniciada en el almacenamiento primario local, el par\u00e1metro system.vm.use.local.storage debe ser puesto en true antes de habilitar la zona.


\u00bfDesea continuar? +message.zone.step.3.desc=Por favor ingrese la siguiente informaci\u00f3n para agregar un nuevo por +message.zoneWizard.enable.local.storage=PRECAUCI\u00d3N\: Si habilita el almacenamiento local para esta zona, debe hacer lo siguiente dependiendo de donde se quieran iniciar las VMs de sistema\:

1. Si las VMs de sistema deben ser iniciadas sobre el almacenamiento primario compartido, este debe agregarse a la zona despu\u00e9s de creada. Tambi\u00e9n puedes iniciar la zona en estado dshabilitado.

2. Si la VM de sistema necesita ser iniciada en el almacenamiento primario local, el par\u00e1metro system.vm.use.local.storage debe ser puesto en true antes de habilitar la zona.


\u00bfDesea continuar? messgae.validate.min=Por favor ingrese un valor mayor o igual que {0}. mode=modo network.rate=Tasa de Red diff --git a/client/WEB-INF/classes/resources/messages_fr_FR.properties b/client/WEB-INF/classes/resources/messages_fr_FR.properties index 17a68c5a38..64c65fd182 100644 --- a/client/WEB-INF/classes/resources/messages_fr_FR.properties +++ b/client/WEB-INF/classes/resources/messages_fr_FR.properties @@ -335,6 +335,7 @@ label.add.primary.storage=Ajouter un stockage primaire label.add.private.gateway=Ajouter Passerelle Priv\u00e9e label.add.region=Ajouter R\u00e9gion label.add.resources=Ajouter ressources +label.add.role=Ajouter R\u00f4le label.add.route=Ajouter route label.add.rule=Ajouter r\u00e8gle label.add.secondary.storage=Ajouter un stockage secondaire @@ -573,6 +574,7 @@ label.delete.PA=Supprimer Palo Alto label.delete.portable.ip.range=Supprimer Plage IP portable label.delete.profile=Supprimer Profil label.delete.project=Supprimer projet +label.delete.role=Supprimer R\u00f4le label.delete.secondary.staging.store=Supprimer Stockage Secondaire Interm\u00e9diaire label.delete.SRX=Supprimer SRX label.delete=Supprimer @@ -658,6 +660,7 @@ label.edit=Modifier label.edit.network.details=Modifier les param\u00e8tres r\u00e9seau label.edit.project.details=Modifier les d\u00e9tails du projet label.edit.region=\u00c9diter R\u00e9gion +label.edit.role=\u00c9diter R\u00f4le label.edit.rule=Modifier r\u00e8gle label.edit.secondary.ips=\u00c9diter IPs secondaires label.edit.tags=Modifier les balises @@ -1183,6 +1186,7 @@ label.password.reset.confirm=Le mot de passe a \u00e9t\u00e9 r\u00e9-initialiser label.path=Chemin label.PA.threat.profile=Profil menace Palo Alto label.perfect.forward.secrecy=Confidentialit\u00e9 persistante +label.permission=Autorisation label.persistent=Persistant label.physical.network.ID=Identifiant du r\u00e9seau physique label.physical.network.name=Nom r\u00e9seau physique @@ -1380,6 +1384,8 @@ label.retry.interval=Interval du nouvel essai label.review=Revoir label.revoke.project.invite=R\u00e9voquer l\\'invitation label.role=R\u00f4le +label.roles=R\u00f4les +label.roletype=Type R\u00f4le label.root.certificate=Certificat racine label.root.disk.controller=Contr\u00f4leur de disque racine label.root.disk.offering=Offre de disque racine @@ -1388,6 +1394,7 @@ label.router.vm.scaled.up=VM Routeur agrandi label.routing.host=H\u00f4te de routage label.routing=Routage label.rule.number=Num\u00e9ro r\u00e8gle +label.rule=R\u00e8gle label.rules=R\u00e8gles label.running.vms=VMs actives label.s3.access_key=Cl\u00e9 d\\'Acc\u00e8s @@ -1583,7 +1590,7 @@ label.timezone.colon=Fuseau horaire \: label.time.zone=Fuseau horaire label.timezone=Fuseau horaire label.token=Jeton unique -label.total.cpu=Capacit\u00e9 Totale en CPU +label.total.cpu=Capacit\u00e9 totale en CPU label.total.CPU=Capacit\u00e9 totale en CPU label.total.hosts=Total H\u00f4tes label.total.memory=Total m\u00e9moire @@ -2142,6 +2149,7 @@ message.restart.network=Tous les services fournit par ce routeur virtuel vont \u message.restart.vpc=Confirmer le red\u00e9marrage du VPC message.restart.vpc.remark=Veuillez confirmer que vous voulez red\u00e9marrer le VPC

Note \: transformer un VPC non-redondant en VPC redondant va forcer un nettoyage du routeur. Le r\u00e9seau associ\u00e9 ne sera pas disponible durant quelques minutes.

message.restoreVM=Voulez-vous restaurer la VM ? +message.role.ordering.fail=La r\u00e9organisation des r\u00e8gles d\\'autorisations a \u00e9t\u00e9 abandonn\u00e9e car la liste a chang\u00e9 pendant que vous apportez des modifications. Veuillez r\u00e9essayer. message.security.group.usage=(Utilisez Ctrl-clic pour s\u00e9lectionner les groupes de s\u00e9curit\u00e9 vis\u00e9s) message.select.affinity.groups=S\u00e9lectionner les groupes d\\'affinit\u00e9 qui appartiendront \u00e0 cette machine virtuelle \: message.select.a.zone=Une zone correspond typiquement \u00e0 un seul centre de donn\u00e9es. Des zones multiples peuvent permettre de rendre votre cloud plus fiable en apportant une isolation physique et de la redondance. diff --git a/client/WEB-INF/classes/resources/messages_it_IT.properties b/client/WEB-INF/classes/resources/messages_it_IT.properties index 45bb43a313..9eddbc1ffd 100644 --- a/client/WEB-INF/classes/resources/messages_it_IT.properties +++ b/client/WEB-INF/classes/resources/messages_it_IT.properties @@ -697,6 +697,7 @@ label.restart.vpc=Riavviare VPC label.restore=Restore label.review=Riesaminare label.revoke.project.invite=Revocare un invit +label.roles=Ruoli label.root.disk.controller=Controller del disco root label.routing=Routing label.rules=Regole diff --git a/client/WEB-INF/classes/resources/messages_ja_JP.properties b/client/WEB-INF/classes/resources/messages_ja_JP.properties index 5fc7adf302..83adc2c618 100644 --- a/client/WEB-INF/classes/resources/messages_ja_JP.properties +++ b/client/WEB-INF/classes/resources/messages_ja_JP.properties @@ -1321,6 +1321,7 @@ label.restore=\u5fa9\u5143 label.retry.interval=\u518d\u8a66\u884c\u9593\u9694 label.review=\u78ba\u8a8d label.revoke.project.invite=\u62db\u5f85\u306e\u53d6\u308a\u6d88\u3057 +label.roles=\u30ed\u30fc\u30eb label.role=\u5f79\u5272 label.root.certificate=\u30eb\u30fc\u30c8\u8a3c\u660e\u66f8 label.root.disk.controller=\u30eb\u30fc\u30c8 \u30c7\u30a3\u30b9\u30af \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc @@ -1642,7 +1643,7 @@ label.vmware.datacenter.name=VMware \u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u label.vmware.datacenter.vcenter=VMware \u30c7\u30fc\u30bf\u30bb\u30f3\u30bf\u30fc\u306e vCenter label.vmware.traffic.label=VMware \u306e\u30c8\u30e9\u30d5\u30a3\u30c3\u30af \u30e9\u30d9\u30eb label.vnet.id=VLAN/VNI ID -label.vnet=VLAN +label.vnet=VLAN/VNI label.vnmc.devices=VNMC \u30c7\u30d0\u30a4\u30b9 label.vnmc=VNMC label.volatile=\u63ee\u767a\u6027 diff --git a/client/WEB-INF/classes/resources/messages_ko_KR.properties b/client/WEB-INF/classes/resources/messages_ko_KR.properties index 6123623a4a..106cf36387 100644 --- a/client/WEB-INF/classes/resources/messages_ko_KR.properties +++ b/client/WEB-INF/classes/resources/messages_ko_KR.properties @@ -316,7 +316,7 @@ label.agent.username=\uc5d0\uc774\uc804\ud2b8 \uc0ac\uc6a9\uc790\uba85 label.agree=\ub3d9\uc758 label.alert=\uc54c\ub9bc \uccb4\uc81c label.algorithm=\uc54c\uace0\ub9ac\uc998 -label.allocated=\ud560\ub2f9 \ub05d\ub09c \uc0c1\ud0dc +label.allocated=\ud560\ub2f9 \uc644\ub8cc \uc0c1\ud0dc label.allocation.state=\ud560\ub2f9 \uc0c1\ud0dc label.api.key=API \ud0a4 label.apply=\uc801\uc6a9 @@ -705,10 +705,10 @@ label.menu.templates=\ud15c\ud50c\ub9bf label.menu.virtual.appliances=\uac00\uc0c1 \uc544\ud504\ub77c\uc774\uc548\uc2a4 label.menu.virtual.resources=\uac00\uc0c1 \uc790\uc6d0 label.menu.volumes=\ubcfc\ub968 -label.metrics.allocated=\ud560\ub2f9 \ub05d\ub09c \uc0c1\ud0dc +label.metrics.allocated=\ud560\ub2f9 \uc644\ub8cc \uc0c1\ud0dc label.metrics.clusters=\ud074\ub7ec\uc2a4\ud130 label.metrics.cpu.used.avg=\uc0ac\uc6a9 \uc911 -label.metrics.disk.allocated=\ud560\ub2f9 \ub05d\ub09c \uc0c1\ud0dc +label.metrics.disk.allocated=\ud560\ub2f9 \uc644\ub8cc \uc0c1\ud0dc label.metrics.disk.size=\ud06c\uae30 label.metrics.disk.storagetype=\uc885\ub958 label.metrics.disk.used=\uc0ac\uc6a9 \uc911 @@ -1336,7 +1336,7 @@ message.installWizard.tooltip.addHost.hostname=\ud638\uc2a4\ud2b8 DNS \uba85 \ub message.installWizard.tooltip.addHost.password=XenServer \uce21\uc5d0\uc11c \uc9c0\uc815\ud55c \uc704\uc758 \uc0ac\uc6a9\uc790\uba85\uc5d0 \ub300\ud55c \uc554\ud638\uc785\ub2c8\ub2e4. message.installWizard.tooltip.addHost.username=\uc6d0\ub798 root \uc785\ub2c8\ub2e4. message.installWizard.tooltip.addPod.name=Pod \uc774\ub984\uc785\ub2c8\ub2e4. -message.installWizard.tooltip.addPod.reservedSystemEndIp=\uc774\uac83\uc740 2\ucc28 \uc2a4\ud1a0\ub9ac\uc9c0 VM \ubc0f \ucf58\uc194 \ud504\ub85d\uc2dc VM\ub97c \uad00\ub9ac\ud558\uae30 \uc704\ud574\uc11c CloudStack\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c\ub0b4\uc758 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 \ucef4\ud4e8\ud305 \uc11c\ubc84\uc640 \uac19\uc740 \uc11c\ube0c\ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \ud560\ub2f9\ud569\ub2c8\ub2e4. +message.installWizard.tooltip.addPod.reservedSystemEndIp=\uc774\uac83\uc740 2\ucc28 \uc2a4\ud1a0\ub9ac\uc9c0 VM \ubc0f \ucf58\uc194 \ud504\ub85d\uc2dc VM\ub97c \uad00\ub9ac\ud558\uae30 \uc704\ud574\uc11c CloudStack\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c\ub0b4 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 \ucef4\ud4e8\ud305 \uc11c\ubc84\uc640 \uac19\uc740 \uc11c\ube0c\ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \ud560\ub2f9\ud569\ub2c8\ub2e4. message.installWizard.tooltip.addPod.reservedSystemGateway=\ud604\uc7ac Pod\ub0b4 \ud638\uc2a4\ud2b8 \uac8c\uc774\ud2b8\uc6e8\uc774\uc785\ub2c8\ub2e4. message.installWizard.tooltip.addPod.reservedSystemNetmask=\uac8c\uc2a4\ud2b8\uac00 \uc0ac\uc6a9\ud558\ub294 \uc11c\ube0c\ub124\ud2b8\uc6cc\ud06c\uc0c1\uc5d0\uc11c \uc9c0\uc815\ud55c \ub137 \ub9c8\uc2a4\ud06c\uc785\ub2c8\ub2e4. message.installWizard.tooltip.addPod.reservedSystemStartIp=\uc774\uac83\uc740 2\ucc28 \uc2a4\ud1a0\ub9ac\uc9c0 VM \ubc0f \ucf58\uc194 \ud504\ub85d\uc2dc VM\ub97c \uad00\ub9ac\ud558\uae30 \uc704\ud574\uc11c CloudStack\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c\ub0b4\uc758 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 \ucef4\ud4e8\ud305 \uc11c\ubc84\uc640 \uac19\uc740 \uc11c\ube0c\ub124\ud2b8\uc6cc\ud06c\uc5d0\uc11c \ud560\ub2f9\ud569\ub2c8\ub2e4. @@ -1345,13 +1345,13 @@ message.installWizard.tooltip.addPrimaryStorage.path=(NFS\uc758 \uacbd\uc6b0) \u message.installWizard.tooltip.addPrimaryStorage.server=(NFS, iSCSI \ub610\ub294 PreSetup\uc758 \uacbd\uc6b0) \uc2a4\ud1a0\ub9ac\uc9c0 \uae30\uae30\uc758 IP \uc8fc\uc18c \ub610\ub294 DNS \uba85\uc785\ub2c8\ub2e4. message.installWizard.tooltip.addSecondaryStorage.nfsServer=2\ucc28 \uc2a4\ud1a0\ub9ac\uc9c0\ub97c \ud638\uc2a4\ud2b8 \ud558\ub294 NFS \uc11c\ubc84 IP \uc8fc\uc18c\uc785\ub2c8\ub2e4. message.installWizard.tooltip.addSecondaryStorage.path=\uc704\uc5d0\uc11c \uc9c0\uc815\ud55c \uc11c\ubc84\uc5d0 \uc874\uc7ac\ud558\ub294 \ub0b4\ubcf4\ub0b4\uae30 \uacbd\ub85c\uc785\ub2c8\ub2e4. -message.installWizard.tooltip.addZone.dns1=Zone\ub0b4 \uac8c\uc2a4\ud2b8 VM \ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \ud604\uc7ac DNS \uc11c\ubc84\uc5d0\ub294 \ub2e4\uc74c\uc5d0 \ucd94\uac00\ud558\ub294 \uacf5\uac1c \ub124\ud2b8\uc6cc\ud06c \uacbd\uc720\ub85c \uc811\uadfc\ud569\ub2c8\ub2e4. Zone\uc758 \uacf5\uac1c IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 \uacf5\uac1c DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. +message.installWizard.tooltip.addZone.dns1=Zone\ub0b4\uc758 \uac8c\uc2a4\ud2b8 VM\uc73c\ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \uc774\ub7ec\ud55c DNS \uc11c\ubc84\uc5d0\ub294 \ub2e4\uc74c\uc5d0 \ucd94\uac00\ud558\ub294 \uacf5\uac1c \ub124\ud2b8\uc6cc\ud06c \uacbd\uc720\ub85c \uc811\uadfc \ud569\ub2c8\ub2e4. Zone\uc758 \uacf5\uac1c IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 \uacf5\uac1c DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. message.installWizard.tooltip.addZone.dns2=Zone\ub0b4 \uac8c\uc2a4\ud2b8 VM \ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \ud604\uc7ac DNS \uc11c\ubc84\uc5d0\ub294 \ub2e4\uc74c\uc5d0 \ucd94\uac00\ud558\ub294 \uacf5\uac1c \ub124\ud2b8\uc6cc\ud06c \uacbd\uc720\ub85c \uc811\uadfc\ud569\ub2c8\ub2e4. Zone\uc758 \uacf5\uac1c IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 \uacf5\uac1c DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. -message.installWizard.tooltip.addZone.internaldns1=Zone\ub0b4 \uc2dc\uc2a4\ud15c VM\uc73c\ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \ud604\uc7ac DNS \uc11c\ubc84\ub294 \uc2dc\uc2a4\ud15c VM\uc758 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c \uc778\ud130\ud398\uc774\uc2a4\ub97c \uac1c\uc785\uc2dc\ucf1c \uc811\uadfc\ud569\ub2c8\ub2e4. Pod\uc758 \uc0ac\uc124 IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. +message.installWizard.tooltip.addZone.internaldns1=Zone\ub0b4\uc758 \uc2dc\uc2a4\ud15c VM \ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \ud604\uc7ac DNS \uc11c\ubc84\ub294 \uc2dc\uc2a4\ud15c VM\uc758 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c \uc778\ud130\ud398\uc774\uc2a4\ub97c \uac1c\uc785\uc2dc\ucf1c \uc811\uadfc\ud569\ub2c8\ub2e4. Pod\uc758 \uc0ac\uc124 IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. message.installWizard.tooltip.addZone.internaldns2=Zone\ub0b4 \uc2dc\uc2a4\ud15c VM\uc73c\ub85c \uc0ac\uc6a9\ud558\ub294 DNS \uc11c\ubc84\uc785\ub2c8\ub2e4. \ud604\uc7ac DNS \uc11c\ubc84\ub294 \uc2dc\uc2a4\ud15c VM\uc758 \uc0ac\uc124 \ub124\ud2b8\uc6cc\ud06c \uc778\ud130\ud398\uc774\uc2a4\ub97c \uac1c\uc785\uc2dc\ucf1c \uc811\uadfc\ud569\ub2c8\ub2e4. Pod\uc758 \uc0ac\uc124 IP \uc8fc\uc18c\uc5d0\uc11c \uc5ec\uae30\uc11c \uc9c0\uc815\ud558\ub294 DNS \uc11c\ubc84\uc5d0 \ud1b5\uc2e0\ud560 \uc218 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. message.installWizard.tooltip.addZone.name=Zone\uc758 \uc774\ub984\uc785\ub2c8\ub2e4. message.installWizard.tooltip.configureGuestTraffic.description=\ub124\ud2b8\uc6cc\ud06c \uc124\uba85\uc785\ub2c8\ub2e4. -message.installWizard.tooltip.configureGuestTraffic.guestEndIp=\ud604\uc7ac Zone\uc758 \uac8c\uc2a4\ud2b8\uc5d0\uac8c \ud560\ub2f9\ud560 \uc218 \uc788\ub294 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc0ac\uc6a9\ud558\ub294 NIC\uac00 \ud55c \uac00\uc9c0 \uacbd\uc6b0\ub294 \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 Pod\uc758 CIDR\uc640 \uac19\uc740 CIDR\uc5d0 \ud3ec\ud568\ub418\uc5b4 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. +message.installWizard.tooltip.configureGuestTraffic.guestEndIp=\ud604\uc7ac Zone\uc758 \uac8c\uc2a4\ud2b8\uc5d0\uac8c \ud560\ub2f9\ud560 \uc218 \uc788\ub294 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc0ac\uc6a9\ud558\ub294 NIC\uac00 \ud55c \uac00\uc9c0\uc778 \uacbd\uc6b0\ub294 \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 Pod\uc758 CIDR\uc640 \uac19\uc740 CIDR\uc5d0 \ud3ec\ud568\ub418\uc5b4 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. message.installWizard.tooltip.configureGuestTraffic.guestGateway=\uac8c\uc2a4\ud2b8\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \uac8c\uc774\ud2b8\uc6e8\uc774\uc785\ub2c8\ub2e4. message.installWizard.tooltip.configureGuestTraffic.guestNetmask=\uac8c\uc2a4\ud2b8\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \uc11c\ube0c\ub124\ud2b8\uc6cc\ud06c\uc0c1\uc5d0\uc11c \uc0ac\uc6a9\ub418\ub294 \ub137 \ub9c8\uc2a4\ud06c\uc785\ub2c8\ub2e4. message.installWizard.tooltip.configureGuestTraffic.guestStartIp=\ud604\uc7ac Zone\uc758 \uac8c\uc2a4\ud2b8\uc5d0\uac8c \ud560\ub2f9\ud560 \uc218 \uc788\ub294 IP \uc8fc\uc18c \ubc94\uc704\uc785\ub2c8\ub2e4. \uc0ac\uc6a9\ud558\ub294 NIC\uac00 \ud55c \uac00\uc9c0 \uacbd\uc6b0\ub294 \uc774\ub7ec\ud55c IP \uc8fc\uc18c\ub294 Pod\uc758 CIDR\uc640 \uac19\uc740 CIDR\uc5d0 \ud3ec\ud568\ub418\uc5b4 \uc788\uc5b4\uc57c \ud569\ub2c8\ub2e4. @@ -1459,7 +1459,7 @@ state.Completed=\uc644\ub8cc state.Creating=\uc0dd\uc131 \uc911 state.Declined=\uac70\uc808 state.Destroyed=\ud30c\uae30\ub41c \uc0c1\ud0dc -state.Disabled=\uc0ac\uc6a9 \uc548\ud568 +state.Disabled=\uc720\ud6a8\ud558\uc9c0 \uc54a\uc740 state.Enabled=\uc0ac\uc6a9\ud568 state.Error=\uc624\ub958 state.Expunging=\uc81c\uac70 \uc911 diff --git a/client/WEB-INF/classes/resources/messages_nb_NO.properties b/client/WEB-INF/classes/resources/messages_nb_NO.properties index a4851d033b..98283abdfd 100644 --- a/client/WEB-INF/classes/resources/messages_nb_NO.properties +++ b/client/WEB-INF/classes/resources/messages_nb_NO.properties @@ -1469,8 +1469,8 @@ label.smb.username=SMB Brukernavn label.snapshot.limits=\u00d8yeblikksbildebegrensning label.snapshot.name=\u00d8yeblikksbildenavn label.snapshot.schedule=Sett Opp Gjentagende \u00f8yeblikksbilder -label.snapshot.s=\u00d8yebliksbilder -label.snapshots=\u00d8yebliksbilder +label.snapshot.s=\u00d8yeblikksbilder +label.snapshots=\u00d8yeblikksbilder label.snapshot=\u00d8yeblikksbilde label.SNMP.community=SNMP Community label.SNMP.port=SNM Port @@ -2106,7 +2106,7 @@ message.number.hosts=

\# av Verter

message.number.pods=

\# av Pods

message.number.storage=

\# av Prim\u00e6rlagringsvolumer

message.number.zones=

\# av Soner

-message.password.has.been.reset.to=Passordet har blitt resatt til +message.password.has.been.reset.to=Passordet har blitt endret til message.password.of.the.vm.has.been.reset.to=Passorde for VM har blitt endre til message.pending.projects.1=Du har f\u00f8lgende prosjektinvitasjoner\: message.pending.projects.2=For \u00e5 se, vennligst g\u00e5 til prosjektseksjonen og velg invitasjoner fra nedtrekksmenyen. diff --git a/client/WEB-INF/classes/resources/messages_nl_NL.properties b/client/WEB-INF/classes/resources/messages_nl_NL.properties index 5cb7413ce8..c4dc841b5c 100644 --- a/client/WEB-INF/classes/resources/messages_nl_NL.properties +++ b/client/WEB-INF/classes/resources/messages_nl_NL.properties @@ -435,7 +435,7 @@ label.broadcast.domain.range=Broadcast domain range label.broadcast.domain.type=Broadcast Domain Type label.broadcast.uri=Broadcast URI label.broadcasturi=broadcasturi -label.broadcat.uri=Broadcast URI +label.broadcat.uri=broadcast URI label.brocade.vcs.address=Vcs switch adres label.brocade.vcs.details=Brocade Vcs switch gegevens label.by.account=Op Account @@ -2105,7 +2105,7 @@ message.number.hosts=

Aantal Hosts

message.number.pods=

Aantal Pods

message.number.storage=

Aantal Primaire Opslag Volumes

message.number.zones=

Aantal Zones

-message.password.has.been.reset.to=Het wachtwoord is gereset naar +message.password.has.been.reset.to=Het wachtwoord is veranderd in message.password.of.the.vm.has.been.reset.to=Het wachtwoord van de VM is veranderd in message.pending.projects.1=U heeft openstaande project uitnodigigingen\: message.pending.projects.2=Ga naar de project sectie om deze te zien. Selecteer de uitnodiging vanuit het drop-down menu. diff --git a/client/WEB-INF/classes/resources/messages_pt_BR.properties b/client/WEB-INF/classes/resources/messages_pt_BR.properties index 444bb1568b..8b99b35894 100644 --- a/client/WEB-INF/classes/resources/messages_pt_BR.properties +++ b/client/WEB-INF/classes/resources/messages_pt_BR.properties @@ -1622,7 +1622,7 @@ label.url=URL label.usage.interface=Usage Interface label.usage.sanity.result=Resultado de Sanidade de Uso label.usage.server=Uso do Servidor -label.usage.type=Tipo +label.usage.type=Uso Tipo label.usage.unit=Unidade label.used=Usado label.user.data=Dados de Usu\u00e1rio @@ -2106,7 +2106,7 @@ message.number.hosts=

Hosts

message.number.pods=

PODs

message.number.storage=

Volumes do Storage Prim\u00e1rio

message.number.zones=

Zonas

-message.password.has.been.reset.to=A senha foi recuperada para +message.password.has.been.reset.to=A senha foi redefinida para message.password.of.the.vm.has.been.reset.to=A senha da VM foi redefinida para message.pending.projects.1=Voc\u00ea possui convites de projetos pendentes\: message.pending.projects.2=Para visualizar, por favor acesse a se\u00e7\u00e3o de projetos, depois selecione os convites no menu drop-down. diff --git a/client/WEB-INF/classes/resources/messages_zh_CN.properties b/client/WEB-INF/classes/resources/messages_zh_CN.properties index 66f99b2699..001ccf056d 100644 --- a/client/WEB-INF/classes/resources/messages_zh_CN.properties +++ b/client/WEB-INF/classes/resources/messages_zh_CN.properties @@ -1319,6 +1319,7 @@ label.restore=\u8fd8\u539f label.retry.interval=\u91cd\u8bd5\u65f6\u95f4\u95f4\u9694 label.review=\u6838\u5bf9 label.revoke.project.invite=\u64a4\u9500\u9080\u8bf7 +label.roles=\u89d2\u8272 label.role=\u89d2\u8272 label.root.certificate=\u6839\u8bc1\u4e66 label.root.disk.controller=\u6839\u78c1\u76d8\u63a7\u5236\u5668 @@ -1328,6 +1329,7 @@ label.routing.host=\u6b63\u5728\u8def\u7531\u4e3b\u673a label.routing=\u6b63\u5728\u8def\u7531 label.rule.number=\u89c4\u5219\u7f16\u53f7 label.rules=\u89c4\u5219 +label.rule=\u89c4\u5219 label.running.vms=\u6b63\u5728\u8fd0\u884c\u7684 VM label.s3.access_key=\u8bbf\u95ee\u5bc6\u94a5 label.s3.bucket=\u5b58\u50a8\u6876 diff --git a/client/bindir/cloud-update-xenserver-licenses.in b/client/bindir/cloud-update-xenserver-licenses.in index c64bc8f7c0..9db50781c2 100755 --- a/client/bindir/cloud-update-xenserver-licenses.in +++ b/client/bindir/cloud-update-xenserver-licenses.in @@ -24,7 +24,7 @@ import glob from random import choice import string from optparse import OptionParser -import MySQLdb +import mysql.connector import paramiko from threading import Thread @@ -59,7 +59,7 @@ parser.add_option("-a", "--all", action="store_true", dest="all", default=False, def e(msg): parser.error(msg) def getknownhosts(host,username,password): - conn = MySQLdb.connect(host=host,user=username,passwd=password) + conn = mysql.connector.connect(host=host, user=username, password=password) cur = conn.cursor() cur.execute("SELECT h.private_ip_address,d.value FROM cloud.host h inner join cloud.host_details d on (h.id = d.host_id) where d.name = 'username' and setup = 1") usernames = dict(cur.fetchall()) diff --git a/client/pom.xml b/client/pom.xml index d329c7f08a..7310cef4f9 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT @@ -50,6 +50,11 @@ cloud-plugin-acl-static-role-based ${project.version} + + org.apache.cloudstack + cloud-plugin-acl-dynamic-role-based + ${project.version} + org.apache.cloudstack cloud-plugin-dedicated-resources @@ -236,6 +241,11 @@ cloud-plugin-host-allocator-random ${project.version} + + org.apache.cloudstack + cloud-plugin-outofbandmanagement-driver-ipmitool + ${project.version} + org.apache.cloudstack cloud-mom-rabbitmq @@ -429,9 +439,9 @@ - org.mortbay.jetty - maven-jetty-plugin - 6.1.26 + org.eclipse.jetty + jetty-maven-plugin + ${cs.jetty.version} diff --git a/client/tomcatconf/catalina.properties.in b/client/tomcatconf/catalina.properties.in index 282892bb76..e0baf61261 100644 --- a/client/tomcatconf/catalina.properties.in +++ b/client/tomcatconf/catalina.properties.in @@ -44,7 +44,7 @@ package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache # "foo/*.jar": Add all the JARs of the specified folder as class # repositories # "foo/bar.jar": Add bar.jar as a class repository -common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,/usr/share/java/mysql-connector-java.jar,/usr/share/cloudstack-mysql-ha/lib/*jar +common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,/usr/share/java/mysql-connector-java.jar,/usr/share/cloudstack-mysql-ha/lib/*.jar # # List of comma-separated paths defining the contents of the "server" diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in deleted file mode 100644 index 32f33c9880..0000000000 --- a/client/tomcatconf/commands.properties.in +++ /dev/null @@ -1,801 +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. - -### bitmap of permissions at the end of each classname, 1 = ADMIN, 2 = RESOURCE_DOMAIN_ADMIN, 4 = DOMAIN_ADMIN, 8 = USER -### Please standardize naming conventions to camel-case (even for acronyms). - -### CloudStack authentication commands -login=15 -logout=15 - -### SAML SSO/SLO commands -samlSso=15 -samlSlo=15 -getSPMetadata=15 -listIdps=15 -authorizeSamlSso=7 -listSamlAuthorization=7 -listAndSwitchSamlAccount=15 - -### Account commands -createAccount=7 -deleteAccount=7 -updateAccount=7 -disableAccount=7 -enableAccount=7 -lockAccount=7 -listAccounts=15 -markDefaultZoneForAccount=1 - -#### User commands -createUser=7 -deleteUser=7 -updateUser=15 -listUsers=15 -lockUser=7 -disableUser=7 -enableUser=7 -getUser=1 - -#### Domain commands -createDomain=1 -updateDomain=1 -deleteDomain=1 -listDomains=7 -listDomainChildren=7 - -####Cloud Identifier commands -getCloudIdentifier=15 - -#### Limit commands -updateResourceLimit=7 -updateResourceCount=7 -listResourceLimits=15 - -#### VM commands -deployVirtualMachine=15 -destroyVirtualMachine=15 -rebootVirtualMachine=15 -startVirtualMachine=15 -stopVirtualMachine=15 -resetPasswordForVirtualMachine=15 -resetSSHKeyForVirtualMachine=15 -updateVirtualMachine=15 -listVirtualMachines=15 -getVMPassword=15 -restoreVirtualMachine=15 -changeServiceForVirtualMachine=15 -scaleVirtualMachine=15 -assignVirtualMachine=7 -migrateVirtualMachine=1 -migrateVirtualMachineWithVolume=1 -recoverVirtualMachine=15 -expungeVirtualMachine=15 -getVirtualMachineUserData=15 - -#### snapshot commands -createSnapshot=15 -listSnapshots=15 -deleteSnapshot=15 -createSnapshotPolicy=15 -updateSnapshotPolicy=15 -deleteSnapshotPolicies=15 -listSnapshotPolicies=15 -revertSnapshot=15 - -#### template commands -createTemplate=15 -registerTemplate=15 -updateTemplate=15 -copyTemplate=15 -deleteTemplate=15 -listTemplates=15 -updateTemplatePermissions=15 -listTemplatePermissions=15 -extractTemplate=15 -prepareTemplate=1 - -#### iso commands -attachIso=15 -detachIso=15 -listIsos=15 -registerIso=15 -updateIso=15 -deleteIso=15 -copyIso=15 -updateIsoPermissions=15 -listIsoPermissions=15 -extractIso=15 - -#### guest OS commands -listOsTypes=15 -listOsCategories=15 -addGuestOs=1 -updateGuestOs=1 -removeGuestOs=1 - -#### guest OS mapping commands -listGuestOsMapping=1 -addGuestOsMapping=1 -updateGuestOsMapping=1 -removeGuestOsMapping=1 - -#### service offering commands -createServiceOffering=7 -deleteServiceOffering=7 -updateServiceOffering=7 -listServiceOfferings=15 - -#### disk offering commands -createDiskOffering=7 -updateDiskOffering=7 -deleteDiskOffering=7 -listDiskOfferings=15 - -#### vlan commands -createVlanIpRange=1 -deleteVlanIpRange=1 -listVlanIpRanges=1 -dedicatePublicIpRange=1 -releasePublicIpRange=1 -dedicateGuestVlanRange=1 -releaseDedicatedGuestVlanRange=1 -listDedicatedGuestVlanRanges=1 - -#### address commands -associateIpAddress=15 -disassociateIpAddress=15 -listPublicIpAddresses=15 -updateIpAddress=15 - -#### firewall commands -listPortForwardingRules=15 -createPortForwardingRule=15 -deletePortForwardingRule=15 -updatePortForwardingRule=15 - -#### NAT commands -enableStaticNat=15 -createIpForwardingRule=15 -deleteIpForwardingRule=15 -listIpForwardingRules=15 -disableStaticNat=15 - -#### load balancer commands -createLoadBalancerRule=15 -deleteLoadBalancerRule=15 -removeFromLoadBalancerRule=15 -assignToLoadBalancerRule=15 -createLBStickinessPolicy=15 -updateLBStickinessPolicy=15 -deleteLBStickinessPolicy=15 -listLoadBalancerRules=15 -listLBStickinessPolicies=15 -listLBHealthCheckPolicies=15 -createLBHealthCheckPolicy=15 -updateLBHealthCheckPolicy=15 -deleteLBHealthCheckPolicy=15 -listLoadBalancerRuleInstances=15 -updateLoadBalancerRule=15 - -##### SSL offload commands - -uploadSslCert=15 -deleteSslCert=15 -listSslCerts=15 -assignCertToLoadBalancer=15 -removeCertFromLoadBalancer=15 - -#### autoscale commands -createCounter=1 -createCondition=15 -createAutoScalePolicy=15 -createAutoScaleVmProfile=15 -createAutoScaleVmGroup=15 -deleteCounter=1 -deleteCondition=15 -deleteAutoScalePolicy=15 -deleteAutoScaleVmProfile=15 -deleteAutoScaleVmGroup=15 -listCounters=15 -listConditions=15 -listAutoScalePolicies=15 -listAutoScaleVmProfiles=15 -listAutoScaleVmGroups=15 -enableAutoScaleVmGroup=15 -disableAutoScaleVmGroup=15 -updateAutoScalePolicy=15 -updateAutoScaleVmProfile=15 -updateAutoScaleVmGroup=15 - -#### router commands -startRouter=7 -rebootRouter=7 -stopRouter=7 -destroyRouter=7 -changeServiceForRouter=7 -listRouters=7 -listVirtualRouterElements=7 -configureVirtualRouterElement=7 -createVirtualRouterElement=7 -upgradeRouterTemplate=1 - -#### system vm commands -startSystemVm=1 -rebootSystemVm=1 -stopSystemVm=1 -destroySystemVm=1 -listSystemVms=3 -migrateSystemVm=1 -changeServiceForSystemVm=1 -scaleSystemVm=1 - -#### configuration commands -updateConfiguration=1 -listConfigurations=1 -listCapabilities=15 -listDeploymentPlanners=1 -cleanVMReservations=1 - -#### pod commands -createPod=1 -updatePod=1 -deletePod=1 -listPods=3 - -#### zone commands -createZone=1 -updateZone=1 -deleteZone=1 -listZones=15 - -#### events commands -listEvents=15 -listEventTypes=15 -archiveEvents=15 -deleteEvents=15 - -#### alerts commands -listAlerts=3 -archiveAlerts=1 -deleteAlerts=1 -generateAlert=1 - -#### system capacity commands -listCapacity=3 - -#### swift commands -addSwift=1 -listSwifts=1 - -#### image store commands -addImageStore=1 -addImageStoreS3=1 -listImageStores=1 -deleteImageStore=1 -createSecondaryStagingStore=1 -listSecondaryStagingStores=1 -deleteSecondaryStagingStore=1 -updateCloudToUseObjectStore=1 - -#### host commands -addHost=3 -addCluster=1 -deleteCluster=1 -updateCluster=1 -reconnectHost=1 -updateHost=1 -deleteHost=3 -prepareHostForMaintenance=1 -cancelHostMaintenance=1 -listHosts=3 -listHostTags=7 -findHostsForMigration=1 -addSecondaryStorage=1 -updateHostPassword=1 -releaseHostReservation=1 - -#### VmWare DC -addVmwareDc=1 -removeVmwareDc=1 -listVmwareDcs=1 - -#### volume commands -attachVolume=15 -uploadVolume=15 -detachVolume=15 -createVolume=15 -deleteVolume=15 -listVolumes=15 -extractVolume=15 -migrateVolume=15 -resizeVolume=15 -updateVolume=1 - -#### registration command: FIXME -- this really should be something in management server that -#### generates a new key for the user and they just have to -#### use that key...the key is stored in the db associated w/ -#### the userId...every request to the developer API should be -#### checked against the key -registerUserKeys=15 - -### async-query command -queryAsyncJobResult=15 -listAsyncJobs=15 - -#### storage pools commands -listStoragePools=3 -listStorageProviders=3 -listStorageTags=7 -createStoragePool=1 -updateStoragePool=1 -deleteStoragePool=1 -listClusters=3 -enableStorageMaintenance=1 -cancelStorageMaintenance=1 -findStoragePoolsForMigration=1 - -#### security group commands -createSecurityGroup=15 -deleteSecurityGroup=15 -authorizeSecurityGroupIngress=15 -revokeSecurityGroupIngress=15 -authorizeSecurityGroupEgress=15 -revokeSecurityGroupEgress=15 -listSecurityGroups=15 - -#### vm group commands -createInstanceGroup=15 -deleteInstanceGroup=15 -updateInstanceGroup=15 -listInstanceGroups=15 - -### Certificate commands -uploadCustomCertificate=1 - -### other commands -listHypervisors=15 - -### VPN -createRemoteAccessVpn=15 -deleteRemoteAccessVpn=15 -listRemoteAccessVpns=15 -updateRemoteAccessVpn=15 - - -addVpnUser=15 -removeVpnUser=15 -listVpnUsers=15 - -#### network offering commands -createNetworkOffering=1 -updateNetworkOffering=1 -deleteNetworkOffering=1 -listNetworkOfferings=15 - -#### network commands -createNetwork=15 -deleteNetwork=15 -listNetworks=15 -restartNetwork=15 -updateNetwork=15 - -#### nic commands #### -addNicToVirtualMachine=15 -removeNicFromVirtualMachine=15 -updateDefaultNicForVirtualMachine=15 - -#### -addIpToNic=15 -removeIpFromNic=15 -updateVmNicIp=15 -listNics=15 - -#### SSH key pair commands -registerSSHKeyPair=15 -createSSHKeyPair=15 -deleteSSHKeyPair=15 -listSSHKeyPairs=15 - -#### Projects commands -createProject=15 -deleteProject=15 -updateProject=15 -activateProject=15 -suspendProject=15 -listProjects=15 -addAccountToProject=15 -deleteAccountFromProject=15 -listProjectAccounts=15 -listProjectInvitations=15 -updateProjectInvitation=15 -deleteProjectInvitation=15 - -#### -createFirewallRule=15 -deleteFirewallRule=15 -listFirewallRules=15 -updateFirewallRule=15 - -#### -createEgressFirewallRule=15 -deleteEgressFirewallRule=15 -listEgressFirewallRules=15 -updateEgressFirewallRule=15 - -#### hypervisor capabilities commands -updateHypervisorCapabilities=1 -listHypervisorCapabilities=1 - -#### Physical Network commands -createPhysicalNetwork=1 -deletePhysicalNetwork=1 -listPhysicalNetworks=1 -updatePhysicalNetwork=1 - -#### Physical Network Service Provider commands -listSupportedNetworkServices=1 -addNetworkServiceProvider=1 -deleteNetworkServiceProvider=1 -listNetworkServiceProviders=1 -updateNetworkServiceProvider=1 - -#### Physical Network Traffic Type commands -addTrafficType=1 -deleteTrafficType=1 -listTrafficTypes=1 -updateTrafficType=1 -listTrafficTypeImplementors=1 - -#### Storage Network commands -createStorageNetworkIpRange=1 -deleteStorageNetworkIpRange=1 -listStorageNetworkIpRange=1 -updateStorageNetworkIpRange=1 - -### Network Devices commands -addNetworkDevice=1 -listNetworkDevice=1 -deleteNetworkDevice=1 - -### VPC commands -createVPC=15 -listVPCs=15 -deleteVPC=15 -updateVPC=15 -restartVPC=15 - -#### VPC offering commands -createVPCOffering=1 -updateVPCOffering=1 -deleteVPCOffering=1 -listVPCOfferings=15 - -#### Private gateway commands -createPrivateGateway=1 -listPrivateGateways=15 -deletePrivateGateway=1 - -#### Network ACL commands -createNetworkACL=15 -updateNetworkACLItem=15 -deleteNetworkACL=15 -listNetworkACLs=15 -createNetworkACLList=15 -deleteNetworkACLList=15 -replaceNetworkACLList=15 -listNetworkACLLists=15 -updateNetworkACLList=15 - - -#### Static route commands -createStaticRoute=15 -deleteStaticRoute=15 -listStaticRoutes=15 - -#### Tags commands -createTags=15 -deleteTags=15 -listTags=15 - -#### Meta Data commands -addResourceDetail=1 -removeResourceDetail=1 -listResourceDetails=15 - -### Site-to-site VPN commands -createVpnCustomerGateway=15 -createVpnGateway=15 -createVpnConnection=15 -deleteVpnCustomerGateway=15 -deleteVpnGateway=15 -deleteVpnConnection=15 -updateVpnCustomerGateway=15 -resetVpnConnection=15 -listVpnCustomerGateways=15 -listVpnGateways=15 -listVpnConnections=15 -updateVpnConnection=15 -updateVpnGateway=15 - -#### router commands -createVirtualRouterElement=7 -configureVirtualRouterElement=7 -listVirtualRouterElements=7 - -#### ovs commands -createOvsElement=7 -configureOvsElement=7 -listOvsElements=7 - -#### usage commands -generateUsageRecords=1 -listUsageRecords=7 -listUsageTypes=1 -removeRawUsageRecords=1 - -#### traffic monitor commands -addTrafficMonitor=1 -deleteTrafficMonitor=1 -listTrafficMonitors=1 - -#### Cisco Nexus 1000v Virtual Supervisor Module (VSM) commands -deleteCiscoNexusVSM=1 -enableCiscoNexusVSM=1 -disableCiscoNexusVSM=1 -listCiscoNexusVSMs=1 - -#### f5 big ip load balancer commands - -#Deprecated commands -addExternalLoadBalancer=1 -deleteExternalLoadBalancer=1 -listExternalLoadBalancers=1 - -addF5LoadBalancer=1 -configureF5LoadBalancer=1 -deleteF5LoadBalancer=1 -listF5LoadBalancers=1 -listF5LoadBalancerNetworks=1 - -#### juniper srx firewall commands -addExternalFirewall=1 -deleteExternalFirewall=1 -listExternalFirewalls=1 - -addSrxFirewall=1 -deleteSrxFirewall=1 -configureSrxFirewall=1 -listSrxFirewalls=1 -listSrxFirewallNetworks=1 - -#### Palo Alto firewall commands -addPaloAltoFirewall=1 -deletePaloAltoFirewall=1 -configurePaloAltoFirewall=1 -listPaloAltoFirewalls=1 -listPaloAltoFirewallNetworks=1 - -####Netapp integration commands -createVolumeOnFiler=15 -destroyVolumeOnFiler=15 -listVolumesOnFiler=15 -createLunOnFiler=15 -destroyLunOnFiler=15 -listLunsOnFiler=15 -associateLun=15 -dissociateLun=15 -createPool=15 -deletePool=15 -modifyPool=15 -listPools=15 - -#### netscaler load balancer commands -addNetscalerLoadBalancer=1 -deleteNetscalerLoadBalancer=1 -configureNetscalerLoadBalancer=1 -listNetscalerLoadBalancers=1 -listNetscalerLoadBalancerNetworks=1 - -#### nicira nvp commands - -addNiciraNvpDevice=1 -deleteNiciraNvpDevice=1 -listNiciraNvpDevices=1 -listNiciraNvpDeviceNetworks=1 - -# Not implemented (yet) -#configureNiciraNvpDevice=1 - -#### brocade vcs commands - -addBrocadeVcsDevice=1 -deleteBrocadeVcsDevice=1 -listBrocadeVcsDevices=1 -listBrocadeVcsDeviceNetworks=1 - -#### bigswitch bcf commands - -addBigSwitchBcfDevice=1 -deleteBigSwitchBcfDevice=1 -listBigSwitchBcfDevices=1 - -#### stratosphere ssp commands - -addStratosphereSsp=1 -deleteStratoshereSsp=1 - -#### nuage vsp commands - -addNuageVspDevice=1 -updateNuageVspDevice=1 -deleteNuageVspDevice=1 -listNuageVspDevices=1 -issueNuageVspResourceRequest=15 - -#### host simulator commands - -configureSimulator=1 -querySimulatorMock=1 -cleanupSimulatorMock=1 - -#### api discovery commands - -listApis=15 - -#### API Rate Limit service command - -getApiLimit=15 -resetApiLimit=1 - -#### API SolidFire Service Command -getSolidFireAccountId=15 -getSolidFireVolumeSize=15 -getSolidFireVolumeAccessGroupId=15 -getSolidFireVolumeIscsiName=15 - -#### Region commands -addRegion=1 -updateRegion=1 -removeRegion=1 -listRegions=15 - -#### GSLB (Global Server Load Balancing) commands -createGlobalLoadBalancerRule=15 -deleteGlobalLoadBalancerRule=15 -updateGlobalLoadBalancerRule=15 -listGlobalLoadBalancerRules=15 -assignToGlobalLoadBalancerRule=15 -removeFromGlobalLoadBalancerRule=15 - -### VM Snapshot commands -listVMSnapshot=15 -createVMSnapshot=15 -deleteVMSnapshot=15 -revertToVMSnapshot=15 - -#### Baremetal commands -addBaremetalHost=1 -addBaremetalPxeKickStartServer=1 -addBaremetalPxePingServer=1 -addBaremetalDhcp=1 -listBaremetalDhcp=1 -listBaremetalPxeServers=1 -addBaremetalRct=1 -deleteBaremetalRct=1 -listBaremetalRct=1 - -#### UCS commands -addUcsManager=1 -listUcsManagers=1 -listUcsProfiles=1 -listUcsBlades=1 -associateUcsProfileToBlade=1 -removedeleteUcsManager=1 - -#### New Load Balancer commands -createLoadBalancer=15 -listLoadBalancers=15 -deleteLoadBalancer=15 -updateLoadBalancer=15 - -#Internal Load Balancer Element commands -configureInternalLoadBalancerElement=7 -createInternalLoadBalancerElement=7 -listInternalLoadBalancerElements=7 - - -#### Affinity group commands -createAffinityGroup=15 -deleteAffinityGroup=15 -listAffinityGroups=15 -updateVMAffinityGroup=15 -listAffinityGroupTypes=15 - -#### Cisco Vnmc commands -addCiscoVnmcResource=1 -deleteCiscoVnmcResource=1 -listCiscoVnmcResources=1 - -#### Cisco Asa1000v commands -addCiscoAsa1000vResource=1 -deleteCiscoAsa1000vResource=1 -listCiscoAsa1000vResources=1 - -#### portable public IP commands -createPortableIpRange=1 -deletePortableIpRange=1 -listPortableIpRanges=1 - -#### Internal LB VM commands -stopInternalLoadBalancerVM=1 -startInternalLoadBalancerVM=1 -listInternalLoadBalancerVMs=1 - -### Network Isolation methods listing -listNetworkIsolationMethods=1 - -#### Dedicated Resource commands -dedicateZone=1 -dedicatePod=1 -dedicateCluster=1 -dedicateHost=1 -releaseDedicatedZone=1 -releaseDedicatedPod=1 -releaseDedicatedCluster=1 -releaseDedicatedHost=1 -listDedicatedZones=1 -listDedicatedPods=1 -listDedicatedClusters=1 -listDedicatedHosts=1 - -### LDAP -listLdapConfigurations=15 -addLdapConfiguration=3 -deleteLdapConfiguration=3 -listLdapUsers=3 -ldapCreateAccount=3 -importLdapUsers=3 -linkDomainToLdap=3 - - -#### juniper-contrail commands -createServiceInstance=1 - -### OpenDaylight plugin commands -addOpenDaylightController=1 -deleteOpenDaylightController=1 -listOpenDaylightControllers=1 - -### GloboDNS commands -addGloboDnsHost=1 - -### volume/template post upload -getUploadParamsForVolume=15 -getUploadParamsForTemplate=15 - -### Quota Service -quotaStatement=15 -quotaBalance=15 -quotaSummary=15 -quotaUpdate=1 -quotaTariffList=15 -quotaTariffUpdate=1 -quotaCredits=1 -quotaEmailTemplateList=1 -quotaEmailTemplateUpdate=1 -quotaIsEnabled=15 diff --git a/client/tomcatconf/db.properties.in b/client/tomcatconf/db.properties.in index 74b926306e..1c2b55f3b8 100644 --- a/client/tomcatconf/db.properties.in +++ b/client/tomcatconf/db.properties.in @@ -25,6 +25,7 @@ region.id=1 db.cloud.username=@DBUSER@ db.cloud.password=@DBPW@ db.cloud.host=@DBHOST@ +db.cloud.driver=@DBDRIVER@ db.cloud.port=3306 db.cloud.name=cloud @@ -56,6 +57,7 @@ db.cloud.encrypt.secret= db.usage.username=@DBUSER@ db.usage.password=@DBPW@ db.usage.host=@DBHOST@ +db.usage.driver=@DBDRIVER@ db.usage.port=3306 db.usage.name=cloud_usage @@ -69,6 +71,7 @@ db.usage.url.params= db.simulator.username=@DBUSER@ db.simulator.password=@DBPW@ db.simulator.host=@DBHOST@ +db.simulator.driver=@DBDRIVER@ db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/core/pom.xml b/core/pom.xml index 9c74333144..60dc02ff57 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/core/resources/META-INF/cloudstack/api/spring-core-lifecycle-api-context-inheritable.xml b/core/resources/META-INF/cloudstack/api/spring-core-lifecycle-api-context-inheritable.xml index f1566b1302..1a33fa21f5 100644 --- a/core/resources/META-INF/cloudstack/api/spring-core-lifecycle-api-context-inheritable.xml +++ b/core/resources/META-INF/cloudstack/api/spring-core-lifecycle-api-context-inheritable.xml @@ -61,6 +61,5 @@ - diff --git a/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml b/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml index 5e2dc7b732..d36f98d404 100644 --- a/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml +++ b/core/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml @@ -306,5 +306,10 @@ class="org.apache.cloudstack.spring.lifecycle.registry.ExtensionRegistry"> - + + + + + diff --git a/core/resources/META-INF/cloudstack/outofbandmanagement/module.properties b/core/resources/META-INF/cloudstack/outofbandmanagement/module.properties new file mode 100644 index 0000000000..73d4bec9ce --- /dev/null +++ b/core/resources/META-INF/cloudstack/outofbandmanagement/module.properties @@ -0,0 +1,21 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name=outofbandmanagement +parent=core diff --git a/core/resources/META-INF/cloudstack/outofbandmanagement/spring-core-lifecycle-outofbandmanagement-context-inheritable.xml b/core/resources/META-INF/cloudstack/outofbandmanagement/spring-core-lifecycle-outofbandmanagement-context-inheritable.xml new file mode 100644 index 0000000000..6a25a2e349 --- /dev/null +++ b/core/resources/META-INF/cloudstack/outofbandmanagement/spring-core-lifecycle-outofbandmanagement-context-inheritable.xml @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/core/src/com/cloud/agent/api/BackupSnapshotCommand.java b/core/src/com/cloud/agent/api/BackupSnapshotCommand.java index 2a46610117..2c8c0cca20 100644 --- a/core/src/com/cloud/agent/api/BackupSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/BackupSnapshotCommand.java @@ -107,4 +107,5 @@ public Long getSnapshotId() { public Long getSecHostId() { return secHostId; } + } diff --git a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java index 7ac2ddedd2..30b59ff4ef 100644 --- a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java @@ -72,4 +72,5 @@ public Long getNewTemplateId() { public String getTemplateName() { return templateName; } + } diff --git a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java index 3025147a30..38a2f94fa4 100644 --- a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java +++ b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java @@ -99,4 +99,5 @@ public Long getAccountId() { public void setTemplateId(long templateId) { _templateId = templateId; } + } diff --git a/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java b/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java index 90a5e39714..52746fefc5 100644 --- a/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java +++ b/core/src/com/cloud/agent/api/CreateStoragePoolCommand.java @@ -19,10 +19,10 @@ package com.cloud.agent.api; -import com.cloud.storage.StoragePool; - import java.util.Map; +import com.cloud.storage.StoragePool; + public class CreateStoragePoolCommand extends ModifyStoragePoolCommand { public static final String DATASTORE_NAME = "datastoreName"; public static final String IQN = "iqn"; @@ -32,9 +32,6 @@ public class CreateStoragePoolCommand extends ModifyStoragePoolCommand { private boolean _createDatastore; private Map _details; - public CreateStoragePoolCommand() { - } - public CreateStoragePoolCommand(boolean add, StoragePool pool) { super(add, pool); } diff --git a/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java b/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java index fa9a4d5846..4526ce7db6 100644 --- a/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java @@ -50,4 +50,5 @@ public CreateVolumeFromSnapshotCommand(StoragePool pool, String secondaryStorage super(pool, secondaryStoragePoolURL, backedUpSnapshotUuid, backedUpSnapshotName, dcId, accountId, volumeId); setWait(wait); } + } diff --git a/core/src/com/cloud/agent/api/GetStorageStatsCommand.java b/core/src/com/cloud/agent/api/GetStorageStatsCommand.java index 23e8f9e3e5..94a574c51b 100644 --- a/core/src/com/cloud/agent/api/GetStorageStatsCommand.java +++ b/core/src/com/cloud/agent/api/GetStorageStatsCommand.java @@ -20,11 +20,12 @@ package com.cloud.agent.api; import com.cloud.agent.api.LogLevel.Log4jLevel; +import com.cloud.agent.api.storage.StorageNfsVersionCommand; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.storage.Storage.StoragePoolType; @LogLevel(Log4jLevel.Trace) -public class GetStorageStatsCommand extends Command { +public class GetStorageStatsCommand extends StorageNfsVersionCommand { private String id; private String localPath; private StoragePoolType pooltype; @@ -54,6 +55,11 @@ public GetStorageStatsCommand(DataStoreTO store) { this.store = store; } + public GetStorageStatsCommand(DataStoreTO store, Integer nfsVersion) { + super(nfsVersion); + this.store = store; + } + public GetStorageStatsCommand(String secUrl) { this.secUrl = secUrl; } diff --git a/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java b/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java index b92bb72082..6e6dadc67f 100644 --- a/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java +++ b/core/src/com/cloud/agent/api/ModifyStoragePoolAnswer.java @@ -24,44 +24,41 @@ import com.cloud.storage.template.TemplateProp; public class ModifyStoragePoolAnswer extends Answer { - StoragePoolInfo poolInfo; - Map templateInfo; - String localDatastoreName = null; - - protected ModifyStoragePoolAnswer() { - } + private StoragePoolInfo poolInfo; + private Map templateInfo; + private String localDatastoreName; public ModifyStoragePoolAnswer(ModifyStoragePoolCommand cmd, long capacityBytes, long availableBytes, Map tInfo) { super(cmd); - this.result = true; - this.poolInfo = - new StoragePoolInfo(null, cmd.getPool().getHost(), cmd.getPool().getPath(), cmd.getLocalPath(), cmd.getPool().getType(), capacityBytes, availableBytes); - this.templateInfo = tInfo; - } + result = true; - public StoragePoolInfo getPoolInfo() { - return poolInfo; + poolInfo = new StoragePoolInfo(null, cmd.getPool().getHost(), cmd.getPool().getPath(), cmd.getLocalPath(), cmd.getPool().getType(), capacityBytes, availableBytes); + + templateInfo = tInfo; } public void setPoolInfo(StoragePoolInfo poolInfo) { this.poolInfo = poolInfo; } - public Map getTemplateInfo() { - return templateInfo; + public StoragePoolInfo getPoolInfo() { + return poolInfo; } public void setTemplateInfo(Map templateInfo) { this.templateInfo = templateInfo; } - public String getLocalDatastoreName() { - return localDatastoreName; + public Map getTemplateInfo() { + return templateInfo; } public void setLocalDatastoreName(String localDatastoreName) { this.localDatastoreName = localDatastoreName; } + public String getLocalDatastoreName() { + return localDatastoreName; + } } diff --git a/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java b/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java index 136eb0938e..c2ab0ab7f3 100644 --- a/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java +++ b/core/src/com/cloud/agent/api/ModifyStoragePoolCommand.java @@ -26,51 +26,49 @@ import com.cloud.storage.StoragePool; public class ModifyStoragePoolCommand extends Command { - - boolean add; - StorageFilerTO pool; - String localPath; - String[] options; public static final String LOCAL_PATH_PREFIX = "/mnt/"; - public ModifyStoragePoolCommand() { - - } + private boolean add; + private StorageFilerTO pool; + private String localPath; + private String storagePath; public ModifyStoragePoolCommand(boolean add, StoragePool pool, String localPath) { this.add = add; this.pool = new StorageFilerTO(pool); this.localPath = localPath; - } public ModifyStoragePoolCommand(boolean add, StoragePool pool) { this(add, pool, LOCAL_PATH_PREFIX + File.separator + UUID.nameUUIDFromBytes((pool.getHostAddress() + pool.getPath()).getBytes())); } - public StorageFilerTO getPool() { - return pool; + public boolean getAdd() { + return add; } public void setPool(StoragePool pool) { this.pool = new StorageFilerTO(pool); } - public boolean getAdd() { - return add; - } - - @Override - public boolean executeInSequence() { - return false; + public StorageFilerTO getPool() { + return pool; } public String getLocalPath() { return localPath; } - public void setOptions(String[] options) { - this.options = options; + public void setStoragePath(String storagePath) { + this.storagePath = storagePath; } + public String getStoragePath() { + return storagePath; + } + + @Override + public boolean executeInSequence() { + return false; + } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java b/core/src/com/cloud/agent/api/ModifyTargetsAnswer.java similarity index 86% rename from plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java rename to core/src/com/cloud/agent/api/ModifyTargetsAnswer.java index 4e1cc431e7..c192e4a0df 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java +++ b/core/src/com/cloud/agent/api/ModifyTargetsAnswer.java @@ -17,10 +17,7 @@ // under the License. // -package com.cloud.network.sync; +package com.cloud.agent.api; - -public interface NuageVspSync { - - public void syncWithNuageVsp(String nuageVspEntity); +public class ModifyTargetsAnswer extends Answer { } diff --git a/core/src/com/cloud/agent/api/ModifyTargetsCommand.java b/core/src/com/cloud/agent/api/ModifyTargetsCommand.java new file mode 100644 index 0000000000..424d797495 --- /dev/null +++ b/core/src/com/cloud/agent/api/ModifyTargetsCommand.java @@ -0,0 +1,57 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.agent.api; + +import java.util.List; +import java.util.Map; + +public class ModifyTargetsCommand extends Command { + public static final String IQN = "iqn"; + public static final String STORAGE_HOST = "storageHost"; + public static final String STORAGE_PORT = "storagePort"; + public static final String CHAP_NAME = "chapName"; + public static final String CHAP_SECRET = "chapSecret"; + public static final String MUTUAL_CHAP_NAME = "mutualChapName"; + public static final String MUTUAL_CHAP_SECRET = "mutualChapSecret"; + + private boolean add; + private List> targets; + + public void setAdd(boolean add) { + this.add = add; + } + + public boolean getAdd() { + return add; + } + + public void setTargets(List> targets) { + this.targets = targets; + } + + public List> getTargets() { + return targets; + } + + @Override + public boolean executeInSequence() { + return false; + } +} diff --git a/core/src/com/cloud/agent/api/RebootCommand.java b/core/src/com/cloud/agent/api/RebootCommand.java index d8f1ce9569..eecf7f635d 100644 --- a/core/src/com/cloud/agent/api/RebootCommand.java +++ b/core/src/com/cloud/agent/api/RebootCommand.java @@ -19,29 +19,25 @@ package com.cloud.agent.api; -import com.cloud.vm.VirtualMachine; - public class RebootCommand extends Command { String vmName; + protected boolean executeInSequence = false; protected RebootCommand() { } - public RebootCommand(VirtualMachine vm) { - vmName = vm.getInstanceName(); - } - - public RebootCommand(String vmName) { + public RebootCommand(String vmName, boolean executeInSequence) { this.vmName = vmName; + this.executeInSequence = executeInSequence; } public String getVmName() { - return vmName; + return this.vmName; } @Override public boolean executeInSequence() { - return true; + return this.executeInSequence; } } diff --git a/core/src/com/cloud/agent/api/RebootRouterCommand.java b/core/src/com/cloud/agent/api/RebootRouterCommand.java index 149ac5d7b3..6d6c0a9038 100644 --- a/core/src/com/cloud/agent/api/RebootRouterCommand.java +++ b/core/src/com/cloud/agent/api/RebootRouterCommand.java @@ -27,7 +27,7 @@ protected RebootRouterCommand() { } public RebootRouterCommand(String vmName, String privateIp) { - super(vmName); + super(vmName, true); this.privateIp = privateIp; } diff --git a/core/src/com/cloud/agent/api/SecStorageSetupCommand.java b/core/src/com/cloud/agent/api/SecStorageSetupCommand.java index 28e55c2f4e..061346cd3b 100644 --- a/core/src/com/cloud/agent/api/SecStorageSetupCommand.java +++ b/core/src/com/cloud/agent/api/SecStorageSetupCommand.java @@ -21,9 +21,10 @@ import org.apache.cloudstack.framework.security.keystore.KeystoreManager; +import com.cloud.agent.api.storage.StorageNfsVersionCommand; import com.cloud.agent.api.to.DataStoreTO; -public class SecStorageSetupCommand extends Command { +public class SecStorageSetupCommand extends StorageNfsVersionCommand { private DataStoreTO store; private String secUrl; private KeystoreManager.Certificates certs; @@ -74,4 +75,5 @@ public String getPostUploadKey() { public void setPostUploadKey(String postUploadKey) { this.postUploadKey = postUploadKey; } + } diff --git a/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java b/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java index b9bdef5646..09f9266669 100644 --- a/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java +++ b/core/src/com/cloud/agent/api/SecurityGroupRulesCmd.java @@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.zip.DeflaterOutputStream; @@ -32,32 +33,48 @@ import com.cloud.utils.net.NetUtils; public class SecurityGroupRulesCmd extends Command { - private static Logger s_logger = Logger.getLogger(SecurityGroupRulesCmd.class); + private static final String CIDR_LENGTH_SEPARATOR = "/"; + private static final char RULE_TARGET_SEPARATOR = ','; + private static final char RULE_COMMAND_SEPARATOR = ':'; + protected static final String EGRESS_RULE = "E:"; + protected static final String INGRESS_RULE = "I:"; + private static final Logger LOGGER = Logger.getLogger(SecurityGroupRulesCmd.class); + + private final String guestIp; + private final String vmName; + private final String guestMac; + private final String signature; + private final Long seqNum; + private final Long vmId; + private Long msId; + private List ingressRuleSet; + private List egressRuleSet; + private final List secIps; public static class IpPortAndProto { - private String proto; - private int startPort; - private int endPort; + private final String proto; + private final int startPort; + private final int endPort; @LogLevel(Log4jLevel.Trace) - private String[] allowedCidrs; + private List allowedCidrs; - public IpPortAndProto() { - } - - public IpPortAndProto(String proto, int startPort, int endPort, String[] allowedCidrs) { + public IpPortAndProto(final String proto, final int startPort, final int endPort, final String... allowedCidrs) { super(); this.proto = proto; this.startPort = startPort; this.endPort = endPort; - this.allowedCidrs = allowedCidrs; + setAllowedCidrs(allowedCidrs); } - public String[] getAllowedCidrs() { + public List getAllowedCidrs() { return allowedCidrs; } - public void setAllowedCidrs(String[] allowedCidrs) { - this.allowedCidrs = allowedCidrs; + public void setAllowedCidrs(final String... allowedCidrs) { + this.allowedCidrs = new ArrayList(); + for (final String allowedCidr : allowedCidrs) { + this.allowedCidrs.add(allowedCidr); + } } public String getProto() { @@ -74,52 +91,28 @@ public int getEndPort() { } - String guestIp; - String vmName; - String guestMac; - String signature; - Long seqNum; - Long vmId; - Long msId; - IpPortAndProto[] ingressRuleSet; - IpPortAndProto[] egressRuleSet; - private List secIps; - - public SecurityGroupRulesCmd() { - super(); - } - - public SecurityGroupRulesCmd(String guestIp, String guestMac, String vmName, Long vmId, String signature, Long seqNum, IpPortAndProto[] ingressRuleSet, - IpPortAndProto[] egressRuleSet) { - super(); - this.guestIp = guestIp; - this.vmName = vmName; - this.ingressRuleSet = ingressRuleSet; - this.egressRuleSet = egressRuleSet; - this.guestMac = guestMac; - this.signature = signature; - this.seqNum = seqNum; - this.vmId = vmId; - if (signature == null) { - String stringified = stringifyRules(); - this.signature = DigestUtils.md5Hex(stringified); - } - } - - public SecurityGroupRulesCmd(String guestIp, String guestMac, String vmName, Long vmId, String signature, Long seqNum, IpPortAndProto[] ingressRuleSet, - IpPortAndProto[] egressRuleSet, List secIps) { - super(); + public SecurityGroupRulesCmd( + final String guestIp, + final String guestMac, + final String vmName, + final Long vmId, + final String signature, + final Long seqNum, + final IpPortAndProto[] ingressRuleSet, + final IpPortAndProto[] egressRuleSet, + final List secIps) { this.guestIp = guestIp; this.vmName = vmName; - this.ingressRuleSet = ingressRuleSet; - this.egressRuleSet = egressRuleSet; + setIngressRuleSet(ingressRuleSet); + this.setEgressRuleSet(egressRuleSet); this.guestMac = guestMac; - this.signature = signature; this.seqNum = seqNum; this.vmId = vmId; if (signature == null) { - String stringified = stringifyRules(); + final String stringified = stringifyRules(); this.signature = DigestUtils.md5Hex(stringified); + } else { + this.signature = signature; } this.secIps = secIps; } @@ -129,20 +122,26 @@ public boolean executeInSequence() { return true; } - public IpPortAndProto[] getIngressRuleSet() { + public List getIngressRuleSet() { return ingressRuleSet; } - public void setIngressRuleSet(IpPortAndProto[] ingressRuleSet) { - this.ingressRuleSet = ingressRuleSet; + public void setIngressRuleSet(final IpPortAndProto... ingressRuleSet) { + this.ingressRuleSet = new ArrayList(); + for(final IpPortAndProto rule: ingressRuleSet) { + this.ingressRuleSet.add(rule); + } } - public IpPortAndProto[] getEgressRuleSet() { + public List getEgressRuleSet() { return egressRuleSet; } - public void setEgressRuleSet(IpPortAndProto[] egressRuleSet) { - this.egressRuleSet = egressRuleSet; + public void setEgressRuleSet(final IpPortAndProto... egressRuleSet) { + this.egressRuleSet = new ArrayList(); + for(final IpPortAndProto rule: egressRuleSet) { + this.egressRuleSet.add(rule); + } } public String getGuestIp() { @@ -157,105 +156,77 @@ public String getVmName() { return vmName; } - public String stringifyRules() { - StringBuilder ruleBuilder = new StringBuilder(); - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getIngressRuleSet()) { - ruleBuilder.append("I:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - ruleBuilder.append(cidr).append(","); - } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); - } - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getEgressRuleSet()) { - ruleBuilder.append("E:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - ruleBuilder.append(cidr).append(","); - } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); - } - return ruleBuilder.toString(); - } - - //convert cidrs in the form "a.b.c.d/e" to "hexvalue of 32bit ip/e" - private String compressCidr(String cidr) { - String[] toks = cidr.split("/"); - long ipnum = NetUtils.ip2Long(toks[0]); - return Long.toHexString(ipnum) + "/" + toks[1]; + private String compressCidrToHexRepresentation(final String cidr) { + final String[] toks = cidr.split(CIDR_LENGTH_SEPARATOR); + final long ipnum = NetUtils.ip2Long(toks[0]); + return Long.toHexString(ipnum) + CIDR_LENGTH_SEPARATOR + toks[1]; } public String getSecIpsString() { - StringBuilder sb = new StringBuilder(); - List ips = getSecIps(); + final StringBuilder sb = new StringBuilder(); + final List ips = getSecIps(); if (ips == null) { - return "0:"; + sb.append("0:"); } else { - for (String ip : ips) { - sb.append(ip).append(":"); + for (final String ip : ips) { + sb.append(ip).append(RULE_COMMAND_SEPARATOR); } } return sb.toString(); } + public String stringifyRules() { + final StringBuilder ruleBuilder = new StringBuilder(); + stringifyRulesFor(getIngressRuleSet(), INGRESS_RULE, false, ruleBuilder); + stringifyRulesFor(getEgressRuleSet(), EGRESS_RULE, false, ruleBuilder); + return ruleBuilder.toString(); + } + public String stringifyCompressedRules() { - StringBuilder ruleBuilder = new StringBuilder(); - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getIngressRuleSet()) { - ruleBuilder.append("I:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - //convert cidrs in the form "a.b.c.d/e" to "hexvalue of 32bit ip/e" - ruleBuilder.append(compressCidr(cidr)).append(","); + final StringBuilder ruleBuilder = new StringBuilder(); + stringifyRulesFor(getIngressRuleSet(), INGRESS_RULE, true, ruleBuilder); + stringifyRulesFor(getEgressRuleSet(), EGRESS_RULE, true, ruleBuilder); + return ruleBuilder.toString(); + } + + private void stringifyRulesFor(final List ipPortAndProtocols, final String inOrEgress, final boolean compressed, final StringBuilder ruleBuilder) { + for (final IpPortAndProto ipPandP : ipPortAndProtocols) { + ruleBuilder.append(inOrEgress).append(ipPandP.getProto()).append(RULE_COMMAND_SEPARATOR).append(ipPandP.getStartPort()).append(RULE_COMMAND_SEPARATOR) + .append(ipPandP.getEndPort()).append(RULE_COMMAND_SEPARATOR); + for (final String cidr : ipPandP.getAllowedCidrs()) { + ruleBuilder.append(represent(cidr, compressed)).append(RULE_TARGET_SEPARATOR); } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); + ruleBuilder.append("NEXT "); } - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getEgressRuleSet()) { - ruleBuilder.append("E:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - //convert cidrs in the form "a.b.c.d/e" to "hexvalue of 32bit ip/e" - ruleBuilder.append(compressCidr(cidr)).append(","); - } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); + } + + private String represent(final String cidr, final boolean compressed) { + if (compressed) { + return compressCidrToHexRepresentation(cidr); + } else { + return cidr; } - return ruleBuilder.toString(); } - /* + /** * Compress the security group rules using zlib compression to allow the call to the hypervisor * to scale beyond 8k cidrs. + * Note : not using {@see GZipOutputStream} since that is for files, using {@see DeflaterOutputStream} instead. + * {@see GZipOutputStream} gives a different header, although the compression is the same */ public String compressStringifiedRules() { - StringBuilder ruleBuilder = new StringBuilder(); - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getIngressRuleSet()) { - ruleBuilder.append("I:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - ruleBuilder.append(cidr).append(","); - } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); - } - for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getEgressRuleSet()) { - ruleBuilder.append("E:").append(ipPandP.getProto()).append(":").append(ipPandP.getStartPort()).append(":").append(ipPandP.getEndPort()).append(":"); - for (String cidr : ipPandP.getAllowedCidrs()) { - ruleBuilder.append(cidr).append(","); - } - ruleBuilder.append("NEXT"); - ruleBuilder.append(" "); - } - String stringified = ruleBuilder.toString(); - ByteArrayOutputStream out = new ByteArrayOutputStream(); + final String stringified = stringifyRules(); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + String encodedResult = null; try { - //Note : not using GZipOutputStream since that is for files - //GZipOutputStream gives a different header, although the compression is the same - DeflaterOutputStream dzip = new DeflaterOutputStream(out); + final DeflaterOutputStream dzip = new DeflaterOutputStream(out); dzip.write(stringified.getBytes()); dzip.close(); - } catch (IOException e) { - s_logger.warn("Exception while compressing security group rules"); - return null; + encodedResult = Base64.encodeBase64String(out.toByteArray()); + } catch (final IOException e) { + LOGGER.warn("Exception while compressing security group rules"); } - return Base64.encodeBase64String(out.toByteArray()); + return encodedResult; } public String getSignature() { @@ -274,19 +245,22 @@ public Long getVmId() { return vmId; } + /** + * used for logging + * @return the number of Cidrs in the in and egress rule sets for this security group rules command. + */ public int getTotalNumCidrs() { - //useful for logging int count = 0; - for (IpPortAndProto i : ingressRuleSet) { - count += i.allowedCidrs.length; + for (final IpPortAndProto i : ingressRuleSet) { + count += i.allowedCidrs.size(); } - for (IpPortAndProto i : egressRuleSet) { - count += i.allowedCidrs.length; + for (final IpPortAndProto i : egressRuleSet) { + count += i.allowedCidrs.size(); } return count; } - public void setMsId(long msId) { + public void setMsId(final long msId) { this.msId = msId; } diff --git a/core/src/com/cloud/agent/api/SnapshotCommand.java b/core/src/com/cloud/agent/api/SnapshotCommand.java index cf4eeb5da5..0e527e2f84 100644 --- a/core/src/com/cloud/agent/api/SnapshotCommand.java +++ b/core/src/com/cloud/agent/api/SnapshotCommand.java @@ -19,6 +19,7 @@ package com.cloud.agent.api; +import com.cloud.agent.api.storage.StorageNfsVersionCommand; import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.storage.StoragePool; @@ -26,7 +27,7 @@ * This currently assumes that both primary and secondary storage are mounted on * the XenServer. */ -public class SnapshotCommand extends Command { +public class SnapshotCommand extends StorageNfsVersionCommand { protected String primaryStoragePoolNameLabel; StorageFilerTO primaryPool; private String snapshotUuid; diff --git a/core/src/com/cloud/agent/api/StartupRoutingCommand.java b/core/src/com/cloud/agent/api/StartupRoutingCommand.java index c4138367b7..b459f88496 100644 --- a/core/src/com/cloud/agent/api/StartupRoutingCommand.java +++ b/core/src/com/cloud/agent/api/StartupRoutingCommand.java @@ -35,7 +35,7 @@ public class StartupRoutingCommand extends StartupCommand { long memory; long dom0MinMemory; boolean poolSync; - + private boolean supportsClonedVolumes; String caps; String pool; @@ -180,4 +180,12 @@ public HashMap> getGpuGroupDetails() { public void setGpuGroupDetails(HashMap> groupDetails) { this.groupDetails = groupDetails; } + + public boolean getSupportsClonedVolumes() { + return supportsClonedVolumes; + } + + public void setSupportsClonedVolumes(boolean supportsClonedVolumes) { + this.supportsClonedVolumes = supportsClonedVolumes; + } } diff --git a/core/src/com/cloud/agent/api/StopCommand.java b/core/src/com/cloud/agent/api/StopCommand.java index c4948cd631..b723d746cc 100644 --- a/core/src/com/cloud/agent/api/StopCommand.java +++ b/core/src/com/cloud/agent/api/StopCommand.java @@ -26,7 +26,6 @@ public class StopCommand extends RebootCommand { private boolean isProxy = false; private String urlPort = null; private String publicConsoleProxyIpAddress = null; - boolean executeInSequence = false; private GPUDeviceTO gpuDevice; boolean checkBeforeCleanup = false; @@ -34,33 +33,30 @@ protected StopCommand() { } public StopCommand(VirtualMachine vm, boolean isProxy, String urlPort, String publicConsoleProxyIpAddress, boolean executeInSequence, boolean checkBeforeCleanup) { - super(vm); + super(vm.getInstanceName(), executeInSequence); this.isProxy = isProxy; this.urlPort = urlPort; this.publicConsoleProxyIpAddress = publicConsoleProxyIpAddress; - this.executeInSequence = executeInSequence; this.checkBeforeCleanup = checkBeforeCleanup; } public StopCommand(VirtualMachine vm, boolean executeInSequence, boolean checkBeforeCleanup) { - super(vm); - this.executeInSequence = executeInSequence; + super(vm.getInstanceName(), executeInSequence); this.checkBeforeCleanup = checkBeforeCleanup; } public StopCommand(String vmName, boolean executeInSequence, boolean checkBeforeCleanup) { - super(vmName); - this.executeInSequence = executeInSequence; + super(vmName, executeInSequence); this.checkBeforeCleanup = checkBeforeCleanup; } @Override public boolean executeInSequence() { - //VR stop doesn't go through queue - if (vmName != null && vmName.startsWith("r-")) { + // VR stop doesn't go through queue + if (this.vmName != null && this.vmName.startsWith("r-")) { return false; } - return executeInSequence; + return this.executeInSequence; } public boolean isProxy() { diff --git a/core/src/com/cloud/agent/api/VmStatsEntry.java b/core/src/com/cloud/agent/api/VmStatsEntry.java index 0f30b6af53..e6063b9ab5 100644 --- a/core/src/com/cloud/agent/api/VmStatsEntry.java +++ b/core/src/com/cloud/agent/api/VmStatsEntry.java @@ -30,13 +30,19 @@ public class VmStatsEntry implements VmStats { double diskWriteIOs; double diskReadKBs; double diskWriteKBs; + double memoryKBs; + double intfreememoryKBs; + double targetmemoryKBs; int numCPUs; String entityType; public VmStatsEntry() { } - public VmStatsEntry(double cpuUtilization, double networkReadKBs, double networkWriteKBs, int numCPUs, String entityType) { + public VmStatsEntry(double memoryKBs,double intfreememoryKBs,double targetmemoryKBs, double cpuUtilization, double networkReadKBs, double networkWriteKBs, int numCPUs, String entityType) { + this.memoryKBs = memoryKBs; + this.intfreememoryKBs = intfreememoryKBs; + this.targetmemoryKBs = targetmemoryKBs; this.cpuUtilization = cpuUtilization; this.networkReadKBs = networkReadKBs; this.networkWriteKBs = networkWriteKBs; @@ -117,6 +123,33 @@ public void setDiskWriteKBs(double diskWriteKBs) { this.diskWriteKBs = diskWriteKBs; } + @Override + public double getMemoryKBs() { + return memoryKBs; + } + + public void setMemoryKBs(double memoryKBs) { + this.memoryKBs = memoryKBs; + } + + @Override + public double getIntFreeMemoryKBs() { + return intfreememoryKBs; + } + + public void setIntFreeMemoryKBs(double intfreememoryKBs) { + this.intfreememoryKBs = intfreememoryKBs; + } + + @Override + public double getTargetMemoryKBs() { + return targetmemoryKBs; + } + + public void setTargetMemoryKBs(double targetmemoryKBs) { + this.targetmemoryKBs = targetmemoryKBs; + } + public int getNumCPUs() { return numCPUs; } diff --git a/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java b/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java index 43c84ee2bc..a75e9ba3be 100644 --- a/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java +++ b/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java @@ -19,11 +19,10 @@ package com.cloud.agent.api.storage; -import com.cloud.agent.api.Command; import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.storage.StoragePool; -public class CopyVolumeCommand extends Command { +public class CopyVolumeCommand extends StorageNfsVersionCommand { long volumeId; String volumePath; @@ -75,4 +74,5 @@ public boolean toSecondaryStorage() { public String getVmName() { return vmName; } + } diff --git a/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java b/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java index 855095280d..6f60933f55 100644 --- a/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java +++ b/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java @@ -24,14 +24,16 @@ public class ListTemplateCommand extends StorageCommand { private DataStoreTO store; - //private String secUrl; - public ListTemplateCommand() { } public ListTemplateCommand(DataStoreTO store) { this.store = store; -// this.secUrl = url; + } + + public ListTemplateCommand(DataStoreTO store, Integer nfsVersion) { + super(nfsVersion); + this.store = store; } @Override @@ -43,8 +45,4 @@ public DataStoreTO getDataStore() { return store; } - // public String getSecUrl() { - // return secUrl; - // } - } diff --git a/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java b/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java index ce8ed217a5..725bd0cdde 100644 --- a/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java +++ b/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java @@ -87,4 +87,5 @@ public String getPrimaryStorageUrl() { public boolean executeInSequence() { return true; } + } diff --git a/core/src/com/cloud/agent/api/storage/ResizeVolumeCommand.java b/core/src/com/cloud/agent/api/storage/ResizeVolumeCommand.java index 3b121e1a54..22cff13de2 100644 --- a/core/src/com/cloud/agent/api/storage/ResizeVolumeCommand.java +++ b/core/src/com/cloud/agent/api/storage/ResizeVolumeCommand.java @@ -25,22 +25,34 @@ public class ResizeVolumeCommand extends Command { private String path; private StorageFilerTO pool; - private String vmInstance; - private Long newSize; private Long currentSize; + private Long newSize; private boolean shrinkOk; + private String vmInstance; - protected ResizeVolumeCommand() { + /* For managed storage */ + private boolean managed; + private String iScsiName; + protected ResizeVolumeCommand() { } public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance) { this.path = path; this.pool = pool; - this.vmInstance = vmInstance; this.currentSize = currentSize; this.newSize = newSize; this.shrinkOk = shrinkOk; + this.vmInstance = vmInstance; + this.managed = false; + } + + public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance, + boolean isManaged, String iScsiName) { + this(path, pool, currentSize, newSize, shrinkOk, vmInstance); + + this.iScsiName = iScsiName; + this.managed = isManaged; } public String getPath() { @@ -55,22 +67,20 @@ public StorageFilerTO getPool() { return pool; } - public long getNewSize() { - return newSize; - } + public long getCurrentSize() { return currentSize; } - public long getCurrentSize() { - return currentSize; - } + public long getNewSize() { return newSize; } - public boolean getShrinkOk() { - return shrinkOk; - } + public boolean getShrinkOk() { return shrinkOk; } public String getInstanceName() { return vmInstance; } + public boolean isManaged() { return managed; } + + public String get_iScsiName() {return iScsiName; } + /** * {@inheritDoc} */ @@ -78,5 +88,4 @@ public String getInstanceName() { public boolean executeInSequence() { return false; } - } diff --git a/core/src/com/cloud/agent/api/storage/SsCommand.java b/core/src/com/cloud/agent/api/storage/SsCommand.java index 187ae03be4..575b2450a2 100644 --- a/core/src/com/cloud/agent/api/storage/SsCommand.java +++ b/core/src/com/cloud/agent/api/storage/SsCommand.java @@ -19,9 +19,7 @@ package com.cloud.agent.api.storage; -import com.cloud.agent.api.Command; - -public abstract class SsCommand extends Command { +public abstract class SsCommand extends StorageNfsVersionCommand { private String secUrl; public SsCommand() { diff --git a/core/src/com/cloud/agent/api/storage/StorageCommand.java b/core/src/com/cloud/agent/api/storage/StorageCommand.java index a6719c40c1..429755cba4 100644 --- a/core/src/com/cloud/agent/api/storage/StorageCommand.java +++ b/core/src/com/cloud/agent/api/storage/StorageCommand.java @@ -19,11 +19,13 @@ package com.cloud.agent.api.storage; -import com.cloud.agent.api.Command; - -public abstract class StorageCommand extends Command { +public abstract class StorageCommand extends StorageNfsVersionCommand { protected StorageCommand() { super(); } + protected StorageCommand(Integer nfsVersion){ + super(nfsVersion); + } + } diff --git a/core/src/com/cloud/agent/api/storage/StorageNfsVersionCommand.java b/core/src/com/cloud/agent/api/storage/StorageNfsVersionCommand.java new file mode 100755 index 0000000000..b99713dea1 --- /dev/null +++ b/core/src/com/cloud/agent/api/storage/StorageNfsVersionCommand.java @@ -0,0 +1,44 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +package com.cloud.agent.api.storage; + +import com.cloud.agent.api.Command; + +public abstract class StorageNfsVersionCommand extends Command { + + protected StorageNfsVersionCommand(){ + super(); + } + + protected StorageNfsVersionCommand(Integer nfsVersion){ + super(); + this.nfsVersion = nfsVersion; + } + + private Integer nfsVersion; + + public Integer getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(Integer nfsVersion) { + this.nfsVersion = nfsVersion; + } + +} diff --git a/core/src/com/cloud/storage/resource/StorageProcessor.java b/core/src/com/cloud/storage/resource/StorageProcessor.java index e2bf1b7877..e5832cc23d 100644 --- a/core/src/com/cloud/storage/resource/StorageProcessor.java +++ b/core/src/com/cloud/storage/resource/StorageProcessor.java @@ -26,6 +26,7 @@ import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import com.cloud.agent.api.Answer; @@ -68,4 +69,6 @@ public interface StorageProcessor { public Answer forgetObject(ForgetObjectCmd cmd); public Answer snapshotAndCopy(SnapshotAndCopyCommand cmd); + + public Answer resignature(ResignatureCommand cmd); } diff --git a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java index fc771e0ff5..d9d2993dba 100644 --- a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java +++ b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java @@ -28,6 +28,7 @@ import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; @@ -64,6 +65,8 @@ public Answer handleStorageCommands(StorageSubSystemCommand command) { return processor.introduceObject((IntroduceObjectCmd)command); } else if (command instanceof SnapshotAndCopyCommand) { return processor.snapshotAndCopy((SnapshotAndCopyCommand)command); + } else if (command instanceof ResignatureCommand) { + return processor.resignature((ResignatureCommand)command); } return new Answer((Command)command, false, "not implemented yet"); diff --git a/core/src/org/apache/cloudstack/storage/command/ResignatureAnswer.java b/core/src/org/apache/cloudstack/storage/command/ResignatureAnswer.java new file mode 100644 index 0000000000..071f6a9cf1 --- /dev/null +++ b/core/src/org/apache/cloudstack/storage/command/ResignatureAnswer.java @@ -0,0 +1,60 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package org.apache.cloudstack.storage.command; + +import com.cloud.agent.api.Answer; +import com.cloud.storage.Storage.ImageFormat; + +public class ResignatureAnswer extends Answer { + private long size; + private String path; + private ImageFormat format; + + public ResignatureAnswer() { + } + + public ResignatureAnswer(String errMsg) { + super(null, false, errMsg); + } + + public void setSize(long size) { + this.size = size; + } + + public long getSize() { + return size; + } + + public void setPath(String path) { + this.path = path; + } + + public String getPath() { + return path; + } + + public void setFormat(ImageFormat format) { + this.format = format; + } + + public ImageFormat getFormat() { + return format; + } +} diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/JobCancellationException.java b/core/src/org/apache/cloudstack/storage/command/ResignatureCommand.java similarity index 54% rename from framework/jobs/src/org/apache/cloudstack/framework/jobs/JobCancellationException.java rename to core/src/org/apache/cloudstack/storage/command/ResignatureCommand.java index 23540e7a07..beb4b65748 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/JobCancellationException.java +++ b/core/src/org/apache/cloudstack/storage/command/ResignatureCommand.java @@ -1,3 +1,4 @@ +// // 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 @@ -14,33 +15,34 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.framework.jobs; +// -import java.util.concurrent.CancellationException; +package org.apache.cloudstack.storage.command; -import com.cloud.utils.SerialVersionUID; +import com.cloud.utils.Utils; -/** - * This exception is fired when the job has been cancelled - * - */ -public class JobCancellationException extends CancellationException { +import java.util.Map; - private static final long serialVersionUID = SerialVersionUID.AffinityConflictException; +public final class ResignatureCommand extends StorageSubSystemCommand { + private final Map details; - public enum Reason { - RequestedByUser, RequestedByCaller, TimedOut; - } + private boolean executeInSequence = true; - Reason reason; + public ResignatureCommand(final Map details) { + this.details = Utils.getImmutableMap(details); + } - public JobCancellationException(Reason reason) { - super("The job was cancelled due to " + reason.toString()); - this.reason = reason; + public Map getDetails() { + return details; } - public Reason getReason() { - return reason; + @Override + public void setExecuteInSequence(final boolean executeInSequence) { + this.executeInSequence = executeInSequence; } + @Override + public boolean executeInSequence() { + return executeInSequence; + } } diff --git a/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java b/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java index 5d1e56bd77..29fdd19116 100644 --- a/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java +++ b/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java @@ -53,6 +53,8 @@ public class TemplateOrVolumePostUploadCommand { private long accountId; + private Integer nfsVersion; + public TemplateOrVolumePostUploadCommand(long entityId, String entityUUID, String absolutePath, String checksum, String type, String name, String imageFormat, String dataTo, String dataToRole) { this.entityId = entityId; @@ -196,4 +198,12 @@ public void setAccountId(long accountId) { public long getAccountId() { return accountId; } + + public Integer getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(Integer nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java index a69f35706d..9b711bc3b3 100644 --- a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java +++ b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java @@ -37,6 +37,7 @@ public class PrimaryDataStoreTO implements DataStoreTO { public static final String CHAP_INITIATOR_SECRET = PrimaryDataStore.CHAP_INITIATOR_SECRET; public static final String CHAP_TARGET_USERNAME = PrimaryDataStore.CHAP_TARGET_USERNAME; public static final String CHAP_TARGET_SECRET = PrimaryDataStore.CHAP_TARGET_SECRET; + public static final String REMOVE_AFTER_COPY = PrimaryDataStore.REMOVE_AFTER_COPY; public static final String VOLUME_SIZE = PrimaryDataStore.VOLUME_SIZE; private final String uuid; diff --git a/core/test/com/cloud/agent/api/SecurityGroupRulesCmdTest.java b/core/test/com/cloud/agent/api/SecurityGroupRulesCmdTest.java new file mode 100644 index 0000000000..37b15ebb72 --- /dev/null +++ b/core/test/com/cloud/agent/api/SecurityGroupRulesCmdTest.java @@ -0,0 +1,93 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.agent.api; + +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Vector; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto; + +/** + * @author daan + * + */ +@RunWith(MockitoJUnitRunner.class) +public class SecurityGroupRulesCmdTest { + private SecurityGroupRulesCmd securityGroupRulesCmd; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + final String guestIp = "10.10.10.10"; + final String guestMac = "aa:aa:aa:aa:aa:aa"; + final String vmName = "vm"; + final Long vmId = 1L; + final String signature = "sig"; + final Long seqNum = 0L; + final String proto = "abc"; + final int startPort = 1; + final int endPort = 2; + final String[] allowedCidrs = new String[] {"1.2.3.4/5","6.7.8.9/0"}; + final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{new IpPortAndProto(proto, startPort, endPort, allowedCidrs)}; + final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{new IpPortAndProto(proto, startPort, endPort, allowedCidrs)}; + final List secIps = new Vector(); + securityGroupRulesCmd = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps); + } + + /** + * Test method for {@link com.cloud.agent.api.SecurityGroupRulesCmd#stringifyRules()}. + */ + @Test + public void testStringifyRules() throws Exception { + final String a = securityGroupRulesCmd.stringifyRules(); +// do verification on a + assertTrue(a.contains(SecurityGroupRulesCmd.EGRESS_RULE)); + } + + /** + * Test method for {@link com.cloud.agent.api.SecurityGroupRulesCmd#stringifyCompressedRules()}. + */ + @Test + public void testStringifyCompressedRules() throws Exception { + final String a = securityGroupRulesCmd.stringifyCompressedRules(); +// do verification on a + assertTrue(a.contains(SecurityGroupRulesCmd.EGRESS_RULE)); + } + + /** + * Test method for {@link com.cloud.agent.api.SecurityGroupRulesCmd#compressStringifiedRules()}. + */ + @Test + public void testCompressStringifiedRules() throws Exception { + final String compressed = "eJzztEpMSrYytDKyMtQz0jPWM9E31THTM9ez0LPUN9Dxc40IUXAlrAQAPdoP3Q=="; + final String a = securityGroupRulesCmd.compressStringifiedRules(); + assertTrue(compressed.equals(a)); + } + +} diff --git a/debian/changelog b/debian/changelog index 2c1a2344ef..04ae4f7537 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,14 +1,14 @@ -cloudstack (4.8.1-SNAPSHOT) unstable; urgency=low +cloudstack (4.9.0-SNAPSHOT) unstable; urgency=low [ Remi Bergsma ] - * Update the version to 4.8.1-SNAPSHOT + * Update the version to 4.9.0.snapshot -- the Apache CloudStack project Wed, 20 Jan 2016 23:43:35 +0100 cloudstack (4.8.0-SNAPSHOT) unstable; urgency=low [ Remi Bergsma ] - * Update the version to 4.8.1.snapshot + * Update the version to 4.8.0.snapshot -- the Apache CloudStack project Sun, 21 Dec 2015 22:11:55 +0100 diff --git a/debian/cloudstack-management.install b/debian/cloudstack-management.install index 4e016dfe29..c66938263e 100644 --- a/debian/cloudstack-management.install +++ b/debian/cloudstack-management.install @@ -18,7 +18,6 @@ /etc/cloudstack/management/catalina.policy /etc/cloudstack/management/catalina.properties /etc/cloudstack/management/logging.properties -/etc/cloudstack/management/commands.properties /etc/cloudstack/management/ehcache.xml /etc/cloudstack/management/server-ssl.xml /etc/cloudstack/management/server-nonssl.xml diff --git a/debian/control b/debian/control index 42cff9da6e..8d40059dcc 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: libs Priority: extra Maintainer: Wido den Hollander Build-Depends: debhelper (>= 9), openjdk-8-jdk | openjdk-7-jdk, genisoimage, - python-mysqldb, maven (>= 3) | maven3, python (>= 2.7) + python-mysql.connector, maven (>= 3) | maven3, python (>= 2.7) Standards-Version: 3.8.1 Homepage: http://www.cloudstack.org/ @@ -15,14 +15,14 @@ Description: A common package which contains files which are shared by several C Package: cloudstack-management Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, cloudstack-common (= ${source:Version}), tomcat6, sudo, jsvc, python-mysqldb, libmysql-java, augeas-tools, mysql-client, adduser, bzip2, lsb-release +Depends: ${misc:Depends}, ${python:Depends}, cloudstack-common (= ${source:Version}), tomcat6 | tomcat7, sudo, jsvc, python-mysql.connector, libmysql-java, augeas-tools, mysql-client, adduser, bzip2, ipmitool, lsb-release Conflicts: cloud-server, cloud-client, cloud-client-ui Description: CloudStack server library The CloudStack management server Package: cloudstack-agent Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, openjdk-8-jre-headless | openjdk-7-jre-headless, cloudstack-common (= ${source:Version}), lsb-base (>= 4.0), libcommons-daemon-java, openssh-client, qemu-kvm (>= 1.0), libvirt-bin (>= 0.9.8), uuid-runtime, iproute, ebtables, vlan, jsvc, ipset, python-libvirt, ethtool, iptables, perl-modules, lsb-release +Depends: ${misc:Depends}, ${python:Depends}, openjdk-8-jre-headless | openjdk-7-jre-headless, cloudstack-common (= ${source:Version}), lsb-base (>= 4.0), libcommons-daemon-java, openssh-client, qemu-kvm (>= 1.0), libvirt-bin (>= 0.9.8), uuid-runtime, iproute, ebtables, vlan, jsvc, ipset, python-libvirt, ethtool, iptables, lsb-release Conflicts: cloud-agent, cloud-agent-libs, cloud-agent-deps, cloud-agent-scripts Description: CloudStack agent The CloudStack agent is in charge of managing shared computing resources in diff --git a/deps/install-non-oss.sh b/deps/install-non-oss.sh index 7d38d53760..2f5027cd4c 100755 --- a/deps/install-non-oss.sh +++ b/deps/install-non-oss.sh @@ -35,3 +35,6 @@ mvn install:install-file -Dfile=vim25_51.jar -DgroupId=com.cloud.com.vmwa # From https://my.vmware.com/group/vmware/get-download?downloadGroup=WEBSDK550 mvn install:install-file -Dfile=vim25_55.jar -DgroupId=com.cloud.com.vmware -DartifactId=vmware-vim25 -Dversion=5.5 -Dpackaging=jar + +# From https://my.vmware.com VMware-vSphere-SDK-6.0.0-3634981.zip +mvn install:install-file -Dfile=vim25_60.jar -DgroupId=com.cloud.com.vmware -DartifactId=vmware-vim25 -Dversion=6.0 -Dpackaging=jar diff --git a/developer/developer-prefill.sql b/developer/developer-prefill.sql index 3097203b41..132659e3d9 100644 --- a/developer/developer-prefill.sql +++ b/developer/developer-prefill.sql @@ -62,6 +62,10 @@ INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', 'expunge.interval', '60'); +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'expunge.workers', '3'); + INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', 'cluster.cpu.allocated.capacity.disablethreshold', '0.95'); @@ -78,6 +82,47 @@ INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', 'pool.storage.capacity.disablethreshold', '0.95'); +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'network.gc.wait', '60'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'network.gc.interval', '60'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'storage.cleanup.interval', '150'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'vm.op.wait.interval', '5'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'workers', '10'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'direct.agent.load.size', '1000'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'ping.interval', '10'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'ping.timeout', '1.5'); + +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'management-server', + 'outofbandmanagement.sync.interval', '1000'); + +-- Enable dynamic RBAC by default for fresh deployments +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) + VALUES ('Advanced', 'DEFAULT', 'RoleService', + 'dynamic.apichecker.enabled', 'true'); + -- Add developer configuration entry; allows management server to be run as a user other than "cloud" INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'management-server', diff --git a/developer/pom.xml b/developer/pom.xml index bdd330a26b..b7d70004b0 100644 --- a/developer/pom.xml +++ b/developer/pom.xml @@ -18,7 +18,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT diff --git a/engine/api/pom.xml b/engine/api/pom.xml index 71003da0eb..1f539fbd04 100644 --- a/engine/api/pom.xml +++ b/engine/api/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml @@ -38,7 +38,7 @@ org.apache.cxf cxf-bundle-jaxrs - 2.7.13 + 2.7.18 org.eclipse.jetty diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/com/cloud/vm/VirtualMachineManager.java index 8b22656422..d68f3485b0 100644 --- a/engine/api/src/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/com/cloud/vm/VirtualMachineManager.java @@ -49,11 +49,10 @@ public interface VirtualMachineManager extends Manager { static final ConfigKey ExecuteInSequence = new ConfigKey("Advanced", Boolean.class, "execute.in.sequence.hypervisor.commands", "false", - "If set to true, StartCommand, StopCommand, CopyCommand, MigrateCommand will be synchronized on the agent side." - + " If set to false, these commands become asynchronous. Default value is false.", false); + "If set to true, start, stop, reboot, copy and migrate commands will be serialized on the agent side. If set to false the commands are executed in parallel. Default value is false.", false); static final ConfigKey VmConfigDriveLabel = new ConfigKey("Hidden", String.class, "vm.configdrive.label", "config", - "The default lable name for the config drive", false); + "The default label name for the config drive", false); public interface Topics { public static final String VM_POWER_STATE = "vm.powerstate"; @@ -199,4 +198,6 @@ void findHostAndMigrate(String vmUuid, Long newSvcOfferingId, DeploymentPlanner. ConcurrentOperationException, ResourceUnavailableException; void migrateForScale(String vmUuid, long srcHostId, DeployDestination dest, Long newSvcOfferingId) throws ResourceUnavailableException, ConcurrentOperationException; + + boolean getExecuteInSequence(HypervisorType hypervisorType); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java index b5601e9693..5d552c4013 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataMotionStrategy.java @@ -30,10 +30,7 @@ public interface DataMotionStrategy { StrategyPriority canHandle(Map volumeMap, Host srcHost, Host destHost); - Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback); - - Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback); - - Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback); + void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback); + void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreCapabilities.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreCapabilities.java index 09883c66ce..2cde5bdc15 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreCapabilities.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreCapabilities.java @@ -18,7 +18,23 @@ */ package org.apache.cloudstack.engine.subsystem.api.storage; +/** + * enumerates different capabilities storage drivers may have + */ public enum DataStoreCapabilities { VOLUME_SNAPSHOT_QUIESCEVM, - STORAGE_SYSTEM_SNAPSHOT // indicates to the StorageSystemSnapshotStrategy that this driver takes snapshots on its own system + /** + * indicates that this driver takes CloudStack volume snapshots on its own system (as either back-end snapshots or back-end clones) + */ + STORAGE_SYSTEM_SNAPSHOT, + /** + * indicates that this driver supports the "cloneOfSnapshot" property of cloud.snapshot_details (for creating a back-end volume + * from a back-end snapshot or a back-end clone) and that it supports the invocation of the createAsync method where a SnapshotInfo is passed in while using + * the "tempVolume" property of snapshot_details + */ + CAN_CREATE_VOLUME_FROM_SNAPSHOT, + /** + * indicates that this driver supports the "cloneOfSnapshot" property of cloud.snapshot_details (for creating a volume from a volume) + */ + CAN_CREATE_VOLUME_FROM_VOLUME } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java index d643d7fab7..e476d8f3b3 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java @@ -18,6 +18,8 @@ */ package org.apache.cloudstack.engine.subsystem.api.storage; +import java.util.List; + import com.cloud.storage.DataStoreProviderApiService; import com.cloud.utils.component.Manager; @@ -29,4 +31,6 @@ public interface DataStoreProviderManager extends Manager, DataStoreProviderApiS DataStoreProvider getDefaultImageDataStoreProvider(); DataStoreProvider getDefaultCacheDataStoreProvider(); + + List getProviders(); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java index 4d6465b806..0613a11572 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java @@ -35,7 +35,5 @@ public interface EndPointSelector { EndPoint select(Scope scope, Long storeId); - EndPoint selectHypervisorHost(Scope scope); - EndPoint select(DataStore store, String downloadUrl); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java index 82ba8b6105..d7e8522a40 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java @@ -21,7 +21,13 @@ import com.cloud.exception.StorageConflictException; public interface HypervisorHostListener { + boolean hostAdded(long hostId); + boolean hostConnect(long hostId, long poolId) throws StorageConflictException; boolean hostDisconnected(long hostId, long poolId); + + boolean hostAboutToBeRemoved(long hostId); + + boolean hostRemoved(long hostId, long clusterId); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStore.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStore.java index 465b7eb243..a399758217 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStore.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStore.java @@ -23,6 +23,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; public interface PrimaryDataStore extends DataStore, PrimaryDataStoreInfo { + DataObject create(DataObject dataObject, boolean createEntryInTempSpoolRef); + VolumeInfo getVolume(long id); List getVolumes(); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java index 0c6bd93982..6dcdf4f0c7 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java @@ -23,30 +23,41 @@ import com.cloud.host.Host; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; public interface PrimaryDataStoreDriver extends DataStoreDriver { - public ChapInfo getChapInfo(VolumeInfo volumeInfo); + ChapInfo getChapInfo(DataObject dataObject); - public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore); + boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore); - public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore); + void revokeAccess(DataObject dataObject, Host host, DataStore dataStore); - // intended for managed storage (cloud.storage_pool.managed = true) - // if not managed, return volume.getSize() - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool storagePool); + /** + * intended for managed storage (cloud.storage_pool.managed = true) + * if not managed, return volume.getSize() + */ + long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool storagePool); - // intended for managed storage (cloud.storage_pool.managed = true) - // if managed storage, return the total number of bytes currently in use for the storage pool in question - // if not managed storage, return 0 - public long getUsedBytes(StoragePool storagePool); + /** + * intended for zone-wide primary storage that is capable of storing a template once and using it in multiple clusters + * if not this kind of storage, return 0 + */ + long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool); - // intended for managed storage (cloud.storage_pool.managed = true) - // if managed storage, return the total number of IOPS currently in use for the storage pool in question - // if not managed storage, return 0 - public long getUsedIops(StoragePool storagePool); + /** + * intended for managed storage (cloud.storage_pool.managed = true) + * if managed storage, return the total number of bytes currently in use for the storage pool in question + * if not managed storage, return 0 + */ + long getUsedBytes(StoragePool storagePool); - public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); + /** + * intended for managed storage (cloud.storage_pool.managed = true) + * if managed storage, return the total number of IOPS currently in use for the storage pool in question + * if not managed storage, return 0 + */ + long getUsedIops(StoragePool storagePool); - public void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback callback); + void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); + + void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback callback); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java index f08d9a4550..7f2f4dc6b8 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java @@ -36,6 +36,7 @@ public interface PrimaryDataStoreInfo extends StoragePool { static final String CHAP_INITIATOR_SECRET = "chapInitiatorSecret"; static final String CHAP_TARGET_USERNAME = "chapTargetUsername"; static final String CHAP_TARGET_SECRET = "chapTargetSecret"; + static final String REMOVE_AFTER_COPY = "removeAfterCopy"; static final String VOLUME_SIZE = "volumeSize"; boolean isHypervisorSupported(HypervisorType hypervisor); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java index 88ce932b26..ff204c663c 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/TemplateService.java @@ -32,6 +32,7 @@ class TemplateApiResult extends CommandResult { public TemplateApiResult(TemplateInfo template) { super(); + this.template = template; } @@ -52,6 +53,8 @@ public TemplateInfo getTemplate() { AsyncCallFuture prepareTemplateOnPrimary(TemplateInfo srcTemplate, StoragePool pool); + AsyncCallFuture deleteTemplateOnPrimary(TemplateInfo template, StoragePool pool); + void syncTemplateToRegionStore(long templateId, DataStore store); void handleSysTemplateDownload(HypervisorType hostHyper, Long dcId); diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java index 8352682ee6..75a7ad96c4 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java @@ -45,7 +45,7 @@ public VolumeInfo getVolume() { } } - ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore); + ChapInfo getChapInfo(DataObject dataObject, DataStore dataStore); boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore); @@ -81,7 +81,7 @@ public VolumeInfo getVolume() { VolumeEntity getVolumeEntity(long volumeId); - AsyncCallFuture createManagedStorageAndVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, + AsyncCallFuture createManagedStorageVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, TemplateInfo srcTemplateInfo, long destHostId); AsyncCallFuture createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, diff --git a/engine/components-api/pom.xml b/engine/components-api/pom.xml index 6947aefc27..7ea56d66dc 100644 --- a/engine/components-api/pom.xml +++ b/engine/components-api/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/components-api/src/com/cloud/agent/AgentManager.java b/engine/components-api/src/com/cloud/agent/AgentManager.java index e9e32495d8..244772d67d 100644 --- a/engine/components-api/src/com/cloud/agent/AgentManager.java +++ b/engine/components-api/src/com/cloud/agent/AgentManager.java @@ -42,7 +42,7 @@ public enum TapAgentsAction { Add, Del, Contains, } - boolean handleDirectConnectAgent(Host host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance) throws ConnectionException; + boolean handleDirectConnectAgent(Host host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance, boolean newHost) throws ConnectionException; /** * easy send method that returns null if there's any errors. It handles all exceptions. @@ -131,8 +131,6 @@ public enum TapAgentsAction { Answer sendTo(Long dcId, HypervisorType type, Command cmd); -// public AgentAttache handleDirectConnectAgent(HostVO host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance) throws ConnectionException; - public boolean agentStatusTransitTo(HostVO host, Status.Event e, long msId); boolean isAgentAttached(long hostId); @@ -146,4 +144,10 @@ public enum TapAgentsAction { boolean reconnect(long hostId); void rescan(); + + void notifyMonitorsOfNewlyAddedHost(long hostId); + + void notifyMonitorsOfHostAboutToBeRemoved(long hostId); + + void notifyMonitorsOfRemovedHost(long hostId, long clusterId); } diff --git a/engine/components-api/src/com/cloud/agent/Listener.java b/engine/components-api/src/com/cloud/agent/Listener.java index 242f90cfee..843a634b4c 100644 --- a/engine/components-api/src/com/cloud/agent/Listener.java +++ b/engine/components-api/src/com/cloud/agent/Listener.java @@ -63,6 +63,12 @@ public interface Listener { */ AgentControlAnswer processControlCommand(long agentId, AgentControlCommand cmd); + /** + * This method is called by AgentManager when a host is added to a cluster. + * @param long the ID of the newly added host + */ + void processHostAdded(long hostId); + /** * This method is called by AgentManager when an agent made a * connection to this server if the listener has @@ -86,6 +92,18 @@ public interface Listener { */ boolean processDisconnect(long agentId, Status state); + /** + * This method is called by AgentManager when a host is about to be removed from a cluster. + * @param long the ID of the host that's about to be removed + */ + void processHostAboutToBeRemoved(long hostId); + + /** + * This method is called by AgentManager when a host is removed from a cluster. + * @param long the ID of the newly removed host + */ + void processHostRemoved(long hostId, long clusterId); + /** * If this Listener is passed to the send() method, this method * is called by AgentManager after processing an answer diff --git a/engine/components-api/src/com/cloud/capacity/CapacityManager.java b/engine/components-api/src/com/cloud/capacity/CapacityManager.java index 51f73326d5..3db6e57815 100644 --- a/engine/components-api/src/com/cloud/capacity/CapacityManager.java +++ b/engine/components-api/src/com/cloud/capacity/CapacityManager.java @@ -53,6 +53,16 @@ public interface CapacityManager { "0.85", "Percentage (as a value between 0 and 1) of allocated storage utilization above which allocators will disable using the pool for low allocated storage available.", true, ConfigKey.Scope.Zone); + static final ConfigKey StorageOperationsExcludeCluster = + new ConfigKey( + Boolean.class, + "cluster.storage.operations.exclude", + "Advanced", + "false", + "Exclude cluster from storage operations", + true, + ConfigKey.Scope.Cluster, + null); public boolean releaseVmCapacity(VirtualMachine vm, boolean moveFromReserved, boolean moveToReservered, Long hostId); diff --git a/engine/components-api/src/com/cloud/network/NetworkStateListener.java b/engine/components-api/src/com/cloud/network/NetworkStateListener.java index 0ed1d9ea7f..ef8dddc1f2 100644 --- a/engine/components-api/src/com/cloud/network/NetworkStateListener.java +++ b/engine/components-api/src/com/cloud/network/NetworkStateListener.java @@ -24,38 +24,29 @@ import javax.inject.Inject; -import com.cloud.utils.fsm.StateMachine2; -import org.apache.log4j.Logger; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; - import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.events.EventBus; import org.apache.cloudstack.framework.events.EventBusException; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import com.cloud.event.EventCategory; -import com.cloud.event.dao.UsageEventDao; import com.cloud.network.Network.Event; import com.cloud.network.Network.State; -import com.cloud.network.dao.NetworkDao; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.fsm.StateListener; +import com.cloud.utils.fsm.StateMachine2; public class NetworkStateListener implements StateListener { @Inject - protected UsageEventDao _usageEventDao; - @Inject - protected NetworkDao _networkDao; - @Inject - protected ConfigurationDao _configDao; + private ConfigurationDao _configDao; - protected static EventBus s_eventBus = null; + private static EventBus s_eventBus = null; private static final Logger s_logger = Logger.getLogger(NetworkStateListener.class); - public NetworkStateListener(UsageEventDao usageEventDao, NetworkDao networkDao, ConfigurationDao configDao) { - _usageEventDao = usageEventDao; - _networkDao = networkDao; + public NetworkStateListener(ConfigurationDao configDao) { _configDao = configDao; } diff --git a/engine/components-api/src/com/cloud/storage/StorageManager.java b/engine/components-api/src/com/cloud/storage/StorageManager.java index aa6c0ce199..129f6b1d35 100644 --- a/engine/components-api/src/com/cloud/storage/StorageManager.java +++ b/engine/components-api/src/com/cloud/storage/StorageManager.java @@ -110,6 +110,30 @@ public interface StorageManager extends StorageService { boolean storagePoolHasEnoughSpace(List volume, StoragePool pool); + /** + * This comment is relevant to managed storage only. + * + * Long clusterId = only used for managed storage + * + * Some managed storage can be more efficient handling VM templates (via cloning) if it knows the capabilities of the compute cluster it is dealing with. + * If the compute cluster supports UUID resigning and the storage system can clone a volume from a volume, then this determines how much more space a + * new root volume (that makes use of a template) will take up on the storage system. + * + * For example, if a storage system can clone a volume from a volume and the compute cluster supports UUID resigning (relevant for hypervisors like + * XenServer and ESXi that put virtual disks in clustered file systems), then the storage system will need to determine if it already has a copy of + * the template or if it will need to create one first before cloning the template to a new volume to be used for the new root disk (assuming the root + * disk is being deployed from a template). If the template doesn't already exists on the storage system, then you need to take into consideration space + * required for that template (stored in one volume) and space required for a new volume created from that template volume (for your new root volume). + * + * If UUID resigning is not available in the compute cluster or the storage system doesn't support cloning a volume from a volume, then for each new + * root disk that uses a template, CloudStack will have the template be copied down to a newly created volume on the storage system (i.e. no need + * to take into consideration the possible need to first create a volume on the storage system for a template that will be used for the root disk + * via cloning). + * + * Cloning volumes on the back-end instead of copying down a new template for each new volume helps to alleviate load on the hypervisors. + */ + boolean storagePoolHasEnoughSpace(List volume, StoragePool pool, Long clusterId); + boolean registerHostListener(String providerUuid, HypervisorHostListener listener); void connectHostToSharedPool(long hostId, long poolId) throws StorageUnavailableException, StorageConflictException; diff --git a/engine/components-api/src/com/cloud/template/TemplateManager.java b/engine/components-api/src/com/cloud/template/TemplateManager.java index 5987ac0ee5..5b2d64ad5a 100644 --- a/engine/components-api/src/com/cloud/template/TemplateManager.java +++ b/engine/components-api/src/com/cloud/template/TemplateManager.java @@ -38,9 +38,16 @@ */ public interface TemplateManager { static final String AllowPublicUserTemplatesCK = "allow.public.user.templates"; + static final String TemplatePreloaderPoolSizeCK = "template.preloader.pool.size"; + static final ConfigKey AllowPublicUserTemplates = new ConfigKey("Advanced", Boolean.class, AllowPublicUserTemplatesCK, "true", "If false, users will not be able to create public templates.", true, ConfigKey.Scope.Account); + static final ConfigKey TemplatePreloaderPoolSize = new ConfigKey("Advanced", Integer.class, TemplatePreloaderPoolSizeCK, "8", + "Size of the TemplateManager threadpool", false, ConfigKey.Scope.Global); + + + /** * Prepares a template for vm creation for a certain storage pool. * diff --git a/engine/components-api/src/com/cloud/vm/VmWorkResizeVolume.java b/engine/components-api/src/com/cloud/vm/VmWorkResizeVolume.java index d269112961..de049b3f0b 100644 --- a/engine/components-api/src/com/cloud/vm/VmWorkResizeVolume.java +++ b/engine/components-api/src/com/cloud/vm/VmWorkResizeVolume.java @@ -24,12 +24,12 @@ public class VmWorkResizeVolume extends VmWork { private long newSize; private Long newMinIops; private Long newMaxIops; + private Integer newHypervisorSnapshotReserve; private Long newServiceOfferingId; private boolean shrinkOk; - public VmWorkResizeVolume(long userId, long accountId, long vmId, String handlerName, - long volumeId, long currentSize, long newSize, Long newMinIops, Long newMaxIops, Long newServiceOfferingId, boolean shrinkOk) { - + public VmWorkResizeVolume(long userId, long accountId, long vmId, String handlerName, long volumeId, long currentSize, long newSize, + Long newMinIops, Long newMaxIops, Integer newHypervisorSnapshotReserve, Long newServiceOfferingId, boolean shrinkOk) { super(userId, accountId, vmId, handlerName); this.volumeId = volumeId; @@ -37,6 +37,7 @@ public VmWorkResizeVolume(long userId, long accountId, long vmId, String handler this.newSize = newSize; this.newMinIops = newMinIops; this.newMaxIops = newMaxIops; + this.newHypervisorSnapshotReserve = newHypervisorSnapshotReserve; this.newServiceOfferingId = newServiceOfferingId; this.shrinkOk = shrinkOk; } @@ -68,4 +69,6 @@ public Long getNewServiceOfferingId() { public boolean isShrinkOk() { return shrinkOk; } + + public Integer getNewHypervisorSnapshotReserve() { return newHypervisorSnapshotReserve; } } diff --git a/engine/network/pom.xml b/engine/network/pom.xml index fca11c6350..a41ed26275 100644 --- a/engine/network/pom.xml +++ b/engine/network/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/orchestration/pom.xml b/engine/orchestration/pom.xml index 099fdc4f35..ee3bb34200 100755 --- a/engine/orchestration/pom.xml +++ b/engine/orchestration/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java b/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java index 0acac3c047..d5ec900983 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java +++ b/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java @@ -44,6 +44,7 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.MaintainCommand; import com.cloud.agent.api.MigrateCommand; +import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.agent.api.PingTestCommand; import com.cloud.agent.api.PvlanSetupCommand; import com.cloud.agent.api.ReadyCommand; @@ -109,11 +110,12 @@ public int compare(final Object o1, final Object o2) { protected AgentManagerImpl _agentMgr; - public final static String[] s_commandsAllowedInMaintenanceMode = new String[] {MaintainCommand.class.toString(), MigrateCommand.class.toString(), + public final static String[] s_commandsAllowedInMaintenanceMode = new String[] { MaintainCommand.class.toString(), MigrateCommand.class.toString(), StopCommand.class.toString(), CheckVirtualMachineCommand.class.toString(), PingTestCommand.class.toString(), CheckHealthCommand.class.toString(), ReadyCommand.class.toString(), ShutdownCommand.class.toString(), SetupCommand.class.toString(), - CleanupNetworkRulesCmd.class.toString(), CheckNetworkCommand.class.toString(), PvlanSetupCommand.class.toString(), CheckOnHostCommand.class.toString()}; - protected final static String[] s_commandsNotAllowedInConnectingMode = new String[] {StartCommand.class.toString(), CreateCommand.class.toString()}; + CleanupNetworkRulesCmd.class.toString(), CheckNetworkCommand.class.toString(), PvlanSetupCommand.class.toString(), CheckOnHostCommand.class.toString(), + ModifyTargetsCommand.class.toString() }; + protected final static String[] s_commandsNotAllowedInConnectingMode = new String[] { StartCommand.class.toString(), CreateCommand.class.toString() }; static { Arrays.sort(s_commandsAllowedInMaintenanceMode); Arrays.sort(s_commandsNotAllowedInConnectingMode); diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java index 45a7dca465..aa7068af53 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -43,6 +43,7 @@ import org.apache.cloudstack.framework.jobs.AsyncJob; import org.apache.cloudstack.framework.jobs.AsyncJobExecutionContext; import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao; import org.apache.cloudstack.utils.identity.ManagementServerNode; import org.apache.log4j.Logger; import org.slf4j.MDC; @@ -139,6 +140,8 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl @Inject protected HostDao _hostDao = null; @Inject + protected OutOfBandManagementDao outOfBandManagementDao; + @Inject protected DataCenterDao _dcDao = null; @Inject protected HostPodDao _podDao = null; @@ -538,6 +541,17 @@ public void removeAgent(final AgentAttache attache, final Status nextState) { } } + @Override + public void notifyMonitorsOfNewlyAddedHost(long hostId) { + for (final Pair monitor : _hostMonitors) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Sending host added to listener: " + monitor.second().getClass().getSimpleName()); + } + + monitor.second().processHostAdded(hostId); + } + } + protected AgentAttache notifyMonitorsOfConnection(final AgentAttache attache, final StartupCommand[] cmd, final boolean forRebalance) throws ConnectionException { final long hostId = attache.getId(); final HostVO host = _hostDao.findById(hostId); @@ -1001,6 +1015,28 @@ public boolean reconnect(final long hostId) { return true; } + @Override + public void notifyMonitorsOfHostAboutToBeRemoved(long hostId) { + for (final Pair monitor : _hostMonitors) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Sending host about to be removed to listener: " + monitor.second().getClass().getSimpleName()); + } + + monitor.second().processHostAboutToBeRemoved(hostId); + } + } + + @Override + public void notifyMonitorsOfRemovedHost(long hostId, long clusterId) { + for (final Pair monitor : _hostMonitors) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Sending host removed to listener: " + monitor.second().getClass().getSimpleName()); + } + + monitor.second().processHostRemoved(hostId, clusterId); + } + } + public boolean executeUserRequest(final long hostId, final Event event) throws AgentUnavailableException { if (event == Event.AgentDisconnected) { if (s_logger.isDebugEnabled()) { @@ -1464,7 +1500,8 @@ public void disconnectWithoutInvestigation(final long hostId, final Status.Event } @Override - public boolean handleDirectConnectAgent(final Host host, final StartupCommand[] cmds, final ServerResource resource, final boolean forRebalance) throws ConnectionException { + public boolean handleDirectConnectAgent(final Host host, final StartupCommand[] cmds, final ServerResource resource, + final boolean forRebalance, boolean newHost) throws ConnectionException { AgentAttache attache; attache = createAttacheForDirectConnect(host, resource); @@ -1473,6 +1510,11 @@ public boolean handleDirectConnectAgent(final Host host, final StartupCommand[] answers[i] = new StartupAnswer(cmds[i], attache.getId(), PingInterval.value()); } attache.process(answers); + + if (newHost) { + notifyMonitorsOfNewlyAddedHost(host.getId()); + } + attache = notifyMonitorsOfConnection(attache, cmds, forRebalance); return attache != null; @@ -1617,6 +1659,10 @@ public AgentControlAnswer processControlCommand(final long agentId, final AgentC return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(final Host host, final StartupCommand cmd, final boolean forRebalance) { if (host.getType().equals(Host.Type.TrafficMonitor) || host.getType().equals(Host.Type.SecondaryStorage)) { @@ -1633,6 +1679,14 @@ public boolean processDisconnect(final long agentId, final Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(final long agentId, final long seq) { return true; diff --git a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java index f35a4efe36..9239adc091 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java @@ -499,7 +499,7 @@ public SocketChannel connectToPeer(final String peerName, final SocketChannel pr SocketChannel ch1 = null; try { ch1 = SocketChannel.open(new InetSocketAddress(addr, Port.value())); - ch1.configureBlocking(true); // make sure we are working at blocking mode + ch1.configureBlocking(false); ch1.socket().setKeepAlive(true); ch1.socket().setSoTimeout(60 * 1000); try { @@ -507,8 +507,11 @@ public SocketChannel connectToPeer(final String peerName, final SocketChannel pr sslEngine = sslContext.createSSLEngine(ip, Port.value()); sslEngine.setUseClientMode(true); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - - Link.doHandshake(ch1, sslEngine, true); + sslEngine.beginHandshake(); + if (!Link.doHandshake(ch1, sslEngine, true)) { + ch1.close(); + throw new IOException("SSL handshake failed!"); + } s_logger.info("SSL: Handshake done"); } catch (final Exception e) { ch1.close(); @@ -733,6 +736,7 @@ public void onManagementNodeLeft(final List node s_logger.info("Marking hosts as disconnected on Management server" + vo.getMsid()); final long lastPing = (System.currentTimeMillis() >> 10) - getTimeout(); _hostDao.markHostsAsDisconnected(vo.getMsid(), lastPing); + outOfBandManagementDao.expireOutOfBandManagementOwnershipByServer(vo.getMsid()); s_logger.info("Deleting entries from op_host_transfer table for Management server " + vo.getMsid()); cleanupTransferMap(vo.getMsid()); } diff --git a/engine/orchestration/src/com/cloud/agent/manager/SynchronousListener.java b/engine/orchestration/src/com/cloud/agent/manager/SynchronousListener.java index 28c60c1a07..96d40777f8 100644 --- a/engine/orchestration/src/com/cloud/agent/manager/SynchronousListener.java +++ b/engine/orchestration/src/com/cloud/agent/manager/SynchronousListener.java @@ -78,6 +78,18 @@ public synchronized boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) { } diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index 2136f8eeb5..9523b928ed 100644 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -1241,11 +1241,11 @@ public void stop(final String vmUuid) throws ResourceUnavailableException { } } - - protected boolean getExecuteInSequence(final HypervisorType hypervisorType) { - if (HypervisorType.KVM == hypervisorType || HypervisorType.LXC == hypervisorType || HypervisorType.XenServer == hypervisorType) { + @Override + public boolean getExecuteInSequence(final HypervisorType hypervisorType) { + if (HypervisorType.KVM == hypervisorType || HypervisorType.XenServer == hypervisorType || HypervisorType.Hyperv == hypervisorType || HypervisorType.LXC == hypervisorType) { return false; - } else if(HypervisorType.VMware == hypervisorType) { + } else if (HypervisorType.VMware == hypervisorType) { final Boolean fullClone = HypervisorGuru.VmwareFullClone.value(); return fullClone; } else { @@ -2585,7 +2585,7 @@ private void orchestrateReboot(final String vmUuid, final Map vmMetadatum) { if(!found) { VMInstanceVO vm = _vmDao.findVMByInstanceName(name); - if(vm.getType() == VirtualMachine.Type.User) { + if(vm != null && vm.getType() == VirtualMachine.Type.User) { updateVmMetaData(vm.getId(), platform); } } @@ -2786,6 +2786,18 @@ public boolean processDisconnect(final long agentId, final Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(final Host agent, final StartupCommand cmd, final boolean forRebalance) throws ConnectionException { if (!(cmd instanceof StartupRoutingCommand)) { @@ -3686,7 +3698,7 @@ public void setStoragePoolAllocators(final List storagePoo // @MessageHandler(topic = Topics.VM_POWER_STATE) - private void HandlePowerStateReport(final String subject, final String senderAddress, final Object args) { + protected void HandlePowerStateReport(final String subject, final String senderAddress, final Object args) { assert args != null; final Long vmId = (Long)args; diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 2cf1635efb..66185c6097 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -578,7 +578,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { _agentMgr.registerForHostEvents(this, true, false, true); - Network.State.getStateMachine().registerListener(new NetworkStateListener(_usageEventDao, _networksDao, _configDao)); + Network.State.getStateMachine().registerListener(new NetworkStateListener(_configDao)); s_logger.info("Network Manager is configured."); @@ -3001,6 +3001,9 @@ public AgentControlAnswer processControlCommand(final long agentId, final AgentC return null; } + public void processHostAdded(long hostId) { + } + @Override public void processConnect(final Host host, final StartupCommand cmd, final boolean forRebalance) throws ConnectionException { if (!(cmd instanceof StartupRoutingCommand)) { @@ -3088,6 +3091,14 @@ public boolean processDisconnect(final long agentId, final Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index 8de6bd24e7..ca4ef4fd2d 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -1251,10 +1251,11 @@ private Pair recreateVolume(VolumeVO vol, VirtualMachinePro future = volService.createVolumeAsync(volume, destPool); } else { - TemplateInfo templ = tmplFactory.getReadyTemplateOnImageStore(templateId, dest.getDataCenter().getId()); + if (templ == null) { s_logger.debug("can't find ready template: " + templateId + " for data center " + dest.getDataCenter().getId()); + throw new CloudRuntimeException("can't find ready template: " + templateId + " for data center " + dest.getDataCenter().getId()); } @@ -1269,13 +1270,13 @@ private Pair recreateVolume(VolumeVO vol, VirtualMachinePro long hostId = vm.getVirtualMachine().getHostId(); - future = volService.createManagedStorageAndVolumeFromTemplateAsync(volume, destPool.getId(), templ, hostId); + future = volService.createManagedStorageVolumeFromTemplateAsync(volume, destPool.getId(), templ, hostId); } else { future = volService.createVolumeFromTemplateAsync(volume, destPool.getId(), templ); } } - VolumeApiResult result = null; + VolumeApiResult result; try { result = future.get(); if (result.isFailed()) { @@ -1299,10 +1300,7 @@ private Pair recreateVolume(VolumeVO vol, VirtualMachinePro newVol = _volsDao.findById(newVol.getId()); break; //break out of template-redeploy retry loop - } catch (InterruptedException e) { - s_logger.error("Unable to create " + newVol, e); - throw new StorageUnavailableException("Unable to create " + newVol + ":" + e.toString(), destPool.getId()); - } catch (ExecutionException e) { + } catch (InterruptedException | ExecutionException e) { s_logger.error("Unable to create " + newVol, e); throw new StorageUnavailableException("Unable to create " + newVol + ":" + e.toString(), destPool.getId()); } diff --git a/engine/orchestration/test/com/cloud/vm/VirtualMachineManagerImplTest.java b/engine/orchestration/test/com/cloud/vm/VirtualMachineManagerImplTest.java index d849eabaaf..9bc22c4927 100644 --- a/engine/orchestration/test/com/cloud/vm/VirtualMachineManagerImplTest.java +++ b/engine/orchestration/test/com/cloud/vm/VirtualMachineManagerImplTest.java @@ -17,6 +17,7 @@ package com.cloud.vm; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.isA; @@ -514,6 +515,14 @@ public void testSendStopWithNullAnswer() throws Exception { Assert.assertFalse(actual); } + @Test + public void testExeceuteInSequence() { + assertTrue(_vmMgr.getExecuteInSequence(HypervisorType.XenServer) == false); + assertTrue(_vmMgr.getExecuteInSequence(HypervisorType.KVM) == false); + assertTrue(_vmMgr.getExecuteInSequence(HypervisorType.VMware) == HypervisorGuru.VmwareFullClone.value()); + assertTrue(_vmMgr.getExecuteInSequence(HypervisorType.Ovm3) == VirtualMachineManager.ExecuteInSequence.value()); + } + @Test public void testCheckIfCanUpgrade() throws Exception { when(_vmInstance.getState()).thenReturn(State.Stopped); diff --git a/engine/pom.xml b/engine/pom.xml index 6895f25f66..c3c0b28e76 100644 --- a/engine/pom.xml +++ b/engine/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/schema/pom.xml b/engine/schema/pom.xml index f7b1fb4075..4d0b90d6de 100644 --- a/engine/schema/pom.xml +++ b/engine/schema/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index 67ed2a7d25..691647829e 100644 --- a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -113,6 +113,8 @@ + + @@ -345,6 +347,6 @@ - + diff --git a/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java index 50d6052bc4..fcccd56dd6 100644 --- a/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java +++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java @@ -50,8 +50,7 @@ List findCapacityBy(Integer capacityType, Long zoneId, List listCapacitiesGroupedByLevelAndType(Integer capacityType, Long zoneId, Long podId, Long clusterId, int level, Long limit); - void updateCapacityState(Long dcId, Long podId, Long clusterId, - Long hostId, String capacityState); + void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState, short[] capacityType); List listClustersCrossingThreshold(short capacityType, Long zoneId, String configName, long computeRequested); diff --git a/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java index bc992b0bb5..1b1b856af7 100644 --- a/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/engine/schema/src/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -962,35 +962,59 @@ public Pair, Map> orderPodsByAggregateCapacity(long zon } @Override - public void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState) { + public void updateCapacityState(Long dcId, Long podId, Long clusterId, Long hostId, String capacityState, short[] capacityType) { TransactionLegacy txn = TransactionLegacy.currentTxn(); StringBuilder sql = new StringBuilder(UPDATE_CAPACITY_STATE); List resourceIdList = new ArrayList(); + StringBuilder where = new StringBuilder(); if (dcId != null) { - sql.append(" data_center_id = ?"); + where.append(" data_center_id = ? "); resourceIdList.add(dcId); } if (podId != null) { - sql.append(" pod_id = ?"); + where.append((where.length() > 0) ? " and pod_id = ? " : " pod_id = ? "); resourceIdList.add(podId); } if (clusterId != null) { - sql.append(" cluster_id = ?"); + where.append((where.length() > 0) ? " and cluster_id = ? " : " cluster_id = ? "); resourceIdList.add(clusterId); } if (hostId != null) { - sql.append(" host_id = ?"); + where.append((where.length() > 0) ? " and host_id = ? " : " host_id = ? "); resourceIdList.add(hostId); } + if (capacityType != null && capacityType.length > 0) { + where.append((where.length() > 0) ? " and capacity_type in " : " capacity_type in "); + + StringBuilder builder = new StringBuilder(); + for( int i = 0 ; i < capacityType.length; i++ ) { + if(i==0){ + builder.append(" (? "); + }else{ + builder.append(" ,? "); + } + } + builder.append(" ) "); + + where.append(builder); + } + sql.append(where); + PreparedStatement pstmt = null; try { pstmt = txn.prepareAutoCloseStatement(sql.toString()); - pstmt.setString(1, capacityState); - for (int i = 0; i < resourceIdList.size(); i++) { - pstmt.setLong(2 + i, resourceIdList.get(i)); + int i = 1; + pstmt.setString(i, capacityState); + i = i + 1; + for (int j=0 ; j < resourceIdList.size(); j++, i++) { + pstmt.setLong(i, resourceIdList.get(j)); } + for(int j=0; j < capacityType.length; i++, j++ ) { + pstmt.setShort(i, capacityType[j]); + } + pstmt.executeUpdate(); } catch (Exception e) { s_logger.warn("Error updating CapacityVO", e); diff --git a/engine/schema/src/com/cloud/dc/dao/ClusterDao.java b/engine/schema/src/com/cloud/dc/dao/ClusterDao.java index 50c234c915..06bc5a3afc 100644 --- a/engine/schema/src/com/cloud/dc/dao/ClusterDao.java +++ b/engine/schema/src/com/cloud/dc/dao/ClusterDao.java @@ -45,4 +45,6 @@ public interface ClusterDao extends GenericDao { List listClustersByDcId(long zoneId); List listAllCusters(long zoneId); + + boolean getSupportsResigning(long clusterId); } diff --git a/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java index 3459e514b7..0c5bd6f4a7 100644 --- a/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java +++ b/engine/schema/src/com/cloud/dc/dao/ClusterDaoImpl.java @@ -28,6 +28,8 @@ import org.springframework.stereotype.Component; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterVO; import com.cloud.dc.HostPodVO; import com.cloud.hypervisor.Hypervisor.HypervisorType; @@ -57,7 +59,9 @@ public class ClusterDaoImpl extends GenericDaoBase implements C private static final String GET_POD_CLUSTER_MAP_PREFIX = "SELECT pod_id, id FROM cloud.cluster WHERE cluster.id IN( "; private static final String GET_POD_CLUSTER_MAP_SUFFIX = " )"; @Inject - protected HostPodDao _hostPodDao; + private ClusterDetailsDao clusterDetailsDao; + @Inject + protected HostPodDao hostPodDao; public ClusterDaoImpl() { super(); @@ -214,7 +218,7 @@ public List listDisabledClusters(long zoneId, Long podId) { @Override public List listClustersWithDisabledPods(long zoneId) { - GenericSearchBuilder disabledPodIdSearch = _hostPodDao.createSearchBuilder(Long.class); + GenericSearchBuilder disabledPodIdSearch = hostPodDao.createSearchBuilder(Long.class); disabledPodIdSearch.selectFields(disabledPodIdSearch.entity().getId()); disabledPodIdSearch.and("dataCenterId", disabledPodIdSearch.entity().getDataCenterId(), Op.EQ); disabledPodIdSearch.and("allocationState", disabledPodIdSearch.entity().getAllocationState(), Op.EQ); @@ -260,4 +264,23 @@ public List listAllCusters(long zoneId) { sc.setParameters("dataCenterId", zoneId); return customSearch(sc, null); } + + @Override + public boolean getSupportsResigning(long clusterId) { + ClusterVO cluster = findById(clusterId); + + if (cluster == null || cluster.getAllocationState() != Grouping.AllocationState.Enabled) { + return false; + } + + ClusterDetailsVO clusterDetailsVO = clusterDetailsDao.findDetail(clusterId, "supportsResign"); + + if (clusterDetailsVO != null) { + String value = clusterDetailsVO.getValue(); + + return Boolean.parseBoolean(value); + } + + return false; + } } diff --git a/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDao.java b/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDao.java index ed7c494744..1422e3f4d3 100644 --- a/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDao.java +++ b/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDao.java @@ -16,10 +16,10 @@ // under the License. package com.cloud.dc.dao; -import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; - import com.cloud.dc.DataCenterDetailVO; import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; public interface DataCenterDetailsDao extends GenericDao, ResourceDetailsDao { + void persist(long zoneId, String name, String value); } \ No newline at end of file diff --git a/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java b/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java index 8bc9effc7f..e36c8ebd6c 100644 --- a/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java +++ b/engine/schema/src/com/cloud/dc/dao/DataCenterDetailsDaoImpl.java @@ -16,7 +16,6 @@ // under the License. package com.cloud.dc.dao; - import org.apache.cloudstack.api.ResourceDetail; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.ConfigKey.Scope; @@ -24,9 +23,21 @@ import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase; import com.cloud.dc.DataCenterDetailVO; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.TransactionLegacy; public class DataCenterDetailsDaoImpl extends ResourceDetailsDaoBase implements DataCenterDetailsDao, ScopedConfigStorage { + private final SearchBuilder DetailSearch; + + DataCenterDetailsDaoImpl() { + DetailSearch = createSearchBuilder(); + DetailSearch.and("zoneId", DetailSearch.entity().getResourceId(), SearchCriteria.Op.EQ); + DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ); + DetailSearch.done(); + } + @Override public Scope getScope() { return ConfigKey.Scope.Zone; @@ -43,4 +54,17 @@ public void addDetail(long resourceId, String key, String value, boolean display super.addDetail(new DataCenterDetailVO(resourceId, key, value, display)); } + @Override + public void persist(long zoneId, String name, String value) { + TransactionLegacy txn = TransactionLegacy.currentTxn(); + txn.start(); + SearchCriteria sc = DetailSearch.create(); + sc.setParameters("zoneId", zoneId); + sc.setParameters("name", name); + expunge(sc); + + DataCenterDetailVO vo = new DataCenterDetailVO(zoneId, name, value, true); + persist(vo); + txn.commit(); + } } diff --git a/engine/schema/src/com/cloud/host/dao/HostDao.java b/engine/schema/src/com/cloud/host/dao/HostDao.java index bd484825c8..88a354725a 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDao.java +++ b/engine/schema/src/com/cloud/host/dao/HostDao.java @@ -23,6 +23,7 @@ import com.cloud.host.Host.Type; import com.cloud.host.HostVO; import com.cloud.host.Status; +import com.cloud.hypervisor.Hypervisor; import com.cloud.info.RunningHostCountInfo; import com.cloud.resource.ResourceState; import com.cloud.utils.db.GenericDao; @@ -81,13 +82,21 @@ public interface HostDao extends GenericDao, StateDao listAllUpAndEnabledNonHAHosts(Type type, Long clusterId, Long podId, long dcId, String haTag); + List findByDataCenterId(Long zoneId); + List findByPodId(Long podId); List findByClusterId(Long clusterId); List listByDataCenterId(long id); + List listByDataCenterIdAndHypervisorType(long zoneId, Hypervisor.HypervisorType hypervisorType); + List listAllHosts(long zoneId); + List listAllHostsByType(Host.Type type); + HostVO findByPublicIp(String publicIp); + + List listByType(Type type); } diff --git a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java index 8342f1fcf7..46f8a4da2b 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java +++ b/engine/schema/src/com/cloud/host/dao/HostDaoImpl.java @@ -47,7 +47,9 @@ import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.Status.Event; +import com.cloud.hypervisor.Hypervisor; import com.cloud.info.RunningHostCountInfo; +import com.cloud.org.Grouping; import com.cloud.org.Managed; import com.cloud.resource.ResourceState; import com.cloud.utils.DateUtil; @@ -421,6 +423,37 @@ public List listByDataCenterId(long id) { return listBy(sc); } + @Override + public List listByDataCenterIdAndHypervisorType(long zoneId, Hypervisor.HypervisorType hypervisorType) { + SearchBuilder clusterSearch = _clusterDao.createSearchBuilder(); + + clusterSearch.and("allocationState", clusterSearch.entity().getAllocationState(), SearchCriteria.Op.EQ); + clusterSearch.and("hypervisorType", clusterSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ); + + SearchBuilder hostSearch = createSearchBuilder(); + + hostSearch.and("dc", hostSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); + hostSearch.and("type", hostSearch.entity().getType(), Op.EQ); + hostSearch.and("status", hostSearch.entity().getStatus(), Op.EQ); + hostSearch.and("resourceState", hostSearch.entity().getResourceState(), Op.EQ); + + hostSearch.join("clusterSearch", clusterSearch, hostSearch.entity().getClusterId(), clusterSearch.entity().getId(), JoinBuilder.JoinType.INNER); + + hostSearch.done(); + + SearchCriteria sc = hostSearch.create(); + + sc.setParameters("dc", zoneId); + sc.setParameters("type", Host.Type.Routing); + sc.setParameters("status", Status.Up); + sc.setParameters("resourceState", ResourceState.Enabled); + + sc.setJoinParameters("clusterSearch", "allocationState", Grouping.AllocationState.Enabled); + sc.setJoinParameters("clusterSearch", "hypervisorType", hypervisorType.toString()); + + return listBy(sc); + } + @Override public HostVO findByGuid(String guid) { SearchCriteria sc = GuidSearch.create("guid", guid); @@ -1048,6 +1081,14 @@ public HostVO findByTypeNameAndZoneId(long zoneId, String name, Host.Type type) return findOneBy(sc); } + @Override + public List findByDataCenterId(Long zoneId) { + SearchCriteria sc = DcSearch.create(); + sc.setParameters("dc", zoneId); + sc.setParameters("type", Type.Routing); + return listBy(sc); + } + @Override public List findByPodId(Long podId) { SearchCriteria sc = PodSearch.create(); @@ -1087,4 +1128,20 @@ public List listAllHosts(long zoneId) { sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId); return customSearch(sc, null); } + + @Override + public List listAllHostsByType(Host.Type type) { + SearchCriteria sc = TypeSearch.create(); + sc.setParameters("type", type); + sc.setParameters("resourceState", ResourceState.Enabled); + + return listBy(sc); + } + + @Override + public List listByType(Host.Type type) { + SearchCriteria sc = TypeSearch.create(); + sc.setParameters("type", type); + return listBy(sc); + } } diff --git a/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java b/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java index 6a8ff56364..b864a59210 100644 --- a/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java +++ b/engine/schema/src/com/cloud/host/dao/HostDetailsDaoImpl.java @@ -65,10 +65,13 @@ public DetailVO findDetail(long hostId, String name) { @Override public Map findDetails(long hostId) { SearchCriteria sc = HostSearch.create(); + sc.setParameters("hostId", hostId); List results = search(sc, null); + Map details = new HashMap(results.size()); + for (DetailVO result : results) { if ("password".equals(result.getName())) { details.put(result.getName(), DBEncryptionUtil.decrypt(result.getValue())); @@ -76,6 +79,7 @@ public Map findDetails(long hostId) { details.put(result.getName(), result.getValue()); } } + return details; } diff --git a/engine/schema/src/com/cloud/storage/UploadVO.java b/engine/schema/src/com/cloud/storage/UploadVO.java index c49b28b679..dda5c38b59 100644 --- a/engine/schema/src/com/cloud/storage/UploadVO.java +++ b/engine/schema/src/com/cloud/storage/UploadVO.java @@ -77,7 +77,7 @@ public class UploadVO implements Upload { @Column(name = "job_id") private String jobId; - @Column(name = "url") + @Column(name = "url", length = 2048) private String uploadUrl; @Column(name = "install_path") diff --git a/engine/schema/src/com/cloud/storage/VMTemplateHostVO.java b/engine/schema/src/com/cloud/storage/VMTemplateHostVO.java index 4ba5088583..fc4d9c1599 100644 --- a/engine/schema/src/com/cloud/storage/VMTemplateHostVO.java +++ b/engine/schema/src/com/cloud/storage/VMTemplateHostVO.java @@ -84,7 +84,7 @@ public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc, DataObj @Column(name = "install_path") private String installPath; - @Column(name = "url") + @Column(name = "url", length = 2048) private String downloadUrl; @Column(name = "is_copy") diff --git a/engine/schema/src/com/cloud/storage/VMTemplateVO.java b/engine/schema/src/com/cloud/storage/VMTemplateVO.java index dd2b35aef9..d28c23b1a5 100644 --- a/engine/schema/src/com/cloud/storage/VMTemplateVO.java +++ b/engine/schema/src/com/cloud/storage/VMTemplateVO.java @@ -63,7 +63,7 @@ public class VMTemplateVO implements VirtualMachineTemplate { @Column(name = "type") private Storage.TemplateType templateType; - @Column(name = "url") + @Column(name = "url", length = 2048) private String url = null; @Column(name = "hvm") diff --git a/engine/schema/src/com/cloud/storage/VolumeHostVO.java b/engine/schema/src/com/cloud/storage/VolumeHostVO.java index 56a9a9285c..d086f2dd0a 100644 --- a/engine/schema/src/com/cloud/storage/VolumeHostVO.java +++ b/engine/schema/src/com/cloud/storage/VolumeHostVO.java @@ -93,7 +93,7 @@ public class VolumeHostVO implements InternalIdentity, DataObjectInStore { @Column(name = "install_path") private String installPath; - @Column(name = "url") + @Column(name = "url", length = 2048) private String downloadUrl; @Column(name = "format") diff --git a/engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java b/engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java index 770e673e88..93aad15337 100644 --- a/engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java +++ b/engine/schema/src/com/cloud/storage/dao/VMTemplatePoolDaoImpl.java @@ -118,9 +118,9 @@ public List listByTemplateId(long templateId) { } @Override - public VMTemplateStoragePoolVO findByPoolTemplate(long hostId, long templateId) { + public VMTemplateStoragePoolVO findByPoolTemplate(long poolId, long templateId) { SearchCriteria sc = PoolTemplateSearch.create(); - sc.setParameters("pool_id", hostId); + sc.setParameters("pool_id", poolId); sc.setParameters("template_id", templateId); return findOneIncludingRemovedBy(sc); } diff --git a/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java b/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java index d2b0066bc6..fc44c4f5e3 100644 --- a/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java +++ b/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java @@ -63,6 +63,7 @@ import com.cloud.upgrade.dao.Upgrade470to471; import com.cloud.upgrade.dao.Upgrade471to480; import com.cloud.upgrade.dao.Upgrade480to481; +import com.cloud.upgrade.dao.Upgrade481to490; import com.cloud.upgrade.dao.UpgradeSnapshot217to224; import com.cloud.upgrade.dao.UpgradeSnapshot223to224; import com.cloud.upgrade.dao.VersionDao; @@ -110,7 +111,7 @@ public DatabaseUpgradeChecker() { new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), - new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.1.8", new DbUpgrade[] {new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), @@ -118,7 +119,7 @@ public DatabaseUpgradeChecker() { new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.1.9", new DbUpgrade[] {new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), @@ -126,165 +127,167 @@ public DatabaseUpgradeChecker() { new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), - new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.1", new DbUpgrade[] {new Upgrade221to222(), new UpgradeSnapshot223to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), - new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.2", new DbUpgrade[] {new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.3", new DbUpgrade[] {new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.4", new DbUpgrade[] {new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.5", new DbUpgrade[] {new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), - new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.6", new DbUpgrade[] {new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.7", new DbUpgrade[] {new Upgrade227to228(), new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), - new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.8", new DbUpgrade[] {new Upgrade228to229(), new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30() , new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.9", new DbUpgrade[] {new Upgrade229to2210(), new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.10", new DbUpgrade[] {new Upgrade2210to2211(), new Upgrade2211to2212(), new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), - new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.12", new DbUpgrade[] {new Upgrade2212to2213(), new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), - new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.13", new DbUpgrade[] {new Upgrade2213to2214(), new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.14", new DbUpgrade[] {new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), - new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.0", new DbUpgrade[] {new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), - new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.1", new DbUpgrade[] {new Upgrade301to302(), new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.2", new DbUpgrade[] {new Upgrade302to40(), new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), - new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.0.0", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.0.0", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.0.1", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.0.1", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.0.2", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.0.2", new DbUpgrade[] {new Upgrade40to41(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.1.0", new DbUpgrade[] {new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.1.0", new DbUpgrade[] {new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.1.1", new DbUpgrade[] {new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.1.1", new DbUpgrade[] {new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.2.0", new DbUpgrade[] {new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.2.0", new DbUpgrade[] {new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.2.1", new DbUpgrade[] {new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.2.1", new DbUpgrade[] {new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.3.0", new DbUpgrade[] {new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.3.0", new DbUpgrade[] {new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.3.1", new DbUpgrade[] {new Upgrade431to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.3.1", new DbUpgrade[] {new Upgrade431to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.3.2", new DbUpgrade[] {new Upgrade432to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.3.2", new DbUpgrade[] {new Upgrade432to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.4.0", new DbUpgrade[] {new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.4.0", new DbUpgrade[] {new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.4.1", new DbUpgrade[] {new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481() }); + _upgradeMap.put("4.4.1", new DbUpgrade[] {new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490() }); - _upgradeMap.put("4.4.2", new DbUpgrade[] {new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.4.2", new DbUpgrade[] {new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.4.3", new DbUpgrade[] {new Upgrade443to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.4.3", new DbUpgrade[] {new Upgrade443to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.4.4", new DbUpgrade[] {new Upgrade444to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.4.4", new DbUpgrade[] {new Upgrade444to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.5.0", new DbUpgrade[] {new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.5.0", new DbUpgrade[] {new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.5.1", new DbUpgrade[] {new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.5.1", new DbUpgrade[] {new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.5.2", new DbUpgrade[] {new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.5.2", new DbUpgrade[] {new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.5.3", new DbUpgrade[] {new Upgrade453to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.5.3", new DbUpgrade[] {new Upgrade453to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.6.0", new DbUpgrade[] {new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.6.0", new DbUpgrade[] {new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.6.1", new DbUpgrade[] {new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.6.1", new DbUpgrade[] {new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.6.2", new DbUpgrade[] {new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.6.2", new DbUpgrade[] {new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.7.0", new DbUpgrade[] {new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("4.7.0", new DbUpgrade[] {new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.7.1", new DbUpgrade[] {new Upgrade471to480(),new Upgrade480to481()}); + _upgradeMap.put("4.7.1", new DbUpgrade[] {new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.7.2", new DbUpgrade[] {new Upgrade471to480(),new Upgrade480to481()}); + _upgradeMap.put("4.7.2", new DbUpgrade[] {new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("4.8.0", new DbUpgrade[] {new Upgrade480to481()}); + _upgradeMap.put("4.8.0", new DbUpgrade[] {new Upgrade480to481(), new Upgrade481to490()}); + + _upgradeMap.put("4.8.1", new DbUpgrade[] {new Upgrade481to490()}); //CP Upgrades _upgradeMap.put("3.0.3", new DbUpgrade[] {new Upgrade303to304(), new Upgrade304to305(), new Upgrade305to306(), new Upgrade306to307(), new Upgrade307to410(), - new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.4", new DbUpgrade[] {new Upgrade304to305(), new Upgrade305to306(), new Upgrade306to307(), new Upgrade307to410(), new Upgrade410to420(), - new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.5", new DbUpgrade[] {new Upgrade305to306(), new Upgrade306to307(), new Upgrade307to410(), new Upgrade410to420(), new Upgrade420to421(), - new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("3.0.6", new DbUpgrade[] {new Upgrade306to307(), new Upgrade307to410(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), - new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); - _upgradeMap.put("3.0.7", new DbUpgrade[] {new Upgrade307to410(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + _upgradeMap.put("3.0.7", new DbUpgrade[] {new Upgrade307to410(), new Upgrade410to420(), new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.15", new DbUpgrade[] {new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to303(), new Upgrade303to304(), new Upgrade304to305(), new Upgrade305to306(), new Upgrade306to307(), new Upgrade307to410(), new Upgrade410to420(), - new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); _upgradeMap.put("2.2.16", new DbUpgrade[] {new Upgrade2214to30(), new Upgrade30to301(), new Upgrade301to302(), new Upgrade302to303(), new Upgrade303to304(), new Upgrade304to305(), new Upgrade305to306(), new Upgrade306to307(), new Upgrade307to410(), new Upgrade410to420(), - new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()}); + new Upgrade420to421(), new Upgrade421to430(), new Upgrade430to440(), new Upgrade440to441(), new Upgrade441to442(), new Upgrade442to450(), new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490()}); } protected void runScript(Connection conn, File file) { diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java index b816fdc9fc..7d67d2eb6a 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -1297,7 +1297,7 @@ private void addHostDetailsIndex(Connection conn) { s_logger.debug("Index already exists on host_details - not adding new one"); } else { // add the index - try(PreparedStatement pstmtUpdate = conn.prepareStatement("ALTER IGNORE TABLE `cloud`.`host_details` ADD INDEX `fk_host_details__host_id` (`host_id`)");) { + try(PreparedStatement pstmtUpdate = conn.prepareStatement("ALTER TABLE `cloud`.`host_details` ADD INDEX `fk_host_details__host_id` (`host_id`)");) { pstmtUpdate.executeUpdate(); s_logger.debug("Index did not exist on host_details - added new one"); }catch (SQLException e) { diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java new file mode 100644 index 0000000000..1c6ce38bd7 --- /dev/null +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade481to490.java @@ -0,0 +1,146 @@ +// 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.upgrade.dao; + +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.db.ScriptRunner; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; +import org.apache.cloudstack.acl.RoleType; +import org.apache.log4j.Logger; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; + +public class Upgrade481to490 implements DbUpgrade { + final static Logger s_logger = Logger.getLogger(Upgrade481to490.class); + + @Override + public String[] getUpgradableVersionRange() { + return new String[] {"4.8.1", "4.9.0"}; + } + + @Override + public String getUpgradedVersion() { + return "4.9.0"; + } + + @Override + public boolean supportsRollingUpgrade() { + return false; + } + + @Override + public File[] getPrepareScripts() { + String script = Script.findScript("", "db/schema-481to490.sql"); + if (script == null) { + throw new CloudRuntimeException("Unable to find db/schema-481to490.sql"); + } + return new File[] {new File(script)}; + } + + @Override + public void performDataMigration(Connection conn) { + setupRolesAndPermissionsForDynamicChecker(conn); + } + + private void migrateAccountsToDefaultRoles(final Connection conn) { + try (final PreparedStatement selectStatement = conn.prepareStatement("SELECT `id`, `type` FROM `cloud`.`account`;"); + final ResultSet selectResultSet = selectStatement.executeQuery()) { + while (selectResultSet.next()) { + final Long accountId = selectResultSet.getLong(1); + final Short accountType = selectResultSet.getShort(2); + final Long roleId = RoleType.getByAccountType(accountType).getId(); + if (roleId < 1L || roleId > 4L) { + s_logger.warn("Skipping role ID migration due to invalid role_id resolved for account id=" + accountId); + continue; + } + try (final PreparedStatement updateStatement = conn.prepareStatement("UPDATE `cloud`.`account` SET account.role_id = ? WHERE account.id = ? ;")) { + updateStatement.setLong(1, roleId); + updateStatement.setLong(2, accountId); + updateStatement.executeUpdate(); + } catch (SQLException e) { + s_logger.error("Failed to update cloud.account role_id for account id:" + accountId + " with exception: " + e.getMessage()); + throw new CloudRuntimeException("Exception while updating cloud.account role_id", e); + } + } + } catch (SQLException e) { + throw new CloudRuntimeException("Exception while migrating existing account table's role_id column to a role based on account type", e); + } + s_logger.debug("Done migrating existing accounts to use one of default roles based on account type"); + } + + private void setupRolesAndPermissionsForDynamicChecker(final Connection conn) { + final String alterTableSql = "ALTER TABLE `cloud`.`account` " + + "ADD COLUMN `role_id` bigint(20) unsigned COMMENT 'role id for this account' AFTER `type`, " + + "ADD KEY `fk_account__role_id` (`role_id`), " + + "ADD CONSTRAINT `fk_account__role_id` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`);"; + try (final PreparedStatement pstmt = conn.prepareStatement(alterTableSql)) { + pstmt.executeUpdate(); + } catch (SQLException e) { + if (e.getMessage().contains("role_id")) { + s_logger.warn("cloud.account table already has the role_id column, skipping altering table and migration of accounts"); + return; + } else { + throw new CloudRuntimeException("Unable to create column role_id in table cloud.account", e); + } + } + + try (final PreparedStatement pstmt = conn.prepareStatement("ALTER TABLE `cloud_usage`.`account` ADD COLUMN `role_id` bigint(20) unsigned AFTER `type`")) { + pstmt.executeUpdate(); + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to create column role_id in table cloud_usage.account", e); + } + + migrateAccountsToDefaultRoles(conn); + + final Map apiMap = PropertiesUtil.processConfigFile(new String[] { PropertiesUtil.getDefaultApiCommandsFileName() }); + if (apiMap == null || apiMap.isEmpty()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("The commands.properties file and default role permissions were not found. " + + "Assuming new installation, configuring default role-api mappings."); + } + String script = Script.findScript("", "db/create-default-role-api-mappings.sql"); + if (script == null) { + s_logger.error("Unable to find default role-api mapping sql file, please configure api per role manually"); + return; + } + try(final FileReader reader = new FileReader(new File(script))) { + ScriptRunner runner = new ScriptRunner(conn, false, true); + runner.runScript(reader); + } catch (SQLException | IOException e) { + s_logger.error("Unable to insert default api-role mappings from file: " + script + ". Please configure api per role manually, giving up!", e); + } + } + } + + @Override + public File[] getCleanupScripts() { + String script = Script.findScript("", "db/schema-481to490-cleanup.sql"); + if (script == null) { + throw new CloudRuntimeException("Unable to find db/schema-481to490-cleanup.sql"); + } + return new File[] {new File(script)}; + } +} diff --git a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java index 9c9ab0bbc0..39f57df714 100644 --- a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java +++ b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java @@ -49,7 +49,7 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage private static final String DELETE_ALL = "DELETE FROM cloud_usage"; private static final String DELETE_ALL_BY_ACCOUNTID = "DELETE FROM cloud_usage WHERE account_id = ?"; private static final String DELETE_ALL_BY_INTERVAL = "DELETE FROM cloud_usage WHERE end_date < DATE_SUB(CURRENT_DATE(), INTERVAL ? DAY)"; - private static final String INSERT_ACCOUNT = "INSERT INTO cloud_usage.account (id, account_name, type, domain_id, removed, cleanup_needed) VALUES (?,?,?,?,?,?)"; + private static final String INSERT_ACCOUNT = "INSERT INTO cloud_usage.account (id, account_name, type, role_id, domain_id, removed, cleanup_needed) VALUES (?,?,?,?,?,?,?)"; private static final String INSERT_USER_STATS = "INSERT INTO cloud_usage.user_statistics (id, data_center_id, account_id, public_ip_address, device_id, device_type, network_id, net_bytes_received," + " net_bytes_sent, current_bytes_received, current_bytes_sent, agg_bytes_received, agg_bytes_sent) VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?)"; @@ -113,16 +113,17 @@ public void saveAccounts(List accounts) { pstmt.setLong(1, acct.getId()); pstmt.setString(2, acct.getAccountName()); pstmt.setShort(3, acct.getType()); - pstmt.setLong(4, acct.getDomainId()); + pstmt.setLong(4, acct.getRoleId()); + pstmt.setLong(5, acct.getDomainId()); Date removed = acct.getRemoved(); if (removed == null) { - pstmt.setString(5, null); + pstmt.setString(6, null); } else { - pstmt.setString(5, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), acct.getRemoved())); + pstmt.setString(6, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), acct.getRemoved())); } - pstmt.setBoolean(6, acct.getNeedsCleanup()); + pstmt.setBoolean(7, acct.getNeedsCleanup()); pstmt.addBatch(); } diff --git a/engine/schema/src/com/cloud/user/AccountVO.java b/engine/schema/src/com/cloud/user/AccountVO.java index 0f5a0446e9..a504d2fdae 100644 --- a/engine/schema/src/com/cloud/user/AccountVO.java +++ b/engine/schema/src/com/cloud/user/AccountVO.java @@ -16,8 +16,8 @@ // under the License. package com.cloud.user; -import java.util.Date; -import java.util.UUID; +import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.acl.RoleType; import javax.persistence.Column; import javax.persistence.Entity; @@ -27,8 +27,8 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; - -import com.cloud.utils.db.GenericDao; +import java.util.Date; +import java.util.UUID; @Entity @Table(name = "account") @@ -44,6 +44,9 @@ public class AccountVO implements Account { @Column(name = "type") private short type = ACCOUNT_TYPE_NORMAL; + @Column(name = "role_id") + private Long roleId; + @Column(name = "domain_id") private long domainId; @@ -78,13 +81,21 @@ public AccountVO(long id) { uuid = UUID.randomUUID().toString(); } - public AccountVO(String accountName, long domainId, String networkDomain, short type, String uuid) { + public AccountVO(final String accountName, final long domainId, final String networkDomain, final short type, final String uuid) { this.accountName = accountName; this.domainId = domainId; this.networkDomain = networkDomain; this.type = type; - state = State.enabled; + this.state = State.enabled; this.uuid = uuid; + this.roleId = RoleType.getRoleByAccountType(null, type); + } + + public AccountVO(final String accountName, final long domainId, final String networkDomain, final short type, final Long roleId, final String uuid) { + this(accountName, domainId, networkDomain, type, uuid); + if (roleId != null) { + this.roleId = roleId; + } } public void setNeedsCleanup(boolean value) { @@ -122,6 +133,14 @@ public void setType(short type) { this.type = type; } + public Long getRoleId() { + return roleId; + } + + public void setRoleId(long roleId) { + this.roleId = roleId; + } + @Override public long getDomainId() { return domainId; diff --git a/engine/schema/src/com/cloud/user/dao/AccountDao.java b/engine/schema/src/com/cloud/user/dao/AccountDao.java index 4c7ce8e31b..374c9cc43d 100644 --- a/engine/schema/src/com/cloud/user/dao/AccountDao.java +++ b/engine/schema/src/com/cloud/user/dao/AccountDao.java @@ -41,6 +41,8 @@ public interface AccountDao extends GenericDao { List findActiveAccountsForDomain(Long domain); + List findAccountsByRole(Long roleId); + void markForCleanup(long accountId); List listAccounts(String accountName, Long domainId, Filter filter); diff --git a/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java b/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java index bff6213c10..27891503dc 100644 --- a/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java +++ b/engine/schema/src/com/cloud/user/dao/AccountDaoImpl.java @@ -44,7 +44,7 @@ public class AccountDaoImpl extends GenericDaoBase implements AccountDao { private static final Logger s_logger = Logger.getLogger(AccountDaoImpl.class); private static final String FIND_USER_ACCOUNT_BY_API_KEY = "SELECT u.id, u.username, u.account_id, u.secret_key, u.state, " - + "a.id, a.account_name, a.type, a.domain_id, a.state " + "FROM `cloud`.`user` u, `cloud`.`account` a " + + "a.id, a.account_name, a.type, a.role_id, a.domain_id, a.state " + "FROM `cloud`.`user` u, `cloud`.`account` a " + "WHERE u.account_id = a.id AND u.api_key = ? and u.removed IS NULL"; protected final SearchBuilder AllFieldsSearch; @@ -53,6 +53,7 @@ public class AccountDaoImpl extends GenericDaoBase implements A protected final SearchBuilder CleanupForRemovedAccountsSearch; protected final SearchBuilder CleanupForDisabledAccountsSearch; protected final SearchBuilder NonProjectAccountSearch; + protected final SearchBuilder AccountByRoleSearch; protected final GenericSearchBuilder AccountIdsSearch; public AccountDaoImpl() { @@ -96,6 +97,10 @@ public AccountDaoImpl() { AccountIdsSearch.selectFields(AccountIdsSearch.entity().getId()); AccountIdsSearch.and("ids", AccountIdsSearch.entity().getDomainId(), Op.IN); AccountIdsSearch.done(); + + AccountByRoleSearch = createSearchBuilder(); + AccountByRoleSearch.and("roleId", AccountByRoleSearch.entity().getRoleId(), SearchCriteria.Op.EQ); + AccountByRoleSearch.done(); } @Override @@ -140,8 +145,9 @@ public Pair findUserAccountByApiKey(String apiKey) { AccountVO a = new AccountVO(rs.getLong(6)); a.setAccountName(rs.getString(7)); a.setType(rs.getShort(8)); - a.setDomainId(rs.getLong(9)); - a.setState(State.valueOf(rs.getString(10))); + a.setRoleId(rs.getLong(9)); + a.setDomainId(rs.getLong(10)); + a.setState(State.valueOf(rs.getString(11))); userAcctPair = new Pair(u, a); } @@ -258,6 +264,13 @@ public List findActiveAccountsForDomain(Long domain) { return listBy(sc); } + @Override + public List findAccountsByRole(Long roleId) { + SearchCriteria sc = AccountByRoleSearch.create(); + sc.setParameters("roleId", roleId); + return listBy(sc); + } + @Override public void markForCleanup(long accountId) { AccountVO account = findByIdIncludingRemoved(accountId); diff --git a/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java b/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java index d555e7930d..ef8829ef01 100644 --- a/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java +++ b/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java @@ -156,4 +156,6 @@ public interface DomainRouterDao extends GenericDao { List listRunningByDataCenter(long dcId); List listStopped(long networkId); + + List listIncludingRemovedByVpcId(long vpcId); } diff --git a/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java index 271644f836..85a8a936b5 100644 --- a/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/DomainRouterDaoImpl.java @@ -432,4 +432,12 @@ public List listStopped(final long networkId) { sc.setParameters("states", State.Stopped); return listBy(sc); } + + @Override + public List listIncludingRemovedByVpcId(long vpcId) { + SearchCriteria sc = VpcSearch.create(); + sc.setParameters("vpcId", vpcId); + sc.setParameters("role", Role.VIRTUAL_ROUTER); + return listIncludingRemovedBy(sc); + } } diff --git a/engine/schema/src/org/apache/cloudstack/acl/RolePermissionVO.java b/engine/schema/src/org/apache/cloudstack/acl/RolePermissionVO.java new file mode 100644 index 0000000000..a81cebb70d --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/RolePermissionVO.java @@ -0,0 +1,120 @@ +// 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.acl; + +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 java.util.UUID; + +@Entity +@Table(name = "role_permissions") +public class RolePermissionVO implements RolePermission { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "role_id") + private long roleId; + + @Column(name = "rule") + private String rule; + + @Column(name = "permission", nullable = false) + @Enumerated(value = EnumType.STRING) + private Permission permission = RolePermission.Permission.DENY; + + @Column(name = "description") + private String description; + + @Column(name = "sort_order") + private long sortOrder = 0; + + public RolePermissionVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public RolePermissionVO(final long roleId, final String rule, final Permission permission, final String description) { + this(); + this.roleId = roleId; + this.rule = rule; + this.permission = permission; + this.description = description; + } + + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + public long getRoleId() { + return roleId; + } + + public void setRoleId(long roleId) { + this.roleId = roleId; + } + + @Override + public Rule getRule() { + return new Rule(rule); + } + + public void setRule(String rule) { + this.rule = rule; + } + + @Override + public Permission getPermission() { + return permission; + } + + public void setPermission(Permission permission) { + this.permission = permission; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public long getSortOrder() { + return sortOrder; + } + + public void setSortOrder(long sortOrder) { + this.sortOrder = sortOrder; + } +} \ No newline at end of file diff --git a/engine/schema/src/org/apache/cloudstack/acl/RoleVO.java b/engine/schema/src/org/apache/cloudstack/acl/RoleVO.java new file mode 100644 index 0000000000..f3404ab6d7 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/RoleVO.java @@ -0,0 +1,106 @@ +// 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.acl; + +import com.cloud.utils.db.GenericDao; + +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 java.util.Date; +import java.util.UUID; + +@Entity +@Table(name = "roles") +public class RoleVO implements Role { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "name") + private String name; + + @Column(name = "role_type", nullable = false) + @Enumerated(value = EnumType.STRING) + private RoleType roleType = RoleType.User; + + @Column(name = "description") + private String description; + + @Column(name = GenericDao.REMOVED_COLUMN) + private Date removed; + + public RoleVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public RoleVO(final String name, final RoleType roleType, final String description) { + this(); + this.name = name; + this.roleType = roleType; + this.description = description; + } + + public RoleVO(final long id, final String name, final RoleType roleType, final String description) { + this(name, roleType, description); + this.id = id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public RoleType getRoleType() { + return roleType; + } + + public void setRoleType(RoleType roleType) { + this.roleType = roleType; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspSyncClient.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java similarity index 69% rename from plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspSyncClient.java rename to engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java index 951ee5ad7e..e53654d998 100644 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspSyncClient.java +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java @@ -1,4 +1,3 @@ -// // 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 @@ -15,15 +14,16 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -// - -package net.nuage.vsp.acs.client; -import java.util.concurrent.ExecutionException; +package org.apache.cloudstack.acl.dao; -public interface NuageVspSyncClient { +import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.acl.RoleVO; - void syncWithNuageVsp(String nuageVspEntity) throws ExecutionException; +import java.util.List; - void setNuageVspApiClient(NuageVspApiClient nuageVspApiClient); -} \ No newline at end of file +public interface RoleDao extends GenericDao { + List findAllByName(String roleName); + List findAllByRoleType(RoleType type); +} diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDaoImpl.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDaoImpl.java new file mode 100644 index 0000000000..c7eb496213 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDaoImpl.java @@ -0,0 +1,61 @@ +// 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.acl.dao; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.acl.RoleVO; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.List; + +@Component +@Local(value = {RoleDao.class}) +public class RoleDaoImpl extends GenericDaoBase implements RoleDao { + private final SearchBuilder RoleByNameSearch; + private final SearchBuilder RoleByTypeSearch; + + public RoleDaoImpl() { + super(); + + RoleByNameSearch = createSearchBuilder(); + RoleByNameSearch.and("roleName", RoleByNameSearch.entity().getName(), SearchCriteria.Op.LIKE); + RoleByNameSearch.done(); + + RoleByTypeSearch = createSearchBuilder(); + RoleByTypeSearch.and("roleType", RoleByTypeSearch.entity().getRoleType(), SearchCriteria.Op.EQ); + RoleByTypeSearch.done(); + } + + @Override + public List findAllByName(final String roleName) { + SearchCriteria sc = RoleByNameSearch.create(); + sc.setParameters("roleName", "%" + roleName + "%"); + return listBy(sc); + } + + @Override + public List findAllByRoleType(final RoleType type) { + SearchCriteria sc = RoleByTypeSearch.create(); + sc.setParameters("roleType", type); + return listBy(sc); + } +} diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java new file mode 100644 index 0000000000..3754491965 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDao.java @@ -0,0 +1,49 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.acl.dao; + +import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RolePermissionVO; + +import java.util.List; + +public interface RolePermissionsDao extends GenericDao { + /** + * Adds a new role permission at the end of the list of role permissions + * @param item the new role permission + * @return returns persisted role permission + */ + RolePermissionVO persist(final RolePermissionVO item); + + /** + * Moves an existing role permission under a given parent role permission + * @param role the existing role + * @param newOrder the new role permissions order + * @return returns true on success + */ + boolean update(final Role role, final List newOrder); + + /** + * Returns ordered linked-list of role permission for a given role + * @param roleId the ID of the role + * @return returns list of role permissions + */ + List findAllByRoleIdSorted(Long roleId); +} diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java new file mode 100644 index 0000000000..8f6fa83f01 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RolePermissionsDaoImpl.java @@ -0,0 +1,165 @@ +// 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.acl.dao; + +import com.cloud.utils.db.Attribute; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.db.UpdateBuilder; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.acl.RolePermissionVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Component +@Local(value = {RolePermissionsDao.class}) +public class RolePermissionsDaoImpl extends GenericDaoBase implements RolePermissionsDao { + protected static final Logger LOGGER = Logger.getLogger(RolePermissionsDaoImpl.class); + + private final SearchBuilder RolePermissionsSearch; + private Attribute sortOrderAttribute; + + public RolePermissionsDaoImpl() { + super(); + + RolePermissionsSearch = createSearchBuilder(); + RolePermissionsSearch.and("uuid", RolePermissionsSearch.entity().getUuid(), SearchCriteria.Op.EQ); + RolePermissionsSearch.and("roleId", RolePermissionsSearch.entity().getRoleId(), SearchCriteria.Op.EQ); + RolePermissionsSearch.and("sortOrder", RolePermissionsSearch.entity().getSortOrder(), SearchCriteria.Op.EQ); + RolePermissionsSearch.done(); + + sortOrderAttribute = _allAttributes.get("sortOrder"); + + assert (sortOrderAttribute != null) : "Couldn't find one of these attributes"; + } + + private boolean updateSortOrder(final RolePermissionVO permissionBeingMoved, final RolePermissionVO parentPermission) { + if (parentPermission != null && permissionBeingMoved.getId() == parentPermission.getId()) { + return true; + } + final List newOrderedPermissionsList = new ArrayList<>(); + // Null parent implies item needs to move to the top + if (parentPermission == null) { + newOrderedPermissionsList.add(permissionBeingMoved); + } + for (final RolePermissionVO permission : findAllByRoleIdSorted(permissionBeingMoved.getRoleId())) { + if (permission.getId() == permissionBeingMoved.getId()) { + continue; + } + newOrderedPermissionsList.add(permission); + if (parentPermission != null && permission.getId() == parentPermission.getId()) { + newOrderedPermissionsList.add(permissionBeingMoved); + } + } + long sortOrder = 0L; + for (final RolePermissionVO permission : newOrderedPermissionsList) { + permission.setSortOrder(sortOrder++); + if (!update(permission.getId(), permission)) { + LOGGER.warn("Failed to update item's sort order with id:" + permission.getId() + " while moving permission with id:" + permissionBeingMoved.getId() + " to a new position"); + return false; + } + } + return true; + } + + @Override + public RolePermissionVO persist(final RolePermissionVO item) { + item.setSortOrder(0); + final List permissionsList = findAllByRoleIdSorted(item.getRoleId()); + if (permissionsList != null && permissionsList.size() > 0) { + RolePermission lastRule = permissionsList.get(permissionsList.size() - 1); + item.setSortOrder(lastRule.getSortOrder() + 1); + } + return super.persist(item); + } + + @Override + public boolean update(final Role role, final List newOrder) { + if (role == null || newOrder == null || newOrder.isEmpty()) { + return false; + } + return Transaction.execute(new TransactionCallback() { + @Override + public Boolean doInTransaction(TransactionStatus status) { + final String failMessage = "The role's rule permissions list has changed while you were making updates, aborted re-ordering of rules. Please try again."; + final List currentOrder = findAllByRoleIdSorted(role.getId()); + if (role.getId() < 1L || newOrder.size() != currentOrder.size()) { + throw new CloudRuntimeException(failMessage); + } + final Set newOrderSet = new HashSet<>(); + for (final RolePermission permission : newOrder) { + if (permission == null) { + continue; + } + newOrderSet.add(permission.getId()); + } + final Set currentOrderSet = new HashSet<>(); + for (final RolePermission permission : currentOrder) { + currentOrderSet.add(permission.getId()); + } + if (!newOrderSet.equals(currentOrderSet)) { + throw new CloudRuntimeException(failMessage); + } + long sortOrder = 0L; + for (RolePermission rolePermission : newOrder) { + final SearchCriteria sc = RolePermissionsSearch.create(); + sc.setParameters("uuid", rolePermission.getUuid()); + sc.setParameters("roleId", role.getId()); + sc.setParameters("sortOrder", rolePermission.getSortOrder()); + + final UpdateBuilder ub = getUpdateBuilder(rolePermission); + ub.set(rolePermission, sortOrderAttribute, sortOrder); + final int result = update(ub, sc, null); + if (result < 1) { + throw new CloudRuntimeException(failMessage); + } + sortOrder++; + } + return true; + } + }); + } + + @Override + public List findAllByRoleIdSorted(final Long roleId) { + final SearchCriteria sc = RolePermissionsSearch.create(); + if (roleId != null && roleId > 0L) { + sc.setParameters("roleId", roleId); + } + final Filter searchBySorted = new Filter(RolePermissionVO.class, "sortOrder", true, null, null); + final List rolePermissionList = listBy(sc, searchBySorted); + if (rolePermissionList == null) { + return Collections.emptyList(); + } + return rolePermissionList; + } +} diff --git a/engine/schema/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementVO.java b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementVO.java new file mode 100644 index 0000000000..b5c357c3f8 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementVO.java @@ -0,0 +1,193 @@ +// 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.outofbandmanagement; + +import com.cloud.utils.db.Encrypt; +import com.cloud.utils.db.StateMachine; + +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 java.util.Date; + +@Entity +@Table(name = "oobm") +public class OutOfBandManagementVO implements OutOfBandManagement { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "host_id") + private Long hostId; + + @Column(name = "enabled") + private boolean enabled = false; + + // There is no setter for status because it has to be set in the dao code + @Enumerated(value = EnumType.STRING) + @StateMachine(state = PowerState.class, event = PowerState.Event.class) + @Column(name = "power_state", updatable = true, nullable = false, length = 32) + private PowerState powerState = null; + + @Column(name = "driver") + private String driver; + + @Column(name = "address") + private String address; + + @Column(name = "port") + private Integer port; + + @Column(name = "username") + private String username; + + @Encrypt + @Column(name = "password") + private String password; + + // This field should be updated every time the state is updated. + // There's no set method in the vo object because it is done with in the dao code. + @Column(name = "update_count", updatable = true, nullable = false) + protected long updateCount; + + @Column(name = "update_time", updatable = true) + @Temporal(value = TemporalType.TIMESTAMP) + protected Date updateTime; + + @Column(name = "mgmt_server_id") + private Long managementServerId; + + public OutOfBandManagementVO(Long hostId) { + this.hostId = hostId; + this.powerState = PowerState.Disabled; + } + + public OutOfBandManagementVO() { + } + + @Override + public long getId() { + return id; + } + + @Override + public PowerState getState() { + return powerState; + } + + public Long getHostId() { + return hostId; + } + + public boolean isEnabled() { + return enabled; + } + + public PowerState getPowerState() { + return powerState; + } + + @Override + public String getDriver() { + return driver; + } + + @Override + public String getAddress() { + return address; + } + + @Override + public Integer getPort() { + return port; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public String getPassword() { + return password; + } + + public long incrUpdateCount() { + updateCount++; + return updateCount; + } + + public long getUpdateCount() { + return updateCount; + } + + public Date getUpdateTime() { + return updateTime; + } + + @Override + public Long getManagementServerId() { + return managementServerId; + } + + public void setHostId(Long hostId) { + this.hostId = hostId; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public void setDriver(String driver) { + this.driver = driver; + } + + @Override + public void setAddress(String address) { + this.address = address; + } + + @Override + public void setPort(Integer port) { + this.port = port; + } + + @Override + public void setUsername(String username) { + this.username = username; + } + + @Override + public void setPassword(String password) { + this.password = password; + } + + public void setManagementServerId(Long managementServerId) { + this.managementServerId = managementServerId; + } +} diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspApiClient.java b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDao.java similarity index 54% rename from plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspApiClient.java rename to engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDao.java index d80daf9eef..5985b81625 100644 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspApiClient.java +++ b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDao.java @@ -1,4 +1,3 @@ -// // 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 @@ -15,18 +14,18 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -// - -package net.nuage.vsp.acs.client; - -import java.util.concurrent.ExecutionException; -public interface NuageVspApiClient { +package org.apache.cloudstack.outofbandmanagement.dao; - void login() throws ExecutionException; +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementVO; - void setNuageVspHost(String restRelativePath, String[] cmsUserInfo, int noofRetry, int retryInterval, String nuageVspCmsId); +import java.util.List; - String executeRestApi(String method, String resource, String resourceId, String childResource, Object entityDetails, String resourceFilter, String proxyUserUuid, - String proxyUserDomainuuid) throws ExecutionException; +public interface OutOfBandManagementDao extends GenericDao, StateDao { + OutOfBandManagement findByHost(long hostId); + List findAllByManagementServer(long serverId); + void expireOutOfBandManagementOwnershipByServer(long serverId); } diff --git a/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDaoImpl.java b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDaoImpl.java new file mode 100644 index 0000000000..b914b6b702 --- /dev/null +++ b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDaoImpl.java @@ -0,0 +1,158 @@ +// 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.outofbandmanagement.dao; + +import com.cloud.utils.DateUtil; +import com.cloud.utils.db.Attribute; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallbackNoReturn; +import com.cloud.utils.db.TransactionLegacy; +import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.db.UpdateBuilder; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.List; + +@DB +@Component +public class OutOfBandManagementDaoImpl extends GenericDaoBase implements OutOfBandManagementDao { + private static final Logger LOG = Logger.getLogger(OutOfBandManagementDaoImpl.class); + + private SearchBuilder HostSearch; + private SearchBuilder ManagementServerSearch; + private SearchBuilder OutOfBandManagementOwnerSearch; + private SearchBuilder StateUpdateSearch; + + private Attribute PowerStateAttr; + private Attribute MsIdAttr; + private Attribute UpdateTimeAttr; + + public OutOfBandManagementDaoImpl() { + super(); + + HostSearch = createSearchBuilder(); + HostSearch.and("hostId", HostSearch.entity().getHostId(), SearchCriteria.Op.EQ); + HostSearch.done(); + + ManagementServerSearch = createSearchBuilder(); + ManagementServerSearch.and("server", ManagementServerSearch.entity().getManagementServerId(), SearchCriteria.Op.EQ); + ManagementServerSearch.done(); + + OutOfBandManagementOwnerSearch = createSearchBuilder(); + OutOfBandManagementOwnerSearch.and("server", OutOfBandManagementOwnerSearch.entity().getManagementServerId(), SearchCriteria.Op.EQ); + OutOfBandManagementOwnerSearch.or("serverNull", OutOfBandManagementOwnerSearch.entity().getManagementServerId(), SearchCriteria.Op.NULL); + OutOfBandManagementOwnerSearch.done(); + + StateUpdateSearch = createSearchBuilder(); + StateUpdateSearch.and("status", StateUpdateSearch.entity().getPowerState(), SearchCriteria.Op.EQ); + StateUpdateSearch.and("id", StateUpdateSearch.entity().getId(), SearchCriteria.Op.EQ); + StateUpdateSearch.and("update", StateUpdateSearch.entity().getUpdateCount(), SearchCriteria.Op.EQ); + StateUpdateSearch.done(); + + PowerStateAttr = _allAttributes.get("powerState"); + MsIdAttr = _allAttributes.get("managementServerId"); + UpdateTimeAttr = _allAttributes.get("updateTime"); + assert (PowerStateAttr != null && MsIdAttr != null && UpdateTimeAttr != null) : "Couldn't find one of these attributes"; + } + + @Override + public OutOfBandManagement findByHost(long hostId) { + SearchCriteria sc = HostSearch.create("hostId", hostId); + return findOneBy(sc); + } + + @Override + public List findAllByManagementServer(long serverId) { + SearchCriteria sc = OutOfBandManagementOwnerSearch.create(); + sc.setParameters("server", serverId); + return listBy(sc, new Filter(OutOfBandManagementVO.class, "updateTime", true, null, null)); + } + + private void executeExpireOwnershipSql(final String sql, final long resource) { + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + TransactionLegacy txn = TransactionLegacy.currentTxn(); + try (final PreparedStatement pstmt = txn.prepareAutoCloseStatement(sql);) { + pstmt.setLong(1, resource); + pstmt.executeUpdate(); + } catch (SQLException e) { + txn.rollback(); + LOG.warn("Failed to expire ownership for out-of-band management server id: " + resource); + } + } + }); + } + + @Override + public void expireOutOfBandManagementOwnershipByServer(long serverId) { + final String resetOwnerSql = "UPDATE oobm set mgmt_server_id=NULL, power_state=NULL where mgmt_server_id=?"; + executeExpireOwnershipSql(resetOwnerSql, serverId); + if (LOG.isDebugEnabled()) { + LOG.debug("Expired out-of-band management ownership for hosts owned by management server id:" + serverId); + } + } + + @Override + public boolean updateState(OutOfBandManagement.PowerState oldStatus, OutOfBandManagement.PowerState.Event event, OutOfBandManagement.PowerState newStatus, OutOfBandManagement vo, Object data) { + OutOfBandManagementVO oobmHost = (OutOfBandManagementVO) vo; + if (oobmHost == null) { + if (LOG.isTraceEnabled()) { + LOG.trace("Invalid out-of-band management host view object provided"); + } + return false; + } + + Long newManagementServerId = event.getServerId(); + // Avoid updates when old ownership and state are same as new + if (oldStatus == newStatus && (oobmHost.getManagementServerId() != null && oobmHost.getManagementServerId().equals(newManagementServerId))) { + return false; + } + + if (event == OutOfBandManagement.PowerState.Event.Disabled) { + newManagementServerId = null; + } + + SearchCriteria sc = StateUpdateSearch.create(); + sc.setParameters("status", oldStatus); + sc.setParameters("id", oobmHost.getId()); + sc.setParameters("update", oobmHost.getUpdateCount()); + + oobmHost.incrUpdateCount(); + UpdateBuilder ub = getUpdateBuilder(oobmHost); + ub.set(oobmHost, PowerStateAttr, newStatus); + ub.set(oobmHost, UpdateTimeAttr, DateUtil.currentGMTTime()); + ub.set(oobmHost, MsIdAttr, newManagementServerId); + + int result = update(ub, sc, null); + if (LOG.isDebugEnabled() && result <= 0) { + LOG.debug(String.format("Failed to update out-of-band management power state from:%s to:%s due to event:%s for the host id:%d", oldStatus, newStatus, event, oobmHost.getHostId())); + } + return result > 0; + } +} diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java index 2d1a3eddd6..2c706774a4 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/ImageStoreVO.java @@ -51,7 +51,7 @@ public class ImageStoreVO implements ImageStore { @Column(name = "protocol", nullable = false) private String protocol; - @Column(name = "url", nullable = false) + @Column(name = "url", nullable = false, length = 2048) private String url; @Column(name = "image_provider_name", nullable = false) diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java index d265da15de..32d1d79224 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java @@ -64,6 +64,8 @@ public interface PrimaryDataStoreDao extends GenericDao { */ List findPoolByName(String name); + List findPoolsByProvider(String provider); + /** * Find pools by the pod that matches the details. * diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java index fd617cce09..c451e1dee4 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java @@ -79,6 +79,7 @@ public PrimaryDataStoreDaoImpl() { AllFieldSearch.and("path", AllFieldSearch.entity().getPath(), SearchCriteria.Op.EQ); AllFieldSearch.and("podId", AllFieldSearch.entity().getPodId(), Op.EQ); AllFieldSearch.and("clusterId", AllFieldSearch.entity().getClusterId(), Op.EQ); + AllFieldSearch.and("storage_provider_name", AllFieldSearch.entity().getStorageProviderName(), Op.EQ); AllFieldSearch.done(); DcPodSearch = createSearchBuilder(); @@ -128,6 +129,13 @@ public List findPoolByName(String name) { return listIncludingRemovedBy(sc); } + @Override + public List findPoolsByProvider(String provider) { + SearchCriteria sc = AllFieldSearch.create(); + sc.setParameters("storage_provider_name", provider); + return listBy(sc); + } + @Override public StoragePoolVO findPoolByUUID(String uuid) { SearchCriteria sc = AllFieldSearch.create(); diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java index bb05300e21..024f05604c 100644 --- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java +++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/TemplateDataStoreVO.java @@ -95,10 +95,10 @@ public class TemplateDataStoreVO implements StateObject org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT cloud-engine-service war @@ -60,17 +60,6 @@ cloud-engine-network ${project.version} - - org.apache.cxf - cxf-bundle-jaxrs - 2.7.13 - - - org.eclipse.jetty - jetty-server - - - org.springframework spring-context @@ -84,9 +73,9 @@ engine - org.mortbay.jetty + org.eclipse.jetty jetty-maven-plugin - 8.1.7.v20120910 + ${cs.jetty.version} 10 diff --git a/engine/storage/cache/pom.xml b/engine/storage/cache/pom.xml index 5290ee3a53..976a2e75a8 100644 --- a/engine/storage/cache/pom.xml +++ b/engine/storage/cache/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/datamotion/pom.xml b/engine/storage/datamotion/pom.xml index a816531af7..3324270198 100644 --- a/engine/storage/datamotion/pom.xml +++ b/engine/storage/datamotion/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java index 24ecff57e9..3124666db1 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -23,9 +23,6 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; @@ -41,7 +38,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.StorageAction; import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; -import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; @@ -49,6 +45,8 @@ import org.apache.cloudstack.storage.RemoteHostEndPoint; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.agent.api.Answer; import com.cloud.agent.api.storage.MigrateVolumeAnswer; @@ -61,9 +59,9 @@ import com.cloud.configuration.Config; import com.cloud.host.Host; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; import com.cloud.storage.VolumeVO; -import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.DB; @@ -99,22 +97,14 @@ protected boolean needCacheStorage(DataObject srcData, DataObject destData) { DataStoreTO srcStoreTO = srcTO.getDataStore(); if (srcStoreTO instanceof NfsTO || srcStoreTO.getRole() == DataStoreRole.ImageCache) { - //|| - // (srcStoreTO instanceof PrimaryDataStoreTO && ((PrimaryDataStoreTO)srcStoreTO).getPoolType() == StoragePoolType.NetworkFilesystem)) { return false; } - DataTO destTO = destData.getTO(); DataStoreTO destStoreTO = destTO.getDataStore(); if (destStoreTO instanceof NfsTO || destStoreTO.getRole() == DataStoreRole.ImageCache) { return false; } - - if (srcData.getType() == DataObjectType.TEMPLATE) { - TemplateInfo template = (TemplateInfo)srcData; - } - if (s_logger.isDebugEnabled()) { s_logger.debug("needCacheStorage true, dest at " + destTO.getPath() + " dest role " + destStoreTO.getRole().toString() + srcTO.getPath() + " src role " + srcStoreTO.getRole().toString()); @@ -429,7 +419,7 @@ protected Answer migrateVolumeToPool(DataObject srcData, DataObject destData) { // Note: destHost is currently only used if the copyObject method is invoked @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { Answer answer = null; String errMsg = null; try { @@ -465,12 +455,6 @@ public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, As CopyCommandResult result = new CopyCommandResult(null, answer); result.setResult(errMsg); callback.complete(result); - return null; - } - - @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - return copyAsync(srcData, destData, null, callback); } @DB @@ -569,11 +553,9 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) { } @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult(null, null); result.setResult("Unsupported operation requested for copying data."); callback.complete(result); - - return null; } } diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java index 3c9334df73..7a59ad07c4 100644 --- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java +++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java @@ -18,14 +18,19 @@ */ package org.apache.cloudstack.storage.motion; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; +import java.util.concurrent.ExecutionException; import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.OperationTimedoutException; import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; @@ -33,21 +38,28 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; -import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.CopyCmdAnswer; +import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.command.ResignatureAnswer; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.api.to.DiskTO; @@ -56,65 +68,98 @@ import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.org.Cluster; -import com.cloud.org.Grouping.AllocationState; -import com.cloud.resource.ResourceState; import com.cloud.server.ManagementService; import com.cloud.storage.DataStoreRole; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.SnapshotVO; -import com.cloud.storage.VolumeVO; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.VolumeDetailVO; +import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.SnapshotDetailsDao; import com.cloud.storage.dao.SnapshotDetailsVO; import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeDetailsDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachineManager; +import com.google.common.base.Preconditions; + @Component public class StorageSystemDataMotionStrategy implements DataMotionStrategy { - private static final Logger s_logger = Logger.getLogger(StorageSystemDataMotionStrategy.class); + private static final Logger LOGGER = Logger.getLogger(StorageSystemDataMotionStrategy.class); + private static final Random RANDOM = new Random(System.nanoTime()); @Inject private AgentManager _agentMgr; @Inject private ConfigurationDao _configDao; + @Inject private DataStoreManager dataStoreMgr; @Inject private DiskOfferingDao _diskOfferingDao; + @Inject private ClusterDao clusterDao; @Inject private HostDao _hostDao; + @Inject private HostDetailsDao hostDetailsDao; @Inject private ManagementService _mgr; @Inject private PrimaryDataStoreDao _storagePoolDao; @Inject private SnapshotDao _snapshotDao; @Inject private SnapshotDetailsDao _snapshotDetailsDao; @Inject private VolumeDao _volumeDao; @Inject private VolumeDataFactory _volumeDataFactory; + @Inject private VolumeDetailsDao volumeDetailsDao; @Inject private VolumeService _volumeService; @Override public StrategyPriority canHandle(DataObject srcData, DataObject destData) { if (srcData instanceof SnapshotInfo) { - if (canHandle(srcData.getDataStore()) || canHandle(destData.getDataStore())) { + if (canHandle(srcData) || canHandle(destData)) { return StrategyPriority.HIGHEST; } } + if (srcData instanceof TemplateInfo && destData instanceof VolumeInfo && + (srcData.getDataStore().getId() == destData.getDataStore().getId()) && + (canHandle(srcData) || canHandle(destData))) { + // Both source and dest are on the same storage, so just clone them. + return StrategyPriority.HIGHEST; + } + return StrategyPriority.CANT_HANDLE; } - private boolean canHandle(DataStore dataStore) { + private boolean canHandle(DataObject dataObject) { + Preconditions.checkArgument(dataObject != null, "Passing 'null' to dataObject of canHandle(DataObject) is not supported."); + + DataStore dataStore = dataObject.getDataStore(); + if (dataStore.getRole() == DataStoreRole.Primary) { Map mapCapabilities = dataStore.getDriver().getCapabilities(); - if (mapCapabilities != null) { + if (mapCapabilities == null) { + return false; + } + + if (dataObject instanceof VolumeInfo || dataObject instanceof SnapshotInfo) { String value = mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString()); - Boolean supportsStorageSystemSnapshots = new Boolean(value); + Boolean supportsStorageSystemSnapshots = Boolean.valueOf(value); if (supportsStorageSystemSnapshots) { - s_logger.info("Using 'StorageSystemDataMotionStrategy'"); + LOGGER.info("Using 'StorageSystemDataMotionStrategy' (dataObject is a volume or snapshot and the storage system supports snapshots)"); + + return true; + } + } else if (dataObject instanceof TemplateInfo) { + // If the storage system can clone volumes, we can cache templates on it. + String value = mapCapabilities.get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString()); + Boolean canCloneVolume = Boolean.valueOf(value); + + if (canCloneVolume) { + LOGGER.info("Using 'StorageSystemDataMotionStrategy' (dataObject is a template and the storage system can create a volume from a volume)"); return true; } + } } @@ -127,43 +172,98 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { if (srcData instanceof SnapshotInfo) { SnapshotInfo snapshotInfo = (SnapshotInfo)srcData; validate(snapshotInfo); - boolean canHandleSrc = canHandle(srcData.getDataStore()); + boolean canHandleSrc = canHandle(srcData); if (canHandleSrc && destData instanceof TemplateInfo && (destData.getDataStore().getRole() == DataStoreRole.Image || destData.getDataStore().getRole() == DataStoreRole.ImageCache)) { - return handleCreateTemplateFromSnapshot(snapshotInfo, (TemplateInfo)destData, callback); + handleCreateTemplateFromSnapshot(snapshotInfo, (TemplateInfo)destData, callback); + + return; } if (destData instanceof VolumeInfo) { VolumeInfo volumeInfo = (VolumeInfo)destData; - boolean canHandleDest = canHandle(destData.getDataStore()); + boolean canHandleDest = canHandle(destData); if (canHandleSrc && canHandleDest) { - return handleCreateVolumeFromSnapshotBothOnStorageSystem(snapshotInfo, volumeInfo, callback); + if (snapshotInfo.getDataStore().getId() == volumeInfo.getDataStore().getId()) { + handleCreateVolumeFromSnapshotBothOnStorageSystem(snapshotInfo, volumeInfo, callback); + return; + } + else { + String errMsg = "This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + + "not supported by source or destination storage plug-in). " + getSrcDestDataStoreMsg(srcData, destData); + + LOGGER.warn(errMsg); + + throw new UnsupportedOperationException(errMsg); + } } if (canHandleSrc) { - throw new UnsupportedOperationException("This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + - "not supported by destination storage plug-in)."); + String errMsg = "This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + + "not supported by destination storage plug-in). " + getDestDataStoreMsg(destData); + + LOGGER.warn(errMsg); + + throw new UnsupportedOperationException(errMsg); } if (canHandleDest) { - throw new UnsupportedOperationException("This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + - "not supported by source storage plug-in)."); + String errMsg = "This operation is not supported (DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT " + + "not supported by source storage plug-in). " + getSrcDataStoreMsg(srcData); + + LOGGER.warn(errMsg); + + throw new UnsupportedOperationException(errMsg); } } + } else if (srcData instanceof TemplateInfo && destData instanceof VolumeInfo) { + boolean canHandleSrc = canHandle(srcData); + + if (!canHandleSrc) { + String errMsg = "This operation is not supported (DataStoreCapabilities.STORAGE_CAN_CREATE_VOLUME_FROM_VOLUME " + + "not supported by destination storage plug-in). " + getDestDataStoreMsg(destData); + + LOGGER.warn(errMsg); + + throw new UnsupportedOperationException(errMsg); + } + + handleCreateVolumeFromTemplateBothOnStorageSystem((TemplateInfo)srcData, (VolumeInfo)destData, callback); + + return; } throw new UnsupportedOperationException("This operation is not supported."); } + private String getSrcDestDataStoreMsg(DataObject srcData, DataObject destData) { + Preconditions.checkArgument(srcData != null, "Passing 'null' to srcData of getSrcDestDataStoreMsg(DataObject, DataObject) is not supported."); + Preconditions.checkArgument(destData != null, "Passing 'null' to destData of getSrcDestDataStoreMsg(DataObject, DataObject) is not supported."); + + return "Source data store = " + srcData.getDataStore().getName() + "; " + "Destination data store = " + destData.getDataStore().getName() + "."; + } + + private String getSrcDataStoreMsg(DataObject srcData) { + Preconditions.checkArgument(srcData != null, "Passing 'null' to srcData of getSrcDataStoreMsg(DataObject) is not supported."); + + return "Source data store = " + srcData.getDataStore().getName() + "."; + } + + private String getDestDataStoreMsg(DataObject destData) { + Preconditions.checkArgument(destData != null, "Passing 'null' to destData of getDestDataStoreMsg(DataObject) is not supported."); + + return "Destination data store = " + destData.getDataStore().getName() + "."; + } + private void validate(SnapshotInfo snapshotInfo) { long volumeId = snapshotInfo.getVolumeId(); @@ -174,7 +274,13 @@ private void validate(SnapshotInfo snapshotInfo) { } } - private Void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, TemplateInfo templateInfo, AsyncCompletionCallback callback) { + private boolean usingBackendSnapshotFor(SnapshotInfo snapshotInfo) { + String property = getProperty(snapshotInfo.getId(), "takeSnapshot"); + + return Boolean.parseBoolean(property); + } + + private void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, TemplateInfo templateInfo, AsyncCompletionCallback callback) { try { snapshotInfo.processEvent(Event.CopyingRequested); } @@ -182,57 +288,168 @@ private Void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, Templat throw new CloudRuntimeException("This snapshot is not currently in a state where it can be used to create a template."); } - HostVO hostVO = getHost(snapshotInfo.getDataStore().getId()); - DataStore srcDataStore = snapshotInfo.getDataStore(); + HostVO hostVO = getHost(snapshotInfo); - String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); - int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); - CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), templateInfo.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); + boolean usingBackendSnapshot = usingBackendSnapshotFor(snapshotInfo); + boolean computeClusterSupportsResign = clusterDao.getSupportsResigning(hostVO.getClusterId()); - String errMsg = null; + if (usingBackendSnapshot && !computeClusterSupportsResign) { + String noSupportForResignErrMsg = "Unable to locate an applicable host with which to perform a resignature operation : Cluster ID = " + hostVO.getClusterId(); - CopyCmdAnswer copyCmdAnswer = null; + LOGGER.warn(noSupportForResignErrMsg); + + throw new CloudRuntimeException(noSupportForResignErrMsg); + } try { - _volumeService.grantAccess(snapshotInfo, hostVO, srcDataStore); + if (usingBackendSnapshot) { + createVolumeFromSnapshot(hostVO, snapshotInfo, true); + } - Map srcDetails = getSnapshotDetails(_storagePoolDao.findById(srcDataStore.getId()), snapshotInfo); + DataStore srcDataStore = snapshotInfo.getDataStore(); - copyCommand.setOptions(srcDetails); + String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); + int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); + CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), templateInfo.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); + + String errMsg = null; + + CopyCmdAnswer copyCmdAnswer = null; - copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); - } - catch (Exception ex) { - throw new CloudRuntimeException(ex.getMessage()); - } - finally { try { - _volumeService.revokeAccess(snapshotInfo, hostVO, srcDataStore); + // If we are using a back-end snapshot, then we should still have access to it from the hosts in the cluster that hostVO is in + // (because we passed in true as the third parameter to createVolumeFromSnapshot above). + if (usingBackendSnapshot == false) { + _volumeService.grantAccess(snapshotInfo, hostVO, srcDataStore); + } + + Map srcDetails = getSnapshotDetails(snapshotInfo); + + copyCommand.setOptions(srcDetails); + + copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); } - catch (Exception ex) { - s_logger.debug(ex.getMessage(), ex); + catch (CloudRuntimeException | AgentUnavailableException | OperationTimedoutException ex) { + String msg = "Failed to create template from snapshot (Snapshot ID = " + snapshotInfo.getId() + ") : "; + + LOGGER.warn(msg, ex); + + throw new CloudRuntimeException(msg + ex.getMessage()); } + finally { + try { + _volumeService.revokeAccess(snapshotInfo, hostVO, srcDataStore); + } + catch (Exception ex) { + LOGGER.warn("Error revoking access to snapshot (Snapshot ID = " + snapshotInfo.getId() + "): " + ex.getMessage(), ex); + } - if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { - if (copyCmdAnswer != null && copyCmdAnswer.getDetails() != null && !copyCmdAnswer.getDetails().isEmpty()) { - errMsg = copyCmdAnswer.getDetails(); + if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { + if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) { + errMsg = copyCmdAnswer.getDetails(); + } + else { + errMsg = "Unable to create template from snapshot"; + } } - else { - errMsg = "Unable to perform host-side operation"; + + try { + if (StringUtils.isEmpty(errMsg)) { + snapshotInfo.processEvent(Event.OperationSuccessed); + } + else { + snapshotInfo.processEvent(Event.OperationFailed); + } + } + catch (Exception ex) { + LOGGER.warn("Error processing snapshot event: " + ex.getMessage(), ex); } } - try { - if (errMsg == null) { - snapshotInfo.processEvent(Event.OperationSuccessed); + CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); + + result.setResult(errMsg); + + callback.complete(result); + } + finally { + if (usingBackendSnapshot) { + deleteVolumeFromSnapshot(snapshotInfo); + } + } + } + + /** + * Clones a template present on the storage to a new volume and resignatures it. + * + * @param templateInfo source template + * @param volumeInfo destination ROOT volume + * @param callback for async + */ + private void handleCreateVolumeFromTemplateBothOnStorageSystem(TemplateInfo templateInfo, VolumeInfo volumeInfo, AsyncCompletionCallback callback) { + Preconditions.checkArgument(templateInfo != null, "Passing 'null' to templateInfo of handleCreateVolumeFromTemplateBothOnStorageSystem is not supported."); + Preconditions.checkArgument(volumeInfo != null, "Passing 'null' to volumeInfo of handleCreateVolumeFromTemplateBothOnStorageSystem is not supported."); + + CopyCmdAnswer copyCmdAnswer = null; + String errMsg = null; + + HostVO hostVO = getHost(volumeInfo.getDataCenterId(), true); + + if (hostVO == null) { + throw new CloudRuntimeException("Unable to locate a host capable of resigning in the zone with the following ID: " + volumeInfo.getDataCenterId()); + } + + boolean computeClusterSupportsResign = clusterDao.getSupportsResigning(hostVO.getClusterId()); + + if (!computeClusterSupportsResign) { + String noSupportForResignErrMsg = "Unable to locate an applicable host with which to perform a resignature operation : Cluster ID = " + hostVO.getClusterId(); + + LOGGER.warn(noSupportForResignErrMsg); + + throw new CloudRuntimeException(noSupportForResignErrMsg); + } + + try { + VolumeDetailVO volumeDetail = new VolumeDetailVO(volumeInfo.getId(), + "cloneOfTemplate", + String.valueOf(templateInfo.getId()), + false); + + volumeDetail = volumeDetailsDao.persist(volumeDetail); + + AsyncCallFuture future = _volumeService.createVolumeAsync(volumeInfo, volumeInfo.getDataStore()); + VolumeApiResult result = future.get(); + + if (volumeDetail != null) { + volumeDetailsDao.remove(volumeDetail.getId()); + } + + if (result.isFailed()) { + LOGGER.warn("Failed to create a volume: " + result.getResult()); + + throw new CloudRuntimeException(result.getResult()); + } + + volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); + + volumeInfo.processEvent(Event.MigrationRequested); + + volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); + + copyCmdAnswer = performResignature(volumeInfo, hostVO); + + if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { + if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) { + throw new CloudRuntimeException(copyCmdAnswer.getDetails()); } else { - snapshotInfo.processEvent(Event.OperationFailed); + throw new CloudRuntimeException("Unable to create a volume from a template"); } } - catch (Exception ex) { - s_logger.debug(ex.getMessage(), ex); - } + } catch (InterruptedException | ExecutionException ex) { + volumeInfo.getDataStore().getDriver().deleteAsync(volumeInfo.getDataStore(), volumeInfo, null); + + throw new CloudRuntimeException("Create volume from template (ID = " + templateInfo.getId() + ") failed " + ex.getMessage()); } CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); @@ -240,12 +457,40 @@ private Void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, Templat result.setResult(errMsg); callback.complete(result); - - return null; } - private Void handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snapshotInfo, VolumeInfo volumeInfo, AsyncCompletionCallback callback) { + private void handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snapshotInfo, VolumeInfo volumeInfo, AsyncCompletionCallback callback) { + CopyCmdAnswer copyCmdAnswer = null; + String errMsg = null; + try { + HostVO hostVO = getHost(snapshotInfo); + + boolean usingBackendSnapshot = usingBackendSnapshotFor(snapshotInfo); + boolean computeClusterSupportsResign = clusterDao.getSupportsResigning(hostVO.getClusterId()); + + if (usingBackendSnapshot && !computeClusterSupportsResign) { + String noSupportForResignErrMsg = "Unable to locate an applicable host with which to perform a resignature operation : Cluster ID = " + hostVO.getClusterId(); + + LOGGER.warn(noSupportForResignErrMsg); + + throw new CloudRuntimeException(noSupportForResignErrMsg); + } + + boolean canStorageSystemCreateVolumeFromVolume = canStorageSystemCreateVolumeFromVolume(snapshotInfo); + boolean useCloning = usingBackendSnapshot || (canStorageSystemCreateVolumeFromVolume && computeClusterSupportsResign); + + VolumeDetailVO volumeDetail = null; + + if (useCloning) { + volumeDetail = new VolumeDetailVO(volumeInfo.getId(), + "cloneOfSnapshot", + String.valueOf(snapshotInfo.getId()), + false); + + volumeDetail = volumeDetailsDao.persist(volumeDetail); + } + // at this point, the snapshotInfo and volumeInfo should have the same disk offering ID (so either one should be OK to get a DiskOfferingVO instance) DiskOfferingVO diskOffering = _diskOfferingDao.findByIdIncludingRemoved(volumeInfo.getDiskOfferingId()); SnapshotVO snapshot = _snapshotDao.findById(snapshotInfo.getId()); @@ -257,99 +502,123 @@ private Void handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snap VolumeApiResult result = future.get(); + if (volumeDetail != null) { + volumeDetailsDao.remove(volumeDetail.getId()); + } + if (result.isFailed()) { - s_logger.debug("Failed to create a volume: " + result.getResult()); + LOGGER.warn("Failed to create a volume: " + result.getResult()); throw new CloudRuntimeException(result.getResult()); } - } - catch (Exception ex) { - throw new CloudRuntimeException(ex.getMessage()); - } - volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); + volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); - volumeInfo.processEvent(Event.MigrationRequested); + volumeInfo.processEvent(Event.MigrationRequested); - volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); + volumeInfo = _volumeDataFactory.getVolume(volumeInfo.getId(), volumeInfo.getDataStore()); - HostVO hostVO = getHost(snapshotInfo.getDataStore().getId()); - - String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); - int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); - CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), volumeInfo.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); + if (useCloning) { + copyCmdAnswer = performResignature(volumeInfo, hostVO); + } + else { + // asking for a XenServer host here so we don't always prefer to use XenServer hosts that support resigning + // even when we don't need those hosts to do this kind of copy work + hostVO = getHost(snapshotInfo.getDataCenterId(), false); - CopyCmdAnswer copyCmdAnswer = null; + copyCmdAnswer = performCopyOfVdi(volumeInfo, snapshotInfo, hostVO); + } - try { - _volumeService.grantAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); - _volumeService.grantAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); + if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { + if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) { + errMsg = copyCmdAnswer.getDetails(); + } + else { + errMsg = "Unable to create volume from snapshot"; + } + } + } + catch (Exception ex) { + errMsg = ex.getMessage() != null ? ex.getMessage() : "Copy operation failed in 'StorageSystemDataMotionStrategy.handleCreateVolumeFromSnapshotBothOnStorageSystem'"; + } - Map srcDetails = getSnapshotDetails(_storagePoolDao.findById(snapshotInfo.getDataStore().getId()), snapshotInfo); + CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); - copyCommand.setOptions(srcDetails); + result.setResult(errMsg); - Map destDetails = getVolumeDetails(volumeInfo); + callback.complete(result); + } - copyCommand.setOptions2(destDetails); + /** + * If the underlying storage system is making use of read-only snapshots, this gives the storage system the opportunity to + * create a volume from the snapshot so that we can copy the VHD file that should be inside of the snapshot to secondary storage. + * + * The resultant volume must be writable because we need to resign the SR and the VDI that should be inside of it before we copy + * the VHD file to secondary storage. + * + * If the storage system is using writable snapshots, then nothing need be done by that storage system here because we can just + * resign the SR and the VDI that should be inside of the snapshot before copying the VHD file to secondary storage. + */ + private void createVolumeFromSnapshot(HostVO hostVO, SnapshotInfo snapshotInfo, boolean keepGrantedAccess) { + SnapshotDetailsVO snapshotDetails = handleSnapshotDetails(snapshotInfo.getId(), "tempVolume", "create"); - copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); - } - catch (Exception ex) { - throw new CloudRuntimeException(ex.getMessage()); + try { + snapshotInfo.getDataStore().getDriver().createAsync(snapshotInfo.getDataStore(), snapshotInfo, null); } finally { - try { - _volumeService.revokeAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); - } - catch (Exception ex) { - s_logger.debug(ex.getMessage(), ex); - } - - try { - _volumeService.revokeAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); - } - catch (Exception ex) { - s_logger.debug(ex.getMessage(), ex); - } + _snapshotDetailsDao.remove(snapshotDetails.getId()); } - String errMsg = null; + CopyCmdAnswer copyCmdAnswer = performResignature(snapshotInfo, hostVO, keepGrantedAccess); if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) { - if (copyCmdAnswer != null && copyCmdAnswer.getDetails() != null && !copyCmdAnswer.getDetails().isEmpty()) { - errMsg = copyCmdAnswer.getDetails(); + if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) { + throw new CloudRuntimeException(copyCmdAnswer.getDetails()); } else { - errMsg = "Unable to perform host-side operation"; + throw new CloudRuntimeException("Unable to create volume from snapshot"); } } + } - CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer); + /** + * If the underlying storage system needed to create a volume from a snapshot for createVolumeFromSnapshot(HostVO, SnapshotInfo), then + * this is its opportunity to delete that temporary volume and restore properties in snapshot_details to the way they were before the + * invocation of createVolumeFromSnapshot(HostVO, SnapshotInfo). + */ + private void deleteVolumeFromSnapshot(SnapshotInfo snapshotInfo) { + SnapshotDetailsVO snapshotDetails = handleSnapshotDetails(snapshotInfo.getId(), "tempVolume", "delete"); - result.setResult(errMsg); + try { + snapshotInfo.getDataStore().getDriver().createAsync(snapshotInfo.getDataStore(), snapshotInfo, null); + } + finally { + _snapshotDetailsDao.remove(snapshotDetails.getId()); + } + } - callback.complete(result); + private SnapshotDetailsVO handleSnapshotDetails(long csSnapshotId, String name, String value) { + _snapshotDetailsDao.removeDetail(csSnapshotId, name); - return null; + SnapshotDetailsVO snapshotDetails = new SnapshotDetailsVO(csSnapshotId, name, value, false); + + return _snapshotDetailsDao.persist(snapshotDetails); } - private Map getSnapshotDetails(StoragePoolVO storagePoolVO, SnapshotInfo snapshotInfo) { - Map details = new HashMap(); + private boolean canStorageSystemCreateVolumeFromVolume(SnapshotInfo snapshotInfo) { + boolean supportsCloningVolumeFromVolume = false; - details.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); - details.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); + DataStore dataStore = dataStoreMgr.getDataStore(snapshotInfo.getDataStore().getId(), DataStoreRole.Primary); - long snapshotId = snapshotInfo.getId(); + Map mapCapabilities = dataStore.getDriver().getCapabilities(); - details.put(DiskTO.IQN, getProperty(snapshotId, DiskTO.IQN)); + if (mapCapabilities != null) { + String value = mapCapabilities.get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString()); - details.put(DiskTO.CHAP_INITIATOR_USERNAME, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_USERNAME)); - details.put(DiskTO.CHAP_INITIATOR_SECRET, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_SECRET)); - details.put(DiskTO.CHAP_TARGET_USERNAME, getProperty(snapshotId, DiskTO.CHAP_TARGET_USERNAME)); - details.put(DiskTO.CHAP_TARGET_SECRET, getProperty(snapshotId, DiskTO.CHAP_TARGET_SECRET)); + supportsCloningVolumeFromVolume = Boolean.valueOf(value); + } - return details; + return supportsCloningVolumeFromVolume; } private String getProperty(long snapshotId, String property) { @@ -363,68 +632,209 @@ private String getProperty(long snapshotId, String property) { } private Map getVolumeDetails(VolumeInfo volumeInfo) { - Map sourceDetails = new HashMap(); + Map volumeDetails = new HashMap(); VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId()); long storagePoolId = volumeVO.getPoolId(); StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); - sourceDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); - sourceDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); - sourceDetails.put(DiskTO.IQN, volumeVO.get_iScsiName()); + volumeDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); + volumeDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); + volumeDetails.put(DiskTO.IQN, volumeVO.get_iScsiName()); ChapInfo chapInfo = _volumeService.getChapInfo(volumeInfo, volumeInfo.getDataStore()); if (chapInfo != null) { - sourceDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); - sourceDetails.put(DiskTO.CHAP_INITIATOR_SECRET, chapInfo.getInitiatorSecret()); - sourceDetails.put(DiskTO.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername()); - sourceDetails.put(DiskTO.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); + volumeDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); + volumeDetails.put(DiskTO.CHAP_INITIATOR_SECRET, chapInfo.getInitiatorSecret()); + volumeDetails.put(DiskTO.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername()); + volumeDetails.put(DiskTO.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); } - return sourceDetails; + return volumeDetails; } - public HostVO getHost(long dataStoreId) { - StoragePoolVO storagePoolVO = _storagePoolDao.findById(dataStoreId); + private Map getSnapshotDetails(SnapshotInfo snapshotInfo) { + Map snapshotDetails = new HashMap(); - List clusters = _mgr.searchForClusters(storagePoolVO.getDataCenterId(), new Long(0), Long.MAX_VALUE, HypervisorType.XenServer.toString()); + long storagePoolId = snapshotInfo.getDataStore().getId(); + StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); - if (clusters == null) { - throw new CloudRuntimeException("Unable to locate an applicable cluster"); - } + snapshotDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); + snapshotDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); - for (Cluster cluster : clusters) { - if (cluster.getAllocationState() == AllocationState.Enabled) { - List hosts = _hostDao.findByClusterId(cluster.getId()); + long snapshotId = snapshotInfo.getId(); - if (hosts != null) { - for (HostVO host : hosts) { - if (host.getResourceState() == ResourceState.Enabled) { - return host; - } - } - } + snapshotDetails.put(DiskTO.IQN, getProperty(snapshotId, DiskTO.IQN)); + + snapshotDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_USERNAME)); + snapshotDetails.put(DiskTO.CHAP_INITIATOR_SECRET, getProperty(snapshotId, DiskTO.CHAP_INITIATOR_SECRET)); + snapshotDetails.put(DiskTO.CHAP_TARGET_USERNAME, getProperty(snapshotId, DiskTO.CHAP_TARGET_USERNAME)); + snapshotDetails.put(DiskTO.CHAP_TARGET_SECRET, getProperty(snapshotId, DiskTO.CHAP_TARGET_SECRET)); + + return snapshotDetails; + } + + private HostVO getHost(SnapshotInfo snapshotInfo) { + HostVO hostVO = getHost(snapshotInfo.getDataCenterId(), true); + + if (hostVO == null) { + hostVO = getHost(snapshotInfo.getDataCenterId(), false); + + if (hostVO == null) { + throw new CloudRuntimeException("Unable to locate an applicable host in data center with ID = " + snapshotInfo.getDataCenterId()); } } - throw new CloudRuntimeException("Unable to locate an applicable cluster"); + return hostVO; } - @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - return copyAsync(srcData, destData, null, callback); + private HostVO getHost(Long zoneId, boolean computeClusterMustSupportResign) { + Preconditions.checkArgument(zoneId != null, "Zone ID cannot be null."); + + List hosts = _hostDao.listByDataCenterIdAndHypervisorType(zoneId, HypervisorType.XenServer); + + if (hosts == null) { + return null; + } + + List clustersToSkip = new ArrayList<>(); + + Collections.shuffle(hosts, RANDOM); + + for (HostVO host : hosts) { + if (computeClusterMustSupportResign) { + long clusterId = host.getClusterId(); + + if (clustersToSkip.contains(clusterId)) { + continue; + } + + if (clusterDao.getSupportsResigning(clusterId)) { + return host; + } + else { + clustersToSkip.add(clusterId); + } + } + else { + return host; + } + } + + return null; } @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult(null, null); result.setResult("Unsupported operation requested for copying data."); callback.complete(result); + } - return null; + private Map getDetails(DataObject dataObj) { + if (dataObj instanceof VolumeInfo) { + return getVolumeDetails((VolumeInfo)dataObj); + } + else if (dataObj instanceof SnapshotInfo) { + return getSnapshotDetails((SnapshotInfo)dataObj); + } + + throw new CloudRuntimeException("'dataObj' must be of type 'VolumeInfo' or 'SnapshotInfo'."); + } + + private CopyCmdAnswer performResignature(DataObject dataObj, HostVO hostVO) { + return performResignature(dataObj, hostVO, false); + } + + private CopyCmdAnswer performResignature(DataObject dataObj, HostVO hostVO, boolean keepGrantedAccess) { + long storagePoolId = dataObj.getDataStore().getId(); + DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + + Map details = getDetails(dataObj); + + ResignatureCommand command = new ResignatureCommand(details); + + ResignatureAnswer answer = null; + + try { + _volumeService.grantAccess(dataObj, hostVO, dataStore); + + answer = (ResignatureAnswer)_agentMgr.send(hostVO.getId(), command); + } + catch (CloudRuntimeException | AgentUnavailableException | OperationTimedoutException ex) { + keepGrantedAccess = false; + + String msg = "Failed to resign the DataObject with the following ID: " + dataObj.getId(); + + LOGGER.warn(msg, ex); + + throw new CloudRuntimeException(msg + ex.getMessage()); + } + finally { + if (keepGrantedAccess == false) { + _volumeService.revokeAccess(dataObj, hostVO, dataStore); + } + } + + if (answer == null || !answer.getResult()) { + final String errMsg; + + if (answer != null && answer.getDetails() != null && !answer.getDetails().isEmpty()) { + errMsg = answer.getDetails(); + } + else { + errMsg = "Unable to perform resignature operation in 'StorageSystemDataMotionStrategy.performResignature'"; + } + + throw new CloudRuntimeException(errMsg); + } + + VolumeObjectTO newVolume = new VolumeObjectTO(); + + newVolume.setSize(answer.getSize()); + newVolume.setPath(answer.getPath()); + newVolume.setFormat(answer.getFormat()); + + return new CopyCmdAnswer(newVolume); + } + + private CopyCmdAnswer performCopyOfVdi(VolumeInfo volumeInfo, SnapshotInfo snapshotInfo, HostVO hostVO) { + String value = _configDao.getValue(Config.PrimaryStorageDownloadWait.toString()); + int primaryStorageDownloadWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.PrimaryStorageDownloadWait.getDefaultValue())); + CopyCommand copyCommand = new CopyCommand(snapshotInfo.getTO(), volumeInfo.getTO(), primaryStorageDownloadWait, VirtualMachineManager.ExecuteInSequence.value()); + + CopyCmdAnswer copyCmdAnswer = null; + + try { + _volumeService.grantAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); + _volumeService.grantAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); + + Map srcDetails = getSnapshotDetails(snapshotInfo); + + copyCommand.setOptions(srcDetails); + + Map destDetails = getVolumeDetails(volumeInfo); + + copyCommand.setOptions2(destDetails); + + copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand); + } + catch (CloudRuntimeException | AgentUnavailableException | OperationTimedoutException ex) { + String msg = "Failed to perform VDI copy : "; + + LOGGER.warn(msg, ex); + + throw new CloudRuntimeException(msg + ex.getMessage()); + } + finally { + _volumeService.revokeAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore()); + _volumeService.revokeAccess(volumeInfo, hostVO, volumeInfo.getDataStore()); + } + + return copyCmdAnswer; } } diff --git a/engine/storage/image/pom.xml b/engine/storage/image/pom.xml index 6617d42622..779f1399ab 100644 --- a/engine/storage/image/pom.xml +++ b/engine/storage/image/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml b/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml index db517dbd86..51be9d99fa 100644 --- a/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml +++ b/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml @@ -29,7 +29,7 @@ + depends-on="dataObjectManagerImpl, dataStoreManagerImpl, dataMotionServiceImpl, objectInDataStoreManagerImpl, defaultEndPointSelector, templateDataFactoryImpl, imageStoreDetailsUtil" /> diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index 9ab3595371..8dcc439f0a 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -27,6 +27,12 @@ import javax.inject.Inject; +import com.cloud.configuration.Resource; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventUtils; +import org.apache.cloudstack.engine.subsystem.api.storage.Scope; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; @@ -73,6 +79,7 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StoragePool; @@ -135,6 +142,10 @@ public class TemplateServiceImpl implements TemplateService { ConfigurationDao _configDao; @Inject StorageCacheManager _cacheMgr; + @Inject + MessageBus _messageBus; + @Inject + ImageStoreDetailsUtil imageStoreDetailsUtil; class TemplateOpContext extends AsyncRpcContext { final TemplateObject template; @@ -352,6 +363,16 @@ public void handleTemplateSync(DataStore store) { toBeDownloaded.add(tmplt); } } else { + if(tmpltStore.getDownloadState() != Status.DOWNLOADED) { + String etype = EventTypes.EVENT_TEMPLATE_CREATE; + if (tmplt.getFormat() == ImageFormat.ISO) { + etype = EventTypes.EVENT_ISO_CREATE; + } + + UsageEventUtils.publishUsageEvent(etype, tmplt.getAccountId(), zoneId, tmplt.getId(), tmplt.getName(), null, null, + tmpltInfo.getPhysicalSize(), tmpltInfo.getSize(), VirtualMachineTemplate.class.getName(), tmplt.getUuid()); + } + tmpltStore.setDownloadPercent(100); tmpltStore.setDownloadState(Status.DOWNLOADED); tmpltStore.setState(ObjectInDataStoreStateMachine.State.Ready); @@ -402,6 +423,14 @@ public void handleTemplateSync(DataStore store) { tmlpt.setSize(tmpltInfo.getSize()); _templateDao.update(tmplt.getId(), tmlpt); associateTemplateToZone(tmplt.getId(), zoneId); + + String etype = EventTypes.EVENT_TEMPLATE_CREATE; + if (tmplt.getFormat() == ImageFormat.ISO) { + etype = EventTypes.EVENT_ISO_CREATE; + } + + UsageEventUtils.publishUsageEvent(etype, tmplt.getAccountId(), zoneId, tmplt.getId(), tmplt.getName(), null, null, + tmpltInfo.getPhysicalSize(), tmpltInfo.getSize(), VirtualMachineTemplate.class.getName(), tmplt.getUuid()); } } else if (tmplt.getState() == VirtualMachineTemplate.State.NotUploaded || tmplt.getState() == VirtualMachineTemplate.State.UploadInProgress) { s_logger.info("Template Sync did not find " + uniqueName + " on image store " + storeId + " uploaded using SSVM, marking it as failed"); @@ -471,8 +500,12 @@ public void handleTemplateSync(DataStore store) { if (availHypers.contains(tmplt.getHypervisorType())) { s_logger.info("Downloading template " + tmplt.getUniqueName() + " to image store " + store.getName()); associateTemplateToZone(tmplt.getId(), zoneId); - TemplateInfo tmpl = _templateFactory.getTemplate(tmplt.getId(), DataStoreRole.Image); - createTemplateAsync(tmpl, store, null); + TemplateInfo tmpl = _templateFactory.getTemplate(tmplt.getId(), store); + TemplateOpContext context = new TemplateOpContext<>(null,(TemplateObject)tmpl, null); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().createTemplateAsyncCallBack(null, null)); + caller.setContext(context); + createTemplateAsync(tmpl, store, caller); } else { s_logger.info("Skip downloading template " + tmplt.getUniqueName() + " since current data center does not have hypervisor " + tmplt.getHypervisorType().toString()); @@ -563,8 +596,50 @@ public void associateCrosszoneTemplatesToZone(long dcId) { } } + protected Void createTemplateAsyncCallBack(AsyncCallbackDispatcher callback, + TemplateOpContext context) { + TemplateInfo template = context.template; + TemplateApiResult result = callback.getResult(); + if (result.isSuccess()) { + VMTemplateVO tmplt = _templateDao.findById(template.getId()); + // need to grant permission for public templates + if (tmplt.isPublicTemplate()) { + _messageBus.publish(null, TemplateManager.MESSAGE_REGISTER_PUBLIC_TEMPLATE_EVENT, PublishScope.LOCAL, tmplt.getId()); + } + long accountId = tmplt.getAccountId(); + if (template.getSize() != null) { + // publish usage event + String etype = EventTypes.EVENT_TEMPLATE_CREATE; + if (tmplt.getFormat() == ImageFormat.ISO) { + etype = EventTypes.EVENT_ISO_CREATE; + } + // get physical size from template_store_ref table + long physicalSize = 0; + DataStore ds = template.getDataStore(); + TemplateDataStoreVO tmpltStore = _vmTemplateStoreDao.findByStoreTemplate(ds.getId(), template.getId()); + if (tmpltStore != null) { + physicalSize = tmpltStore.getPhysicalSize(); + } else { + s_logger.warn("No entry found in template_store_ref for template id: " + template.getId() + " and image store id: " + ds.getId() + + " at the end of registering template!"); + } + Scope dsScope = ds.getScope(); + if (dsScope.getScopeId() != null) { + UsageEventUtils.publishUsageEvent(etype, template.getAccountId(), dsScope.getScopeId(), template.getId(), template.getName(), null, null, + physicalSize, template.getSize(), VirtualMachineTemplate.class.getName(), template.getUuid()); + } else { + s_logger.warn("Zone scope image store " + ds.getId() + " has a null scope id"); + } + _resourceLimitMgr.incrementResourceCount(accountId, Resource.ResourceType.secondary_storage, template.getSize()); + } + } + + return null; + } + private Map listTemplate(DataStore ssStore) { - ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO()); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(ssStore.getId()); + ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), nfsVersion); EndPoint ep = _epSelector.select(ssStore); Answer answer = null; if (ep == null) { @@ -844,6 +919,25 @@ public AsyncCallFuture prepareTemplateOnPrimary(TemplateInfo return copyAsync(srcTemplate, srcTemplate, (DataStore)pool); } + @Override + public AsyncCallFuture deleteTemplateOnPrimary(TemplateInfo template, StoragePool pool) { + TemplateObject templateObject = (TemplateObject)_templateFactory.getTemplate(template.getId(), (DataStore)pool); + + templateObject.processEvent(ObjectInDataStoreStateMachine.Event.DestroyRequested); + + DataStore dataStore = _storeMgr.getPrimaryDataStore(pool.getId()); + + AsyncCallFuture future = new AsyncCallFuture<>(); + TemplateOpContext context = new TemplateOpContext<>(null, templateObject, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + + caller.setCallback(caller.getTarget().deleteTemplateCallback(null, null)).setContext(context); + + dataStore.getDriver().deleteAsync(dataStore, templateObject, caller); + + return future; + } + protected Void copyTemplateCallBack(AsyncCallbackDispatcher callback, TemplateOpContext context) { TemplateInfo destTemplate = context.getTemplate(); CopyCommandResult result = callback.getResult(); diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java index 473959b081..6e78f190d5 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java @@ -28,7 +28,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; @@ -54,6 +53,9 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; +import com.google.common.base.Strings; + +@SuppressWarnings("serial") public class TemplateObject implements TemplateInfo { private static final Logger s_logger = Logger.getLogger(TemplateObject.class); private VMTemplateVO imageVO; @@ -189,12 +191,15 @@ public void processEvent(ObjectInDataStoreStateMachine.Event event, Answer answe TemplateObjectTO newTemplate = (TemplateObjectTO)cpyAnswer.getNewData(); VMTemplateStoragePoolVO templatePoolRef = templatePoolDao.findByPoolTemplate(getDataStore().getId(), getId()); templatePoolRef.setDownloadPercent(100); - if (newTemplate.getSize() != null) { - templatePoolRef.setTemplateSize(newTemplate.getSize()); - } + + setTemplateSizeIfNeeded(newTemplate, templatePoolRef); + templatePoolRef.setDownloadState(Status.DOWNLOADED); - templatePoolRef.setLocalDownloadPath(newTemplate.getPath()); - templatePoolRef.setInstallPath(newTemplate.getPath()); + + setDownloadPathIfNeeded(newTemplate, templatePoolRef); + + setInstallPathIfNeeded(newTemplate, templatePoolRef); + templatePoolDao.update(templatePoolRef.getId(), templatePoolRef); } } else if (getDataStore().getRole() == DataStoreRole.Image || getDataStore().getRole() == DataStoreRole.ImageCache) { @@ -243,6 +248,33 @@ public void processEvent(ObjectInDataStoreStateMachine.Event event, Answer answe } } + /** + * In the case of managed storage, the install path may already be specified (by the storage plug-in), so do not overwrite it. + */ + private void setInstallPathIfNeeded(TemplateObjectTO template, VMTemplateStoragePoolVO templatePoolRef) { + if (Strings.isNullOrEmpty(templatePoolRef.getInstallPath())) { + templatePoolRef.setInstallPath(template.getPath()); + } + } + + /** + * In the case of managed storage, the local download path may already be specified (by the storage plug-in), so do not overwrite it. + */ + private void setDownloadPathIfNeeded(TemplateObjectTO template, VMTemplateStoragePoolVO templatePoolRef) { + if (Strings.isNullOrEmpty(templatePoolRef.getLocalDownloadPath())) { + templatePoolRef.setLocalDownloadPath(template.getPath()); + } + } + + /** + * In the case of managed storage, the template size may already be specified (by the storage plug-in), so do not overwrite it. + */ + private void setTemplateSizeIfNeeded(TemplateObjectTO template, VMTemplateStoragePoolVO templatePoolRef) { + if (templatePoolRef.getTemplateSize() == 0 && template.getSize() != null) { + templatePoolRef.setTemplateSize(template.getSize()); + } + } + @Override public void incRefCount() { if (dataStore == null) { @@ -299,28 +331,17 @@ public DataTO getTO() { @Override public String getInstallPath() { - if (installPath != null) + if (installPath != null) { return installPath; + } if (dataStore == null) { return null; } - // managed primary data stores should not have an install path - if (dataStore instanceof PrimaryDataStore) { - PrimaryDataStore primaryDataStore = (PrimaryDataStore)dataStore; - - Map details = primaryDataStore.getDetails(); - - boolean managed = details != null && Boolean.parseBoolean(details.get(PrimaryDataStore.MANAGED)); - - if (managed) { - return null; - } - } - DataObjectInStore obj = objectInStoreMgr.findObject(this, dataStore); - return obj.getInstallPath(); + + return obj != null ? obj.getInstallPath() : null; } public void setInstallPath(String installPath) { @@ -435,7 +456,7 @@ public String getTemplateTag() { } @Override - public Map getDetails() { + public Map getDetails() { return imageVO.getDetails(); } diff --git a/engine/storage/integration-test/pom.xml b/engine/storage/integration-test/pom.xml index 50990aa2e8..d648129574 100644 --- a/engine/storage/integration-test/pom.xml +++ b/engine/storage/integration-test/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java index 896342890c..f732805016 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java @@ -51,7 +51,7 @@ public MockLocalNfsSecondaryStorageResource() { } @Override - public String getRootDir(String secUrl) { + public String getRootDir(String secUrl, Integer nfsVersion) { return "/mnt"; } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java index b34b697af0..0e4755e034 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/DirectAgentManagerSimpleImpl.java @@ -278,9 +278,16 @@ public boolean isAgentAttached(long hostId) { } @Override - public boolean handleDirectConnectAgent(Host host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance) throws ConnectionException { + public boolean handleDirectConnectAgent(Host host, StartupCommand[] cmds, ServerResource resource, boolean forRebalance, boolean newHost) throws ConnectionException { // TODO Auto-generated method stub return false; } + @Override + public void notifyMonitorsOfHostAboutToBeRemoved(long hostId) { + } + + @Override + public void notifyMonitorsOfRemovedHost(long hostId, long clusterId) { + } } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java index 1f1ba24b6b..a86b3219ee 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/FakePrimaryDataStoreDriver.java @@ -28,6 +28,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; @@ -44,8 +45,8 @@ public class FakePrimaryDataStoreDriver implements PrimaryDataStoreDriver { boolean snapshotResult = true; @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { - return null; // To change body of implemented methods, use File | Settings | File Templates. + public ChapInfo getChapInfo(DataObject dataObject) { + return null; } @Override @@ -65,8 +66,13 @@ public long getUsedIops(StoragePool storagePool) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { - return volume.getSize(); + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + return dataObject.getSize(); + } + + @Override + public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) { + return 0L; } @Override @@ -90,23 +96,21 @@ public void makeTakeSnapshotSucceed(boolean success) { } @Override - public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback) { - //To change body of implemented methods use File | Settings | File Templates. + public void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback callback) { } @Override public DataTO getTO(DataObject data) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } @Override public DataStoreTO getStoreTO(DataStore store) { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } @Override public void createAsync(DataStore store, DataObject data, AsyncCompletionCallback callback) { - //To change body of implemented methods use File | Settings | File Templates. } @Override @@ -119,22 +123,19 @@ public void deleteAsync(DataStore store, DataObject data, AsyncCompletionCallbac @Override public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback callback) { - //To change body of implemented methods use File | Settings | File Templates. } @Override public boolean canCopy(DataObject srcData, DataObject destData) { - return false; //To change body of implemented methods use File | Settings | File Templates. + return false; } @Override public void resize(DataObject data, AsyncCompletionCallback callback) { - //To change body of implemented methods use File | Settings | File Templates. } @Override public Map getCapabilities() { - // TODO Auto-generated method stub return null; } } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java index accfeb5318..757d96caba 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java @@ -19,25 +19,17 @@ package org.apache.cloudstack.storage.test; import java.util.Map; -import java.util.UUID; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.command.CopyCmdAnswer; -import org.apache.cloudstack.storage.to.SnapshotObjectTO; -import org.apache.cloudstack.storage.to.TemplateObjectTO; -import com.cloud.agent.api.to.DataObjectType; -import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.host.Host; -import com.cloud.storage.Storage; public class MockStorageMotionStrategy implements DataMotionStrategy { @@ -58,46 +50,13 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { throw new UnsupportedOperationException(); } @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - CopyCmdAnswer answer = null; - DataTO data = null; - if (!success) { - CopyCommandResult result = new CopyCommandResult(null, null); - result.setResult("Failed"); - callback.complete(result); - } - if (destData.getType() == DataObjectType.SNAPSHOT) { - SnapshotInfo srcSnapshot = (SnapshotInfo)srcData; - - SnapshotObjectTO newSnapshot = new SnapshotObjectTO(); - newSnapshot.setPath(UUID.randomUUID().toString()); - if (srcSnapshot.getParent() != null) { - newSnapshot.setParentSnapshotPath(srcSnapshot.getParent().getPath()); - } - data = newSnapshot; - } else if (destData.getType() == DataObjectType.TEMPLATE) { - TemplateObjectTO newTemplate = new TemplateObjectTO(); - newTemplate.setPath(UUID.randomUUID().toString()); - newTemplate.setFormat(Storage.ImageFormat.QCOW2); - newTemplate.setSize(10L); - newTemplate.setPhysicalSize(10L); - data = newTemplate; - } - answer = new CopyCmdAnswer(data); - CopyCommandResult result = new CopyCommandResult("something", answer); - callback.complete(result); - return null; - } - - @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult("something", null); callback.complete(result); - return null; } } diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/TestHttp.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/TestHttp.java index b1524f37ef..43a2476891 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/TestHttp.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/TestHttp.java @@ -24,11 +24,9 @@ import java.io.IOException; import java.io.OutputStream; -import junit.framework.Assert; - -import org.apache.commons.httpclient.HttpException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpHead; import org.apache.http.impl.client.DefaultHttpClient; @@ -37,13 +35,15 @@ import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; import org.testng.annotations.Parameters; +import junit.framework.Assert; + @ContextConfiguration(locations = "classpath:/storageContext.xml") public class TestHttp extends AbstractTestNGSpringContextTests { @Test @Parameters("template-url") public void testHttpclient(String templateUrl) { - HttpHead method = new HttpHead(templateUrl); - DefaultHttpClient client = new DefaultHttpClient(); + final HttpHead method = new HttpHead(templateUrl); + final DefaultHttpClient client = new DefaultHttpClient(); OutputStream output = null; long length = 0; @@ -51,34 +51,35 @@ public void testHttpclient(String templateUrl) { HttpResponse response = client.execute(method); length = Long.parseLong(response.getFirstHeader("Content-Length").getValue()); System.out.println(response.getFirstHeader("Content-Length").getValue()); - File localFile = new File("/tmp/test"); + final File localFile = new File("/tmp/test"); if (!localFile.exists()) { localFile.createNewFile(); } - HttpGet getMethod = new HttpGet(templateUrl); + final HttpGet getMethod = new HttpGet(templateUrl); response = client.execute(getMethod); - HttpEntity entity = response.getEntity(); + final HttpEntity entity = response.getEntity(); output = new BufferedOutputStream(new FileOutputStream(localFile)); entity.writeTo(output); - } catch (HttpException e) { + } catch (final ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); - } catch (IOException e) { + } catch (final IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { - if (output != null) + if (output != null) { output.close(); - } catch (IOException e) { + } + } catch (final IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } - File f = new File("/tmp/test"); + final File f = new File("/tmp/test"); Assert.assertEquals(f.length(), length); } } diff --git a/engine/storage/pom.xml b/engine/storage/pom.xml index 1cfd140a6c..cf9a8ea973 100644 --- a/engine/storage/pom.xml +++ b/engine/storage/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml b/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml index 8040d801b3..a45e4ee3e4 100644 --- a/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml +++ b/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml @@ -69,5 +69,7 @@ + + diff --git a/engine/storage/snapshot/pom.xml b/engine/storage/snapshot/pom.xml index c3c216e666..eda47be41e 100644 --- a/engine/storage/snapshot/pom.xml +++ b/engine/storage/snapshot/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml @@ -37,6 +37,11 @@ test-jar test + + org.apache.cloudstack + cloud-engine-storage-volume + ${project.version} + diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java index c6960eb4a1..02691ff318 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/StorageSystemSnapshotStrategy.java @@ -16,14 +16,16 @@ // under the License. package org.apache.cloudstack.storage.snapshot; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import javax.inject.Inject; import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; @@ -38,11 +40,15 @@ import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.springframework.stereotype.Component; + +import com.google.common.base.Optional; + import com.cloud.agent.AgentManager; import com.cloud.agent.api.to.DiskTO; +import com.cloud.dc.dao.ClusterDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; @@ -71,18 +77,18 @@ public class StorageSystemSnapshotStrategy extends SnapshotStrategyBase { private static final Logger s_logger = Logger.getLogger(StorageSystemSnapshotStrategy.class); - @Inject private AgentManager _agentMgr; - @Inject private DataStoreManager _dataStoreMgr; - @Inject private HostDao _hostDao; - @Inject private ManagementService _mgr; - @Inject private PrimaryDataStoreDao _storagePoolDao; - @Inject private SnapshotDao _snapshotDao; - @Inject private SnapshotDataFactory _snapshotDataFactory; - @Inject private SnapshotDataStoreDao _snapshotStoreDao; - @Inject private SnapshotDetailsDao _snapshotDetailsDao; - @Inject private VMInstanceDao _vmInstanceDao; - @Inject private VolumeDao _volumeDao; - @Inject private VolumeService _volService; + @Inject private AgentManager agentMgr; + @Inject private ClusterDao clusterDao; + @Inject private DataStoreManager dataStoreMgr; + @Inject private HostDao hostDao; + @Inject private ManagementService mgr; + @Inject private PrimaryDataStoreDao storagePoolDao; + @Inject private SnapshotDao snapshotDao; + @Inject private SnapshotDataFactory snapshotDataFactory; + @Inject private SnapshotDetailsDao snapshotDetailsDao; + @Inject private VMInstanceDao vmInstanceDao; + @Inject private VolumeDao volumeDao; + @Inject private VolumeService volService; @Override public SnapshotInfo backupSnapshot(SnapshotInfo snapshotInfo) { @@ -91,14 +97,14 @@ public SnapshotInfo backupSnapshot(SnapshotInfo snapshotInfo) { @Override public boolean deleteSnapshot(Long snapshotId) { - SnapshotVO snapshotVO = _snapshotDao.findById(snapshotId); + SnapshotVO snapshotVO = snapshotDao.findById(snapshotId); if (Snapshot.State.Destroyed.equals(snapshotVO.getState())) { return true; } if (Snapshot.State.Error.equals(snapshotVO.getState())) { - _snapshotDao.remove(snapshotId); + snapshotDao.remove(snapshotId); return true; } @@ -107,12 +113,12 @@ public boolean deleteSnapshot(Long snapshotId) { throw new InvalidParameterValueException("Unable to delete snapshotshot " + snapshotId + " because it is in the following state: " + snapshotVO.getState()); } - SnapshotObject snapshotObj = (SnapshotObject)_snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary); + SnapshotObject snapshotObj = (SnapshotObject)snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary); if (snapshotObj == null) { s_logger.debug("Can't find snapshot; deleting it in DB"); - _snapshotDao.remove(snapshotId); + snapshotDao.remove(snapshotId); return true; } @@ -165,7 +171,7 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { throw new CloudRuntimeException("Only the " + ImageFormat.VHD.toString() + " image type is currently supported."); } - SnapshotVO snapshotVO = _snapshotDao.acquireInLockTable(snapshotInfo.getId()); + SnapshotVO snapshotVO = snapshotDao.acquireInLockTable(snapshotInfo.getId()); if (snapshotVO == null) { throw new CloudRuntimeException("Failed to acquire lock on the following snapshot: " + snapshotInfo.getId()); @@ -176,7 +182,24 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { try { volumeInfo.stateTransit(Volume.Event.SnapshotRequested); - // tell the storage driver to create a back-end volume (eventually used to create a new SR on and to copy the VM snapshot VDI to) + // only XenServer is currently supported + HostVO hostVO = getHost(volumeInfo.getId()); + + boolean canStorageSystemCreateVolumeFromSnapshot = canStorageSystemCreateVolumeFromSnapshot(volumeInfo.getPoolId()); + boolean computeClusterSupportsResign = clusterDao.getSupportsResigning(hostVO.getClusterId()); + + // if canStorageSystemCreateVolumeFromSnapshot && computeClusterSupportsResign, then take a back-end snapshot or create a back-end clone; + // else, just create a new back-end volume (eventually used to create a new SR on and to copy a VDI to) + + if (canStorageSystemCreateVolumeFromSnapshot && computeClusterSupportsResign) { + SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO(snapshotInfo.getId(), + "takeSnapshot", + Boolean.TRUE.toString(), + false); + + snapshotDetailsDao.persist(snapshotDetail); + } + result = snapshotSvr.takeSnapshot(snapshotInfo); if (result.isFailed()) { @@ -185,9 +208,9 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { throw new CloudRuntimeException(result.getResult()); } - // send a command to XenServer to create a VM snapshot on the applicable SR (get back the VDI UUID of the VM snapshot) - - performSnapshotAndCopyOnHostSide(volumeInfo, snapshotInfo); + if (!canStorageSystemCreateVolumeFromSnapshot || !computeClusterSupportsResign) { + performSnapshotAndCopyOnHostSide(volumeInfo, snapshotInfo); + } markAsBackedUp((SnapshotObject)result.getSnashot()); } @@ -199,19 +222,35 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshotInfo) { volumeInfo.stateTransit(Volume.Event.OperationFailed); } - _snapshotDao.releaseFromLockTable(snapshotInfo.getId()); + snapshotDao.releaseFromLockTable(snapshotInfo.getId()); } return snapshotInfo; } + private boolean canStorageSystemCreateVolumeFromSnapshot(long storagePoolId) { + boolean supportsCloningVolumeFromSnapshot = false; + + DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + + Map mapCapabilities = dataStore.getDriver().getCapabilities(); + + if (mapCapabilities != null) { + String value = mapCapabilities.get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_SNAPSHOT.toString()); + + supportsCloningVolumeFromSnapshot = Boolean.valueOf(value); + } + + return supportsCloningVolumeFromSnapshot; + } + private void performSnapshotAndCopyOnHostSide(VolumeInfo volumeInfo, SnapshotInfo snapshotInfo) { Map sourceDetails = null; - VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId()); + VolumeVO volumeVO = volumeDao.findById(volumeInfo.getId()); Long vmInstanceId = volumeVO.getInstanceId(); - VMInstanceVO vmInstanceVO = _vmInstanceDao.findById(vmInstanceId); + VMInstanceVO vmInstanceVO = vmInstanceDao.findById(vmInstanceId); Long hostId = null; @@ -233,11 +272,30 @@ private void performSnapshotAndCopyOnHostSide(VolumeInfo volumeInfo, SnapshotInf sourceDetails = getSourceDetails(volumeInfo); } - HostVO hostVO = getHost(hostId, volumeVO); + HostVO hostVO = null; + + if (hostId != null) { + hostVO = hostDao.findById(hostId); + } + else { + Optional optHostVO = getHost(volumeInfo.getDataCenterId(), false); + + if (optHostVO.isPresent()) { + hostVO = optHostVO.get(); + } + } + + if (hostVO == null) { + final String errMsg = "Unable to locate an applicable host"; + + s_logger.error("performSnapshotAndCopyOnHostSide: " + errMsg); + + throw new CloudRuntimeException(errMsg); + } long storagePoolId = volumeVO.getPoolId(); - StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); - DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + StoragePoolVO storagePoolVO = storagePoolDao.findById(storagePoolId); + DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); Map destDetails = getDestDetails(storagePoolVO, snapshotInfo); @@ -248,23 +306,23 @@ private void performSnapshotAndCopyOnHostSide(VolumeInfo volumeInfo, SnapshotInf try { // if sourceDetails != null, we need to connect the host(s) to the volume if (sourceDetails != null) { - _volService.grantAccess(volumeInfo, hostVO, dataStore); + volService.grantAccess(volumeInfo, hostVO, dataStore); } - _volService.grantAccess(snapshotInfo, hostVO, dataStore); + volService.grantAccess(snapshotInfo, hostVO, dataStore); - snapshotAndCopyAnswer = (SnapshotAndCopyAnswer)_agentMgr.send(hostVO.getId(), snapshotAndCopyCommand); + snapshotAndCopyAnswer = (SnapshotAndCopyAnswer)agentMgr.send(hostVO.getId(), snapshotAndCopyCommand); } catch (Exception ex) { throw new CloudRuntimeException(ex.getMessage()); } finally { try { - _volService.revokeAccess(snapshotInfo, hostVO, dataStore); + volService.revokeAccess(snapshotInfo, hostVO, dataStore); // if sourceDetails != null, we need to disconnect the host(s) from the volume if (sourceDetails != null) { - _volService.revokeAccess(volumeInfo, hostVO, dataStore); + volService.revokeAccess(volumeInfo, hostVO, dataStore); } } catch (Exception ex) { @@ -292,22 +350,22 @@ private void performSnapshotAndCopyOnHostSide(VolumeInfo volumeInfo, SnapshotInf path, false); - _snapshotDetailsDao.persist(snapshotDetail); + snapshotDetailsDao.persist(snapshotDetail); } private Map getSourceDetails(VolumeInfo volumeInfo) { - Map sourceDetails = new HashMap(); + Map sourceDetails = new HashMap<>(); - VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId()); + VolumeVO volumeVO = volumeDao.findById(volumeInfo.getId()); long storagePoolId = volumeVO.getPoolId(); - StoragePoolVO storagePoolVO = _storagePoolDao.findById(storagePoolId); + StoragePoolVO storagePoolVO = storagePoolDao.findById(storagePoolId); sourceDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); sourceDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); sourceDetails.put(DiskTO.IQN, volumeVO.get_iScsiName()); - ChapInfo chapInfo = _volService.getChapInfo(volumeInfo, volumeInfo.getDataStore()); + ChapInfo chapInfo = volService.getChapInfo(volumeInfo, volumeInfo.getDataStore()); if (chapInfo != null) { sourceDetails.put(DiskTO.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); @@ -320,7 +378,7 @@ private Map getSourceDetails(VolumeInfo volumeInfo) { } private Map getDestDetails(StoragePoolVO storagePoolVO, SnapshotInfo snapshotInfo) { - Map destDetails = new HashMap(); + Map destDetails = new HashMap<>(); destDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress()); destDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort())); @@ -338,7 +396,7 @@ private Map getDestDetails(StoragePoolVO storagePoolVO, Snapshot } private String getProperty(long snapshotId, String property) { - SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshotId, property); + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotId, property); if (snapshotDetails != null) { return snapshotDetails.getValue(); @@ -347,38 +405,87 @@ private String getProperty(long snapshotId, String property) { return null; } - private HostVO getHost(Long hostId, VolumeVO volumeVO) { - HostVO hostVO = _hostDao.findById(hostId); + private HostVO getHost(long volumeId) { + VolumeVO volumeVO = volumeDao.findById(volumeId); + + Long vmInstanceId = volumeVO.getInstanceId(); + VMInstanceVO vmInstanceVO = vmInstanceDao.findById(vmInstanceId); + + Long hostId = null; + + // if the volume to snapshot is associated with a VM + if (vmInstanceVO != null) { + hostId = vmInstanceVO.getHostId(); + + // if the VM is not associated with a host + if (hostId == null) { + hostId = vmInstanceVO.getLastHostId(); + } + } + + return getHost(volumeVO.getDataCenterId(), hostId); + } + + private HostVO getHost(long zoneId, Long hostId) { + Optional optHostVO = getHost(zoneId, true); + + if (optHostVO.isPresent()) { + return optHostVO.get(); + } + + HostVO hostVO = hostDao.findById(hostId); if (hostVO != null) { return hostVO; } - // pick a host in any XenServer cluster that's in the applicable zone + optHostVO = getHost(zoneId, false); - long zoneId = volumeVO.getDataCenterId(); + if (optHostVO.isPresent()) { + return optHostVO.get(); + } - List clusters = _mgr.searchForClusters(zoneId, new Long(0), Long.MAX_VALUE, HypervisorType.XenServer.toString()); + throw new CloudRuntimeException("Unable to locate an applicable host"); + } + + private Optional getHost(long zoneId, boolean computeClusterMustSupportResign) { + List clusters = mgr.searchForClusters(zoneId, 0L, Long.MAX_VALUE, HypervisorType.XenServer.toString()); if (clusters == null) { - throw new CloudRuntimeException("Unable to locate an applicable cluster"); + clusters = new ArrayList<>(); } + Collections.shuffle(clusters, new Random(System.nanoTime())); + + clusters: for (Cluster cluster : clusters) { if (cluster.getAllocationState() == AllocationState.Enabled) { - List hosts = _hostDao.findByClusterId(cluster.getId()); + List hosts = hostDao.findByClusterId(cluster.getId()); if (hosts != null) { + Collections.shuffle(hosts, new Random(System.nanoTime())); + for (HostVO host : hosts) { if (host.getResourceState() == ResourceState.Enabled) { - return host; + if (computeClusterMustSupportResign) { + if (clusterDao.getSupportsResigning(cluster.getId())) { + return Optional.of(host); + } + else { + // no other host in the cluster in question should be able to satisfy our requirements here, so move on to the next cluster + continue clusters; + } + } + else { + return Optional.of(host); + } } } } } } - throw new CloudRuntimeException("Unable to locate an applicable cluster"); + return Optional.absent(); } private void markAsBackedUp(SnapshotObject snapshotObj) { @@ -406,18 +513,18 @@ public StrategyPriority canHandle(Snapshot snapshot, SnapshotOperation op) { long volumeId = snapshot.getVolumeId(); - VolumeVO volumeVO = _volumeDao.findByIdIncludingRemoved(volumeId); + VolumeVO volumeVO = volumeDao.findByIdIncludingRemoved(volumeId); long storagePoolId = volumeVO.getPoolId(); - DataStore dataStore = _dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); if (dataStore != null) { Map mapCapabilities = dataStore.getDriver().getCapabilities(); if (mapCapabilities != null) { String value = mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString()); - Boolean supportsStorageSystemSnapshots = new Boolean(value); + Boolean supportsStorageSystemSnapshots = Boolean.valueOf(value); if (supportsStorageSystemSnapshots) { return StrategyPriority.HIGHEST; diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java index edd194e605..25444843fe 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java @@ -36,6 +36,7 @@ import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; +import org.apache.cloudstack.storage.datastore.PrimaryDataStoreImpl; import org.apache.cloudstack.storage.to.SnapshotObjectTO; import com.cloud.exception.InvalidParameterValueException; @@ -53,6 +54,7 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; @@ -76,6 +78,8 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase { VolumeDao volumeDao; @Inject SnapshotDataFactory snapshotDataFactory; + @Inject + private SnapshotDao _snapshotDao; @Override public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) { @@ -263,6 +267,10 @@ public boolean deleteSnapshot(Long snapshotId) { //snapshot is deleted on backup storage, need to delete it on primary storage SnapshotDataStoreVO snapshotOnPrimary = snapshotStoreDao.findBySnapshot(snapshotId, DataStoreRole.Primary); if (snapshotOnPrimary != null) { + SnapshotInfo snapshotOnPrimaryInfo = snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary); + if (((PrimaryDataStoreImpl)snapshotOnPrimaryInfo.getDataStore()).getPoolType() == StoragePoolType.RBD) { + snapshotSvr.deleteSnapshot(snapshotOnPrimaryInfo); + } snapshotOnPrimary.setState(State.Destroyed); snapshotStoreDao.update(snapshotOnPrimary.getId(), snapshotOnPrimary); } @@ -283,7 +291,7 @@ public boolean deleteSnapshot(Long snapshotId) { @Override public boolean revertSnapshot(SnapshotInfo snapshot) { if (canHandle(snapshot,SnapshotOperation.REVERT) == StrategyPriority.CANT_HANDLE) { - throw new UnsupportedOperationException("Reverting not supported. Create a template or volume based on the snapshot instead."); + throw new CloudRuntimeException("Reverting not supported. Create a template or volume based on the snapshot instead."); } SnapshotVO snapshotVO = snapshotDao.acquireInLockTable(snapshot.getId()); @@ -371,15 +379,17 @@ public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) { try { SnapshotInfo parent = snapshot.getParent(); - if (backupedSnapshot != null && parent != null) { - Long parentSnapshotId = parent.getId(); - while (parentSnapshotId != null && parentSnapshotId != 0L) { - SnapshotDataStoreVO snapshotDataStoreVO = snapshotStoreDao.findByStoreSnapshot(primaryStore.getRole(), primaryStore.getId(), parentSnapshotId); - if (snapshotDataStoreVO != null) { - parentSnapshotId = snapshotDataStoreVO.getParentSnapshotId(); - snapshotStoreDao.remove(snapshotDataStoreVO.getId()); - } else { - parentSnapshotId = null; + if (backupedSnapshot != null && parent != null && primaryStore instanceof PrimaryDataStoreImpl) { + if (((PrimaryDataStoreImpl)primaryStore).getPoolType() != StoragePoolType.RBD) { + Long parentSnapshotId = parent.getId(); + while (parentSnapshotId != null && parentSnapshotId != 0L) { + SnapshotDataStoreVO snapshotDataStoreVO = snapshotStoreDao.findByStoreSnapshot(primaryStore.getRole(), primaryStore.getId(), parentSnapshotId); + if (snapshotDataStoreVO != null) { + parentSnapshotId = snapshotDataStoreVO.getParentSnapshotId(); + snapshotStoreDao.remove(snapshotDataStoreVO.getId()); + } else { + parentSnapshotId = null; + } } } SnapshotDataStoreVO snapshotDataStoreVO = snapshotStoreDao.findByStoreSnapshot(primaryStore.getRole(), primaryStore.getId(), snapshot.getId()); diff --git a/engine/storage/snapshot/test/resources/db.properties b/engine/storage/snapshot/test/resources/db.properties index a458b2306f..e8e94121fe 100644 --- a/engine/storage/snapshot/test/resources/db.properties +++ b/engine/storage/snapshot/test/resources/db.properties @@ -26,6 +26,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -46,6 +47,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -59,6 +62,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java b/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java index 1f59cc6cc8..3bad62eb57 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java +++ b/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java @@ -160,6 +160,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { // TODO Auto-generated method stub @@ -172,6 +176,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { // TODO Auto-generated method stub diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java index 73a8544f51..194f7bd857 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java @@ -223,7 +223,7 @@ protected boolean filter(ExcludeList avoid, StoragePool pool, DiskProfile dskCh, Volume volume = _volumeDao.findById(dskCh.getVolumeId()); List requestVolumes = new ArrayList(); requestVolumes.add(volume); - return storageMgr.storagePoolHasEnoughIops(requestVolumes, pool) && storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool); + return storageMgr.storagePoolHasEnoughIops(requestVolumes, pool) && storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool, plan.getClusterId()); } /* diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java index 6e36514c49..98eeb6b440 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java @@ -218,6 +218,7 @@ public void setImageStoreProviderMgr(ImageStoreProviderManager imageDataStorePro this.imageStoreProviderMgr = imageDataStoreProviderMgr; } + @Override public List getProviders() { return providers; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java index df9c83641f..f1d932355b 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java @@ -78,7 +78,7 @@ public class ObjectInDataStoreVO implements StateObject'true' or t.value is null"); //Added for exclude cluster's subquery sbuilder.append(" ORDER by rand() limit 1"); String sql = sbuilder.toString(); HostVO host = null; @@ -260,8 +263,9 @@ private List listUpAndConnectingSecondaryStorageVmHost(Long dcId) { public EndPoint select(DataObject object) { DataStore store = object.getDataStore(); EndPoint ep = select(store); - if (ep != null) + if (ep != null) { return ep; + } if (object instanceof TemplateInfo) { TemplateInfo tmplInfo = (TemplateInfo)object; if (store.getScope().getScopeType() == ScopeType.ZONE && store.getScope().getScopeId() == null && tmplInfo.getTemplateType() == TemplateType.SYSTEM) { @@ -380,40 +384,4 @@ public List selectAll(DataStore store) { } return endPoints; } - - @Override - public EndPoint selectHypervisorHost(Scope scope) { - StringBuilder sbuilder = new StringBuilder(); - sbuilder.append(findOneHypervisorHostInScope); - if (scope.getScopeType() == ScopeType.ZONE) { - sbuilder.append(" and h.data_center_id = "); - sbuilder.append(scope.getScopeId()); - } else if (scope.getScopeType() == ScopeType.CLUSTER) { - sbuilder.append(" and h.cluster_id = "); - sbuilder.append(scope.getScopeId()); - } - sbuilder.append(" ORDER by rand() limit 1"); - - String sql = sbuilder.toString(); - HostVO host = null; - TransactionLegacy txn = TransactionLegacy.currentTxn(); - - try ( - PreparedStatement pstmt = txn.prepareStatement(sql); - ResultSet rs = pstmt.executeQuery(); - ) { - while (rs.next()) { - long id = rs.getLong(1); - host = hostDao.findById(id); - } - } catch (SQLException e) { - s_logger.warn("can't find endpoint", e); - } - - if (host == null) { - return null; - } - - return RemoteHostEndPoint.getHypervisorHostEndPoint(host); - } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java index 0068c2d4f7..288fae4e1a 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/BaseImageStoreDriverImpl.java @@ -79,6 +79,7 @@ public abstract class BaseImageStoreDriverImpl implements ImageStoreDriver { VMTemplateZoneDao _vmTemplateZoneDao; @Inject AlertManager _alertMgr; + protected String _proxy = null; protected Proxy getHttpProxy() { diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java new file mode 100755 index 0000000000..28d9d4646e --- /dev/null +++ b/engine/storage/src/org/apache/cloudstack/storage/image/NfsImageStoreDriverImpl.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.image; + +import java.util.Map; + +import javax.inject.Inject; + +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; + +public abstract class NfsImageStoreDriverImpl extends BaseImageStoreDriverImpl { + + @Inject + ImageStoreDetailsDao _imageStoreDetailsDao; + + private static final String NFS_VERSION_DETAILS_KEY = "nfs.version"; + + /** + * Retrieve NFS version to be used for imgStoreId store, if provided in image_store_details table + * @param imgStoreId store id + * @return "nfs.version" associated value for imgStoreId in image_store_details table if exists, null if not + */ + protected Integer getNfsVersion(long imgStoreId){ + Map imgStoreDetails = _imageStoreDetailsDao.getDetails(imgStoreId); + if (imgStoreDetails != null && imgStoreDetails.containsKey(NFS_VERSION_DETAILS_KEY)){ + String nfsVersionParam = imgStoreDetails.get(NFS_VERSION_DETAILS_KEY); + return (nfsVersionParam != null ? Integer.valueOf(nfsVersionParam) : null); + } + return null; + } + +} diff --git a/engine/storage/volume/pom.xml b/engine/storage/volume/pom.xml index 41058374e7..340010ba34 100644 --- a/engine/storage/volume/pom.xml +++ b/engine/storage/volume/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-engine - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml @@ -25,6 +25,11 @@ cloud-engine-storage ${project.version} + + org.apache.cloudstack + cloud-engine-storage-image + ${project.version} + diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java index f3c9e79027..81966784be 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java @@ -26,6 +26,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; @@ -65,6 +66,7 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.storage.encoding.EncodingType; +@SuppressWarnings("serial") public class PrimaryDataStoreImpl implements PrimaryDataStore { private static final Logger s_logger = Logger.getLogger(PrimaryDataStoreImpl.class); @@ -239,10 +241,34 @@ public boolean isManaged() { return pdsv.isManaged(); } + private boolean canCloneVolume() { + return Boolean.valueOf(getDriver().getCapabilities().get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString())); + } + + /** + * The parameter createEntryInTempSpoolRef in the overloaded create(DataObject, boolean) method only applies to managed storage. We pass + * in "true" here. + * + * In the case of managed storage that can create a volume from a volume (clone), if the DataObject passed in is a TemplateInfo, + * we do want to create an entry in the cloud.template_spool_ref table (so that multiple uses of the template can be leveraged from + * the one copy on managed storage). + * + * In cases where UUID resigning is not available, then the code calling "create" should invoke the overloaded "create" method whose second + * parameter is a boolean. This code can pass in "false" so that an entry in the cloud.template_spool_ref table is not created (no template to share + * on the primary storage). + */ + @Override + public DataObject create(DataObject dataObject) { + return create(dataObject, true); + } + + /** + * Please read the comment for the create(DataObject) method if you are planning on passing in "false" for createEntryInTempSpoolRef. + */ @Override - public DataObject create(DataObject obj) { + public DataObject create(DataObject obj, boolean createEntryInTempSpoolRef) { // create template on primary storage - if (obj.getType() == DataObjectType.TEMPLATE && !isManaged()) { + if (obj.getType() == DataObjectType.TEMPLATE && (!isManaged() || (createEntryInTempSpoolRef && canCloneVolume()))) { try { String templateIdPoolIdString = "templateId:" + obj.getId() + "poolId:" + getId(); VMTemplateStoragePoolVO templateStoragePoolRef; diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java index 89af0765fd..64533d54d2 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java @@ -54,6 +54,11 @@ public class DefaultHostListener implements HypervisorHostListener { @Inject PrimaryDataStoreDao primaryStoreDao; + @Override + public boolean hostAdded(long hostId) { + return true; + } + @Override public boolean hostConnect(long hostId, long poolId) throws StorageConflictException { StoragePool pool = (StoragePool)this.dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary); @@ -109,4 +114,13 @@ public boolean hostDisconnected(long hostId, long poolId) { return false; } + @Override + public boolean hostAboutToBeRemoved(long hostId) { + return true; + } + + @Override + public boolean hostRemoved(long hostId, long clusterId) { + return true; + } } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index a2fd656d4b..05ec7d0270 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -19,14 +19,21 @@ package org.apache.cloudstack.storage.volume; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import javax.inject.Inject; +import com.cloud.dc.dao.ClusterDao; import com.cloud.offering.DiskOffering; +import com.cloud.org.Cluster; +import com.cloud.org.Grouping.AllocationState; +import com.cloud.resource.ResourceState; +import com.cloud.server.ManagementService; import com.cloud.storage.RegisterVolumePayload; import com.cloud.utils.Pair; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; @@ -36,6 +43,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionService; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; @@ -59,8 +67,10 @@ import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO; +import org.apache.cloudstack.storage.image.store.TemplateObject; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.log4j.Logger; @@ -80,7 +90,9 @@ import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ResourceAllocationException; import com.cloud.host.Host; +import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; import com.cloud.storage.ScopeType; @@ -134,6 +146,14 @@ public class VolumeServiceImpl implements VolumeService { EndPointSelector _epSelector; @Inject HostDao _hostDao; + @Inject + private PrimaryDataStoreDao storagePoolDao; + @Inject + private HostDetailsDao hostDetailsDao; + @Inject + private ManagementService mgr; + @Inject + private ClusterDao clusterDao; public VolumeServiceImpl() { } @@ -160,11 +180,11 @@ public AsyncCallFuture getFuture() { } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore) { + public ChapInfo getChapInfo(DataObject dataObject, DataStore dataStore) { DataStoreDriver dataStoreDriver = dataStore.getDriver(); if (dataStoreDriver instanceof PrimaryDataStoreDriver) { - return ((PrimaryDataStoreDriver)dataStoreDriver).getChapInfo(volumeInfo); + return ((PrimaryDataStoreDriver)dataStoreDriver).getChapInfo(dataObject); } return null; @@ -554,6 +574,49 @@ protected Void managedCopyBaseImageCallback(AsyncCallbackDispatcher callback, CreateVolumeContext context) { + CreateCmdResult result = callback.getResult(); + VolumeApiResult res = new VolumeApiResult(null); + + res.setResult(result.getResult()); + + AsyncCallFuture future = context.getFuture(); + DataObject templateOnPrimaryStoreObj = context.getVolume(); + + if (result.isSuccess()) { + ((TemplateObject)templateOnPrimaryStoreObj).setInstallPath(result.getPath()); + templateOnPrimaryStoreObj.processEvent(Event.OperationSuccessed, result.getAnswer()); + } + else { + templateOnPrimaryStoreObj.processEvent(Event.OperationFailed); + } + + future.complete(res); + + return null; + } + + protected Void copyManagedTemplateCallback(AsyncCallbackDispatcher callback, CreateBaseImageContext context) { + CopyCommandResult result = callback.getResult(); + VolumeApiResult res = new VolumeApiResult(context.getVolume()); + + res.setResult(result.getResult()); + + AsyncCallFuture future = context.getFuture(); + DataObject templateOnPrimaryStoreObj = context.destObj; + + if (result.isSuccess()) { + templateOnPrimaryStoreObj.processEvent(Event.OperationSuccessed, result.getAnswer()); + } + else { + templateOnPrimaryStoreObj.processEvent(Event.OperationFailed); + } + + future.complete(res); + + return null; + } + @DB protected Void copyBaseImageCallback(AsyncCallbackDispatcher callback, CreateBaseImageContext context) { CopyCommandResult result = callback.getResult(); @@ -636,8 +699,10 @@ protected Void createVolumeFromBaseImageCallBack(AsyncCallbackDispatcher createManagedStorageAndVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, - TemplateInfo srcTemplateInfo, long destHostId) { - PrimaryDataStore destPrimaryDataStore = dataStoreMgr.getPrimaryDataStore(destDataStoreId); - TemplateInfo destTemplateInfo = (TemplateInfo)destPrimaryDataStore.create(srcTemplateInfo); - Host destHost = _hostDao.findById(destHostId); + /** + * Creates a template volume on managed storage, which will be used for creating ROOT volumes by cloning. + * + * @param srcTemplateInfo Source template on secondary storage + * @param destPrimaryDataStore Managed storage on which we need to create the volume + */ + private TemplateInfo createManagedTemplateVolume(TemplateInfo srcTemplateInfo, PrimaryDataStore destPrimaryDataStore) { + // create a template volume on primary storage + AsyncCallFuture createTemplateFuture = new AsyncCallFuture<>(); + TemplateInfo templateOnPrimary = (TemplateInfo)destPrimaryDataStore.create(srcTemplateInfo); - if (destHost == null) { - throw new CloudRuntimeException("Destinatin host should not be null."); + VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId()); + + if (templatePoolRef == null) { + throw new CloudRuntimeException("Failed to find template " + srcTemplateInfo.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId()); } - AsyncCallFuture future = new AsyncCallFuture(); + // At this point, we have an entry in the DB that points to our cached template. + // We need to lock it as there may be other VMs that may get started using the same template. + // We want to avoid having to create multiple cache copies of the same template. + + int storagePoolMaxWaitSeconds = NumbersUtil.parseInt(configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600); + long templatePoolRefId = templatePoolRef.getId(); + + templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolRefId, storagePoolMaxWaitSeconds); + + if (templatePoolRef == null) { + throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templatePoolRefId); + } + + // Template already exists + if (templatePoolRef.getState() == ObjectInDataStoreStateMachine.State.Ready) { + _tmpltPoolDao.releaseFromLockTable(templatePoolRefId); + + return templateOnPrimary; + } try { - // must call driver to have a volume created - AsyncCallFuture createVolumeFuture = createVolumeAsync(volumeInfo, destPrimaryDataStore); + // create a cache volume on the back-end + + templateOnPrimary.processEvent(Event.CreateOnlyRequested); + + CreateVolumeContext createContext = new CreateVolumeContext<>(null, templateOnPrimary, createTemplateFuture); + AsyncCallbackDispatcher createCaller = AsyncCallbackDispatcher.create(this); + + createCaller.setCallback(createCaller.getTarget().createManagedTemplateImageCallback(null, null)).setContext(createContext); + + destPrimaryDataStore.getDriver().createAsync(destPrimaryDataStore, templateOnPrimary, createCaller); + + VolumeApiResult result = createTemplateFuture.get(); + + if (result.isFailed()) { + String errMesg = result.getResult(); + + throw new CloudRuntimeException("Unable to create template " + templateOnPrimary.getId() + + " on primary storage " + destPrimaryDataStore.getId() + ":" + errMesg); + } + } catch (Throwable e) { + s_logger.debug("Failed to create template volume on storage", e); + + templateOnPrimary.processEvent(Event.OperationFailed); + + throw new CloudRuntimeException(e.getMessage()); + } + finally { + _tmpltPoolDao.releaseFromLockTable(templatePoolRefId); + } + + return templateOnPrimary; + } + + /** + * This function copies a template from secondary storage to a template volume + * created on managed storage. This template volume will be used as a cache. + * Instead of copying the template to a ROOT volume every time, a clone is performed instead. + * + * @param srcTemplateInfo Source from which to copy the template + * @param templateOnPrimary Dest to copy to + * @param templatePoolRef Template reference on primary storage (entry in the template_spool_ref) + * @param destPrimaryDataStore The managed primary storage + * @param destHost The host that we will use for the copy + */ + private void copyTemplateToManagedTemplateVolume(TemplateInfo srcTemplateInfo, TemplateInfo templateOnPrimary, VMTemplateStoragePoolVO templatePoolRef, + PrimaryDataStore destPrimaryDataStore, Host destHost) + { + AsyncCallFuture copyTemplateFuture = new AsyncCallFuture<>(); + int storagePoolMaxWaitSeconds = NumbersUtil.parseInt(configDao.getValue(Config.StoragePoolMaxWaitSeconds.key()), 3600); + long templatePoolRefId = templatePoolRef.getId(); + templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolRefId, storagePoolMaxWaitSeconds); + + if (templatePoolRef == null) { + throw new CloudRuntimeException("Unable to acquire lock on VMTemplateStoragePool: " + templatePoolRefId); + } + + if (templatePoolRef.getDownloadState() == Status.DOWNLOADED) { + // There can be cases where we acquired the lock, but the template + // was already copied by a previous thread. Just return in that case. + + s_logger.debug("Template already downloaded, nothing to do"); + + return; + } + + try { + // copy the template from sec storage to the created volume + CreateBaseImageContext copyContext = new CreateBaseImageContext<>( + null, null, destPrimaryDataStore, srcTemplateInfo, + copyTemplateFuture, templateOnPrimary, templatePoolRefId + ); + + AsyncCallbackDispatcher copyCaller = AsyncCallbackDispatcher.create(this); + copyCaller.setCallback(copyCaller.getTarget().copyManagedTemplateCallback(null, null)).setContext(copyContext); + + // Populate details which will be later read by the storage subsystem. + Map details = new HashMap(); + + details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString()); + details.put(PrimaryDataStore.STORAGE_HOST, destPrimaryDataStore.getHostAddress()); + details.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(destPrimaryDataStore.getPort())); + details.put(PrimaryDataStore.MANAGED_STORE_TARGET, ((TemplateObject)templateOnPrimary).getInstallPath()); + details.put(PrimaryDataStore.MANAGED_STORE_TARGET_ROOT_VOLUME, srcTemplateInfo.getUniqueName()); + details.put(PrimaryDataStore.REMOVE_AFTER_COPY, Boolean.TRUE.toString()); + details.put(PrimaryDataStore.VOLUME_SIZE, String.valueOf(templateOnPrimary.getSize())); + + ChapInfo chapInfo = getChapInfo(templateOnPrimary, destPrimaryDataStore); + + if (chapInfo != null) { + details.put(PrimaryDataStore.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); + details.put(PrimaryDataStore.CHAP_INITIATOR_SECRET, chapInfo.getInitiatorSecret()); + details.put(PrimaryDataStore.CHAP_TARGET_USERNAME, chapInfo.getTargetUsername()); + details.put(PrimaryDataStore.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); + } + + templateOnPrimary.processEvent(Event.CopyingRequested); + + destPrimaryDataStore.setDetails(details); + + grantAccess(templateOnPrimary, destHost, destPrimaryDataStore); + + VolumeApiResult result = null; + + try { + motionSrv.copyAsync(srcTemplateInfo, templateOnPrimary, destHost, copyCaller); + + result = copyTemplateFuture.get(); + } + finally { + revokeAccess(templateOnPrimary, destHost, destPrimaryDataStore); + } + + if (result.isFailed()) { + throw new CloudRuntimeException("Failed to copy template " + templateOnPrimary.getId() + + " to primary storage " + destPrimaryDataStore.getId() + ": " + result.getResult()); + // XXX: I find it is useful to destroy the volume on primary storage instead of another thread trying the copy again because I've seen + // something weird happens to the volume (XenServer creates an SR, but the VDI copy can fail). + // For now, I just retry the copy. + } + } + catch (Throwable e) { + s_logger.debug("Failed to create a template on primary storage", e); + + templateOnPrimary.processEvent(Event.OperationFailed); + + throw new CloudRuntimeException(e.getMessage()); + } + finally { + _tmpltPoolDao.releaseFromLockTable(templatePoolRefId); + } + } + + /** + * Clones the template volume on managed storage to the ROOT volume + * + * @param volumeInfo ROOT volume to create + * @param templateOnPrimary Template from which to clone the ROOT volume + * @param destPrimaryDataStore Primary storage of the volume + * @param future For async + */ + private void createManagedVolumeCloneTemplateAsync(VolumeInfo volumeInfo, TemplateInfo templateOnPrimary, PrimaryDataStore destPrimaryDataStore, + AsyncCallFuture future) { + VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId()); + + if (templatePoolRef == null) { + throw new CloudRuntimeException("Failed to find template " + templateOnPrimary.getUniqueName() + " in storage pool " + destPrimaryDataStore.getId()); + } + + //XXX: not sure if this the right thing to do here. We can always fallback to the "copy from sec storage" + if (templatePoolRef.getDownloadState() == Status.NOT_DOWNLOADED) { + throw new CloudRuntimeException("Template " + templateOnPrimary.getUniqueName() + " has not been downloaded to primary storage."); + } + + try { + volumeInfo.processEvent(Event.CreateOnlyRequested); + + CreateVolumeFromBaseImageContext context = + new CreateVolumeFromBaseImageContext<>(null, volumeInfo, destPrimaryDataStore, templateOnPrimary, future, null); + + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + + caller.setCallback(caller.getTarget().createVolumeFromBaseImageCallBack(null, null)); + caller.setContext(context); + + motionSrv.copyAsync(templateOnPrimary, volumeInfo, caller); + } catch (Throwable e) { + s_logger.debug("Failed to clone template on primary storage", e); + + volumeInfo.processEvent(Event.OperationFailed); + + throw new CloudRuntimeException(e.getMessage()); + } + } + + private void createManagedVolumeCopyTemplateAsync(VolumeInfo volumeInfo, PrimaryDataStore primaryDataStore, TemplateInfo srcTemplateInfo, Host destHost, + AsyncCallFuture future) { + try { + // Create a volume on managed storage. + + TemplateInfo destTemplateInfo = (TemplateInfo)primaryDataStore.create(srcTemplateInfo, false); + + AsyncCallFuture createVolumeFuture = createVolumeAsync(volumeInfo, primaryDataStore); VolumeApiResult createVolumeResult = createVolumeFuture.get(); if (createVolumeResult.isFailed()) { throw new CloudRuntimeException("Creation of a volume failed: " + createVolumeResult.getResult()); } - // refresh the volume from the DB - volumeInfo = volFactory.getVolume(volumeInfo.getId(), destPrimaryDataStore); - - grantAccess(volumeInfo, destHost, destPrimaryDataStore); + // Refresh the volume info from the DB. + volumeInfo = volFactory.getVolume(volumeInfo.getId(), primaryDataStore); ManagedCreateBaseImageContext context = new ManagedCreateBaseImageContext(null, volumeInfo, - destPrimaryDataStore, srcTemplateInfo, future); + primaryDataStore, srcTemplateInfo, future); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().managedCopyBaseImageCallback(null, null)).setContext(context); Map details = new HashMap(); details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString()); - details.put(PrimaryDataStore.STORAGE_HOST, destPrimaryDataStore.getHostAddress()); - details.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(destPrimaryDataStore.getPort())); + details.put(PrimaryDataStore.STORAGE_HOST, primaryDataStore.getHostAddress()); + details.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(primaryDataStore.getPort())); // for managed storage, the storage repository (XenServer) or datastore (ESX) name is based off of the iScsiName property of a volume details.put(PrimaryDataStore.MANAGED_STORE_TARGET, volumeInfo.get_iScsiName()); details.put(PrimaryDataStore.MANAGED_STORE_TARGET_ROOT_VOLUME, volumeInfo.getName()); details.put(PrimaryDataStore.VOLUME_SIZE, String.valueOf(volumeInfo.getSize())); - ChapInfo chapInfo = getChapInfo(volumeInfo, destPrimaryDataStore); + ChapInfo chapInfo = getChapInfo(volumeInfo, primaryDataStore); if (chapInfo != null) { details.put(PrimaryDataStore.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername()); @@ -705,17 +973,21 @@ public AsyncCallFuture createManagedStorageAndVolumeFromTemplat details.put(PrimaryDataStore.CHAP_TARGET_SECRET, chapInfo.getTargetSecret()); } - destPrimaryDataStore.setDetails(details); + primaryDataStore.setDetails(details); - motionSrv.copyAsync(srcTemplateInfo, destTemplateInfo, destHost, caller); - } - catch (Throwable t) { + grantAccess(volumeInfo, destHost, primaryDataStore); + + try { + motionSrv.copyAsync(srcTemplateInfo, destTemplateInfo, destHost, caller); + } + finally { + revokeAccess(volumeInfo, destHost, primaryDataStore); + } + } catch (Throwable t) { String errMsg = t.toString(); volumeInfo.processEvent(Event.DestroyRequested); - revokeAccess(volumeInfo, destHost, destPrimaryDataStore); - try { AsyncCallFuture expungeVolumeFuture = expungeVolumeAsync(volumeInfo); @@ -735,10 +1007,112 @@ public AsyncCallFuture createManagedStorageAndVolumeFromTemplat future.complete(result); } + } + + @Override + public AsyncCallFuture createManagedStorageVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId, + TemplateInfo srcTemplateInfo, long destHostId) { + PrimaryDataStore destPrimaryDataStore = dataStoreMgr.getPrimaryDataStore(destDataStoreId); + Host destHost = _hostDao.findById(destHostId); + + if (destHost == null) { + throw new CloudRuntimeException("Destination host should not be null."); + } + + Boolean storageCanCloneVolume = new Boolean( + destPrimaryDataStore.getDriver().getCapabilities().get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString()) + ); + + boolean computeZoneSupportsResign = computeZoneSupportsResign(destHost.getDataCenterId(), destHost.getHypervisorType()); + + AsyncCallFuture future = new AsyncCallFuture<>(); + + if (storageCanCloneVolume && computeZoneSupportsResign) { + s_logger.debug("Storage " + destDataStoreId + " can support cloning using a cached template and host cluster can perform UUID resigning."); + + TemplateInfo templateOnPrimary = destPrimaryDataStore.getTemplate(srcTemplateInfo.getId()); + + if (templateOnPrimary == null) { + templateOnPrimary = createManagedTemplateVolume(srcTemplateInfo, destPrimaryDataStore); + + if (templateOnPrimary == null) { + throw new CloudRuntimeException("Failed to create template " + srcTemplateInfo.getUniqueName() + " on primary storage: " + destDataStoreId); + } + } + + // Copy the template to the template volume. + VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.findByPoolTemplate(destPrimaryDataStore.getId(), templateOnPrimary.getId()); + + if (templatePoolRef == null) { + throw new CloudRuntimeException("Failed to find template " + + srcTemplateInfo.getUniqueName() + " in storage pool " + + destPrimaryDataStore.getId() + ); + } + + if (templatePoolRef.getDownloadState() == Status.NOT_DOWNLOADED) { + copyTemplateToManagedTemplateVolume(srcTemplateInfo, templateOnPrimary, templatePoolRef, destPrimaryDataStore, destHost); + } + + // We have a template on primary storage. Clone it to new volume. + s_logger.debug("Creating a clone from template on primary storage " + destDataStoreId); + createManagedVolumeCloneTemplateAsync(volumeInfo, templateOnPrimary, destPrimaryDataStore, future); + } else { + s_logger.debug("Primary storage does not support cloning or no support for UUID resigning on the host side; copying the template normally"); + createManagedVolumeCopyTemplateAsync(volumeInfo, destPrimaryDataStore, srcTemplateInfo, destHost, future); + } return future; } + private boolean computeZoneSupportsResign(long zoneId, HypervisorType hypervisorType) { + return getHost(zoneId, hypervisorType, true) != null; + } + + private HostVO getHost(Long zoneId, HypervisorType hypervisorType, boolean computeClusterMustSupportResign) { + if (zoneId == null) { + throw new CloudRuntimeException("Zone ID cannot be null."); + } + + List clusters = mgr.searchForClusters(zoneId, new Long(0), Long.MAX_VALUE, hypervisorType.toString()); + + if (clusters == null) { + clusters = new ArrayList<>(); + } + + Collections.shuffle(clusters, new Random(System.nanoTime())); + + clusters: + for (Cluster cluster : clusters) { + if (cluster.getAllocationState() == AllocationState.Enabled) { + List hosts = _hostDao.findByClusterId(cluster.getId()); + + if (hosts != null) { + Collections.shuffle(hosts, new Random(System.nanoTime())); + + for (HostVO host : hosts) { + if (host.getResourceState() == ResourceState.Enabled) { + if (computeClusterMustSupportResign) { + if (clusterDao.getSupportsResigning(cluster.getId())) { + return host; + } + else { + // no other host in the cluster in question should be able to satisfy our requirements here, so move on to the next cluster + continue clusters; + } + } + else { + return host; + } + } + } + } + } + } + + return null; + } + @DB @Override public AsyncCallFuture createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template) { @@ -1332,7 +1706,8 @@ public void resizeVolumeOnHypervisor(long volumeId, long newSize, long destHostI if (ep != null) { VolumeVO volume = volDao.findById(volumeId); PrimaryDataStore primaryDataStore = this.dataStoreMgr.getPrimaryDataStore(volume.getPoolId()); - ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(volume.getPath(), new StorageFilerTO(primaryDataStore), volume.getSize(), newSize, true, instanceName); + ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(volume.getPath(), new StorageFilerTO(primaryDataStore), + volume.getSize(), newSize, true, instanceName, primaryDataStore.isManaged(), volume.get_iScsiName()); answer = ep.sendMessage(resizeCmd); } else { diff --git a/framework/cluster/pom.xml b/framework/cluster/pom.xml index 68142ac7ee..d14e5c455d 100644 --- a/framework/cluster/pom.xml +++ b/framework/cluster/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/cluster/src/com/cloud/cluster/ClusterServiceServletHttpHandler.java b/framework/cluster/src/com/cloud/cluster/ClusterServiceServletHttpHandler.java index 3a85302c4a..e12e0fe5ae 100644 --- a/framework/cluster/src/com/cloud/cluster/ClusterServiceServletHttpHandler.java +++ b/framework/cluster/src/com/cloud/cluster/ClusterServiceServletHttpHandler.java @@ -20,11 +20,11 @@ import java.io.IOException; import java.net.URLDecoder; -import org.apache.commons.httpclient.HttpStatus; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpException; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; import org.apache.http.entity.BasicHttpEntity; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpRequestHandler; @@ -55,14 +55,14 @@ public void handle(HttpRequest request, HttpResponse response, HttpContext conte s_logger.trace("Handle cluster HTTP request done"); } - } catch (Throwable e) { + } catch (final Throwable e) { if (s_logger.isDebugEnabled()) { s_logger.debug("Exception " + e.toString()); } try { writeResponse(response, HttpStatus.SC_INTERNAL_SERVER_ERROR, null); - } catch (Throwable e2) { + } catch (final Throwable e2) { if (s_logger.isDebugEnabled()) { s_logger.debug("Exception " + e2.toString()); } @@ -73,20 +73,20 @@ public void handle(HttpRequest request, HttpResponse response, HttpContext conte @SuppressWarnings("deprecation") private void parseRequest(HttpRequest request) throws IOException { if (request instanceof HttpEntityEnclosingRequest) { - HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest)request; + final HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest)request; - String body = EntityUtils.toString(entityRequest.getEntity()); + final String body = EntityUtils.toString(entityRequest.getEntity()); if (body != null) { - String[] paramArray = body.split("&"); + final String[] paramArray = body.split("&"); if (paramArray != null) { - for (String paramEntry : paramArray) { - String[] paramValue = paramEntry.split("="); + for (final String paramEntry : paramArray) { + final String[] paramValue = paramEntry.split("="); if (paramValue.length != 2) { continue; } - String name = URLDecoder.decode(paramValue[0]); - String value = URLDecoder.decode(paramValue[1]); + final String name = URLDecoder.decode(paramValue[0]); + final String value = URLDecoder.decode(paramValue[1]); if (s_logger.isTraceEnabled()) { s_logger.trace("Parsed request parameter " + name + "=" + value); @@ -103,17 +103,17 @@ private void writeResponse(HttpResponse response, int statusCode, String content content = ""; } response.setStatusCode(statusCode); - BasicHttpEntity body = new BasicHttpEntity(); + final BasicHttpEntity body = new BasicHttpEntity(); body.setContentType("text/html; charset=UTF-8"); - byte[] bodyData = content.getBytes(); + final byte[] bodyData = content.getBytes(); body.setContent(new ByteArrayInputStream(bodyData)); body.setContentLength(bodyData.length); response.setEntity(body); } protected void handleRequest(HttpRequest req, HttpResponse response) { - String method = (String)req.getParams().getParameter("method"); + final String method = (String)req.getParams().getParameter("method"); int nMethod = RemoteMethodConstants.METHOD_UNKNOWN; String responseContent = null; @@ -133,22 +133,24 @@ protected void handleRequest(HttpRequest req, HttpResponse response) { case RemoteMethodConstants.METHOD_UNKNOWN: default: - assert (false); + assert false; s_logger.error("unrecognized method " + nMethod); break; } - } catch (Throwable e) { + } catch (final Throwable e) { s_logger.error("Unexpected exception when processing cluster service request : ", e); } if (responseContent != null) { - if (s_logger.isTraceEnabled()) + if (s_logger.isTraceEnabled()) { s_logger.trace("Write reponse with HTTP OK " + responseContent); + } writeResponse(response, HttpStatus.SC_OK, responseContent); } else { - if (s_logger.isTraceEnabled()) + if (s_logger.isTraceEnabled()) { s_logger.trace("Write reponse with HTTP Bad request"); + } writeResponse(response, HttpStatus.SC_BAD_REQUEST, null); } @@ -156,16 +158,16 @@ protected void handleRequest(HttpRequest req, HttpResponse response) { private String handleDeliverPduMethodCall(HttpRequest req) { - String pduSeq = (String)req.getParams().getParameter("pduSeq"); - String pduAckSeq = (String)req.getParams().getParameter("pduAckSeq"); - String sourcePeer = (String)req.getParams().getParameter("sourcePeer"); - String destPeer = (String)req.getParams().getParameter("destPeer"); - String agentId = (String)req.getParams().getParameter("agentId"); - String gsonPackage = (String)req.getParams().getParameter("gsonPackage"); - String stopOnError = (String)req.getParams().getParameter("stopOnError"); - String pduType = (String)req.getParams().getParameter("pduType"); + final String pduSeq = (String)req.getParams().getParameter("pduSeq"); + final String pduAckSeq = (String)req.getParams().getParameter("pduAckSeq"); + final String sourcePeer = (String)req.getParams().getParameter("sourcePeer"); + final String destPeer = (String)req.getParams().getParameter("destPeer"); + final String agentId = (String)req.getParams().getParameter("agentId"); + final String gsonPackage = (String)req.getParams().getParameter("gsonPackage"); + final String stopOnError = (String)req.getParams().getParameter("stopOnError"); + final String pduType = (String)req.getParams().getParameter("pduType"); - ClusterServicePdu pdu = new ClusterServicePdu(); + final ClusterServicePdu pdu = new ClusterServicePdu(); pdu.setSourcePeer(sourcePeer); pdu.setDestPeer(destPeer); pdu.setAgentId(Long.parseLong(agentId)); @@ -180,7 +182,7 @@ private String handleDeliverPduMethodCall(HttpRequest req) { } private String handlePingMethodCall(HttpRequest req) { - String callingPeer = (String)req.getParams().getParameter("callingPeer"); + final String callingPeer = (String)req.getParams().getParameter("callingPeer"); if (s_logger.isDebugEnabled()) { s_logger.debug("Handle ping request from " + callingPeer); diff --git a/framework/config/pom.xml b/framework/config/pom.xml index d9d9c6cfc2..349e9f29d3 100644 --- a/framework/config/pom.xml +++ b/framework/config/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/db/pom.xml b/framework/db/pom.xml index f311ecea57..71b9af36b4 100644 --- a/framework/db/pom.xml +++ b/framework/db/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/db/src/com/cloud/utils/db/DriverLoader.java b/framework/db/src/com/cloud/utils/db/DriverLoader.java new file mode 100644 index 0000000000..06c8da5c35 --- /dev/null +++ b/framework/db/src/com/cloud/utils/db/DriverLoader.java @@ -0,0 +1,69 @@ +// 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 +// 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.utils.db; + +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.log4j.Logger; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DriverLoader { + + private static final Logger LOGGER = Logger.getLogger(DriverLoader.class.getName()); + private static final List LOADED_DRIVERS; + private static final Map DRIVERS; + + static { + DRIVERS = new HashMap(); + DRIVERS.put("jdbc:mysql", "com.mysql.jdbc.Driver"); + DRIVERS.put("jdbc:postgresql", "org.postgresql.Driver"); + DRIVERS.put("jdbc:h2", "org.h2.Driver"); + + LOADED_DRIVERS = new ArrayList(); + } + + + public static void loadDriver(String dbDriver) { + String driverClass = DRIVERS.get(dbDriver); + if (driverClass == null) { + LOGGER.error("DB driver type " + dbDriver + " is not supported!"); + throw new CloudRuntimeException("DB driver type " + dbDriver + " is not supported!"); + } + + if (LOADED_DRIVERS.contains(dbDriver)) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("DB driver " + driverClass + " was already loaded."); + } + return; + } + + try { + Class.forName(driverClass).newInstance(); + LOADED_DRIVERS.add(dbDriver); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Successfully loaded DB driver " + driverClass); + } + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + LOGGER.error("Failed to load DB driver " + driverClass); + throw new CloudRuntimeException("Failed to load DB driver " + driverClass, e); + } + } + +} diff --git a/framework/db/src/com/cloud/utils/db/GenericDaoBase.java b/framework/db/src/com/cloud/utils/db/GenericDaoBase.java index 29adbe257a..f1b8d0d4dc 100644 --- a/framework/db/src/com/cloud/utils/db/GenericDaoBase.java +++ b/framework/db/src/com/cloud/utils/db/GenericDaoBase.java @@ -942,12 +942,18 @@ protected List listIncludingRemovedBy(final SearchCriteria sc) { @DB() @SuppressWarnings("unchecked") public T findById(final ID id) { + T result = null; if (_cache != null) { final Element element = _cache.get(id); - return element == null ? lockRow(id, null) : (T)element.getObjectValue(); + if (element == null) { + result = lockRow(id, null); + } else { + result = (T)element.getObjectValue(); + } } else { - return lockRow(id, null); + result = lockRow(id, null); } + return result; } @Override @@ -968,8 +974,19 @@ public T findByUuidIncludingRemoved(final String uuid) { @Override @DB() - public T findByIdIncludingRemoved(ID id) { - return findById(id, true, null); + public T findByIdIncludingRemoved(final ID id) { + T result = null; + if (_cache != null) { + final Element element = _cache.get(id); + if (element == null) { + result = findById(id, true, null); + } else { + result = (T)element.getObjectValue(); + } + } else { + result = findById(id, true, null); + } + return result; } @Override diff --git a/framework/db/src/com/cloud/utils/db/SqlGenerator.java b/framework/db/src/com/cloud/utils/db/SqlGenerator.java index 864ee73274..e6cb9cb889 100644 --- a/framework/db/src/com/cloud/utils/db/SqlGenerator.java +++ b/framework/db/src/com/cloud/utils/db/SqlGenerator.java @@ -38,10 +38,12 @@ import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.FetchType; +import javax.persistence.MappedSuperclass; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.SecondaryTable; import javax.persistence.TableGenerator; +import org.apache.commons.lang.ArrayUtils; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; import com.cloud.utils.db.Attribute.Flag; @@ -54,6 +56,7 @@ public class SqlGenerator { LinkedHashMap> _ids; HashMap _generators; ArrayList _ecAttrs; + Field[] _mappedSuperclassFields; public SqlGenerator(Class clazz) { _clazz = clazz; @@ -91,6 +94,12 @@ protected boolean checkMethods(Class clazz, Map attrs) { protected void buildAttributes(Class clazz, String tableName, AttributeOverride[] overrides, boolean embedded, boolean isId) { if (!embedded && clazz.getAnnotation(Entity.class) == null) { + // A class designated with the MappedSuperclass annotation can be mapped in the same way as an entity + // except that the mappings will apply only to its subclasses since no table exists for the mapped superclass itself + if (clazz.getAnnotation(MappedSuperclass.class) != null){ + Field[] declaredFields = clazz.getDeclaredFields(); + _mappedSuperclassFields = (Field[]) ArrayUtils.addAll(_mappedSuperclassFields, declaredFields); + } return; } @@ -105,6 +114,8 @@ protected void buildAttributes(Class clazz, String tableName, AttributeOverri } Field[] fields = clazz.getDeclaredFields(); + fields = (Field[]) ArrayUtils.addAll(fields, _mappedSuperclassFields); + _mappedSuperclassFields = null; for (Field field : fields) { field.setAccessible(true); diff --git a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java index af834ca115..847ec1ee29 100644 --- a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java +++ b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java @@ -1024,6 +1024,7 @@ public static void initDataSource(Properties dbProps) { final String cloudUsername = dbProps.getProperty("db.cloud.username"); final String cloudPassword = dbProps.getProperty("db.cloud.password"); final String cloudHost = dbProps.getProperty("db.cloud.host"); + final String cloudDriver = dbProps.getProperty("db.cloud.driver"); final int cloudPort = Integer.parseInt(dbProps.getProperty("db.cloud.port")); final String cloudDbName = dbProps.getProperty("db.cloud.name"); final boolean cloudAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.cloud.autoReconnect")); @@ -1072,10 +1073,12 @@ public static void initDataSource(Properties dbProps) { new GenericObjectPool(null, cloudMaxActive, GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION, cloudMaxWait, cloudMaxIdle, cloudTestOnBorrow, false, cloudTimeBtwEvictionRunsMillis, 1, cloudMinEvcitableIdleTimeMillis, cloudTestWhileIdle); - final ConnectionFactory cloudConnectionFactory = - new DriverManagerConnectionFactory("jdbc:mysql://" + cloudHost + (s_dbHAEnabled ? "," + cloudSlaves : "") + ":" + cloudPort + "/" + cloudDbName + - "?autoReconnect=" + cloudAutoReconnect + (url != null ? "&" + url : "") + (useSSL ? "&useSSL=true" : "") + - (s_dbHAEnabled ? "&" + cloudDbHAParams : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""), cloudUsername, cloudPassword); + final String cloudConnectionUri = cloudDriver + "://" + cloudHost + (s_dbHAEnabled ? "," + cloudSlaves : "") + ":" + cloudPort + "/" + cloudDbName + + "?autoReconnect=" + cloudAutoReconnect + (url != null ? "&" + url : "") + (useSSL ? "&useSSL=true" : "") + + (s_dbHAEnabled ? "&" + cloudDbHAParams : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""); + DriverLoader.loadDriver(cloudDriver); + + final ConnectionFactory cloudConnectionFactory = new DriverManagerConnectionFactory(cloudConnectionUri, cloudUsername, cloudPassword); final KeyedObjectPoolFactory poolableObjFactory = (cloudPoolPreparedStatements ? new StackKeyedObjectPoolFactory() : null); @@ -1092,6 +1095,7 @@ public static void initDataSource(Properties dbProps) { final String usageUsername = dbProps.getProperty("db.usage.username"); final String usagePassword = dbProps.getProperty("db.usage.password"); final String usageHost = dbProps.getProperty("db.usage.host"); + final String usageDriver = dbProps.getProperty("db.usage.driver"); final int usagePort = Integer.parseInt(dbProps.getProperty("db.usage.port")); final String usageDbName = dbProps.getProperty("db.usage.name"); final boolean usageAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.usage.autoReconnect")); @@ -1100,11 +1104,12 @@ public static void initDataSource(Properties dbProps) { final GenericObjectPool usageConnectionPool = new GenericObjectPool(null, usageMaxActive, GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION, usageMaxWait, usageMaxIdle); - final ConnectionFactory usageConnectionFactory = - new DriverManagerConnectionFactory("jdbc:mysql://" + usageHost + (s_dbHAEnabled ? "," + dbProps.getProperty("db.cloud.slaves") : "") + ":" + usagePort + - "/" + usageDbName + "?autoReconnect=" + usageAutoReconnect + (usageUrl != null ? "&" + usageUrl : "") + - (s_dbHAEnabled ? "&" + getDBHAParams("usage", dbProps) : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""), usageUsername, - usagePassword); + final String usageConnectionUri = usageDriver + "://" + usageHost + (s_dbHAEnabled ? "," + dbProps.getProperty("db.cloud.slaves") : "") + ":" + usagePort + + "/" + usageDbName + "?autoReconnect=" + usageAutoReconnect + (usageUrl != null ? "&" + usageUrl : "") + + (s_dbHAEnabled ? "&" + getDBHAParams("usage", dbProps) : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : ""); + DriverLoader.loadDriver(usageDriver); + + final ConnectionFactory usageConnectionFactory = new DriverManagerConnectionFactory(usageConnectionUri, usageUsername, usagePassword); final PoolableConnectionFactory usagePoolableConnectionFactory = new PoolableConnectionFactory(usageConnectionFactory, usageConnectionPool, new StackKeyedObjectPoolFactory(), null, false, false); @@ -1120,6 +1125,7 @@ public static void initDataSource(Properties dbProps) { final String simulatorUsername = dbProps.getProperty("db.simulator.username"); final String simulatorPassword = dbProps.getProperty("db.simulator.password"); final String simulatorHost = dbProps.getProperty("db.simulator.host"); + final String simulatorDriver = dbProps.getProperty("db.simulator.driver"); final int simulatorPort = Integer.parseInt(dbProps.getProperty("db.simulator.port")); final String simulatorDbName = dbProps.getProperty("db.simulator.name"); final boolean simulatorAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.simulator.autoReconnect")); @@ -1127,9 +1133,11 @@ public static void initDataSource(Properties dbProps) { final GenericObjectPool simulatorConnectionPool = new GenericObjectPool(null, simulatorMaxActive, GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION, simulatorMaxWait, simulatorMaxIdle); - final ConnectionFactory simulatorConnectionFactory = - new DriverManagerConnectionFactory("jdbc:mysql://" + simulatorHost + ":" + simulatorPort + "/" + simulatorDbName + "?autoReconnect=" + - simulatorAutoReconnect, simulatorUsername, simulatorPassword); + final String simulatorConnectionUri = simulatorDriver + "://" + simulatorHost + ":" + simulatorPort + "/" + simulatorDbName + "?autoReconnect=" + + simulatorAutoReconnect; + DriverLoader.loadDriver(simulatorDriver); + + final ConnectionFactory simulatorConnectionFactory = new DriverManagerConnectionFactory(simulatorConnectionUri, simulatorUsername, simulatorPassword); final PoolableConnectionFactory simulatorPoolableConnectionFactory = new PoolableConnectionFactory(simulatorConnectionFactory, simulatorConnectionPool, new StackKeyedObjectPoolFactory(), null, false, false); diff --git a/framework/db/test/db.properties b/framework/db/test/db.properties index 49fd68aa93..c7aeaad264 100644 --- a/framework/db/test/db.properties +++ b/framework/db/test/db.properties @@ -29,6 +29,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -49,6 +50,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -62,6 +65,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/framework/events/pom.xml b/framework/events/pom.xml index d8a69cf572..a633a779fc 100644 --- a/framework/events/pom.xml +++ b/framework/events/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/ipc/pom.xml b/framework/ipc/pom.xml index dee2edf589..0341ff7dea 100644 --- a/framework/ipc/pom.xml +++ b/framework/ipc/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/ipc/src/org/apache/cloudstack/framework/async/Void.java b/framework/ipc/src/org/apache/cloudstack/framework/async/Void.java deleted file mode 100644 index b4c6d4a173..0000000000 --- a/framework/ipc/src/org/apache/cloudstack/framework/async/Void.java +++ /dev/null @@ -1,27 +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.framework.async; - -/** - * This is place-holder class to help AsyncMethod to indicate void return value - * public void AsyncMethod(Object realParam, AsyncCompletionCallback callback) { - * - */ -public class Void { -} diff --git a/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleListenerStyleCaller.java b/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleListenerStyleCaller.java index b1dbfc5a16..2c7c86f0b6 100644 --- a/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleListenerStyleCaller.java +++ b/framework/ipc/test/org/apache/cloudstack/framework/codestyle/AsyncSampleListenerStyleCaller.java @@ -23,14 +23,5 @@ public class AsyncSampleListenerStyleCaller { public void MethodThatWillCallAsyncMethod() { String vol = new String(); - - /* _ds.createVolume(vol, - new AsyncCompletionCallback() { - @Override - public void complete(String resultObject) { - // TODO Auto-generated method stub - - } - });*/ } } diff --git a/framework/jobs/pom.xml b/framework/jobs/pom.xml index dd3cce4814..ff17f48358 100644 --- a/framework/jobs/pom.xml +++ b/framework/jobs/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/jobs/test/resources/db.properties b/framework/jobs/test/resources/db.properties index 9d250ba8b0..235de85869 100644 --- a/framework/jobs/test/resources/db.properties +++ b/framework/jobs/test/resources/db.properties @@ -22,6 +22,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -42,6 +43,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -55,6 +58,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/framework/managed-context/pom.xml b/framework/managed-context/pom.xml index 72572348fc..e2058fe03f 100644 --- a/framework/managed-context/pom.xml +++ b/framework/managed-context/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-maven-standard - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../maven-standard/pom.xml diff --git a/framework/pom.xml b/framework/pom.xml index 7b58cdd098..a60841c750 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT install diff --git a/framework/quota/pom.xml b/framework/quota/pom.xml index 1687892576..82d43cdd4d 100644 --- a/framework/quota/pom.xml +++ b/framework/quota/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java index a57e0c27db..b31af52c00 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java @@ -27,7 +27,6 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.TransactionLegacy; -import com.cloud.utils.exception.CloudRuntimeException; import com.google.common.base.Strings; import com.sun.mail.smtp.SMTPMessage; import com.sun.mail.smtp.SMTPSSLTransport; @@ -83,6 +82,8 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana private ConfigurationDao _configDao; @Inject private QuotaUsageDao _quotaUsage; + @Inject + private QuotaManager _quotaManager; private EmailQuotaAlert _emailQuotaAlert; private boolean _lockAccountEnforcement = false; @@ -153,12 +154,13 @@ public void checkAndSendQuotaAlertEmails() { BigDecimal thresholdBalance = quotaAccount.getQuotaMinBalance(); if (accountBalance != null) { AccountVO account = _accountDao.findById(quotaAccount.getId()); + if (account == null) continue; // the account is removed if (s_logger.isDebugEnabled()) { s_logger.debug("checkAndSendQuotaAlertEmails: Check id=" + account.getId() + " bal=" + accountBalance + ", alertDate=" + alertDate + ", lockable=" + lockable); } if (accountBalance.compareTo(zeroBalance) < 0) { if (_lockAccountEnforcement && (lockable == 1)) { - if (account.getType() == Account.ACCOUNT_TYPE_NORMAL) { + if (_quotaManager.isLockable(account)) { s_logger.info("Locking account " + account.getAccountName() + " due to quota < 0."); lockAccount(account.getId()); } @@ -382,7 +384,8 @@ protected PasswordAuthentication getPasswordAuthentication() { public void sendQuotaAlert(List emails, String subject, String body) throws MessagingException, UnsupportedEncodingException { if (_smtpSession == null) { - throw new CloudRuntimeException("Unable to create smtp session."); + s_logger.error("Unable to create smtp session."); + return; } SMTPMessage msg = new SMTPMessage(_smtpSession); msg.setSender(new InternetAddress(_emailSender, _emailSender)); diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaManager.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaManager.java index 1cda3b22e4..7811bcbcca 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaManager.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaManager.java @@ -16,10 +16,13 @@ //under the License. package org.apache.cloudstack.quota; +import com.cloud.user.AccountVO; import com.cloud.utils.component.Manager; public interface QuotaManager extends Manager { boolean calculateQuotaUsage(); + boolean isLockable(AccountVO account); + } diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java index b039e26a9b..7f592f85cb 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -220,7 +220,9 @@ public void processQuotaBalanceForAccount(final AccountVO account, final List= s_LAST_STATEMENT_SENT_DAYS + 1) { + BigDecimal quotaUsage = _quotaUsage.findTotalQuotaUsage(account.getAccountId(), account.getDomainId(), null, interval[0].getTime(), interval[1].getTime()); + s_logger.info("For account=" + quotaAccount.getId() + ", quota used = " + quotaUsage); + // send statement + deferredQuotaEmailList.add(new DeferredQuotaEmail(account, quotaAccount, quotaUsage, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_STATEMENT)); + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("For " + quotaAccount.getId() + " the statement has been sent recently"); + } } } } else if (lastStatementDate != null) { @@ -263,7 +265,7 @@ public Calendar[] getCurrentStatementTime() { return null; } - public Calendar[] statementTime(final Calendar today, final STATEMENT_PERIODS period) { + public Calendar[] statementTime(final Calendar today, final QuotaStatementPeriods period) { //check if it is statement time int day_of_month = today.get(Calendar.DAY_OF_MONTH); int month_of_year = today.get(Calendar.MONTH); diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java index aa650e165a..d8ce7acc97 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java @@ -156,7 +156,7 @@ public List doInTransaction(final TransactionStatus status) { // get records before startDate to find start balance for (QuotaBalanceVO entry : quotaUsageRecords) { if (s_logger.isDebugEnabled()) { - s_logger.debug("FindQuotaBalIance Entry=" + entry); + s_logger.debug("FindQuotaBalance Entry=" + entry); } if (entry.getCreditsId() > 0) { trimmedRecords.add(entry); diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java index b454a14b92..509702a867 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java @@ -62,7 +62,7 @@ public QuotaBalanceVO(final QuotaCreditsVO credit) { this.accountId = credit.getAccountId(); this.domainId = credit.getDomainId(); this.creditBalance = credit.getCredit(); - this.updatedOn = credit.getUpdatedOn() == null ? null : new Date(credit.getUpdatedOn().getTime()); + this.updatedOn = credit.getUpdatedOn() == null ? null : new Date(credit.getUpdatedOn().getTime()); this.creditsId = credit.getId(); } @@ -72,7 +72,7 @@ public QuotaBalanceVO(final Long accountId, final Long domainId, final BigDecima this.domainId = domainId; this.creditBalance = creditBalance; this.creditsId = 0L; - this.updatedOn = updatedOn == null ? null : new Date(updatedOn.getTime()); + this.updatedOn = updatedOn == null ? null : new Date(updatedOn.getTime()); } @Override @@ -108,6 +108,10 @@ public void setCreditsId(Long creditsId) { this.creditsId = creditsId; } + public boolean isBalanceEntry(){ + return creditsId==0; + } + public BigDecimal getCreditBalance() { return creditBalance; } @@ -121,7 +125,7 @@ public Date getUpdatedOn() { } public void setUpdatedOn(Date updatedOn) { - this.updatedOn = updatedOn == null ? null : new Date(updatedOn.getTime()); + this.updatedOn = updatedOn == null ? null : new Date(updatedOn.getTime()); } @Override diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java index 2d11edda77..795a178238 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java @@ -16,6 +16,7 @@ //under the License. package org.apache.cloudstack.quota.vo; +import java.util.HashMap; import java.util.Map; import javax.persistence.Column; @@ -74,14 +75,9 @@ public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering @Column(name = "deployment_planner") private String deploymentPlanner = null; - // This is a delayed load value. If the value is null, - // then this field has not been loaded yet. - // Call service offering dao to load it. @Transient - Map details; + Map details = new HashMap(); - // This flag is required to tell if the offering is dynamic once the cpu, memory and speed are set. - // In some cases cpu, memory and speed are set to non-null values even if the offering is dynamic. @Transient boolean isDynamic; @@ -90,7 +86,7 @@ protected ServiceOfferingVO() { } public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, String displayText, - ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, boolean defaultUse) { + ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, boolean defaultUse) { super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true); this.cpu = cpu; this.ramSize = ramSize; @@ -105,7 +101,8 @@ public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer spee } public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse, - boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, Long domainId) { + boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, + VirtualMachine.Type vmType, Long domainId) { super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true, domainId); this.cpu = cpu; this.ramSize = ramSize; @@ -118,68 +115,26 @@ public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer spee this.vmType = vmType == null ? null : vmType.toString().toLowerCase(); } - public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, - boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, - VirtualMachine.Type vmType, Long domainId, String hostTag) { - this(name, - cpu, - ramSize, - speed, - rateMbps, - multicastRateMbps, - offerHA, - limitResourceUse, - volatileVm, - displayText, - provisioningType, - useLocalStorage, - recreatable, - tags, - systemUse, - vmType, - domainId); + public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, + boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, + VirtualMachine.Type vmType, Long domainId, String hostTag) { + this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, provisioningType, useLocalStorage, recreatable, tags, + systemUse, vmType, domainId); this.hostTag = hostTag; } - public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, - boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, - VirtualMachine.Type vmType, Long domainId, String hostTag, String deploymentPlanner) { - this(name, - cpu, - ramSize, - speed, - rateMbps, - multicastRateMbps, - offerHA, - limitResourceUse, - volatileVm, - displayText, - provisioningType, - useLocalStorage, - recreatable, - tags, - systemUse, - vmType, - domainId, - hostTag); + public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitResourceUse, + boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, + VirtualMachine.Type vmType, Long domainId, String hostTag, String deploymentPlanner) { + this(name, cpu, ramSize, speed, rateMbps, multicastRateMbps, offerHA, limitResourceUse, volatileVm, displayText, provisioningType, useLocalStorage, recreatable, tags, + systemUse, vmType, domainId, hostTag); this.deploymentPlanner = deploymentPlanner; } public ServiceOfferingVO(ServiceOfferingVO offering) { - super(offering.getId(), - offering.getName(), - offering.getDisplayText(), - offering.getProvisioningType(), - false, - offering.getTags(), - offering.isRecreatable(), - offering.getUseLocalStorage(), - offering.getSystemUse(), - true, - offering.isCustomizedIops()== null ? false:offering.isCustomizedIops(), - offering.getDomainId(), - offering.getMinIops(), - offering.getMaxIops()); + super(offering.getId(), offering.getName(), offering.getDisplayText(), offering.getProvisioningType(), false, offering.getTags(), offering.isRecreatable(), + offering.getUseLocalStorage(), offering.getSystemUse(), true, offering.isCustomizedIops() == null ? false : offering.isCustomizedIops(), offering.getDomainId(), + offering.getMinIops(), offering.getMaxIops()); cpu = offering.getCpu(); ramSize = offering.getRamSize(); speed = offering.getSpeed(); @@ -310,14 +265,10 @@ public Map getDetails() { } public String getDetail(String name) { - assert (details != null) : "Did you forget to load the details?"; - - return details != null ? details.get(name) : null; + return details.get(name); } - public void setDetail(String name, String value) { - assert (details != null) : "Did you forget to load the details?"; - + public void addDetail(String name, String value) { details.put(name, value); } diff --git a/framework/quota/test/org/apache/cloudstack/quota/QuotaManagerImplTest.java b/framework/quota/test/org/apache/cloudstack/quota/QuotaManagerImplTest.java index 792728f5e8..c9f6dcd5a3 100644 --- a/framework/quota/test/org/apache/cloudstack/quota/QuotaManagerImplTest.java +++ b/framework/quota/test/org/apache/cloudstack/quota/QuotaManagerImplTest.java @@ -197,4 +197,42 @@ public void testProcessQuotaBalanceForAccount() { Mockito.verify(quotaAcc, Mockito.times(1)).persistQuotaAccount(Mockito.any(QuotaAccountVO.class)); } + private AccountVO accountVO = new AccountVO(); + + @Test + public void testAdminLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_ADMIN); + assertFalse(quotaManager.isLockable(accountVO)); + } + + @Test + public void testNormalLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_NORMAL); + assertTrue(quotaManager.isLockable(accountVO)); + } + + @Test + public void tesDomainAdmingLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_DOMAIN_ADMIN); + assertTrue(quotaManager.isLockable(accountVO)); + } + + @Test + public void testReadOnlyAdminLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_READ_ONLY_ADMIN); + assertFalse(quotaManager.isLockable(accountVO)); + } + + @Test + public void testResourceDomainAdminLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN); + assertFalse(quotaManager.isLockable(accountVO)); + } + + @Test + public void testProjectLockableAccount() { + accountVO.setType(Account.ACCOUNT_TYPE_PROJECT); + assertFalse(quotaManager.isLockable(accountVO)); + } + } diff --git a/framework/quota/test/org/apache/cloudstack/quota/QuotaStatementTest.java b/framework/quota/test/org/apache/cloudstack/quota/QuotaStatementTest.java index d1cc7ace29..e2b5a0abe9 100644 --- a/framework/quota/test/org/apache/cloudstack/quota/QuotaStatementTest.java +++ b/framework/quota/test/org/apache/cloudstack/quota/QuotaStatementTest.java @@ -21,7 +21,7 @@ import com.cloud.utils.db.TransactionLegacy; import junit.framework.TestCase; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.quota.QuotaStatementImpl.STATEMENT_PERIODS; +import org.apache.cloudstack.quota.QuotaStatementImpl.QuotaStatementPeriods; import org.apache.cloudstack.quota.dao.QuotaAccountDao; import org.apache.cloudstack.quota.dao.QuotaUsageDao; import org.apache.cloudstack.quota.vo.QuotaAccountVO; @@ -85,12 +85,12 @@ public void testStatementPeriodBIMONTHLY() { //BIMONTHLY - first statement of month date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS + 1); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.BIMONTHLY); assertTrue(period == null); //1 of this month date.set(Calendar.DATE, 1); - period = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY); + period = quotaStatement.statementTime(date, QuotaStatementPeriods.BIMONTHLY); assertTrue(period != null); assertTrue(period.length == 2); assertTrue(period[0].toString(), period[0].before(period[1])); @@ -100,12 +100,12 @@ public void testStatementPeriodBIMONTHLY() { //BIMONTHLY - second statement of month date = Calendar.getInstance(); date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS + 16); - period = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY); + period = quotaStatement.statementTime(date, QuotaStatementPeriods.BIMONTHLY); assertTrue(period == null); //17 of this month date.set(Calendar.DATE, 17); - period = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY); + period = quotaStatement.statementTime(date, QuotaStatementPeriods.BIMONTHLY); assertTrue(period != null); assertTrue(period.length == 2); assertTrue(period[0].toString(), period[0].before(period[1])); @@ -128,12 +128,12 @@ public void testStatementPeriodMONTHLY() { //MONTHLY date = Calendar.getInstance(); date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS + 1); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.MONTHLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.MONTHLY); assertTrue(period == null); //1 of this month date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS - 1); - period = quotaStatement.statementTime(date, STATEMENT_PERIODS.MONTHLY); + period = quotaStatement.statementTime(date, QuotaStatementPeriods.MONTHLY); assertTrue(period != null); assertTrue(period.length == 2); assertTrue(period[0].toString(), period[0].before(period[1])); @@ -157,7 +157,7 @@ public void testStatementPeriodQUATERLY() { date = Calendar.getInstance(); date.set(Calendar.MONTH, Calendar.JANUARY); // 1 Jan date.set(Calendar.DATE, 1); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.QUATERLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.QUATERLY); assertTrue(period != null); assertTrue(period.length == 2); assertTrue("period[0].before(period[1])" + period[0].toString(), period[0].before(period[1])); @@ -182,7 +182,7 @@ public void testStatementPeriodHALFYEARLY() { date = Calendar.getInstance(); date.set(Calendar.MONTH, Calendar.JANUARY); // 1 Jan date.set(Calendar.DATE, 1); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.HALFYEARLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.HALFYEARLY); assertTrue(period != null); assertTrue(period.length == 2); assertTrue("period[0].before(period[1])" + period[0].toString(), period[0].before(period[1])); @@ -207,7 +207,7 @@ public void testStatementPeriodYEARLY() { date = Calendar.getInstance(); date.set(Calendar.MONTH, Calendar.JANUARY); // 1 Jan date.set(Calendar.DATE, 1); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.YEARLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.YEARLY); assertTrue("period != null", period != null); assertTrue(period.length == 2); assertTrue("period[0].before(period[1])" + period[0].toString(), period[0].before(period[1])); @@ -244,7 +244,7 @@ public void testSendStatement() throws UnsupportedEncodingException, MessagingEx // call real method on send monthly statement quotaStatement.sendStatement(); - Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.MONTHLY); + Calendar period[] = quotaStatement.statementTime(date, QuotaStatementPeriods.MONTHLY); if (period != null){ Mockito.verify(alertManager, Mockito.times(1)).sendQuotaAlert(Mockito.any(QuotaAlertManagerImpl.DeferredQuotaEmail.class)); } diff --git a/framework/rest/pom.xml b/framework/rest/pom.xml index 545a651e78..03aad768dc 100644 --- a/framework/rest/pom.xml +++ b/framework/rest/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml cloud-framework-rest @@ -33,32 +33,32 @@ com.fasterxml.jackson.module jackson-module-jaxb-annotations - 2.6.3 + ${cs.jackson.version} com.fasterxml.jackson.core jackson-annotations - 2.6.3 + ${cs.jackson.version} com.fasterxml.jackson.core jackson-core - 2.6.3 + ${cs.jackson.version} com.fasterxml.jackson.core jackson-databind - 2.6.3 + ${cs.jackson.version} com.fasterxml.jackson.jaxrs jackson-jaxrs-json-provider - 2.6.3 + ${cs.jackson.version} org.apache.cxf - cxf-bundle-jaxrs - 2.7.13 + cxf-rt-frontend-jaxrs + ${cs.cxf.version} org.eclipse.jetty diff --git a/framework/security/pom.xml b/framework/security/pom.xml index 6649e9946f..cfe04de079 100644 --- a/framework/security/pom.xml +++ b/framework/security/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-framework - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/framework/spring/lifecycle/pom.xml b/framework/spring/lifecycle/pom.xml index 15b3367fd1..93160c472c 100644 --- a/framework/spring/lifecycle/pom.xml +++ b/framework/spring/lifecycle/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-maven-standard - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../maven-standard/pom.xml diff --git a/framework/spring/module/pom.xml b/framework/spring/module/pom.xml index 17e89f8d60..6f89f53530 100644 --- a/framework/spring/module/pom.xml +++ b/framework/spring/module/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-maven-standard - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../maven-standard/pom.xml diff --git a/maven-standard/pom.xml b/maven-standard/pom.xml index dd8d83c25c..6f8530a0f5 100644 --- a/maven-standard/pom.xml +++ b/maven-standard/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index b000bd1926..c267e8fdfe 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -50,7 +50,7 @@ BuildRequires: jpackage-utils BuildRequires: gcc BuildRequires: glibc-devel BuildRequires: /usr/bin/mkisofs -BuildRequires: MySQL-python +BuildRequires: mysql-connector-python #BuildRequires: maven => 3.0.0 %description @@ -79,7 +79,7 @@ Requires: /sbin/service Requires: /sbin/chkconfig Requires: /usr/bin/ssh-keygen Requires: mkisofs -Requires: MySQL-python +Requires: mysql-connector-python Requires: python-paramiko Requires: ipmitool Requires: %{name}-common = %{_ver} @@ -234,7 +234,6 @@ mkdir -p ${RPM_BUILD_ROOT}%{python_sitearch}/ mkdir -p ${RPM_BUILD_ROOT}%/usr/bin cp -r scripts/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts install -D systemvm/dist/systemvm.iso ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.iso -install -D systemvm/dist/systemvm.zip ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.zip install python/lib/cloud_utils.py ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py cp -r python/lib/cloudutils ${RPM_BUILD_ROOT}%{python_sitearch}/ python -m py_compile ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py @@ -300,6 +299,7 @@ install -D packaging/centos63/cloud-management.rc ${RPM_BUILD_ROOT}%{_initrddir} install -D packaging/centos63/cloud-management.sysconfig ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/%{name}-management install -D server/target/conf/cloudstack-sudoers ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management install -D packaging/centos63/tomcat.sh ${RPM_BUILD_ROOT}%{_initrddir}/tomcat.sh +install -D server/target/conf/cloudstack-catalina.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-catalina chmod 440 ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management chmod 770 ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/Catalina @@ -395,6 +395,13 @@ if [ -d "%{_sysconfdir}/cloud" ] ; then mv %{_sysconfdir}/cloud %{_sysconfdir}/cloud.rpmsave fi +# in case of upgrade to 4.9+ copy commands.properties if not exists in /etc/cloudstack/management/ +if [ "$1" == "2" ] ; then + if [ -f "%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties" ] && [ ! -f "%{_sysconfdir}/%{name}/management/commands.properties" ] ; then + cp -p %{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties %{_sysconfdir}/%{name}/management/commands.properties + fi +fi + %post management if [ "$1" == "1" ] ; then /sbin/chkconfig --add cloudstack-management > /dev/null 2>&1 || true @@ -580,6 +587,7 @@ fi %{_defaultdocdir}/%{name}-management-%{version}/LICENSE %{_defaultdocdir}/%{name}-management-%{version}/NOTICE %attr(0644,cloud,cloud) %{_localstatedir}/log/%{name}/management/catalina.out +%attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-catalina %files agent %attr(0755,root,root) %{_bindir}/%{name}-setup-agent @@ -603,7 +611,6 @@ fi %attr(0755,root,root) %{_datadir}/%{name}-common/scripts %attr(0755,root,root) /usr/bin/cloudstack-sccs %attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.iso -%attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.zip %attr(0644,root,root) %{python_sitearch}/cloud_utils.py %attr(0644,root,root) %{python_sitearch}/cloud_utils.pyc %attr(0644,root,root) %{python_sitearch}/cloudutils/* diff --git a/packaging/centos63/replace.properties b/packaging/centos63/replace.properties index 6a3101f9b5..bdf6e223b5 100644 --- a/packaging/centos63/replace.properties +++ b/packaging/centos63/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql COMPONENTS-SPEC=components-premium.xml REMOTEHOST=localhost AGENTCLASSPATH= diff --git a/packaging/centos7/cloud-management.sysconfig b/packaging/centos7/cloud-management.sysconfig index c262b11518..6e5fcf9d8d 100644 --- a/packaging/centos7/cloud-management.sysconfig +++ b/packaging/centos7/cloud-management.sysconfig @@ -45,5 +45,5 @@ SHUTDOWN_VERBOSE="false" # Set the TOMCAT_PID location CATALINA_PID="/var/run/cloudstack-management.pid" -CLASSPATH=/etc/cloudstack/management:/usr/share/cloudstack-common:/usr/share/cloudstack-management/setup:/usr/share/java/mysql-connector-java.jar +CLASSPATH=/etc/cloudstack/management:/usr/share/cloudstack-common:/usr/share/cloudstack-management/setup diff --git a/packaging/centos7/cloud.spec b/packaging/centos7/cloud.spec index e94ef655c9..b99d950d83 100644 --- a/packaging/centos7/cloud.spec +++ b/packaging/centos7/cloud.spec @@ -50,7 +50,7 @@ BuildRequires: jpackage-utils BuildRequires: gcc BuildRequires: glibc-devel BuildRequires: /usr/bin/mkisofs -BuildRequires: MySQL-python +BuildRequires: mysql-connector-python BuildRequires: maven => 3.0.0 %description @@ -79,7 +79,7 @@ Requires: /sbin/service Requires: /sbin/chkconfig Requires: /usr/bin/ssh-keygen Requires: mkisofs -Requires: MySQL-python +Requires: mysql-connector-python Requires: ipmitool Requires: %{name}-common = %{_ver} Requires: iptables-services @@ -202,7 +202,6 @@ mkdir -p ${RPM_BUILD_ROOT}%{python_sitearch}/ mkdir -p ${RPM_BUILD_ROOT}%/usr/bin cp -r scripts/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts install -D systemvm/dist/systemvm.iso ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.iso -install -D systemvm/dist/systemvm.zip ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.zip install python/lib/cloud_utils.py ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py cp -r python/lib/cloudutils ${RPM_BUILD_ROOT}%{python_sitearch}/ python -m py_compile ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py @@ -272,6 +271,7 @@ install -D server/target/conf/cloudstack-sudoers ${RPM_BUILD_ROOT}%{_sysconfdir} install -D packaging/centos7/cloud-management.service ${RPM_BUILD_ROOT}%{_unitdir}/%{name}-management.service install -D packaging/centos7/cloud.limits ${RPM_BUILD_ROOT}%{_sysconfdir}/security/limits.d/cloud touch ${RPM_BUILD_ROOT}%{_localstatedir}/run/%{name}-management.pid +install -D server/target/conf/cloudstack-catalina.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-catalina chmod 440 ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management chmod 770 ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/Catalina @@ -351,6 +351,13 @@ id cloud > /dev/null 2>&1 || /usr/sbin/useradd -M -c "CloudStack unprivileged us rm -rf %{_localstatedir}/cache/cloudstack +# in case of upgrade to 4.9+ copy commands.properties if not exists in /etc/cloudstack/management/ +if [ "$1" == "2" ] ; then + if [ -f "%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties" ] && [ ! -f "%{_sysconfdir}/%{name}/management/commands.properties" ] ; then + cp -p %{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties %{_sysconfdir}/%{name}/management/commands.properties + fi +fi + %post management if [ "$1" == "1" ] ; then /usr/bin/systemctl on cloudstack-management > /dev/null 2>&1 || true @@ -476,6 +483,7 @@ fi %{_defaultdocdir}/%{name}-management-%{version}/LICENSE %{_defaultdocdir}/%{name}-management-%{version}/NOTICE %attr(0644,cloud,cloud) %{_localstatedir}/log/%{name}/management/catalina.out +%attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-catalina %files agent %attr(0755,root,root) %{_bindir}/%{name}-setup-agent @@ -499,7 +507,6 @@ fi %attr(0755,root,root) %{_datadir}/%{name}-common/scripts %attr(0755,root,root) /usr/bin/cloudstack-sccs %attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.iso -%attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.zip %attr(0644,root,root) %{python_sitearch}/cloud_utils.py %attr(0644,root,root) %{python_sitearch}/cloud_utils.pyc %attr(0644,root,root) %{python_sitearch}/cloudutils/* diff --git a/packaging/centos7/replace.properties b/packaging/centos7/replace.properties index aec359e2e6..0b0f2cc12d 100644 --- a/packaging/centos7/replace.properties +++ b/packaging/centos7/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql COMPONENTS-SPEC=components-premium.xml REMOTEHOST=localhost AGENTCLASSPATH= diff --git a/packaging/centos7/tomcat7/catalina.properties b/packaging/centos7/tomcat7/catalina.properties index 282892bb76..e0baf61261 100644 --- a/packaging/centos7/tomcat7/catalina.properties +++ b/packaging/centos7/tomcat7/catalina.properties @@ -44,7 +44,7 @@ package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache # "foo/*.jar": Add all the JARs of the specified folder as class # repositories # "foo/bar.jar": Add bar.jar as a class repository -common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,/usr/share/java/mysql-connector-java.jar,/usr/share/cloudstack-mysql-ha/lib/*jar +common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,/usr/share/java/mysql-connector-java.jar,/usr/share/cloudstack-mysql-ha/lib/*.jar # # List of comma-separated paths defining the contents of the "server" diff --git a/packaging/centos7/tomcat7/db.properties b/packaging/centos7/tomcat7/db.properties index 36ade8ce86..6161f3a6e2 100644 --- a/packaging/centos7/tomcat7/db.properties +++ b/packaging/centos7/tomcat7/db.properties @@ -25,6 +25,7 @@ region.id=1 db.cloud.username=cloud db.cloud.password=ENC(vlzQjmqOV4s5q7n+S1OMbA==) db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -56,6 +57,8 @@ db.cloud.encrypt.secret=ENC(zaGuSF5a4KyWayn2t0yyjDa0HjdToVtZ) db.usage.password=ENC(cQEcN5aVucSYK+WUkPjDcw==) db.usage.username=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -69,6 +72,8 @@ db.usage.url.params= db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/packaging/debian/replace.properties b/packaging/debian/replace.properties index 6d55a98820..e1d28bb954 100644 --- a/packaging/debian/replace.properties +++ b/packaging/debian/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql COMPONENTS-SPEC=components-premium.xml REMOTEHOST=localhost AGENTCLASSPATH= diff --git a/packaging/fedora20/cloud.spec b/packaging/fedora20/cloud.spec index 93cf1863e6..0a80991154 100644 --- a/packaging/fedora20/cloud.spec +++ b/packaging/fedora20/cloud.spec @@ -50,7 +50,7 @@ BuildRequires: jpackage-utils BuildRequires: gcc BuildRequires: glibc-devel BuildRequires: /usr/bin/mkisofs -BuildRequires: MySQL-python +BuildRequires: mysql-connector-python #BuildRequires: maven => 3.0.0 %description @@ -79,7 +79,7 @@ Requires: /sbin/service Requires: /sbin/chkconfig Requires: /usr/bin/ssh-keygen Requires: mkisofs -Requires: MySQL-python +Requires: mysql-connector-python Requires: python-paramiko Requires: ipmitool Requires: %{name}-common = %{_ver} @@ -234,7 +234,6 @@ mkdir -p ${RPM_BUILD_ROOT}%{python_sitearch}/ mkdir -p ${RPM_BUILD_ROOT}%/usr/bin cp -r scripts/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts install -D systemvm/dist/systemvm.iso ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.iso -install -D systemvm/dist/systemvm.zip ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.zip install python/lib/cloud_utils.py ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py cp -r python/lib/cloudutils ${RPM_BUILD_ROOT}%{python_sitearch}/ python -m py_compile ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py @@ -299,6 +298,7 @@ install -D packaging/centos63/cloud-ipallocator.rc ${RPM_BUILD_ROOT}%{_initrddir install -D packaging/centos63/cloud-management.rc ${RPM_BUILD_ROOT}%{_initrddir}/%{name}-management install -D packaging/centos63/cloud-management.sysconfig ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/%{name}-management install -D packaging/centos63/tomcat.sh ${RPM_BUILD_ROOT}%{_initrddir}/tomcat.sh +install -D server/target/conf/cloudstack-catalina.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-catalina chmod 440 ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management chmod 770 ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/Catalina @@ -394,6 +394,13 @@ if [ -d "%{_sysconfdir}/cloud" ] ; then mv %{_sysconfdir}/cloud %{_sysconfdir}/cloud.rpmsave fi +# in case of upgrade to 4.9+ copy commands.properties if not exists in /etc/cloudstack/management/ +if [ "$1" == "2" ] ; then + if [ -f "%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties" ] && [ ! -f "%{_sysconfdir}/%{name}/management/commands.properties" ] ; then + cp -p %{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties %{_sysconfdir}/%{name}/management/commands.properties + fi +fi + %post management if [ "$1" == "1" ] ; then /sbin/chkconfig --add cloudstack-management > /dev/null 2>&1 || true @@ -578,6 +585,7 @@ fi %{_defaultdocdir}/%{name}-management-%{version}/LICENSE %{_defaultdocdir}/%{name}-management-%{version}/NOTICE %attr(0644,cloud,cloud) %{_localstatedir}/log/%{name}/management/catalina.out +%attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-catalina %files agent %attr(0755,root,root) %{_bindir}/%{name}-setup-agent @@ -601,7 +609,6 @@ fi %attr(0755,root,root) %{_datadir}/%{name}-common/scripts %attr(0755,root,root) /usr/bin/cloudstack-sccs %attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.iso -%attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.zip %attr(0644,root,root) %{python_sitearch}/cloud_utils.py %attr(0644,root,root) %{python_sitearch}/cloud_utils.pyc %attr(0644,root,root) %{python_sitearch}/cloudutils/* diff --git a/packaging/fedora20/replace.properties b/packaging/fedora20/replace.properties index 6a3101f9b5..bdf6e223b5 100644 --- a/packaging/fedora20/replace.properties +++ b/packaging/fedora20/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql COMPONENTS-SPEC=components-premium.xml REMOTEHOST=localhost AGENTCLASSPATH= diff --git a/packaging/fedora21/cloud.spec b/packaging/fedora21/cloud.spec index e089b120d0..a749d13254 100644 --- a/packaging/fedora21/cloud.spec +++ b/packaging/fedora21/cloud.spec @@ -50,7 +50,7 @@ BuildRequires: jpackage-utils BuildRequires: gcc BuildRequires: glibc-devel BuildRequires: /usr/bin/mkisofs -BuildRequires: MySQL-python +BuildRequires: mysql-connector-python #BuildRequires: maven => 3.0.0 %description @@ -79,7 +79,7 @@ Requires: /sbin/service Requires: /sbin/chkconfig Requires: /usr/bin/ssh-keygen Requires: mkisofs -Requires: MySQL-python +Requires: mysql-connector-python Requires: python-paramiko Requires: ipmitool Requires: %{name}-common = %{_ver} @@ -234,7 +234,6 @@ mkdir -p ${RPM_BUILD_ROOT}%{python_sitearch}/ mkdir -p ${RPM_BUILD_ROOT}%/usr/bin cp -r scripts/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/scripts install -D systemvm/dist/systemvm.iso ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.iso -install -D systemvm/dist/systemvm.zip ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/vms/systemvm.zip install python/lib/cloud_utils.py ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py cp -r python/lib/cloudutils ${RPM_BUILD_ROOT}%{python_sitearch}/ python -m py_compile ${RPM_BUILD_ROOT}%{python_sitearch}/cloud_utils.py @@ -299,6 +298,7 @@ install -D packaging/centos63/cloud-ipallocator.rc ${RPM_BUILD_ROOT}%{_initrddir install -D packaging/centos63/cloud-management.rc ${RPM_BUILD_ROOT}%{_initrddir}/%{name}-management install -D packaging/centos63/cloud-management.sysconfig ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/%{name}-management install -D packaging/centos63/tomcat.sh ${RPM_BUILD_ROOT}%{_initrddir}/tomcat.sh +install -D server/target/conf/cloudstack-catalina.logrotate ${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d/%{name}-catalina chmod 440 ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management chmod 770 ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/management/Catalina @@ -394,6 +394,13 @@ if [ -d "%{_sysconfdir}/cloud" ] ; then mv %{_sysconfdir}/cloud %{_sysconfdir}/cloud.rpmsave fi +# in case of upgrade to 4.9+ copy commands.properties if not exists in /etc/cloudstack/management/ +if [ "$1" == "2" ] ; then + if [ -f "%{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties" ] && [ ! -f "%{_sysconfdir}/%{name}/management/commands.properties" ] ; then + cp -p %{_datadir}/%{name}-management/webapps/client/WEB-INF/classes/commands.properties %{_sysconfdir}/%{name}/management/commands.properties + fi +fi + %post management if [ "$1" == "1" ] ; then /sbin/chkconfig --add cloudstack-management > /dev/null 2>&1 || true @@ -578,6 +585,7 @@ fi %{_defaultdocdir}/%{name}-management-%{version}/LICENSE %{_defaultdocdir}/%{name}-management-%{version}/NOTICE %attr(0644,cloud,cloud) %{_localstatedir}/log/%{name}/management/catalina.out +%attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-catalina %files agent %attr(0755,root,root) %{_bindir}/%{name}-setup-agent @@ -601,7 +609,6 @@ fi %attr(0755,root,root) %{_datadir}/%{name}-common/scripts %attr(0755,root,root) /usr/bin/cloudstack-sccs %attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.iso -%attr(0644, root, root) %{_datadir}/%{name}-common/vms/systemvm.zip %attr(0644,root,root) %{python_sitearch}/cloud_utils.py %attr(0644,root,root) %{python_sitearch}/cloud_utils.pyc %attr(0644,root,root) %{python_sitearch}/cloudutils/* diff --git a/packaging/fedora21/replace.properties b/packaging/fedora21/replace.properties index 6a3101f9b5..bdf6e223b5 100644 --- a/packaging/fedora21/replace.properties +++ b/packaging/fedora21/replace.properties @@ -21,6 +21,7 @@ DBROOTPW= MSLOG=vmops.log APISERVERLOG=api.log DBHOST=localhost +DBDRIVER=jdbc:mysql COMPONENTS-SPEC=components-premium.xml REMOTEHOST=localhost AGENTCLASSPATH= diff --git a/packaging/systemd/cloudstack-usage.service b/packaging/systemd/cloudstack-usage.service index 9a1827da61..641d125d25 100644 --- a/packaging/systemd/cloudstack-usage.service +++ b/packaging/systemd/cloudstack-usage.service @@ -27,10 +27,11 @@ Environment=JAVA_HOME=/usr/lib/jvm/jre Environment=JAVA_HEAP_INITIAL=256m Environment=JAVA_HEAP_MAX=2048m Environment=JAVA_CLASS=com.cloud.usage.UsageServer +Environment=JAVA_PID=$$ ExecStart=/bin/sh -ec '\ - export UCP=`ls /usr/share/cloudstack-usage/cloud-usage-*.jar /usr/share/cloudstack-usage/lib/*.jar | tr "\\n" ":"`; \ + export UCP=`ls /usr/share/cloudstack-usage/cloud-usage-*.jar /usr/share/cloudstack-usage/lib/*.jar /usr/share/cloudstack-mysql-ha/lib/*.jar | tr "\\n" ":"`; \ export CLASSPATH="$UCP:/etc/cloudstack/usage:/usr/share/java/mysql-connector-java.jar"; \ - ${JAVA_HOME}/bin/java -Xms${JAVA_HEAP_INITIAL} -Xmx${JAVA_HEAP_MAX} -cp "$CLASSPATH" $JAVA_CLASS' + ${JAVA_HOME}/bin/java -Dpid=${JAVA_PID} -Xms${JAVA_HEAP_INITIAL} -Xmx${JAVA_HEAP_MAX} -cp "$CLASSPATH" $JAVA_CLASS' Restart=always RestartSec=10s diff --git a/plugins/acl/dynamic-role-based/pom.xml b/plugins/acl/dynamic-role-based/pom.xml new file mode 100644 index 0000000000..96d7e53d1c --- /dev/null +++ b/plugins/acl/dynamic-role-based/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + cloud-plugin-acl-dynamic-role-based + Apache CloudStack Plugin - ACL Dynamic Role Based + + org.apache.cloudstack + cloudstack-plugins + 4.9.0-SNAPSHOT + ../../pom.xml + + diff --git a/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties new file mode 100644 index 0000000000..dda9998224 --- /dev/null +++ b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties @@ -0,0 +1,18 @@ +# 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. +name=acl-dynamic-role-based +parent=api diff --git a/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/spring-acl-dynamic-role-based-context.xml b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/spring-acl-dynamic-role-based-context.xml new file mode 100644 index 0000000000..9ffe465a9a --- /dev/null +++ b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/spring-acl-dynamic-role-based-context.xml @@ -0,0 +1,33 @@ + + + + + + + diff --git a/plugins/acl/dynamic-role-based/src/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java b/plugins/acl/dynamic-role-based/src/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java new file mode 100644 index 0000000000..754d4cc86a --- /dev/null +++ b/plugins/acl/dynamic-role-based/src/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java @@ -0,0 +1,144 @@ +// 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.acl; + +import com.cloud.exception.PermissionDeniedException; +import com.cloud.user.Account; +import com.cloud.user.AccountService; +import com.cloud.user.User; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.component.PluggableService; +import com.google.common.base.Strings; +import org.apache.cloudstack.api.APICommand; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Local(value = APIChecker.class) +public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements APIChecker { + + @Inject + private AccountService accountService; + @Inject + private RoleService roleService; + + private List services; + private Map> annotationRoleBasedApisMap = new HashMap<>(); + + protected DynamicRoleBasedAPIAccessChecker() { + super(); + for (RoleType roleType : RoleType.values()) { + annotationRoleBasedApisMap.put(roleType, new HashSet()); + } + } + + private void denyApiAccess(final String commandName) throws PermissionDeniedException { + throw new PermissionDeniedException("The API does not exist or is blacklisted for the account's role. " + + "The account with is not allowed to request the api: " + commandName); + } + + public boolean isDisabled() { + return !roleService.isEnabled(); + } + + @Override + public boolean checkAccess(User user, String commandName) throws PermissionDeniedException { + if (isDisabled()) { + return true; + } + Account account = accountService.getAccount(user.getAccountId()); + if (account == null) { + throw new PermissionDeniedException("The account id=" + user.getAccountId() + "for user id=" + user.getId() + "is null"); + } + + final Role accountRole = roleService.findRole(account.getRoleId()); + if (accountRole == null || accountRole.getId() < 1L) { + denyApiAccess(commandName); + } + + // Allow all APIs for root admins + if (accountRole.getRoleType() == RoleType.Admin && accountRole.getId() == RoleType.Admin.getId()) { + return true; + } + + // Check against current list of permissions + for (final RolePermission permission : roleService.findAllPermissionsBy(accountRole.getId())) { + if (permission.getRule().matches(commandName)) { + if (RolePermission.Permission.ALLOW.equals(permission.getPermission())) { + return true; + } else { + denyApiAccess(commandName); + } + } + } + + // Check annotations + if (annotationRoleBasedApisMap.get(accountRole.getRoleType()) != null + && annotationRoleBasedApisMap.get(accountRole.getRoleType()).contains(commandName)) { + return true; + } + + // Default deny all + denyApiAccess(commandName); + return false; + } + + public void addApiToRoleBasedAnnotationsMap(final RoleType roleType, final String commandName) { + if (roleType == null || Strings.isNullOrEmpty(commandName)) { + return; + } + final Set commands = annotationRoleBasedApisMap.get(roleType); + if (commands != null && !commands.contains(commandName)) { + commands.add(commandName); + } + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + return true; + } + + @Override + public boolean start() { + for (PluggableService service : services) { + for (Class clz : service.getCommands()) { + APICommand command = clz.getAnnotation(APICommand.class); + for (RoleType role : command.authorized()) { + addApiToRoleBasedAnnotationsMap(role, command.name()); + } + } + } + return super.start(); + } + + public List getServices() { + return services; + } + + @Inject + public void setServices(List services) { + this.services = services; + } + +} diff --git a/plugins/acl/dynamic-role-based/test/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessCheckerTest.java b/plugins/acl/dynamic-role-based/test/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessCheckerTest.java new file mode 100644 index 0000000000..12ebbe56f5 --- /dev/null +++ b/plugins/acl/dynamic-role-based/test/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessCheckerTest.java @@ -0,0 +1,164 @@ +// 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.acl; + +import com.cloud.exception.PermissionDeniedException; +import com.cloud.user.Account; +import com.cloud.user.AccountService; +import com.cloud.user.AccountVO; +import com.cloud.user.User; +import com.cloud.user.UserVO; +import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import java.lang.reflect.Field; +import java.util.Collections; + +@RunWith(MockitoJUnitRunner.class) +public class DynamicRoleBasedAPIAccessCheckerTest extends TestCase { + + @Mock + private AccountService accountService; + @Mock + private RoleService roleService; + + private DynamicRoleBasedAPIAccessChecker apiAccessChecker; + + private User getTestUser() { + return new UserVO(12L, "some user", "password", "firstName", "lastName", + "email@gmail.com", "GMT", "uuid", User.Source.UNKNOWN); + } + + private Account getTestAccount() { + return new AccountVO("some name", 1L, "network-domain", (short)0, "some-uuid"); + } + + private Role getTestRole() { + return new RoleVO(4L, "SomeRole", RoleType.User, "some description"); + } + + private void setupMockField(final Object obj, final String fieldName, final Object mock) throws NoSuchFieldException, IllegalAccessException { + Field roleDaoField = DynamicRoleBasedAPIAccessChecker.class.getDeclaredField(fieldName); + roleDaoField.setAccessible(true); + roleDaoField.set(obj, mock); + } + + @Override + @Before + public void setUp() throws NoSuchFieldException, IllegalAccessException { + apiAccessChecker = Mockito.spy(new DynamicRoleBasedAPIAccessChecker()); + setupMockField(apiAccessChecker, "accountService", accountService); + setupMockField(apiAccessChecker, "roleService", roleService); + + Mockito.when(accountService.getAccount(Mockito.anyLong())).thenReturn(getTestAccount()); + Mockito.when(roleService.findRole(Mockito.anyLong())).thenReturn((RoleVO) getTestRole()); + + // Enabled plugin + Mockito.doReturn(false).when(apiAccessChecker).isDisabled(); + Mockito.doCallRealMethod().when(apiAccessChecker).checkAccess(Mockito.any(User.class), Mockito.anyString()); + } + + @Test + public void testInvalidAccountCheckAccess() { + Mockito.when(accountService.getAccount(Mockito.anyLong())).thenReturn(null); + try { + apiAccessChecker.checkAccess(getTestUser(), "someApi"); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testInvalidAccountRoleCheckAccess() { + Mockito.when(roleService.findRole(Mockito.anyLong())).thenReturn(null); + try { + apiAccessChecker.checkAccess(getTestUser(), "someApi"); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testDefaultRootAdminAccess() { + Mockito.when(accountService.getAccount(Mockito.anyLong())).thenReturn(new AccountVO("root admin", 1L, null, (short)1, "some-uuid")); + Mockito.when(roleService.findRole(Mockito.anyLong())).thenReturn(new RoleVO(1L, "SomeRole", RoleType.Admin, "default root admin role")); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), "anyApi")); + } + + @Test + public void testInvalidRolePermissionsCheckAccess() { + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.emptyList()); + try { + apiAccessChecker.checkAccess(getTestUser(), "someApi"); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testValidAllowRolePermissionApiCheckAccess() { + final String allowedApiName = "someAllowedApi"; + final RolePermission permission = new RolePermissionVO(1L, allowedApiName, RolePermission.Permission.ALLOW, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), allowedApiName)); + } + + @Test + public void testValidAllowRolePermissionWildcardCheckAccess() { + final String allowedApiName = "someAllowedApi"; + final RolePermission permission = new RolePermissionVO(1L, "some*", RolePermission.Permission.ALLOW, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), allowedApiName)); + } + + @Test + public void testValidDenyRolePermissionApiCheckAccess() { + final String denyApiName = "someDeniedApi"; + final RolePermission permission = new RolePermissionVO(1L, denyApiName, RolePermission.Permission.DENY, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + try { + apiAccessChecker.checkAccess(getTestUser(), denyApiName); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testValidDenyRolePermissionWildcardCheckAccess() { + final String denyApiName = "someDenyApi"; + final RolePermission permission = new RolePermissionVO(1L, "*Deny*", RolePermission.Permission.DENY, null); + Mockito.when(roleService.findAllPermissionsBy(Mockito.anyLong())).thenReturn(Collections.singletonList(permission)); + try { + apiAccessChecker.checkAccess(getTestUser(), denyApiName); + fail("Exception was expected"); + } catch (PermissionDeniedException ignored) { + } + } + + @Test + public void testAnnotationFallbackCheckAccess() { + final String allowedApiName = "someApiWithAnnotations"; + apiAccessChecker.addApiToRoleBasedAnnotationsMap(getTestRole().getRoleType(), allowedApiName); + assertTrue(apiAccessChecker.checkAccess(getTestUser(), allowedApiName)); + } + +} \ No newline at end of file diff --git a/plugins/acl/static-role-based/pom.xml b/plugins/acl/static-role-based/pom.xml index 5171886ccf..62ba16696f 100644 --- a/plugins/acl/static-role-based/pom.xml +++ b/plugins/acl/static-role-based/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java b/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java index 9221ea4c78..fc78268fc6 100644 --- a/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java +++ b/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java @@ -41,18 +41,20 @@ // based on the account type, access is granted public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIChecker { - protected static final Logger s_logger = Logger.getLogger(StaticRoleBasedAPIAccessChecker.class); + protected static final Logger LOGGER = Logger.getLogger(StaticRoleBasedAPIAccessChecker.class); - Set commandPropertyFiles = new HashSet(); - Set commandsPropertiesOverrides = new HashSet(); - Map> commandsPropertiesRoleBasedApisMap = new HashMap>(); - Map> annotationRoleBasedApisMap = new HashMap>(); + private Set commandPropertyFiles = new HashSet(); + private Set commandsPropertiesOverrides = new HashSet(); + private Map> commandsPropertiesRoleBasedApisMap = new HashMap>(); + private Map> annotationRoleBasedApisMap = new HashMap>(); + private List services; - List _services; @Inject - AccountService _accountService; + private AccountService accountService; + @Inject + private RoleService roleService; - protected StaticRoleBasedAPIAccessChecker() { + public StaticRoleBasedAPIAccessChecker() { super(); for (RoleType roleType : RoleType.values()) { commandsPropertiesRoleBasedApisMap.put(roleType, new HashSet()); @@ -60,23 +62,31 @@ protected StaticRoleBasedAPIAccessChecker() { } } + public boolean isDisabled() { + return roleService.isEnabled(); + } + @Override public boolean checkAccess(User user, String commandName) throws PermissionDeniedException { - Account account = _accountService.getAccount(user.getAccountId()); + if (isDisabled()) { + return true; + } + + Account account = accountService.getAccount(user.getAccountId()); if (account == null) { throw new PermissionDeniedException("The account id=" + user.getAccountId() + "for user id=" + user.getId() + "is null"); } - RoleType roleType = _accountService.getRoleType(account); + RoleType roleType = accountService.getRoleType(account); boolean isAllowed = commandsPropertiesOverrides.contains(commandName) ? commandsPropertiesRoleBasedApisMap.get(roleType).contains(commandName) : annotationRoleBasedApisMap.get( roleType).contains(commandName); - if (!isAllowed) { - throw new PermissionDeniedException("The API does not exist or is blacklisted. Role type=" + roleType.toString() + " is not allowed to request the api: " + - commandName); + if (isAllowed) { + return true; } - return isAllowed; + + throw new PermissionDeniedException("The API does not exist or is blacklisted. Role type=" + roleType.toString() + " is not allowed to request the api: " + commandName); } @Override @@ -91,7 +101,7 @@ public boolean configure(String name, Map params) throws Configu @Override public boolean start() { - for (PluggableService service : _services) { + for (PluggableService service : services) { for (Class clz : service.getCommands()) { APICommand command = clz.getAnnotation(APICommand.class); for (RoleType role : command.authorized()) { @@ -112,22 +122,22 @@ private void processMapping(Map configMap) { try { short cmdPermissions = Short.parseShort(roleMask); for (RoleType roleType : RoleType.values()) { - if ((cmdPermissions & roleType.getValue()) != 0) + if ((cmdPermissions & roleType.getMask()) != 0) commandsPropertiesRoleBasedApisMap.get(roleType).add(apiName); } } catch (NumberFormatException nfe) { - s_logger.info("Malformed key=value pair for entry: " + entry.toString()); + LOGGER.info("Malformed key=value pair for entry: " + entry.toString()); } } } public List getServices() { - return _services; + return services; } @Inject public void setServices(List services) { - this._services = services; + this.services = services; } public Set getCommandPropertyFiles() { diff --git a/plugins/affinity-group-processors/explicit-dedication/pom.xml b/plugins/affinity-group-processors/explicit-dedication/pom.xml index e8b13d0643..d4fc0f1a2c 100644 --- a/plugins/affinity-group-processors/explicit-dedication/pom.xml +++ b/plugins/affinity-group-processors/explicit-dedication/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/affinity-group-processors/host-anti-affinity/pom.xml b/plugins/affinity-group-processors/host-anti-affinity/pom.xml index 7f712a96f8..58e205d18b 100644 --- a/plugins/affinity-group-processors/host-anti-affinity/pom.xml +++ b/plugins/affinity-group-processors/host-anti-affinity/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/alert-handlers/snmp-alerts/pom.xml b/plugins/alert-handlers/snmp-alerts/pom.xml index 7b2727d78e..7cbca893fd 100644 --- a/plugins/alert-handlers/snmp-alerts/pom.xml +++ b/plugins/alert-handlers/snmp-alerts/pom.xml @@ -22,7 +22,7 @@ cloudstack-plugins org.apache.cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/plugins/alert-handlers/syslog-alerts/pom.xml b/plugins/alert-handlers/syslog-alerts/pom.xml index 8ad576627c..e4616acd07 100644 --- a/plugins/alert-handlers/syslog-alerts/pom.xml +++ b/plugins/alert-handlers/syslog-alerts/pom.xml @@ -22,7 +22,7 @@ cloudstack-plugins org.apache.cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml 4.0.0 diff --git a/plugins/api/discovery/pom.xml b/plugins/api/discovery/pom.xml index 93e8b2d7b5..049061abfa 100644 --- a/plugins/api/discovery/pom.xml +++ b/plugins/api/discovery/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java b/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java index be0d5d5326..66d8c5d64e 100644 --- a/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java +++ b/plugins/api/discovery/src/org/apache/cloudstack/api/command/user/discovery/ListApisCmd.java @@ -18,6 +18,7 @@ import javax.inject.Inject; +import org.apache.cloudstack.acl.RoleType; import org.apache.log4j.Logger; import org.apache.cloudstack.api.APICommand; @@ -38,7 +39,7 @@ description = "lists all available apis on the server, provided by the Api Discovery plugin", since = "4.1.0", requestHasSensitiveInfo = false, - responseHasSensitiveInfo = false) + responseHasSensitiveInfo = false, authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) public class ListApisCmd extends BaseCmd { public static final Logger s_logger = Logger.getLogger(ListApisCmd.class.getName()); diff --git a/plugins/api/rate-limit/pom.xml b/plugins/api/rate-limit/pom.xml index 0690489148..3e826c2b49 100644 --- a/plugins/api/rate-limit/pom.xml +++ b/plugins/api/rate-limit/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/api/solidfire-intg-test/pom.xml b/plugins/api/solidfire-intg-test/pom.xml index a991112098..fa5302b14b 100644 --- a/plugins/api/solidfire-intg-test/pom.xml +++ b/plugins/api/solidfire-intg-test/pom.xml @@ -19,11 +19,11 @@ 4.0.0 cloud-plugin-api-solidfire-intg-test - Apache CloudStack Plugin - API SolidFire + Apache CloudStack Plugin - API SolidFire Integration Testing org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/api/solidfire-intg-test/resources/META-INF/cloudstack/solidfire-intg-test/spring-solidfire-intg-test-context.xml b/plugins/api/solidfire-intg-test/resources/META-INF/cloudstack/solidfire-intg-test/spring-solidfire-intg-test-context.xml index 1bab7349ca..2fe875af69 100644 --- a/plugins/api/solidfire-intg-test/resources/META-INF/cloudstack/solidfire-intg-test/spring-solidfire-intg-test-context.xml +++ b/plugins/api/solidfire-intg-test/resources/META-INF/cloudstack/solidfire-intg-test/spring-solidfire-intg-test-context.xml @@ -27,6 +27,8 @@ http://www.springframework.org/schema/context/spring-context-3.0.xsd" > - + + + diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetPathForVolumeCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetPathForVolumeCmd.java new file mode 100644 index 0000000000..5ff178a2e9 --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetPathForVolumeCmd.java @@ -0,0 +1,67 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.solidfire; + +import javax.inject.Inject; + +import org.apache.log4j.Logger; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.solidfire.ApiPathForVolumeResponse; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; + +@APICommand(name = "getPathForVolume", responseObject = ApiPathForVolumeResponse.class, description = "Get the path associated with the provided volume UUID", + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class GetPathForVolumeCmd extends BaseCmd { + private static final Logger LOGGER = Logger.getLogger(GetPathForVolumeCmd.class.getName()); + private static final String NAME = "getpathforvolumeresponse"; + + @Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.STRING, description = "CloudStack Volume UUID", required = true) + private String _volumeUuid; + + @Inject private SolidFireIntegrationTestUtil _util; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return NAME; + } + + @Override + public long getEntityOwnerId() { + return _util.getAccountIdForVolumeUuid(_volumeUuid); + } + + @Override + public void execute() { + LOGGER.info("'GetPathForVolumeIdCmd.execute' method invoked"); + + String pathForVolume = _util.getPathForVolumeUuid(_volumeUuid); + + ApiPathForVolumeResponse response = new ApiPathForVolumeResponse(pathForVolume); + + response.setResponseName(getCommandName()); + response.setObjectName("apipathforvolume"); + + setResponseObject(response); + } +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireAccountIdCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireAccountIdCmd.java similarity index 60% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireAccountIdCmd.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireAccountIdCmd.java index f4c0076f86..9bb8481c3c 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireAccountIdCmd.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireAccountIdCmd.java @@ -14,10 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.command.user.solidfire; - -import com.cloud.user.Account; -import com.cloud.user.dao.AccountDao; +package org.apache.cloudstack.api.command.admin.solidfire; import javax.inject.Inject; @@ -27,26 +24,23 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.response.ApiSolidFireAccountIdResponse; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.solidfire.ApiSolidFireService; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.api.response.solidfire.ApiSolidFireAccountIdResponse; +import org.apache.cloudstack.solidfire.SolidFireIntegrationTestManager; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; @APICommand(name = "getSolidFireAccountId", responseObject = ApiSolidFireAccountIdResponse.class, description = "Get SolidFire Account ID", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class GetSolidFireAccountIdCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(GetSolidFireAccountIdCmd.class.getName()); - private static final String s_name = "getsolidfireaccountidresponse"; + private static final Logger LOGGER = Logger.getLogger(GetSolidFireAccountIdCmd.class.getName()); + private static final String NAME = "getsolidfireaccountidresponse"; @Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.STRING, description = "CloudStack Account UUID", required = true) - private String accountUuid; + private String csAccountUuid; @Parameter(name = ApiConstants.STORAGE_ID, type = CommandType.STRING, description = "Storage Pool UUID", required = true) private String storagePoolUuid; - @Inject private ApiSolidFireService _apiSolidFireService; - @Inject private AccountDao _accountDao; - @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private SolidFireIntegrationTestManager manager; + @Inject private SolidFireIntegrationTestUtil util; ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -54,26 +48,21 @@ public class GetSolidFireAccountIdCmd extends BaseCmd { @Override public String getCommandName() { - return s_name; + return NAME; } @Override public long getEntityOwnerId() { - Account account = CallContext.current().getCallingAccount(); - - if (account != null) { - return account.getId(); - } - - return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + return util.getAccountIdForAccountUuid(csAccountUuid); } @Override public void execute() { - Account account = _accountDao.findByUuid(accountUuid); - StoragePoolVO storagePool = _storagePoolDao.findByUuid(storagePoolUuid); + LOGGER.info("'GetSolidFireAccountIdCmd.execute' method invoked"); + + long sfAccountId = manager.getSolidFireAccountId(csAccountUuid, storagePoolUuid); - ApiSolidFireAccountIdResponse response = _apiSolidFireService.getSolidFireAccountId(account.getId(), storagePool.getId()); + ApiSolidFireAccountIdResponse response = new ApiSolidFireAccountIdResponse(sfAccountId); response.setResponseName(getCommandName()); response.setObjectName("apisolidfireaccountid"); diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java similarity index 70% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java index c432fb1109..5c15e01a30 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeAccessGroupIdCmd.java @@ -14,12 +14,9 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.command.user.solidfire; +package org.apache.cloudstack.api.command.admin.solidfire; import com.cloud.user.Account; -import com.cloud.org.Cluster; -import com.cloud.storage.StoragePool; -import com.cloud.dc.dao.ClusterDao; import javax.inject.Inject; @@ -29,25 +26,24 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeAccessGroupIdResponse; +import org.apache.cloudstack.api.response.solidfire.ApiSolidFireVolumeAccessGroupIdResponse; import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.solidfire.ApiSolidFireService; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.solidfire.SolidFireIntegrationTestManager; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; @APICommand(name = "getSolidFireVolumeAccessGroupId", responseObject = ApiSolidFireVolumeAccessGroupIdResponse.class, description = "Get the SF Volume Access Group ID", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class GetSolidFireVolumeAccessGroupIdCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(GetSolidFireVolumeAccessGroupIdCmd.class.getName()); - private static final String s_name = "getsolidfirevolumeaccessgroupidresponse"; + private static final Logger LOGGER = Logger.getLogger(GetSolidFireVolumeAccessGroupIdCmd.class.getName()); + private static final String NAME = "getsolidfirevolumeaccessgroupidresponse"; @Parameter(name = ApiConstants.CLUSTER_ID, type = CommandType.STRING, description = "Cluster UUID", required = true) private String clusterUuid; @Parameter(name = ApiConstants.STORAGE_ID, type = CommandType.STRING, description = "Storage Pool UUID", required = true) private String storagePoolUuid; - @Inject private ApiSolidFireService _apiSolidFireService; - @Inject private ClusterDao _clusterDao; - @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private SolidFireIntegrationTestManager manager; + @Inject private SolidFireIntegrationTestUtil util; ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -55,7 +51,7 @@ public class GetSolidFireVolumeAccessGroupIdCmd extends BaseCmd { @Override public String getCommandName() { - return s_name; + return NAME; } @Override @@ -71,10 +67,11 @@ public long getEntityOwnerId() { @Override public void execute() { - Cluster cluster = _clusterDao.findByUuid(clusterUuid); - StoragePool storagePool = _storagePoolDao.findByUuid(storagePoolUuid); + LOGGER.info("'GetSolidFireVolumeAccessGroupIdCmd.execute' method invoked"); - ApiSolidFireVolumeAccessGroupIdResponse response = _apiSolidFireService.getSolidFireVolumeAccessGroupId(cluster.getId(), storagePool.getId()); + long sfVagId = manager.getSolidFireVolumeAccessGroupId(clusterUuid, storagePoolUuid); + + ApiSolidFireVolumeAccessGroupIdResponse response = new ApiSolidFireVolumeAccessGroupIdResponse(sfVagId); response.setResponseName(getCommandName()); response.setObjectName("apisolidfirevolumeaccessgroupid"); diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeSizeCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeSizeCmd.java similarity index 57% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeSizeCmd.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeSizeCmd.java index 3a27a66811..d7c8acfe37 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeSizeCmd.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeSizeCmd.java @@ -14,12 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.command.user.solidfire; - -import com.cloud.storage.Volume; -import com.cloud.user.Account; -import com.cloud.storage.dao.VolumeDao; -import com.cloud.storage.StoragePool; +package org.apache.cloudstack.api.command.admin.solidfire; import javax.inject.Inject; @@ -29,25 +24,21 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeSizeResponse; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.solidfire.ApiSolidFireService; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.api.response.solidfire.ApiSolidFireVolumeSizeResponse; +import org.apache.cloudstack.solidfire.SolidFireIntegrationTestManager; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; @APICommand(name = "getSolidFireVolumeSize", responseObject = ApiSolidFireVolumeSizeResponse.class, description = "Get the SF volume size including Hypervisor Snapshot Reserve", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class GetSolidFireVolumeSizeCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(GetSolidFireVolumeSizeCmd.class.getName()); - private static final String s_name = "getsolidfirevolumesizeresponse"; + private static final Logger LOGGER = Logger.getLogger(GetSolidFireVolumeSizeCmd.class.getName()); + private static final String NAME = "getsolidfirevolumesizeresponse"; @Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.STRING, description = "Volume UUID", required = true) private String volumeUuid; - @Parameter(name = ApiConstants.STORAGE_ID, type = CommandType.STRING, description = "Storage Pool UUID", required = true) - private String storagePoolUuid; - @Inject private ApiSolidFireService _apiSolidFireService; - @Inject private VolumeDao _volumeDao; - @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private SolidFireIntegrationTestManager manager; + @Inject private SolidFireIntegrationTestUtil util; ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -55,26 +46,21 @@ public class GetSolidFireVolumeSizeCmd extends BaseCmd { @Override public String getCommandName() { - return s_name; + return NAME; } @Override public long getEntityOwnerId() { - Account account = CallContext.current().getCallingAccount(); - - if (account != null) { - return account.getId(); - } - - return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + return util.getAccountIdForVolumeUuid(volumeUuid); } @Override public void execute() { - Volume volume = _volumeDao.findByUuid(volumeUuid); - StoragePool storagePool = _storagePoolDao.findByUuid(storagePoolUuid); + LOGGER.info("'GetSolidFireVolumeSizeCmd.execute' method invoked"); + + long sfVolumeSize = manager.getSolidFireVolumeSize(volumeUuid); - ApiSolidFireVolumeSizeResponse response = _apiSolidFireService.getSolidFireVolumeSize(volume, storagePool); + ApiSolidFireVolumeSizeResponse response = new ApiSolidFireVolumeSizeResponse(sfVolumeSize); response.setResponseName(getCommandName()); response.setObjectName("apisolidfirevolumesize"); diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeSnapshotDetailsCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeSnapshotDetailsCmd.java new file mode 100644 index 0000000000..5b9ce37332 --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeSnapshotDetailsCmd.java @@ -0,0 +1,73 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.solidfire; + +import java.util.List; + +import javax.inject.Inject; + +import org.apache.log4j.Logger; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.solidfire.ApiVolumeSnapshotDetailsResponse; +import org.apache.cloudstack.api.response.solidfire.ApiVolumeiScsiNameResponse; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; + +@APICommand(name = "getVolumeSnapshotDetails", responseObject = ApiVolumeiScsiNameResponse.class, description = "Get Volume Snapshot Details", + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) + +public class GetVolumeSnapshotDetailsCmd extends BaseCmd { + private static final Logger LOGGER = Logger.getLogger(GetVolumeSnapshotDetailsCmd.class.getName()); + private static final String NAME = "getvolumesnapshotdetailsresponse"; + + @Parameter(name = ApiConstants.SNAPSHOT_ID, type = CommandType.STRING, description = "CloudStack Snapshot UUID", required = true) + private String snapshotUuid; + + @Inject private SolidFireIntegrationTestUtil util; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return NAME; + } + + @Override + public long getEntityOwnerId() { + return util.getAccountIdForSnapshotUuid(snapshotUuid); + } + + @Override + public void execute() { + LOGGER.info("'" + GetVolumeSnapshotDetailsCmd.class.getSimpleName() + ".execute' method invoked"); + + List responses = util.getSnapshotDetails(snapshotUuid); + + ListResponse listReponse = new ListResponse<>(); + + listReponse.setResponses(responses); + listReponse.setResponseName(getCommandName()); + listReponse.setObjectName("apivolumesnapshotdetails"); + + this.setResponseObject(listReponse); + } +} \ No newline at end of file diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeIscsiNameCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeiScsiNameCmd.java similarity index 55% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeIscsiNameCmd.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeiScsiNameCmd.java index 7afa301403..dd6992caf3 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeIscsiNameCmd.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeiScsiNameCmd.java @@ -14,11 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.command.user.solidfire; - -import com.cloud.storage.dao.VolumeDao; -import com.cloud.storage.Volume; -import com.cloud.user.Account; +package org.apache.cloudstack.api.command.admin.solidfire; import javax.inject.Inject; @@ -27,22 +23,20 @@ import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeIscsiNameResponse; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.solidfire.ApiSolidFireService; +import org.apache.cloudstack.api.response.solidfire.ApiVolumeiScsiNameResponse; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; -@APICommand(name = "getSolidFireVolumeIscsiName", responseObject = ApiSolidFireVolumeIscsiNameResponse.class, description = "Get SolidFire Volume's Iscsi Name", +@APICommand(name = "getVolumeiScsiName", responseObject = ApiVolumeiScsiNameResponse.class, description = "Get Volume's iSCSI Name", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) -public class GetSolidFireVolumeIscsiNameCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(GetSolidFireVolumeIscsiNameCmd.class.getName()); - private static final String s_name = "getsolidfirevolumeiscsinameresponse"; +public class GetVolumeiScsiNameCmd extends BaseCmd { + private static final Logger LOGGER = Logger.getLogger(GetVolumeiScsiNameCmd.class.getName()); + private static final String NAME = "getvolumeiscsinameresponse"; @Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.STRING, description = "CloudStack Volume UUID", required = true) private String volumeUuid; - @Inject private ApiSolidFireService _apiSolidFireService; - @Inject private VolumeDao _volumeDao; + @Inject private SolidFireIntegrationTestUtil _util; ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -50,28 +44,24 @@ public class GetSolidFireVolumeIscsiNameCmd extends BaseCmd { @Override public String getCommandName() { - return s_name; + return NAME; } @Override public long getEntityOwnerId() { - Account account = CallContext.current().getCallingAccount(); - - if (account != null) { - return account.getId(); - } - - return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + return _util.getAccountIdForVolumeUuid(volumeUuid); } @Override public void execute() { - Volume volume = _volumeDao.findByUuid(volumeUuid); + LOGGER.info("'GetVolumeiScsiNameCmd.execute' method invoked"); + + String volume_iScsiName = _util.getVolume_iScsiName(volumeUuid); - ApiSolidFireVolumeIscsiNameResponse response = _apiSolidFireService.getSolidFireVolumeIscsiName(volume); + ApiVolumeiScsiNameResponse response = new ApiVolumeiScsiNameResponse(volume_iScsiName); response.setResponseName(getCommandName()); - response.setObjectName("apisolidfirevolumeiscsiname"); + response.setObjectName("apivolumeiscsiname"); this.setResponseObject(response); } diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeIscsiNameResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiPathForVolumeResponse.java similarity index 65% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeIscsiNameResponse.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiPathForVolumeResponse.java index 517cba93ec..3e0f820aea 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeIscsiNameResponse.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiPathForVolumeResponse.java @@ -14,24 +14,20 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.response; - -import com.cloud.serializer.Param; - -import com.google.gson.annotations.SerializedName; +package org.apache.cloudstack.api.response.solidfire; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; -public class ApiSolidFireVolumeIscsiNameResponse extends BaseResponse { - @SerializedName("solidFireVolumeIscsiName") - @Param(description = "SolidFire Volume Iscsi Name") - private String solidFireVolumeIscsiName; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; - public ApiSolidFireVolumeIscsiNameResponse(String sfVolumeIscsiName) { - solidFireVolumeIscsiName = sfVolumeIscsiName; - } +public class ApiPathForVolumeResponse extends BaseResponse { + @SerializedName(ApiConstants.PATH) + @Param(description = "The path field for the volume") + private String path; - public String getSolidFireVolumeIscsiName() { - return solidFireVolumeIscsiName; + public ApiPathForVolumeResponse(String path) { + this.path = path; } -} \ No newline at end of file +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireAccountIdResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireAccountIdResponse.java similarity index 90% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireAccountIdResponse.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireAccountIdResponse.java index ad77c7495d..a1c2a4c32d 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireAccountIdResponse.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireAccountIdResponse.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.response; +package org.apache.cloudstack.api.response.solidfire; import com.cloud.serializer.Param; @@ -30,8 +30,4 @@ public class ApiSolidFireAccountIdResponse extends BaseResponse { public ApiSolidFireAccountIdResponse(long sfAccountId) { solidFireAccountId = sfAccountId; } - - public long getSolidFireAccountId() { - return solidFireAccountId; - } } diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeAccessGroupIdResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdResponse.java similarity index 90% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeAccessGroupIdResponse.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdResponse.java index 8b63192b7c..202a7e9ebb 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeAccessGroupIdResponse.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeAccessGroupIdResponse.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.response; +package org.apache.cloudstack.api.response.solidfire; import com.cloud.serializer.Param; @@ -30,8 +30,4 @@ public class ApiSolidFireVolumeAccessGroupIdResponse extends BaseResponse { public ApiSolidFireVolumeAccessGroupIdResponse(long sfVolumeAccessGroupId) { solidFireVolumeAccessGroupId = sfVolumeAccessGroupId; } - - public long getSolidFireAccessGroupId() { - return solidFireVolumeAccessGroupId; - } } \ No newline at end of file diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeSizeResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeSizeResponse.java similarity index 90% rename from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeSizeResponse.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeSizeResponse.java index b320adab87..d8a7d0407c 100644 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeSizeResponse.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiSolidFireVolumeSizeResponse.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.response; +package org.apache.cloudstack.api.response.solidfire; import com.cloud.serializer.Param; @@ -30,8 +30,4 @@ public class ApiSolidFireVolumeSizeResponse extends BaseResponse { public ApiSolidFireVolumeSizeResponse(long sfVolumeSize) { solidFireVolumeSize = sfVolumeSize; } - - public long getSolidFireVolumeSize() { - return solidFireVolumeSize; - } } \ No newline at end of file diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeSnapshotDetailsResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeSnapshotDetailsResponse.java new file mode 100644 index 0000000000..364ded8dce --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeSnapshotDetailsResponse.java @@ -0,0 +1,43 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response.solidfire; + +import com.cloud.serializer.Param; + +import com.google.gson.annotations.SerializedName; + +import org.apache.cloudstack.api.BaseResponse; + +public class ApiVolumeSnapshotDetailsResponse extends BaseResponse { + @SerializedName("volumeSnapshotId") + @Param(description = "CloudStack Volume Snapshot ID") + private long volumeSnapshotId; + + @SerializedName("snapshotDetailsName") + @Param(description = "Snapshot Details Name") + private String volumeSnapshotDetailsName; + + @SerializedName("snapshotDetailsValue") + @Param(description = "Snapshot Details Value") + private String volumeSnapshotDetailsValue; + + public ApiVolumeSnapshotDetailsResponse(long volumeSnapshotId, String volumeSnapshotDetailsName, String volumeSnapshotDetailsValue) { + this.volumeSnapshotId = volumeSnapshotId; + this.volumeSnapshotDetailsName = volumeSnapshotDetailsName; + this.volumeSnapshotDetailsValue = volumeSnapshotDetailsValue; + } +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/response/StatusResponse.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeiScsiNameResponse.java similarity index 70% rename from api/src/org/apache/cloudstack/api/response/StatusResponse.java rename to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeiScsiNameResponse.java index fa2b4b2020..f43e53352a 100644 --- a/api/src/org/apache/cloudstack/api/response/StatusResponse.java +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeiScsiNameResponse.java @@ -14,21 +14,20 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.api.response; +package org.apache.cloudstack.api.response.solidfire; + +import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; import org.apache.cloudstack.api.BaseResponse; -public class StatusResponse extends BaseResponse { - @SerializedName("status") - private Boolean status; - - public Boolean getStatus() { - return status; - } +public class ApiVolumeiScsiNameResponse extends BaseResponse { + @SerializedName("volumeiScsiName") + @Param(description = "Volume iSCSI Name") + private String volumeiScsiName; - public void setStatus(Boolean status) { - this.status = status; + public ApiVolumeiScsiNameResponse(String volumeiScsiName) { + this.volumeiScsiName = volumeiScsiName; } } diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestService.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestService.java new file mode 100644 index 0000000000..ff206d3a3b --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestService.java @@ -0,0 +1,22 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.solidfire; + +import com.cloud.utils.component.PluggableService; + +public interface ApiSolidFireIntegrationTestService extends PluggableService { +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestServiceImpl.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestServiceImpl.java new file mode 100644 index 0000000000..04589038d3 --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestServiceImpl.java @@ -0,0 +1,48 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.solidfire; + +import java.util.List; +import java.util.ArrayList; + +import org.apache.cloudstack.api.command.admin.solidfire.GetPathForVolumeCmd; +// import org.apache.log4j.Logger; +import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireAccountIdCmd; +import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireVolumeAccessGroupIdCmd; +import org.apache.cloudstack.api.command.admin.solidfire.GetVolumeSnapshotDetailsCmd; +import org.apache.cloudstack.api.command.admin.solidfire.GetVolumeiScsiNameCmd; +import org.apache.cloudstack.api.command.admin.solidfire.GetSolidFireVolumeSizeCmd; +import org.springframework.stereotype.Component; + +import com.cloud.utils.component.AdapterBase; + +@Component +public class ApiSolidFireIntegrationTestServiceImpl extends AdapterBase implements ApiSolidFireIntegrationTestService { + @Override + public List> getCommands() { + List> cmdList = new ArrayList>(); + + cmdList.add(GetPathForVolumeCmd.class); + cmdList.add(GetSolidFireAccountIdCmd.class); + cmdList.add(GetSolidFireVolumeAccessGroupIdCmd.class); + cmdList.add(GetVolumeiScsiNameCmd.class); + cmdList.add(GetSolidFireVolumeSizeCmd.class); + cmdList.add(GetVolumeSnapshotDetailsCmd.class); + + return cmdList; + } +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireService.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireService.java deleted file mode 100644 index 92828d4b81..0000000000 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireService.java +++ /dev/null @@ -1,37 +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.solidfire; - -import com.cloud.utils.component.PluggableService; -import com.cloud.storage.Volume; -import com.cloud.storage.StoragePool; - -import org.apache.cloudstack.api.response.ApiSolidFireAccountIdResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeSizeResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeAccessGroupIdResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeIscsiNameResponse; - -/** - * Provide API for SolidFire integration tests - * - */ -public interface ApiSolidFireService extends PluggableService { - public ApiSolidFireAccountIdResponse getSolidFireAccountId(Long csAccountId, Long storagePoolId); - public ApiSolidFireVolumeSizeResponse getSolidFireVolumeSize(Volume volume, StoragePool storagePool); - public ApiSolidFireVolumeAccessGroupIdResponse getSolidFireVolumeAccessGroupId(Long csClusterId, Long storagePoolId); - public ApiSolidFireVolumeIscsiNameResponse getSolidFireVolumeIscsiName(Volume volume); -} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireServiceImpl.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireServiceImpl.java deleted file mode 100644 index fbda65433a..0000000000 --- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/ApiSolidFireServiceImpl.java +++ /dev/null @@ -1,126 +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.solidfire; - -import java.util.Map; -import java.util.List; -import java.util.ArrayList; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -// import org.apache.log4j.Logger; -import org.apache.cloudstack.acl.APIChecker; -import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; -import org.apache.cloudstack.api.command.user.solidfire.GetSolidFireAccountIdCmd; -import org.apache.cloudstack.api.command.user.solidfire.GetSolidFireVolumeAccessGroupIdCmd; -import org.apache.cloudstack.api.command.user.solidfire.GetSolidFireVolumeIscsiNameCmd; -import org.apache.cloudstack.api.command.user.solidfire.GetSolidFireVolumeSizeCmd; -import org.apache.cloudstack.api.response.ApiSolidFireAccountIdResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeAccessGroupIdResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeIscsiNameResponse; -import org.apache.cloudstack.api.response.ApiSolidFireVolumeSizeResponse; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; -import org.springframework.stereotype.Component; - -import com.cloud.dc.ClusterDetailsDao; -import com.cloud.dc.ClusterDetailsVO; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; -import com.cloud.user.AccountDetailsDao; -import com.cloud.user.AccountDetailVO; -import com.cloud.user.User; -import com.cloud.utils.component.AdapterBase; - -@Component -public class ApiSolidFireServiceImpl extends AdapterBase implements APIChecker, ApiSolidFireService { - // private static final Logger s_logger = Logger.getLogger(ApiSolidFireServiceImpl.class); - - @Inject private AccountDetailsDao _accountDetailsDao; - @Inject private DataStoreProviderManager _dataStoreProviderMgr; - @Inject private ClusterDetailsDao _clusterDetailsDao; - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - super.configure(name, params); - - return true; - } - - @Override - public ApiSolidFireAccountIdResponse getSolidFireAccountId(Long csAccountId, Long storagePoolId) { - AccountDetailVO accountDetail = _accountDetailsDao.findDetail(csAccountId, SolidFireUtil.getAccountKey(storagePoolId)); - String sfAccountId = accountDetail.getValue(); - - return new ApiSolidFireAccountIdResponse(Long.parseLong(sfAccountId)); - } - - @Override - public ApiSolidFireVolumeSizeResponse getSolidFireVolumeSize(Volume volume, StoragePool storagePool) { - PrimaryDataStoreDriver primaryStoreDriver = null; - - try { - DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(storagePool.getStorageProviderName()); - DataStoreDriver storeDriver = storeProvider.getDataStoreDriver(); - - if (storeDriver instanceof PrimaryDataStoreDriver) { - primaryStoreDriver = (PrimaryDataStoreDriver)storeDriver; - } - } - catch (InvalidParameterValueException e) { - throw new InvalidParameterValueException("Invalid Storage Driver Type"); - } - - return new ApiSolidFireVolumeSizeResponse(primaryStoreDriver.getVolumeSizeIncludingHypervisorSnapshotReserve(volume, storagePool)); - } - - @Override - public ApiSolidFireVolumeAccessGroupIdResponse getSolidFireVolumeAccessGroupId(Long csClusterId, Long storagePoolId) { - ClusterDetailsVO clusterDetails = _clusterDetailsDao.findDetail(csClusterId, SolidFireUtil.getVagKey(storagePoolId)); - String sfVagId = clusterDetails.getValue(); - - return new ApiSolidFireVolumeAccessGroupIdResponse(Long.parseLong(sfVagId)); - } - - @Override - public ApiSolidFireVolumeIscsiNameResponse getSolidFireVolumeIscsiName(Volume volume) { - return new ApiSolidFireVolumeIscsiNameResponse(volume.get_iScsiName()); - } - - - @Override - public boolean checkAccess(User user, String apiCommandName) throws PermissionDeniedException { - return true; - } - - @Override - public List> getCommands() { - List> cmdList = new ArrayList>(); - - cmdList.add(GetSolidFireAccountIdCmd.class); - cmdList.add(GetSolidFireVolumeSizeCmd.class); - cmdList.add(GetSolidFireVolumeAccessGroupIdCmd.class); - cmdList.add(GetSolidFireVolumeIscsiNameCmd.class); - - return cmdList; - } -} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java new file mode 100644 index 0000000000..bdc11807ef --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java @@ -0,0 +1,23 @@ +// 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.solidfire; + +public interface SolidFireIntegrationTestManager { + long getSolidFireAccountId(String csAccountUuid, String storagePoolUuid); + long getSolidFireVolumeAccessGroupId(String csClusterUuid, String storagePoolUuid); + long getSolidFireVolumeSize(String volumeUuid); +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManagerImpl.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManagerImpl.java new file mode 100644 index 0000000000..ff6e72cb29 --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManagerImpl.java @@ -0,0 +1,78 @@ +// 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.solidfire; + +import javax.inject.Inject; + +import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; +import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil; +import org.springframework.stereotype.Component; + +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.storage.VolumeDetailVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeDetailsDao; +import com.cloud.user.AccountDetailsDao; +import com.cloud.user.AccountDetailVO; +import com.cloud.utils.exception.CloudRuntimeException; + +@Component +public class SolidFireIntegrationTestManagerImpl implements SolidFireIntegrationTestManager { + + @Inject private AccountDetailsDao accountDetailsDao; + @Inject private ClusterDetailsDao clusterDetailsDao; + @Inject private SolidFireIntegrationTestUtil util; + @Inject private VolumeDao volumeDao; + @Inject private VolumeDetailsDao volumeDetailsDao; + + @Override + public long getSolidFireAccountId(String csAccountUuid, String storagePoolUuid) { + long csAccountId = util.getAccountIdForAccountUuid(csAccountUuid); + long storagePoolId = util.getStoragePoolIdForStoragePoolUuid(storagePoolUuid); + + AccountDetailVO accountDetail = accountDetailsDao.findDetail(csAccountId, SolidFireUtil.getAccountKey(storagePoolId)); + String sfAccountId = accountDetail.getValue(); + + return Long.parseLong(sfAccountId); + } + + @Override + public long getSolidFireVolumeAccessGroupId(String csClusterUuid, String storagePoolUuid) { + long csClusterId = util.getClusterIdForClusterUuid(csClusterUuid); + long storagePoolId = util.getStoragePoolIdForStoragePoolUuid(storagePoolUuid); + + ClusterDetailsVO clusterDetails = clusterDetailsDao.findDetail(csClusterId, SolidFireUtil.getVagKey(storagePoolId)); + String sfVagId = clusterDetails.getValue(); + + return Long.parseLong(sfVagId); + } + + @Override + public long getSolidFireVolumeSize(String volumeUuid) { + VolumeVO volume = volumeDao.findByUuid(volumeUuid); + + VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volume.getId(), SolidFireUtil.VOLUME_SIZE); + + if (volumeDetail != null && volumeDetail.getValue() != null) { + return Long.parseLong(volumeDetail.getValue()); + } + + throw new CloudRuntimeException("Unable to determine the size of the SolidFire volume"); + } +} diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/util/solidfire/SolidFireIntegrationTestUtil.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/util/solidfire/SolidFireIntegrationTestUtil.java new file mode 100644 index 0000000000..307e8c5969 --- /dev/null +++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/util/solidfire/SolidFireIntegrationTestUtil.java @@ -0,0 +1,112 @@ +// 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.util.solidfire; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.response.solidfire.ApiVolumeSnapshotDetailsResponse; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + +import com.cloud.dc.ClusterVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.SnapshotDetailsDao; +import com.cloud.storage.dao.SnapshotDetailsVO; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.user.Account; +import com.cloud.user.dao.AccountDao; + +public class SolidFireIntegrationTestUtil { + @Inject private AccountDao accountDao; + @Inject private ClusterDao clusterDao; + @Inject private PrimaryDataStoreDao storagePoolDao; + @Inject private SnapshotDao snapshotDao; + @Inject private SnapshotDetailsDao snapshotDetailsDao; + @Inject private VolumeDao volumeDao; + + private SolidFireIntegrationTestUtil() {} + + public long getAccountIdForAccountUuid(String accountUuid) { + Account account = accountDao.findByUuid(accountUuid); + + return account.getAccountId(); + } + + public long getAccountIdForVolumeUuid(String volumeUuid) { + VolumeVO volume = volumeDao.findByUuid(volumeUuid); + + return volume.getAccountId(); + } + + public long getAccountIdForSnapshotUuid(String snapshotUuid) { + SnapshotVO snapshot = snapshotDao.findByUuid(snapshotUuid); + + return snapshot.getAccountId(); + } + + public long getClusterIdForClusterUuid(String clusterUuid) { + ClusterVO cluster = clusterDao.findByUuid(clusterUuid); + + return cluster.getId(); + } + + public long getStoragePoolIdForStoragePoolUuid(String storagePoolUuid) { + StoragePoolVO storagePool = storagePoolDao.findByUuid(storagePoolUuid); + + return storagePool.getId(); + } + + public String getPathForVolumeUuid(String volumeUuid) { + VolumeVO volume = volumeDao.findByUuid(volumeUuid); + + return volume.getPath(); + } + + public String getVolume_iScsiName(String volumeUuid) { + VolumeVO volume = volumeDao.findByUuid(volumeUuid); + + return volume.get_iScsiName(); + } + + public List getSnapshotDetails(String snapshotUuid) { + SnapshotVO snapshot = snapshotDao.findByUuid(snapshotUuid); + + List snapshotDetails = snapshotDetailsDao.listDetails(snapshot.getId()); + + List responses = new ArrayList<>(); + + if (snapshotDetails != null) { + for (SnapshotDetailsVO snapshotDetail : snapshotDetails) { + ApiVolumeSnapshotDetailsResponse response = new ApiVolumeSnapshotDetailsResponse( + snapshotDetail.getResourceId(), + snapshotDetail.getName(), + snapshotDetail.getValue() + ); + + responses.add(response); + } + } + + return responses; + } +} diff --git a/plugins/database/mysql-ha/pom.xml b/plugins/database/mysql-ha/pom.xml index 9b89047dc1..c275743cef 100644 --- a/plugins/database/mysql-ha/pom.xml +++ b/plugins/database/mysql-ha/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/database/quota/pom.xml b/plugins/database/quota/pom.xml index 450eb67860..b429c0ddd9 100644 --- a/plugins/database/quota/pom.xml +++ b/plugins/database/quota/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java index 125844548a..f12733d2ce 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java @@ -123,7 +123,7 @@ public void execute() { if (getValue() == null) { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please send a valid non-empty quota value"); } - if (getQuotaEnforce() != null && getQuotaEnforce()) { + if (getQuotaEnforce() != null) { _quotaService.setLockAccount(accountId, getQuotaEnforce()); } if (getMinBalance() != null) { @@ -133,7 +133,7 @@ public void execute() { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please set a value for min balance"); } - final QuotaCreditsResponse response = _responseBuilder.addQuotaCredits(accountId, getDomainId(), getValue(), CallContext.current().getCallingUserId()); + final QuotaCreditsResponse response = _responseBuilder.addQuotaCredits(accountId, getDomainId(), getValue(), CallContext.current().getCallingUserId(), getQuotaEnforce()); response.setResponseName(getCommandName()); response.setObjectName("quotacredits"); setResponseObject(response); diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaSummaryCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaSummaryCmd.java index b4f2001f95..88466e08c6 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaSummaryCmd.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaSummaryCmd.java @@ -59,7 +59,7 @@ public QuotaSummaryCmd() { public void execute() { Account caller = CallContext.current().getCallingAccount(); List responses; - if (caller.getAccountId() <= 2) { //non root admin or system + if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN) { //admin account if (getAccountName() != null && getDomainId() != null) responses = _responseBuilder.createQuotaSummaryResponse(caller.getAccountName(), caller.getDomainId()); else diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java index 6e7ab81118..0f276973ee 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java @@ -51,7 +51,7 @@ public interface QuotaResponseBuilder { List getQuotaBalance(QuotaBalanceCmd cmd); - QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy); + QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy, Boolean enforce); List listQuotaEmailTemplates(QuotaEmailTemplateListCmd cmd); diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java index 1b6f400f40..5748de5896 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java @@ -32,6 +32,7 @@ import org.apache.cloudstack.api.command.QuotaStatementCmd; import org.apache.cloudstack.api.command.QuotaTariffListCmd; import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd; +import org.apache.cloudstack.quota.QuotaManager; import org.apache.cloudstack.quota.QuotaService; import org.apache.cloudstack.quota.QuotaStatement; import org.apache.cloudstack.quota.constant.QuotaConfig; @@ -98,6 +99,8 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { private AccountManager _accountMgr; @Inject private QuotaStatement _statement; + @Inject + private QuotaManager _quotaManager; @Override public QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO tariff) { @@ -138,6 +141,7 @@ public List createQuotaSummaryResponse(Boolean listAll) { } else { for (final QuotaAccountVO quotaAccount : _quotaAccountDao.listAllQuotaAccount()) { AccountVO account = _accountDao.findById(quotaAccount.getId()); + if (account == null) continue; QuotaSummaryResponse qr = getQuotaSummaryResponse(account); result.add(qr); } @@ -167,17 +171,19 @@ private QuotaSummaryResponse getQuotaSummaryResponse(final Account account) { qr.setObjectName("summary"); return qr; } else { - throw new InvalidParameterValueException("Quota summary response for an account requires a valid account."); + return new QuotaSummaryResponse(); } } @Override public QuotaBalanceResponse createQuotaBalanceResponse(List quotaBalance, Date startDate, Date endDate) { if (quotaBalance == null || quotaBalance.isEmpty()) { - new InvalidParameterValueException("The request period does not contain balance entries."); + throw new InvalidParameterValueException("The request period does not contain balance entries."); } Collections.sort(quotaBalance, new Comparator() { public int compare(QuotaBalanceVO o1, QuotaBalanceVO o2) { + o1 = o1 == null ? new QuotaBalanceVO() : o1; + o2 = o2 == null ? new QuotaBalanceVO() : o2; return o2.getUpdatedOn().compareTo(o1.getUpdatedOn()); // desc } }); @@ -186,7 +192,7 @@ public int compare(QuotaBalanceVO o1, QuotaBalanceVO o2) { //check that there is at least one balance entry for (Iterator it = quotaBalance.iterator(); it.hasNext();) { QuotaBalanceVO entry = it.next(); - if (entry.getCreditsId() > 0) { + if (entry.isBalanceEntry()) { have_balance_entries = true; break; } @@ -382,11 +388,10 @@ public QuotaTariffVO updateQuotaTariffPlan(QuotaTariffUpdateCmd cmd) { } @Override - public QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy) { + public QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy, Boolean enforce) { Date despositedOn = _quotaService.computeAdjustedTime(new Date()); QuotaBalanceVO qb = _quotaBalanceDao.findLaterBalanceEntry(accountId, domainId, despositedOn); - if (qb != null) { throw new InvalidParameterValueException("Incorrect deposit date: " + despositedOn + " there are balance entries after this date"); } @@ -396,6 +401,9 @@ public QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Doubl QuotaCreditsVO result = _quotaCreditsDao.saveCredits(credits); final AccountVO account = _accountDao.findById(accountId); + if (account == null) { + throw new InvalidParameterValueException("Account does not exist with account id " + accountId); + } final boolean lockAccountEnforcement = "true".equalsIgnoreCase(QuotaConfig.QuotaEnableEnforcement.value()); final BigDecimal currentAccountBalance = _quotaBalanceDao.lastQuotaBalance(accountId, domainId, startOfNextDay(new Date(despositedOn.getTime()))); if (s_logger.isDebugEnabled()) { @@ -405,16 +413,12 @@ public QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Doubl _quotaService.saveQuotaAccount(account, currentAccountBalance, despositedOn); if (lockAccountEnforcement) { if (currentAccountBalance.compareTo(new BigDecimal(0)) >= 0) { - if (account.getType() == Account.ACCOUNT_TYPE_NORMAL) { - if (account.getState() == Account.State.locked) { - s_logger.info("UnLocking account " + account.getAccountName() + " , due to positive balance " + currentAccountBalance); - _accountMgr.enableAccount(account.getAccountName(), domainId, accountId); - } - } else { - s_logger.warn("Only normal accounts will get locked " + account.getAccountName() + " even if they have run out of quota " + currentAccountBalance); + if (account.getState() == Account.State.locked) { + s_logger.info("UnLocking account " + account.getAccountName() + " , due to positive balance " + currentAccountBalance); + _accountMgr.enableAccount(account.getAccountName(), domainId, accountId); } } else { // currentAccountBalance < 0 then lock the account - if (account.getState() == Account.State.enabled) { + if (_quotaManager.isLockable(account) && account.getState() == Account.State.enabled && enforce) { s_logger.info("Locking account " + account.getAccountName() + " , due to negative balance " + currentAccountBalance); _accountMgr.lockAccount(account.getAccountName(), domainId, accountId); } diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java index 0fd7101bf6..3efc0959e6 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java @@ -274,14 +274,14 @@ public Date computeAdjustedTime(final Date date) { } @Override - public void setLockAccount(Long accountId, Boolean state) { + public void setLockAccount(Long accountId, Boolean enforce) { QuotaAccountVO acc = _quotaAcc.findByIdQuotaAccount(accountId); if (acc == null) { acc = new QuotaAccountVO(accountId); - acc.setQuotaEnforce(state ? 1 : 0); + acc.setQuotaEnforce(enforce ? 1 : 0); _quotaAcc.persistQuotaAccount(acc); } else { - acc.setQuotaEnforce(state ? 1 : 0); + acc.setQuotaEnforce(enforce ? 1 : 0); _quotaAcc.updateQuotaAccount(accountId, acc); } } diff --git a/plugins/database/quota/test/org/apache/cloudstack/api/command/QuotaCreditsCmdTest.java b/plugins/database/quota/test/org/apache/cloudstack/api/command/QuotaCreditsCmdTest.java index f4d16b7b68..1f22508d81 100644 --- a/plugins/database/quota/test/org/apache/cloudstack/api/command/QuotaCreditsCmdTest.java +++ b/plugins/database/quota/test/org/apache/cloudstack/api/command/QuotaCreditsCmdTest.java @@ -65,7 +65,7 @@ public void testQuotaCreditsCmd() throws NoSuchFieldException, IllegalAccessExce AccountVO acc = new AccountVO(); acc.setId(2L); Mockito.when(accountService.getActiveAccountByName(Mockito.anyString(), Mockito.anyLong())).thenReturn(acc); - Mockito.when(responseBuilder.addQuotaCredits(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyDouble(), Mockito.anyLong())).thenReturn(new QuotaCreditsResponse()); + Mockito.when(responseBuilder.addQuotaCredits(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyDouble(), Mockito.anyLong(), Mockito.anyBoolean())).thenReturn(new QuotaCreditsResponse()); // No value provided test try { @@ -79,7 +79,7 @@ public void testQuotaCreditsCmd() throws NoSuchFieldException, IllegalAccessExce cmd.execute(); Mockito.verify(quotaService, Mockito.times(0)).setLockAccount(Mockito.anyLong(), Mockito.anyBoolean()); Mockito.verify(quotaService, Mockito.times(1)).setMinBalance(Mockito.anyLong(), Mockito.anyDouble()); - Mockito.verify(responseBuilder, Mockito.times(1)).addQuotaCredits(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyDouble(), Mockito.anyLong()); + Mockito.verify(responseBuilder, Mockito.times(1)).addQuotaCredits(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyDouble(), Mockito.anyLong(), Mockito.anyBoolean()); } diff --git a/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java b/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java index 73ead4a71b..4a76052f69 100644 --- a/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java +++ b/plugins/database/quota/test/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java @@ -118,7 +118,7 @@ private QuotaTariffVO makeTariffTestData() { tariffVO.setUsageType(QuotaTypes.IP_ADDRESS); tariffVO.setUsageName("ip address"); tariffVO.setUsageUnit("IP-Month"); - tariffVO.setCurrencyValue(new BigDecimal(100.19)); + tariffVO.setCurrencyValue(BigDecimal.valueOf(100.19)); tariffVO.setEffectiveOn(new Date()); tariffVO.setUsageDiscriminator(""); return tariffVO; @@ -150,7 +150,7 @@ public void testAddQuotaCredits() { account.setState(Account.State.locked); Mockito.when(accountDao.findById(Mockito.anyLong())).thenReturn(account); - QuotaCreditsResponse resp = quotaResponseBuilder.addQuotaCredits(accountId, domainId, amount, updatedBy); + QuotaCreditsResponse resp = quotaResponseBuilder.addQuotaCredits(accountId, domainId, amount, updatedBy, true); assertTrue(resp.getCredits().compareTo(credit.getCredit()) == 0); } diff --git a/plugins/dedicated-resources/pom.xml b/plugins/dedicated-resources/pom.xml index 24a86913bb..040e936d49 100644 --- a/plugins/dedicated-resources/pom.xml +++ b/plugins/dedicated-resources/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/plugins/deployment-planners/implicit-dedication/pom.xml b/plugins/deployment-planners/implicit-dedication/pom.xml index 15b56bfa4f..f0f817ce9f 100644 --- a/plugins/deployment-planners/implicit-dedication/pom.xml +++ b/plugins/deployment-planners/implicit-dedication/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/deployment-planners/user-concentrated-pod/pom.xml b/plugins/deployment-planners/user-concentrated-pod/pom.xml index f22932b5e7..d27188dcc8 100644 --- a/plugins/deployment-planners/user-concentrated-pod/pom.xml +++ b/plugins/deployment-planners/user-concentrated-pod/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/deployment-planners/user-dispersing/pom.xml b/plugins/deployment-planners/user-dispersing/pom.xml index 20a63d902a..413993f24f 100644 --- a/plugins/deployment-planners/user-dispersing/pom.xml +++ b/plugins/deployment-planners/user-dispersing/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/event-bus/inmemory/pom.xml b/plugins/event-bus/inmemory/pom.xml index 50c842c6dc..efbf29086d 100644 --- a/plugins/event-bus/inmemory/pom.xml +++ b/plugins/event-bus/inmemory/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/event-bus/kafka/pom.xml b/plugins/event-bus/kafka/pom.xml index 4d380b9973..2bae703443 100644 --- a/plugins/event-bus/kafka/pom.xml +++ b/plugins/event-bus/kafka/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml @@ -36,7 +36,7 @@ org.apache.kafka kafka-clients - 0.8.2.0 + 0.9.0.1 diff --git a/plugins/event-bus/rabbitmq/pom.xml b/plugins/event-bus/rabbitmq/pom.xml index e68d49a28a..7e797099c0 100644 --- a/plugins/event-bus/rabbitmq/pom.xml +++ b/plugins/event-bus/rabbitmq/pom.xml @@ -24,14 +24,14 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml com.rabbitmq amqp-client - 3.5.4 + 3.6.1 org.apache.cloudstack diff --git a/plugins/file-systems/netapp/pom.xml b/plugins/file-systems/netapp/pom.xml index 205eddc795..2b2c7bd923 100644 --- a/plugins/file-systems/netapp/pom.xml +++ b/plugins/file-systems/netapp/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/ha-planners/skip-heurestics/pom.xml b/plugins/ha-planners/skip-heurestics/pom.xml index 140737ce87..1511f8da0d 100644 --- a/plugins/ha-planners/skip-heurestics/pom.xml +++ b/plugins/ha-planners/skip-heurestics/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/host-allocators/random/pom.xml b/plugins/host-allocators/random/pom.xml index 9d55949952..62284c229f 100644 --- a/plugins/host-allocators/random/pom.xml +++ b/plugins/host-allocators/random/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/baremetal/pom.xml b/plugins/hypervisors/baremetal/pom.xml index 109e418179..6e569cf680 100755 --- a/plugins/hypervisors/baremetal/pom.xml +++ b/plugins/hypervisors/baremetal/pom.xml @@ -21,7 +21,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml cloud-plugin-hypervisor-baremetal diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java index 2451b561bc..aca756502e 100644 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalVlanManagerImpl.java @@ -37,12 +37,13 @@ import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.QueryBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.vm.VirtualMachineProfile; -import com.google.gson.Gson; -import org.apache.cloudstack.api.AddBaremetalRctCmd; -import org.apache.cloudstack.api.DeleteBaremetalRctCmd; -import org.apache.cloudstack.api.ListBaremetalRctCmd; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VirtualMachineProfile; +import com.google.gson.Gson; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.AddBaremetalRctCmd; +import org.apache.cloudstack.api.DeleteBaremetalRctCmd; +import org.apache.cloudstack.api.ListBaremetalRctCmd; import org.apache.cloudstack.utils.baremetal.BaremetalUtils; import org.springframework.web.client.RestTemplate; @@ -244,12 +245,14 @@ public boolean start() { acnt = new AccountVO(); acnt.setAccountName(BaremetalUtils.BAREMETAL_SYSTEM_ACCOUNT_NAME); - acnt.setUuid(UUID.randomUUID().toString()); - acnt.setState(Account.State.enabled); - acnt.setDomainId(1); - acnt = acntDao.persist(acnt); - - UserVO user = new UserVO(); + acnt.setUuid(UUID.randomUUID().toString()); + acnt.setState(Account.State.enabled); + acnt.setDomainId(1); + acnt.setType(RoleType.User.getAccountType()); + acnt.setRoleId(RoleType.User.getId()); + acnt = acntDao.persist(acnt); + + UserVO user = new UserVO(); user.setState(Account.State.enabled); user.setUuid(UUID.randomUUID().toString()); user.setAccountId(acnt.getAccountId()); diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java index b9e4858895..b100929da9 100644 --- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java +++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java @@ -1,205 +1,205 @@ -// 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. -// -// Automatically generated by addcopyright.py at 01/29/2013 -// Apache License, Version 2.0 (the "License"); you may not use this -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// -// Automatically generated by addcopyright.py at 04/03/2012 - -package com.cloud.baremetal.networkservice; - -import com.cloud.agent.api.SecurityGroupRuleAnswer; -import com.cloud.agent.api.SecurityGroupRulesCmd; -import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto; -import com.cloud.baremetal.networkservice.schema.SecurityGroupRule; -import com.cloud.baremetal.networkservice.schema.SecurityGroupVmRuleSet; -import com.cloud.utils.Pair; -import com.cloud.utils.exception.CloudRuntimeException; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.StringRequestEntity; -import org.apache.log4j.Logger; - -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; -import java.io.StringWriter; -import java.net.SocketTimeoutException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.TimeUnit; - -public class SecurityGroupHttpClient { - private static final Logger logger = Logger.getLogger(SecurityGroupHttpClient.class); - private static final String ARG_NAME = "args"; - private static final String COMMAND = "command"; - private JAXBContext context; - private int port; - private static HttpClient httpClient; - static { - MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager(); - httpClient = new HttpClient(connman); - httpClient.setConnectionTimeout(5000); - } - - private enum OpConstant { - setRules, echo, - } - - public SecurityGroupHttpClient() { - try { - context = JAXBContext.newInstance(SecurityGroupRule.class, SecurityGroupVmRuleSet.class); - port = 9988; - } catch (Exception e) { - throw new CloudRuntimeException( - "Unable to create JAXBContext for security group", e); - } - } - - private List generateRules(IpPortAndProto[] ipps) { - List rules = new ArrayList( - ipps.length); - for (SecurityGroupRulesCmd.IpPortAndProto ipp : ipps) { - SecurityGroupRule r = new SecurityGroupRule(); - r.setProtocol(ipp.getProto()); - r.setStartPort(ipp.getStartPort()); - r.setEndPort(ipp.getEndPort()); - for (String cidr : ipp.getAllowedCidrs()) { - r.getIp().add(cidr); - } - rules.add(r); - } - return rules; - } - - public HashMap> sync(String vmName, Long vmId, String agentIp) { - HashMap> states = new HashMap>(); - PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort())); - try { - post.addRequestHeader("command", "sync"); - if (httpClient.executeMethod(post) != 200) { - logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString())); - } else { - String res = post.getResponseBodyAsString(); - // res = ';'.join([vmName, vmId, seqno]) - String[] rulelogs = res.split(","); - if (rulelogs.length != 6) { - logger.debug(String.format("host[%s] returns invalid security group sync document[%s], reset rules", agentIp, res)); - states.put(vmName, new Pair(vmId, -1L)); - return states; - } - Pair p = new Pair(Long.valueOf(rulelogs[1]), Long.valueOf(rulelogs[5])); - states.put(rulelogs[0], p); - return states; - } - } catch (SocketTimeoutException se) { - logger.warn(String.format("unable to sync security group rules on host[%s], %s", agentIp, se.getMessage())); - } catch (Exception e) { - logger.warn(String.format("unable to sync security group rules on host[%s]", agentIp), e); - } finally { - if (post != null) { - post.releaseConnection(); - } - } - return states; - } - - - public boolean echo(String agentIp, long l, long m) { - boolean ret = false; - int count = 1; - while (true) { - try { - Thread.sleep(m); - count++; - } catch (InterruptedException e1) { - logger.warn("", e1); - break; - } - PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort())); - try { - post.addRequestHeader("command", "echo"); - if (httpClient.executeMethod(post) != 200) { - logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString())); - } else { - ret = true; - } - break; - } catch (Exception e) { - if (count*m >= l) { - logger.debug(String.format("ping security group agent on vm[%s] timeout after %s minutes, starting vm failed, count=%s", agentIp, TimeUnit.MILLISECONDS.toSeconds(l), count)); - break; - } else { - logger.debug(String.format("Having pinged security group agent on vm[%s] %s times, continue to wait...", agentIp, count)); - } - } finally { - if (post != null) { - post.releaseConnection(); - } - } - } - return ret; - } - - public SecurityGroupRuleAnswer call(String agentIp, SecurityGroupRulesCmd cmd) { - PostMethod post = new PostMethod(String.format( - "http://%s:%s", agentIp, getPort())); - try { - SecurityGroupVmRuleSet rset = new SecurityGroupVmRuleSet(); - rset.getEgressRules().addAll(generateRules(cmd.getEgressRuleSet())); - rset.getIngressRules().addAll( - generateRules(cmd.getIngressRuleSet())); - rset.setVmName(cmd.getVmName()); - rset.setVmIp(cmd.getGuestIp()); - rset.setVmMac(cmd.getGuestMac()); - rset.setVmId(cmd.getVmId()); - rset.setSignature(cmd.getSignature()); - rset.setSequenceNumber(cmd.getSeqNum()); - Marshaller marshaller = context.createMarshaller(); - StringWriter writer = new StringWriter(); - marshaller.marshal(rset, writer); - String xmlContents = writer.toString(); - logger.debug(xmlContents); - - post.addRequestHeader("command", "set_rules"); - StringRequestEntity entity = new StringRequestEntity(xmlContents); - post.setRequestEntity(entity); - if (httpClient.executeMethod(post) != 200) { - return new SecurityGroupRuleAnswer(cmd, false, - post.getResponseBodyAsString()); - } else { - return new SecurityGroupRuleAnswer(cmd); - } - } catch (Exception e) { - return new SecurityGroupRuleAnswer(cmd, false, e.getMessage()); - } finally { - if (post != null) { - post.releaseConnection(); - } - } - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } -} +// 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. +// +// Automatically generated by addcopyright.py at 01/29/2013 +// Apache License, Version 2.0 (the "License"); you may not use this +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// Automatically generated by addcopyright.py at 04/03/2012 + +package com.cloud.baremetal.networkservice; + +import com.cloud.agent.api.SecurityGroupRuleAnswer; +import com.cloud.agent.api.SecurityGroupRulesCmd; +import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto; +import com.cloud.baremetal.networkservice.schema.SecurityGroupRule; +import com.cloud.baremetal.networkservice.schema.SecurityGroupVmRuleSet; +import com.cloud.utils.Pair; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.apache.log4j.Logger; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import java.io.StringWriter; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class SecurityGroupHttpClient { + private static final Logger logger = Logger.getLogger(SecurityGroupHttpClient.class); + private static final String ARG_NAME = "args"; + private static final String COMMAND = "command"; + private JAXBContext context; + private int port; + private static HttpClient httpClient; + static { + MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager(); + httpClient = new HttpClient(connman); + httpClient.setConnectionTimeout(5000); + } + + private enum OpConstant { + setRules, echo, + } + + public SecurityGroupHttpClient() { + try { + context = JAXBContext.newInstance(SecurityGroupRule.class, SecurityGroupVmRuleSet.class); + port = 9988; + } catch (Exception e) { + throw new CloudRuntimeException( + "Unable to create JAXBContext for security group", e); + } + } + + private List generateRules(final List ipps) { + List rules = new ArrayList( + ipps.size()); + for (SecurityGroupRulesCmd.IpPortAndProto ipp : ipps) { + SecurityGroupRule r = new SecurityGroupRule(); + r.setProtocol(ipp.getProto()); + r.setStartPort(ipp.getStartPort()); + r.setEndPort(ipp.getEndPort()); + for (String cidr : ipp.getAllowedCidrs()) { + r.getIp().add(cidr); + } + rules.add(r); + } + return rules; + } + + public HashMap> sync(String vmName, Long vmId, String agentIp) { + HashMap> states = new HashMap>(); + PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort())); + try { + post.addRequestHeader("command", "sync"); + if (httpClient.executeMethod(post) != 200) { + logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString())); + } else { + String res = post.getResponseBodyAsString(); + // res = ';'.join([vmName, vmId, seqno]) + String[] rulelogs = res.split(","); + if (rulelogs.length != 6) { + logger.debug(String.format("host[%s] returns invalid security group sync document[%s], reset rules", agentIp, res)); + states.put(vmName, new Pair(vmId, -1L)); + return states; + } + Pair p = new Pair(Long.valueOf(rulelogs[1]), Long.valueOf(rulelogs[5])); + states.put(rulelogs[0], p); + return states; + } + } catch (SocketTimeoutException se) { + logger.warn(String.format("unable to sync security group rules on host[%s], %s", agentIp, se.getMessage())); + } catch (Exception e) { + logger.warn(String.format("unable to sync security group rules on host[%s]", agentIp), e); + } finally { + if (post != null) { + post.releaseConnection(); + } + } + return states; + } + + + public boolean echo(String agentIp, long l, long m) { + boolean ret = false; + int count = 1; + while (true) { + try { + Thread.sleep(m); + count++; + } catch (InterruptedException e1) { + logger.warn("", e1); + break; + } + PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort())); + try { + post.addRequestHeader("command", "echo"); + if (httpClient.executeMethod(post) != 200) { + logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString())); + } else { + ret = true; + } + break; + } catch (Exception e) { + if (count*m >= l) { + logger.debug(String.format("ping security group agent on vm[%s] timeout after %s minutes, starting vm failed, count=%s", agentIp, TimeUnit.MILLISECONDS.toSeconds(l), count)); + break; + } else { + logger.debug(String.format("Having pinged security group agent on vm[%s] %s times, continue to wait...", agentIp, count)); + } + } finally { + if (post != null) { + post.releaseConnection(); + } + } + } + return ret; + } + + public SecurityGroupRuleAnswer call(String agentIp, SecurityGroupRulesCmd cmd) { + PostMethod post = new PostMethod(String.format( + "http://%s:%s", agentIp, getPort())); + try { + SecurityGroupVmRuleSet rset = new SecurityGroupVmRuleSet(); + rset.getEgressRules().addAll(generateRules(cmd.getEgressRuleSet())); + rset.getIngressRules().addAll( + generateRules(cmd.getIngressRuleSet())); + rset.setVmName(cmd.getVmName()); + rset.setVmIp(cmd.getGuestIp()); + rset.setVmMac(cmd.getGuestMac()); + rset.setVmId(cmd.getVmId()); + rset.setSignature(cmd.getSignature()); + rset.setSequenceNumber(cmd.getSeqNum()); + Marshaller marshaller = context.createMarshaller(); + StringWriter writer = new StringWriter(); + marshaller.marshal(rset, writer); + String xmlContents = writer.toString(); + logger.debug(xmlContents); + + post.addRequestHeader("command", "set_rules"); + StringRequestEntity entity = new StringRequestEntity(xmlContents); + post.setRequestEntity(entity); + if (httpClient.executeMethod(post) != 200) { + return new SecurityGroupRuleAnswer(cmd, false, + post.getResponseBodyAsString()); + } else { + return new SecurityGroupRuleAnswer(cmd); + } + } catch (Exception e) { + return new SecurityGroupRuleAnswer(cmd, false, e.getMessage()); + } finally { + if (post != null) { + post.releaseConnection(); + } + } + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } +} diff --git a/plugins/hypervisors/hyperv/pom.xml b/plugins/hypervisors/hyperv/pom.xml index f13301cc00..165eaf6cf4 100644 --- a/plugins/hypervisors/hyperv/pom.xml +++ b/plugins/hypervisors/hyperv/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml @@ -41,11 +41,6 @@ cloud-core ${project.version} - - org.mortbay.jetty - jetty - 6.1.26 - org.apache.cloudstack cloud-utils diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java index fd8db4a564..fd54d43241 100644 --- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java +++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java @@ -106,6 +106,10 @@ public final AgentControlAnswer processControlCommand(final long agentId, final return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public final void processConnect(final Host agent, final StartupCommand cmd, final boolean forRebalance) throws ConnectionException { // Limit the commands we can process @@ -176,6 +180,14 @@ public final boolean processDisconnect(final long agentId, final Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public final boolean isRecurring() { return false; diff --git a/plugins/hypervisors/hyperv/src/org/apache/cloudstack/storage/motion/HypervStorageMotionStrategy.java b/plugins/hypervisors/hyperv/src/org/apache/cloudstack/storage/motion/HypervStorageMotionStrategy.java index 8a1c414fb4..19c655b8f2 100644 --- a/plugins/hypervisors/hyperv/src/org/apache/cloudstack/storage/motion/HypervStorageMotionStrategy.java +++ b/plugins/hypervisors/hyperv/src/org/apache/cloudstack/storage/motion/HypervStorageMotionStrategy.java @@ -48,9 +48,9 @@ import com.cloud.exception.OperationTimedoutException; import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; import com.cloud.storage.VolumeVO; -import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; @@ -82,21 +82,12 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { throw new UnsupportedOperationException(); } @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - CopyCommandResult result = new CopyCommandResult(null, null); - result.setResult("Unsupported operation requested for copying data."); - callback.complete(result); - - return null; - } - - @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { Answer answer = null; String errMsg = null; @@ -115,7 +106,6 @@ public Void copyAsync(Map volumeMap, VirtualMachineTO vmT CopyCommandResult result = new CopyCommandResult(null, answer); result.setResult(errMsg); callback.complete(result); - return null; } private Answer migrateVmWithVolumes(VMInstanceVO vm, VirtualMachineTO to, Host srcHost, diff --git a/plugins/hypervisors/kvm/pom.xml b/plugins/hypervisors/kvm/pom.xml index 8275e253c0..f8100a50c0 100644 --- a/plugins/hypervisors/kvm/pom.xml +++ b/plugins/hypervisors/kvm/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/kvm/src/com/cloud/ha/KVMInvestigator.java b/plugins/hypervisors/kvm/src/com/cloud/ha/KVMInvestigator.java index 32388df6a7..8337a7b764 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/ha/KVMInvestigator.java +++ b/plugins/hypervisors/kvm/src/com/cloud/ha/KVMInvestigator.java @@ -27,7 +27,11 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; import com.cloud.resource.ResourceManager; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.component.AdapterBase; + +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import javax.inject.Inject; @@ -41,6 +45,8 @@ public class KVMInvestigator extends AdapterBase implements Investigator { AgentManager _agentMgr; @Inject ResourceManager _resourceMgr; + @Inject + PrimaryDataStoreDao _storagePoolDao; @Override public boolean isVmAlive(com.cloud.vm.VirtualMachine vm, Host host) throws UnknownVM { @@ -60,6 +66,21 @@ public Status isAgentAlive(Host agent) { if (agent.getHypervisorType() != Hypervisor.HypervisorType.KVM && agent.getHypervisorType() != Hypervisor.HypervisorType.LXC) { return null; } + + List clusterPools = _storagePoolDao.listPoolsByCluster(agent.getClusterId()); + boolean hasNfs = false; + for (StoragePoolVO pool : clusterPools) { + 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."); + return Status.Disconnected; + } + Status hostStatus = null; Status neighbourStatus = null; CheckOnHostCommand cmd = new CheckOnHostCommand(agent); @@ -78,7 +99,8 @@ public Status isAgentAlive(Host agent) { List neighbors = _resourceMgr.listHostsInClusterByStatus(agent.getClusterId(), Status.Up); for (HostVO neighbor : neighbors) { - if (neighbor.getId() == agent.getId() || (neighbor.getHypervisorType() != Hypervisor.HypervisorType.KVM && neighbor.getHypervisorType() != Hypervisor.HypervisorType.LXC)) { + if (neighbor.getId() == agent.getId() + || (neighbor.getHypervisorType() != Hypervisor.HypervisorType.KVM && neighbor.getHypervisorType() != Hypervisor.HypervisorType.LXC)) { continue; } s_logger.debug("Investigating host:" + agent.getId() + " via neighbouring host:" + neighbor.getId()); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java old mode 100755 new mode 100644 index 883c8c9942..eea16ae953 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -52,6 +52,8 @@ import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; import org.libvirt.Connect; import org.libvirt.Domain; @@ -60,6 +62,7 @@ import org.libvirt.DomainInfo.DomainState; import org.libvirt.DomainInterfaceStats; import org.libvirt.LibvirtException; +import org.libvirt.MemoryStatistic; import org.libvirt.NodeInfo; import com.cloud.agent.api.Answer; @@ -188,8 +191,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv private String _clusterId; private long _hvVersion; - private long _kernelVersion; private int _timeout; + private static final int NUMMEMSTATS =2; private KVMHAMonitor _monitor; public static final String SSHKEYSPATH = "/root/.ssh"; @@ -630,9 +633,9 @@ public boolean configure(final String name, final Map params) th throw new ConfigurationException("Unable to find versions.sh"); } - _patchViaSocketPath = Script.findScript(kvmScriptsDir + "/patch/", "patchviasocket.pl"); + _patchViaSocketPath = Script.findScript(kvmScriptsDir + "/patch/", "patchviasocket.py"); if (_patchViaSocketPath == null) { - throw new ConfigurationException("Unable to find patchviasocket.pl"); + throw new ConfigurationException("Unable to find patchviasocket.py"); } _heartBeatPath = Script.findScript(kvmScriptsDir, "kvmheartbeat.sh"); @@ -956,13 +959,6 @@ public boolean configure(final String name, final Map params) th storageProcessor.configure(name, params); storageHandler = new StorageSubsystemCommandHandlerBase(storageProcessor); - final String unameKernelVersion = Script.runSimpleBashScript("uname -r"); - final String[] kernelVersions = unameKernelVersion.split("[\\.\\-]"); - _kernelVersion = Integer.parseInt(kernelVersions[0]) * 1000 * 1000 + (long)Integer.parseInt(kernelVersions[1]) * 1000 + Integer.parseInt(kernelVersions[2]); - - /* Disable this, the code using this is pretty bad and non portable - * getOsVersion(); - */ return true; } @@ -2626,7 +2622,14 @@ protected List getHostInfo() { final NodeInfo hosts = conn.nodeInfo(); speed = getCpuSpeed(hosts); + /* + * Some CPUs report a single socket and multiple NUMA cells. + * We need to multiply them to get the correct socket count. + */ cpuSockets = hosts.sockets; + if (hosts.nodes > 0) { + cpuSockets = hosts.sockets * hosts.nodes; + } cpus = hosts.cpus; ram = hosts.memory * 1024L; final LibvirtCapXMLParser parser = new LibvirtCapXMLParser(); @@ -3025,12 +3028,19 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li Domain dm = null; try { dm = getDomain(conn, vmName); - final DomainInfo info = dm.getInfo(); - + if (dm == null) { + return null; + } + DomainInfo info = dm.getInfo(); final VmStatsEntry stats = new VmStatsEntry(); + stats.setNumCPUs(info.nrVirtCpu); stats.setEntityType("vm"); + stats.setMemoryKBs(info.maxMem); + stats.setTargetMemoryKBs(info.memory); + stats.setIntFreeMemoryKBs(getMemoryFreeInKBs(dm)); + /* get cpu utilization */ VmStats oldStats = null; @@ -3124,6 +3134,21 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li } } + /** + * This method retrieves the memory statistics from the domain given as parameters. + * If no memory statistic is found, it will return {@link NumberUtils#LONG_ZERO} as the value of free memory in the domain. + * If it can retrieve the domain memory statistics, it will return the free memory statistic; that means, it returns the value at the first position of the array returned by {@link Domain#memoryStats(int)}. + * + * @return the amount of free memory in KBs + */ + protected long getMemoryFreeInKBs(Domain dm) throws LibvirtException { + MemoryStatistic[] mems = dm.memoryStats(NUMMEMSTATS); + if (ArrayUtils.isEmpty(mems)) { + return NumberUtils.LONG_ZERO; + } + return mems[0].getValue(); + } + private boolean canBridgeFirewall(final String prvNic) { final Script cmd = new Script(_securityGroupPath, _timeout, s_logger); cmd.add("can_bridge_firewall"); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRebootRouterCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRebootRouterCommandWrapper.java index 4d13c1bf5c..b5604d41e7 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRebootRouterCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRebootRouterCommandWrapper.java @@ -34,7 +34,7 @@ public final class LibvirtRebootRouterCommandWrapper extends CommandWrapper getDisks(final Connect conn, final String vmName) { // IO traffic as generated by the logic above, must be greater than zero Assert.assertTrue(vmStat.getDiskReadKBs() > 0); Assert.assertTrue(vmStat.getDiskWriteKBs() > 0); + // Memory limit of VM must be greater than zero + Assert.assertTrue(vmStat.getIntFreeMemoryKBs() >= 0); + Assert.assertTrue(vmStat.getMemoryKBs() >= 0); + Assert.assertTrue(vmStat.getTargetMemoryKBs() >= vmStat.getMemoryKBs()); } @Test @@ -708,10 +718,9 @@ public void testGetVmDiskStatsCommand() { } } - @SuppressWarnings("unchecked") @Test + @SuppressWarnings("unchecked") public void testGetVmDiskStatsCommandException() { - Mockito.mock(Connect.class); final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final String vmName = "Test"; @@ -748,7 +757,7 @@ public void testRebootCommand() { final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final String vmName = "Test"; - final RebootCommand command = new RebootCommand(vmName); + final RebootCommand command = new RebootCommand(vmName, true); when(libvirtComputingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper); try { @@ -777,7 +786,7 @@ public void testRebootCommandException1() { final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final String vmName = "Test"; - final RebootCommand command = new RebootCommand(vmName); + final RebootCommand command = new RebootCommand(vmName, true); when(libvirtComputingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper); try { @@ -806,7 +815,7 @@ public void testRebootCommandError() { final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final String vmName = "Test"; - final RebootCommand command = new RebootCommand(vmName); + final RebootCommand command = new RebootCommand(vmName, true); when(libvirtComputingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper); try { @@ -837,7 +846,7 @@ public void testRebootCommandException2() { final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final String vmName = "Test"; - final RebootCommand command = new RebootCommand(vmName); + final RebootCommand command = new RebootCommand(vmName, true); when(libvirtComputingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper); try { @@ -931,7 +940,6 @@ public void testRebootRouterCommandConnect() { public void testGetHostStatsCommand() { // A bit difficult to test due to the logger being passed and the parser itself relying on the connection. // Have to spend some more time afterwards in order to refactor the wrapper itself. - Mockito.mock(LibvirtUtilitiesHelper.class); final CPUStat cpuStat = Mockito.mock(CPUStat.class); final MemStat memStat = Mockito.mock(MemStat.class); @@ -2895,8 +2903,11 @@ public void testSecurityGroupRulesCmdFalse() { final Long seqNum = 1l; final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; + final List secIps = new Vector(); + final List cidrs = new Vector(); + cidrs.add("0.0.0.0/0"); - final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet); + final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps); final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final Connect conn = Mockito.mock(Connect.class); @@ -2916,12 +2927,12 @@ public void testSecurityGroupRulesCmdFalse() { when(ingressRuleSet[0].getProto()).thenReturn("tcp"); when(ingressRuleSet[0].getStartPort()).thenReturn(22); when(ingressRuleSet[0].getEndPort()).thenReturn(22); - when(ingressRuleSet[0].getAllowedCidrs()).thenReturn(new String[]{"0.0.0.0/0"}); + when(ingressRuleSet[0].getAllowedCidrs()).thenReturn(cidrs); when(egressRuleSet[0].getProto()).thenReturn("tcp"); when(egressRuleSet[0].getStartPort()).thenReturn(22); when(egressRuleSet[0].getEndPort()).thenReturn(22); - when(egressRuleSet[0].getAllowedCidrs()).thenReturn(new String[]{"0.0.0.0/0"}); + when(egressRuleSet[0].getAllowedCidrs()).thenReturn(cidrs); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); assertNotNull(wrapper); @@ -2947,8 +2958,11 @@ public void testSecurityGroupRulesCmdTrue() { final Long seqNum = 1l; final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; + final List secIps = new Vector(); + final List cidrs = new Vector(); + cidrs.add("0.0.0.0/0"); - final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet); + final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps); final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final Connect conn = Mockito.mock(Connect.class); @@ -2974,12 +2988,12 @@ public void testSecurityGroupRulesCmdTrue() { when(ingressRuleSet[0].getProto()).thenReturn("tcp"); when(ingressRuleSet[0].getStartPort()).thenReturn(22); when(ingressRuleSet[0].getEndPort()).thenReturn(22); - when(ingressRuleSet[0].getAllowedCidrs()).thenReturn(new String[]{"0.0.0.0/0"}); + when(ingressRuleSet[0].getAllowedCidrs()).thenReturn(cidrs); when(egressRuleSet[0].getProto()).thenReturn("tcp"); when(egressRuleSet[0].getStartPort()).thenReturn(22); when(egressRuleSet[0].getEndPort()).thenReturn(22); - when(egressRuleSet[0].getAllowedCidrs()).thenReturn(new String[]{"0.0.0.0/0"}); + when(egressRuleSet[0].getAllowedCidrs()).thenReturn(cidrs); when(libvirtComputingResource.addNetworkRules(command.getVmName(), Long.toString(command.getVmId()), command.getGuestIp(), command.getSignature(), Long.toString(command.getSeqNum()), command.getGuestMac(), command.stringifyRules(), vif, brname, command.getSecIpsString())).thenReturn(true); @@ -3009,8 +3023,9 @@ public void testSecurityGroupRulesCmdException() { final Long seqNum = 1l; final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; + final List secIps = new Vector(); - final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet); + final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps); final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final Connect conn = Mockito.mock(Connect.class); @@ -3514,7 +3529,6 @@ public void testNetworkUsageCommandVpcNoOption() { verify(libvirtComputingResource, times(1)).configureVPCNetworkUsage(command.getPrivateIP(), command.getGatewayIP(), command.getOption(), command.getVpcCIDR()); } - @SuppressWarnings("unchecked") @Test public void testCreatePrivateTemplateFromVolumeCommand() { //Simple test used to make sure the flow (LibvirtComputingResource => Request => CommandWrapper) is working. @@ -5023,4 +5037,40 @@ public void testIsInterface () { } } } -} \ No newline at end of file + + @Test + public void testMemoryFreeInKBsDomainReturningOfSomeMemoryStatistics() throws LibvirtException { + LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource(); + + MemoryStatistic[] mem = createMemoryStatisticFreeMemory100(); + Domain domainMock = getDomainConfiguredToReturnMemoryStatistic(mem); + long memoryFreeInKBs = libvirtComputingResource.getMemoryFreeInKBs(domainMock); + + Assert.assertEquals(100, memoryFreeInKBs); + } + + @Test + public void testMemoryFreeInKBsDomainReturningNoMemoryStatistics() throws LibvirtException { + LibvirtComputingResource libvirtComputingResource = new LibvirtComputingResource(); + + Domain domainMock = getDomainConfiguredToReturnMemoryStatistic(null); + long memoryFreeInKBs = libvirtComputingResource.getMemoryFreeInKBs(domainMock); + + Assert.assertEquals(0, memoryFreeInKBs); + } + + private MemoryStatistic[] createMemoryStatisticFreeMemory100() { + virDomainMemoryStats stat = new virDomainMemoryStats(); + stat.val = 100; + + MemoryStatistic[] mem = new MemoryStatistic[2]; + mem[0] = new MemoryStatistic(stat); + return mem; + } + + private Domain getDomainConfiguredToReturnMemoryStatistic(MemoryStatistic[] mem) throws LibvirtException { + Domain domainMock = Mockito.mock(Domain.class); + when(domainMock.memoryStats(2)).thenReturn(mem); + return domainMock; + } +} diff --git a/plugins/hypervisors/ovm/pom.xml b/plugins/hypervisors/ovm/pom.xml index 2ad537cc3d..e754e632a8 100644 --- a/plugins/hypervisors/ovm/pom.xml +++ b/plugins/hypervisors/ovm/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java b/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java index 0541b7e61a..648bf7fc39 100644 --- a/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java +++ b/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java @@ -940,8 +940,8 @@ private Answer execute(SecurityGroupRulesCmd cmd) { s_logger.warn("Failed to program network rules for vm " + cmd.getVmName()); return new SecurityGroupRuleAnswer(cmd, false, "programming network rules failed"); } else { - s_logger.info("Programmed network rules for vm " + cmd.getVmName() + " guestIp=" + cmd.getGuestIp() + ":ingress num rules=" + cmd.getIngressRuleSet().length + - ":egress num rules=" + cmd.getEgressRuleSet().length); + s_logger.info("Programmed network rules for vm " + cmd.getVmName() + " guestIp=" + cmd.getGuestIp() + ":ingress num rules=" + cmd.getIngressRuleSet().size() + + ":egress num rules=" + cmd.getEgressRuleSet().size()); return new SecurityGroupRuleAnswer(cmd); } } diff --git a/plugins/hypervisors/ovm3/pom.xml b/plugins/hypervisors/ovm3/pom.xml index 1bc4ae3e4e..8da1430137 100644 --- a/plugins/hypervisors/ovm3/pom.xml +++ b/plugins/hypervisors/ovm3/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3Discoverer.java b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3Discoverer.java index 4743600d50..3f245273a2 100755 --- a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3Discoverer.java +++ b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3Discoverer.java @@ -338,6 +338,10 @@ public AgentControlAnswer processControlCommand(long agentId, return null; } + @Override + public void processHostAdded(long hostId) { + } + /* for reconnecting */ @Override public void processConnect(Host host, StartupCommand cmd, @@ -351,6 +355,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; diff --git a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorGuru.java b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorGuru.java index 0d60a2d39b..432474d043 100755 --- a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorGuru.java +++ b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorGuru.java @@ -19,21 +19,11 @@ import javax.inject.Inject; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; -import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; -import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.log4j.Logger; import com.cloud.agent.api.Command; -import com.cloud.agent.api.to.DataObjectType; -import com.cloud.agent.api.to.DataStoreTO; -import com.cloud.agent.api.to.DataTO; -import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.VirtualMachineTO; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorGuru; import com.cloud.hypervisor.HypervisorGuruBase; @@ -45,15 +35,7 @@ public class Ovm3HypervisorGuru extends HypervisorGuruBase implements HypervisorGuru { private final Logger LOGGER = Logger.getLogger(Ovm3HypervisorGuru.class); @Inject - GuestOSDao guestOsDao; - @Inject - EndPointSelector endPointSelector; - @Inject - HostDao hostDao; - - protected Ovm3HypervisorGuru() { - super(); - } + private GuestOSDao guestOsDao; @Override public HypervisorType getHypervisorType() { @@ -65,7 +47,6 @@ public VirtualMachineTO implement(VirtualMachineProfile vm) { VirtualMachineTO to = toVirtualMachineTO(vm); to.setBootloader(vm.getBootLoaderType()); - // Determine the VM's OS description GuestOSVO guestOS = guestOsDao.findById(vm.getVirtualMachine() .getGuestOSId()); to.setOs(guestOS.getDisplayName()); @@ -78,35 +59,13 @@ public boolean trackVmHostChange() { return true; } - /* I dislike the notion of having to place this here, and not being able to just override - * - * (non-Javadoc) - * @see com.cloud.hypervisor.HypervisorGuruBase#getCommandHostDelegation(long, com.cloud.agent.api.Command) - */ + @Override public Pair getCommandHostDelegation(long hostId, Command cmd) { LOGGER.debug("getCommandHostDelegation: " + cmd.getClass()); if (cmd instanceof StorageSubSystemCommand) { StorageSubSystemCommand c = (StorageSubSystemCommand)cmd; c.setExecuteInSequence(true); } - if (cmd instanceof CopyCommand) { - CopyCommand cpyCommand = (CopyCommand)cmd; - DataTO srcData = cpyCommand.getSrcTO(); - DataTO destData = cpyCommand.getDestTO(); - - if (HypervisorType.Ovm3.equals(srcData.getHypervisorType()) && srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.TEMPLATE) { - LOGGER.debug("Snapshot to Template: " + cmd); - DataStoreTO srcStore = srcData.getDataStore(); - DataStoreTO destStore = destData.getDataStore(); - if (srcStore instanceof NfsTO && destStore instanceof NfsTO) { - HostVO host = hostDao.findById(hostId); - EndPoint ep = endPointSelector.selectHypervisorHost(new ZoneScope(host.getDataCenterId())); - if (ep != null) { - return new Pair(Boolean.TRUE, Long.valueOf(ep.getId())); - } - } - } - } return new Pair(Boolean.FALSE, Long.valueOf(hostId)); } } diff --git a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java index 3c28f1fde3..7c89921936 100644 --- a/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java +++ b/plugins/hypervisors/ovm3/src/main/java/com/cloud/hypervisor/ovm3/resources/Ovm3StorageProcessor.java @@ -31,6 +31,8 @@ import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.ResignatureAnswer; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.to.SnapshotObjectTO; @@ -805,9 +807,17 @@ public Answer forgetObject(ForgetObjectCmd cmd) { * iSCSI? */ @Override - public Answer snapshotAndCopy(SnapshotAndCopyCommand cmd) { - LOGGER.debug("execute snapshotAndCopy: "+ cmd.getClass()); - return new SnapshotAndCopyAnswer("not implemented yet"); + public SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand cmd) { + LOGGER.info("'SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand)' not currently used for Ovm3StorageProcessor"); + + return new SnapshotAndCopyAnswer("Not implemented"); + } + + @Override + public ResignatureAnswer resignature(final ResignatureCommand cmd) { + LOGGER.info("'ResignatureAnswer resignature(ResignatureCommand)' not currently used for Ovm3StorageProcessor"); + + return new ResignatureAnswer("Not implemented"); } /** diff --git a/plugins/hypervisors/ovm3/src/test/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorResourceTest.java b/plugins/hypervisors/ovm3/src/test/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorResourceTest.java index 86df00c24f..cb02a230f5 100644 --- a/plugins/hypervisors/ovm3/src/test/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorResourceTest.java +++ b/plugins/hypervisors/ovm3/src/test/java/com/cloud/hypervisor/ovm3/resources/Ovm3HypervisorResourceTest.java @@ -172,7 +172,7 @@ private Boolean rebootVm(String name) throws ConfigurationException { con.removeMethodResponse("list_vms"); con.addResult(xen.getMultipleVmsListXML()); con.addResult(xen.getMultipleVmsListXML()); - RebootCommand cmd = new RebootCommand(name); + RebootCommand cmd = new RebootCommand(name, true); Answer ra = hypervisor.executeRequest(cmd); return ra.getResult(); } diff --git a/plugins/hypervisors/simulator/pom.xml b/plugins/hypervisors/simulator/pom.xml index ebe8870591..dbebba0146 100644 --- a/plugins/hypervisors/simulator/pom.xml +++ b/plugins/hypervisors/simulator/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml cloud-plugin-hypervisor-simulator diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java index 6602e1f1ad..6eaf09cad8 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockVmManagerImpl.java @@ -319,7 +319,7 @@ public Answer getVmStats(final GetVmStatsCommand cmd) { final HashMap vmStatsNameMap = new HashMap(); final List vmNames = cmd.getVmNames(); for (final String vmName : vmNames) { - final VmStatsEntry entry = new VmStatsEntry(0, 0, 0, 0, "vm"); + final VmStatsEntry entry = new VmStatsEntry(0, 0, 0, 0, 0, 0, 0, "vm"); entry.setNetworkReadKBs(32768); // default values 256 KBps entry.setNetworkWriteKBs(16384); entry.setCPUUtilization(10); @@ -626,7 +626,7 @@ private boolean logSecurityGroupAction(final SecurityGroupRulesCmd cmd, final Te reason = ", seqno_new"; } s_logger.info("Programmed network rules for vm " + cmd.getVmName() + " seqno=" + cmd.getSeqNum() + " signature=" + cmd.getSignature() + " guestIp=" + - cmd.getGuestIp() + ", numIngressRules=" + cmd.getIngressRuleSet().length + ", numEgressRules=" + cmd.getEgressRuleSet().length + " total cidrs=" + + cmd.getGuestIp() + ", numIngressRules=" + cmd.getIngressRuleSet().size() + ", numEgressRules=" + cmd.getEgressRuleSet().size() + " total cidrs=" + cmd.getTotalNumCidrs() + action + reason); return updateSeqnoAndSig; } diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java index 751da9e3d2..c77550e5da 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java @@ -109,7 +109,7 @@ public boolean configure(String name, Map params) throws Configu } @Override - public String getRootDir(String url) { + public String getRootDir(String url, Integer nfsVersion) { // TODO Auto-generated method stub return null; } diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java index 76eb1c08a7..c942c8ff55 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java @@ -245,6 +245,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { @@ -273,6 +277,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java index 6e75244c32..e09a5a950a 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java @@ -140,6 +140,10 @@ public boolean processCommands(long agentId, long seq, Command[] commands) { return false; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { @@ -155,6 +159,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return false; diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java index cae926179f..9d86bc31b7 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java @@ -35,6 +35,8 @@ import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.ResignatureAnswer; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.to.SnapshotObjectTO; @@ -66,6 +68,13 @@ public SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand cmd) { return new SnapshotAndCopyAnswer(); } + @Override + public ResignatureAnswer resignature(ResignatureCommand cmd) { + s_logger.info("'ResignatureAnswer resignature(ResignatureCommand)' not currently used for SimulatorStorageProcessor"); + + return new ResignatureAnswer(); + } + @Override public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { TemplateObjectTO template = new TemplateObjectTO(); diff --git a/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java index 4497448af0..14d75f846e 100644 --- a/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java +++ b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/datastore/driver/SimulatorImageStoreDriverImpl.java @@ -35,7 +35,7 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; -import org.apache.cloudstack.storage.image.BaseImageStoreDriverImpl; +import org.apache.cloudstack.storage.image.NfsImageStoreDriverImpl; import org.apache.cloudstack.storage.image.store.ImageStoreImpl; import com.cloud.agent.api.storage.DownloadAnswer; @@ -47,7 +47,7 @@ import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; -public class SimulatorImageStoreDriverImpl extends BaseImageStoreDriverImpl { +public class SimulatorImageStoreDriverImpl extends NfsImageStoreDriverImpl { private static final Logger s_logger = Logger.getLogger(SimulatorImageStoreDriverImpl.class); @Inject @@ -67,6 +67,7 @@ public DataStoreTO getStoreTO(DataStore store) { NfsTO nfsTO = new NfsTO(); nfsTO.setRole(store.getRole()); nfsTO.setUrl(nfsStore.getUri()); + nfsTO.setNfsVersion(getNfsVersion(nfsStore.getId())); return nfsTO; } diff --git a/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java index 40909629c7..5e72babf08 100644 --- a/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java +++ b/plugins/hypervisors/simulator/src/org/apache/cloudstack/storage/motion/SimulatorDataMotionStrategy.java @@ -43,21 +43,13 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { throw new UnsupportedOperationException(); } @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { CopyCommandResult result = new CopyCommandResult("something", null); callback.complete(result); - return null; - } - - @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { - CopyCommandResult result = new CopyCommandResult("something", null); - callback.complete(result); - return null; } } diff --git a/plugins/hypervisors/ucs/pom.xml b/plugins/hypervisors/ucs/pom.xml index ea1536747a..c8a14d19b0 100755 --- a/plugins/hypervisors/ucs/pom.xml +++ b/plugins/hypervisors/ucs/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml cloud-plugin-hypervisor-ucs diff --git a/plugins/hypervisors/vmware/pom.xml b/plugins/hypervisors/vmware/pom.xml index fd0f1709cf..455fb5819d 100644 --- a/plugins/hypervisors/vmware/pom.xml +++ b/plugins/hypervisors/vmware/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java index 72ee2184e3..65590500a0 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java @@ -36,7 +36,7 @@ public interface VmwareManager { String getSystemVMDefaultNicAdapterType(); - void prepareSecondaryStorageStore(String strStorageUrl); + void prepareSecondaryStorageStore(String strStorageUrl, Long storeId); void setupResourceStartupParams(Map params); @@ -48,7 +48,7 @@ public interface VmwareManager { String getManagementPortGroupName(); - String getSecondaryStorageStoreUrl(long dcId); + Pair getSecondaryStorageStoreUrlAndId(long dcId); File getSystemVMKeyFile(); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index 575801fa60..da83283afd 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -105,6 +105,7 @@ import com.cloud.org.Cluster.ClusterType; import com.cloud.secstorage.CommandExecLogDao; import com.cloud.server.ConfigurationServer; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.StorageLayer; import com.cloud.utils.FileUtil; @@ -167,6 +168,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private ManagementServerHostPeerDao _mshostPeerDao; @Inject private ClusterManager _clusterMgr; + @Inject + private ImageStoreDetailsUtil imageStoreDetailsUtil; private String _mountParent; private StorageLayer _storage; @@ -439,12 +442,14 @@ public List addHostToPodCluster(VmwareContext serviceCon } @Override - public String getSecondaryStorageStoreUrl(long dcId) { + public Pair getSecondaryStorageStoreUrlAndId(long dcId) { String secUrl = null; + Long secId = null; DataStore secStore = _dataStoreMgr.getImageStore(dcId); if (secStore != null) { secUrl = secStore.getUri(); + secId = secStore.getId(); } if (secUrl == null) { @@ -453,12 +458,13 @@ public String getSecondaryStorageStoreUrl(long dcId) { DataStore cacheStore = _dataStoreMgr.getImageCacheStore(dcId); if (cacheStore != null) { secUrl = cacheStore.getUri(); + secId = cacheStore.getId(); } else { s_logger.warn("No staging storage is found when non-NFS secondary storage is used"); } } - return secUrl; + return new Pair(secUrl, secId); } @Override @@ -546,8 +552,9 @@ public boolean needRecycle(String workerTag) { } @Override - public void prepareSecondaryStorageStore(String storageUrl) { - String mountPoint = getMountPoint(storageUrl); + public void prepareSecondaryStorageStore(String storageUrl, Long storeId) { + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(storeId); + String mountPoint = getMountPoint(storageUrl, nfsVersion); GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm"); try { @@ -655,7 +662,7 @@ public void run() { } @Override - public String getMountPoint(String storageUrl) { + public String getMountPoint(String storageUrl, Integer nfsVersion) { String mountPoint = null; synchronized (_storageMounts) { mountPoint = _storageMounts.get(storageUrl); @@ -670,7 +677,8 @@ public String getMountPoint(String storageUrl) { s_logger.error("Invalid storage URL format ", e); throw new CloudRuntimeException("Unable to create mount point due to invalid storage URL format " + storageUrl); } - mountPoint = mount(uri.getHost() + ":" + uri.getPath(), _mountParent); + + mountPoint = mount(uri.getHost() + ":" + uri.getPath(), _mountParent, nfsVersion); if (mountPoint == null) { s_logger.error("Unable to create mount point for " + storageUrl); return "/mnt/sec"; // throw new CloudRuntimeException("Unable to create mount point for " + storageUrl); @@ -745,7 +753,7 @@ private void shutdownCleanup() { } } - protected String mount(String path, String parent) { + protected String mount(String path, String parent, Integer nfsVersion) { String mountPoint = setupMountPoint(parent); if (mountPoint == null) { s_logger.warn("Unable to create a mount point"); @@ -756,6 +764,9 @@ protected String mount(String path, String parent) { String result = null; Script command = new Script(true, "mount", _timeout, s_logger); command.add("-t", "nfs"); + if (nfsVersion != null){ + command.add("-o", "vers=" + nfsVersion); + } // command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0"); if ("Mac OS X".equalsIgnoreCase(System.getProperty("os.name"))) { command.add("-o", "resvport"); @@ -831,6 +842,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) { if (cmd instanceof StartupCommand) { @@ -872,6 +887,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; @@ -1234,4 +1257,5 @@ public boolean hasNexusVSM(Long clusterId) { return true; } } + } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index 4109ff2345..c5c1c438eb 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -92,6 +92,9 @@ import com.cloud.vm.snapshot.VMSnapshot; public class VmwareStorageManagerImpl implements VmwareStorageManager { + + private Integer _nfsVersion; + @Override public boolean execute(VmwareHostService hostService, CreateEntityDownloadURLCommand cmd) { DataTO data = cmd.getData(); @@ -138,6 +141,12 @@ public VmwareStorageManagerImpl(VmwareStorageMount mountService) { _mountService = mountService; } + public VmwareStorageManagerImpl(VmwareStorageMount mountService, Integer nfsVersion) { + assert (mountService != null); + _mountService = mountService; + _nfsVersion = nfsVersion; + } + public void configure(Map params) { s_logger.info("Configure VmwareStorageManagerImpl"); @@ -156,7 +165,7 @@ public String createOvaForTemplate(TemplateObjectTO template) { String secStorageUrl = nfsStore.getUrl(); assert (secStorageUrl != null); String installPath = template.getPath(); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, _nfsVersion); String installFullPath = secondaryMountPoint + "/" + installPath; try { if (installFullPath.endsWith(".ova")) { @@ -194,7 +203,7 @@ public String createOvaForVolume(VolumeObjectTO volume) { String installPath = volume.getPath(); int index = installPath.lastIndexOf(File.separator); String volumeUuid = installPath.substring(index + 1); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, _nfsVersion); //The real volume path String volumePath = installPath + File.separator + volumeUuid + ".ova"; String installFullPath = secondaryMountPoint + "/" + installPath; @@ -271,7 +280,8 @@ public Answer execute(VmwareHostService hostService, PrimaryStorageDownloadComma assert (morDs != null); DatastoreMO primaryStorageDatastoreMo = new DatastoreMO(context, morDs); - copyTemplateFromSecondaryToPrimary(hyperHost, primaryStorageDatastoreMo, secondaryStorageUrl, mountPoint, templateName, templateUuidName); + copyTemplateFromSecondaryToPrimary(hyperHost, primaryStorageDatastoreMo, secondaryStorageUrl, mountPoint, templateName, templateUuidName, + cmd.getNfsVersion()); } else { s_logger.info("Template " + templateName + " has already been setup, skip the template setup process in primary storage"); } @@ -345,7 +355,7 @@ public Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd) snapshotBackupUuid = backupSnapshotToSecondaryStorage(vmMo, accountId, volumeId, cmd.getVolumePath(), snapshotUuid, secondaryStorageUrl, prevSnapshotUuid, prevBackupUuid, - hostService.getWorkerName(context, cmd, 1)); + hostService.getWorkerName(context, cmd, 1), cmd.getNfsVersion()); success = (snapshotBackupUuid != null); if (success) { @@ -413,7 +423,7 @@ public Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVo Ternary result = createTemplateFromVolume(vmMo, accountId, templateId, cmd.getUniqueName(), secondaryStoragePoolURL, volumePath, - hostService.getWorkerName(context, cmd, 0)); + hostService.getWorkerName(context, cmd, 0), cmd.getNfsVersion()); return new CreatePrivateTemplateAnswer(cmd, true, null, result.first(), result.third(), result.second(), cmd.getUniqueName(), ImageFormat.OVA); @@ -441,7 +451,8 @@ public Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSn VmwareContext context = hostService.getServiceContext(cmd); try { - Ternary result = createTemplateFromSnapshot(accountId, newTemplateId, uniqeName, secondaryStorageUrl, volumeId, backedUpSnapshotUuid); + Ternary result = createTemplateFromSnapshot(accountId, newTemplateId, uniqeName, secondaryStorageUrl, volumeId, backedUpSnapshotUuid, + cmd.getNfsVersion()); return new CreatePrivateTemplateAnswer(cmd, true, null, result.first(), result.third(), result.second(), uniqeName, ImageFormat.OVA); } catch (Throwable e) { @@ -471,7 +482,7 @@ public Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd) { if (cmd.toSecondaryStorage()) { result = copyVolumeToSecStorage(hostService, hyperHost, cmd, vmName, volumeId, cmd.getPool().getUuid(), volumePath, secondaryStorageURL, - hostService.getWorkerName(context, cmd, 0)); + hostService.getWorkerName(context, cmd, 0), cmd.getNfsVersion()); } else { StorageFilerTO poolTO = cmd.getPool(); @@ -484,8 +495,9 @@ public Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd) { } } - result = copyVolumeFromSecStorage(hyperHost, volumeId, new DatastoreMO(context, morDatastore), secondaryStorageURL, volumePath); - deleteVolumeDirOnSecondaryStorage(volumeId, secondaryStorageURL); + result = copyVolumeFromSecStorage(hyperHost, volumeId, new DatastoreMO(context, morDatastore), secondaryStorageURL, volumePath, + cmd.getNfsVersion()); + deleteVolumeDirOnSecondaryStorage(volumeId, secondaryStorageURL, cmd.getNfsVersion()); } return new CopyVolumeAnswer(cmd, true, null, result.first(), result.second()); } catch (Throwable e) { @@ -523,7 +535,8 @@ public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCom } DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs); - details = createVolumeFromSnapshot(hyperHost, primaryDsMo, newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid); + details = createVolumeFromSnapshot(hyperHost, primaryDsMo, newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid, + cmd.getNfsVersion()); if (details == null) { success = true; } @@ -542,12 +555,12 @@ public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCom // templateName: name in secondary storage // templateUuid: will be used at hypervisor layer private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl, - String templatePathAtSecondaryStorage, String templateName, String templateUuid) throws Exception { + String templatePathAtSecondaryStorage, String templateName, String templateUuid, Integer nfsVersion) throws Exception { s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage + ", templateName: " + templateName); - String secondaryMountPoint = _mountService.getMountPoint(secondaryStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secondaryStorageUrl, nfsVersion); s_logger.info("Secondary storage mount point: " + secondaryMountPoint); String srcOVAFileName = secondaryMountPoint + "/" + templatePathAtSecondaryStorage + templateName + "." + ImageFormat.OVA.getFileExtension(); @@ -598,9 +611,9 @@ private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, } private Ternary createTemplateFromVolume(VirtualMachineMO vmMo, long accountId, long templateId, String templateUniqueName, String secStorageUrl, - String volumePath, String workerVmName) throws Exception { + String volumePath, String workerVmName, Integer nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); String installFullPath = secondaryMountPoint + "/" + installPath; synchronized (installPath.intern()) { @@ -663,9 +676,9 @@ private Ternary createTemplateFromVolume(VirtualMachineMO vm } private Ternary createTemplateFromSnapshot(long accountId, long templateId, String templateUniqueName, String secStorageUrl, long volumeId, - String backedUpSnapshotUuid) throws Exception { + String backedUpSnapshotUuid, Integer nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); String installFullPath = secondaryMountPoint + "/" + installPath; String installFullOVAName = installFullPath + "/" + templateUniqueName + ".ova"; //Note: volss for tmpl @@ -847,16 +860,16 @@ private void writeMetaOvaForTemplate(String installFullPath, String ovfFilename, } private String createVolumeFromSnapshot(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, long accountId, long volumeId, - String secStorageUrl, String snapshotBackupUuid) throws Exception { + String secStorageUrl, String snapshotBackupUuid, Integer nfsVersion) throws Exception { - restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), snapshotBackupUuid); + restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), snapshotBackupUuid, nfsVersion); return null; } private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, String secStorageUrl, String secStorageDir, - String backupName) throws Exception { + String backupName, Integer nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String srcOVAFileName = secondaryMountPoint + "/" + secStorageDir + "/" + backupName + "." + ImageFormat.OVA.getFileExtension(); String snapshotDir = ""; if (backupName.contains("/")) { @@ -914,17 +927,17 @@ private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, Datasto } private String backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, long accountId, long volumeId, String volumePath, String snapshotUuid, String secStorageUrl, - String prevSnapshotUuid, String prevBackupUuid, String workerVmName) throws Exception { + String prevSnapshotUuid, String prevBackupUuid, String workerVmName, Integer nfsVersion) throws Exception { String backupUuid = UUID.randomUUID().toString(); - exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), backupUuid, workerVmName); + exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), backupUuid, workerVmName, nfsVersion); return backupUuid + "/" + backupUuid; } private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, String secStorageUrl, String secStorageDir, String exportName, - String workerVmName) throws Exception { + String workerVmName, Integer nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String exportPath = secondaryMountPoint + "/" + secStorageDir + "/" + exportName; synchronized (exportPath.intern()) { @@ -967,7 +980,7 @@ private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volume } private Pair copyVolumeToSecStorage(VmwareHostService hostService, VmwareHypervisorHost hyperHost, CopyVolumeCommand cmd, String vmName, - long volumeId, String poolId, String volumePath, String secStorageUrl, String workerVmName) throws Exception { + long volumeId, String poolId, String volumePath, String secStorageUrl, String workerVmName, Integer nfsVersion) throws Exception { String volumeFolder = String.valueOf(volumeId) + "/"; VirtualMachineMO workerVm = null; @@ -1004,7 +1017,7 @@ private Pair copyVolumeToSecStorage(VmwareHostService hostServic vmMo.createSnapshot(exportName, "Temporary snapshot for copy-volume command", false, false); exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, "volumes/" + volumeFolder, exportName, - hostService.getWorkerName(hyperHost.getContext(), cmd, 1)); + hostService.getWorkerName(hyperHost.getContext(), cmd, 1), nfsVersion); return new Pair(volumeFolder, exportName); } finally { @@ -1025,12 +1038,12 @@ private String getVolumePathInDatastore(DatastoreMO dsMo, String volumeFileName) return datastoreVolumePath; } - private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, long volumeId, DatastoreMO dsMo, String secStorageUrl, String exportName) + private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, long volumeId, DatastoreMO dsMo, String secStorageUrl, String exportName, Integer nfsVersion) throws Exception { String volumeFolder = String.valueOf(volumeId) + "/"; String newVolume = UUID.randomUUID().toString().replaceAll("-", ""); - restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, "volumes/" + volumeFolder, exportName); + restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, "volumes/" + volumeFolder, exportName, nfsVersion); return new Pair(volumeFolder, newVolume); } @@ -1445,8 +1458,8 @@ public RevertToVMSnapshotAnswer execute(VmwareHostService hostService, RevertToV } } - private String deleteVolumeDirOnSecondaryStorage(long volumeId, String secStorageUrl) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + private String deleteVolumeDirOnSecondaryStorage(long volumeId, String secStorageUrl, Integer nfsVersion) throws Exception { + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String volumeMountRoot = secondaryMountPoint + "/" + getVolumeRelativeDirInSecStroage(volumeId); return deleteDir(volumeMountRoot); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java index dd07029766..fd139e418b 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java @@ -17,5 +17,5 @@ package com.cloud.hypervisor.vmware.manager; public interface VmwareStorageMount { - String getMountPoint(String storageUrl); + String getMountPoint(String storageUrl, Integer nfsVersion); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index dd419f2574..238ba3ed86 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -94,11 +94,15 @@ import com.vmware.vim25.VirtualMachineRelocateSpec; import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator; import com.vmware.vim25.VirtualMachineRuntimeInfo; +import com.vmware.vim25.VirtualMachineVideoCard; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; +import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; +import org.apache.cloudstack.storage.resource.NfsSecondaryStorageResource; import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.commons.lang.math.NumberUtils; import com.cloud.agent.IAgentControl; import com.cloud.agent.api.Answer; @@ -147,6 +151,8 @@ import com.cloud.agent.api.ModifySshKeysCommand; import com.cloud.agent.api.ModifyStoragePoolAnswer; import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.agent.api.ModifyTargetsAnswer; +import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.agent.api.NetworkUsageAnswer; import com.cloud.agent.api.NetworkUsageCommand; import com.cloud.agent.api.PingCommand; @@ -302,6 +308,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected String _password; protected String _guid; protected String _vCenterAddress; + protected Integer storageNfsVersion; protected String _privateNetworkVSwitchName; protected VmwareTrafficLabel _guestTrafficInfo = new VmwareTrafficLabel(TrafficType.Guest); @@ -408,6 +415,8 @@ public Answer executeRequest(Command cmd) { answer = execute((DestroyCommand)cmd); } else if (clz == CreateStoragePoolCommand.class) { return execute((CreateStoragePoolCommand)cmd); + } else if (clz == ModifyTargetsCommand.class) { + answer = execute((ModifyTargetsCommand)cmd); } else if (clz == ModifyStoragePoolCommand.class) { answer = execute((ModifyStoragePoolCommand)cmd); } else if (clz == DeleteStoragePoolCommand.class) { @@ -469,6 +478,7 @@ public Answer executeRequest(Command cmd) { } else if (clz == UnregisterVMCommand.class) { return execute((UnregisterVMCommand) cmd); } else if (cmd instanceof StorageSubSystemCommand) { + checkStorageProcessorAndHandlerNfsVersionAttribute((StorageSubSystemCommand)cmd); return storageHandler.handleStorageCommands((StorageSubSystemCommand) cmd); } else if (clz == ScaleVmCommand.class) { return execute((ScaleVmCommand)cmd); @@ -517,6 +527,64 @@ public Answer executeRequest(Command cmd) { return answer; } + /** + * Check if storage NFS version is already set or needs to be reconfigured.
+ * If _storageNfsVersion is not null -> nothing to do, version already set.
+ * If _storageNfsVersion is null -> examine StorageSubSystemCommand to get NFS version and set it + * to the storage processor and storage handler. + * @param cmd command to execute + */ + protected void checkStorageProcessorAndHandlerNfsVersionAttribute(StorageSubSystemCommand cmd) { + if (storageNfsVersion != null) return; + if (cmd instanceof CopyCommand){ + examineStorageSubSystemCommandNfsVersion((CopyCommand) cmd); + } + } + + /** + * Examine StorageSubSystem command to get storage NFS version, if provided + * @param cmd command to execute + */ + protected void examineStorageSubSystemCommandNfsVersion(CopyCommand cmd){ + DataStoreTO srcDataStore = cmd.getSrcTO().getDataStore(); + boolean nfsVersionFound = false; + + if (srcDataStore instanceof NfsTO){ + nfsVersionFound = getStorageNfsVersionFromNfsTO((NfsTO) srcDataStore); + } + + if (nfsVersionFound){ + setCurrentNfsVersionInProcessorAndHandler(); + } + } + + /** + * Get storage NFS version from NfsTO + * @param nfsTO nfsTO + * @return true if NFS version was found and not null, false in other case + */ + protected boolean getStorageNfsVersionFromNfsTO(NfsTO nfsTO){ + if (nfsTO != null && nfsTO.getNfsVersion() != null){ + storageNfsVersion = nfsTO.getNfsVersion(); + return true; + } + return false; + } + + /** + * Sets _storageNfsVersion into storage processor and storage handler by calling reconfigureNfsVersion on the storage handler, + * which will set NFS version into it and the storage processor. + */ + protected void setCurrentNfsVersionInProcessorAndHandler() { + VmwareStorageSubsystemCommandHandler handler = (VmwareStorageSubsystemCommandHandler) storageHandler; + boolean success = handler.reconfigureNfsVersion(storageNfsVersion); + if (success){ + s_logger.info("NFS version " + storageNfsVersion + " successfully set in VmwareStorageProcessor and VmwareStorageSubsystemCommandHandler"); + } else { + s_logger.error("Error while setting NFS version " + storageNfsVersion); + } + } + /** * Registers the vm to the inventory given the vmx file. */ @@ -932,7 +1000,7 @@ private PlugNicAnswer execute(PlugNicCommand cmd) { */ // Fallback to E1000 if no specific nicAdapter is passed VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.E1000; - Map details = cmd.getDetails(); + Map details = cmd.getDetails(); if (details != null) { nicDeviceType = VirtualEthernetCardType.valueOf((String) details.get("nicAdapter")); } @@ -1635,12 +1703,14 @@ protected StartAnswer execute(StartCommand cmd) { // prepare systemvm patch ISO if (vmSpec.getType() != VirtualMachine.Type.User) { // attach ISO (for patching of system VM) - String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); + Pair secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId)); + String secStoreUrl = secStoreUrlAndId.first(); + Long secStoreId = secStoreUrlAndId.second(); if (secStoreUrl == null) { String msg = "secondary storage for dc " + _dcId + " is not ready yet?"; throw new Exception(msg); } - mgr.prepareSecondaryStorageStore(secStoreUrl); + mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnHost(secStoreUrl); if (morSecDs == null) { @@ -1894,6 +1964,8 @@ protected StartAnswer execute(StartCommand cmd) { postDiskConfigBeforeStart(vmMo, vmSpec, sortedDisks, ideControllerKey, scsiControllerKey, iqnToPath, hyperHost, context); + postVideoCardMemoryConfigBeforeStart(vmMo, vmSpec); + // // Power-on VM // @@ -1942,6 +2014,79 @@ protected StartAnswer execute(StartCommand cmd) { } } + /** + * Sets video card memory to the one provided in detail svga.vramSize (if provided). + * 64MB was always set before. + * Size must be in KB. + * @param vmMo virtual machine mo + * @param vmSpec virtual machine specs + */ + protected void postVideoCardMemoryConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec) { + String paramVRamSize = "svga.vramSize"; + if (vmSpec.getDetails().containsKey(paramVRamSize)){ + String value = vmSpec.getDetails().get(paramVRamSize); + try { + long svgaVmramSize = Long.parseLong(value); + setNewVRamSizeVmVideoCard(vmMo, svgaVmramSize); + } + catch (NumberFormatException e){ + s_logger.error("Unexpected value, cannot parse " + value + " to long due to: " + e.getMessage()); + } + catch (Exception e){ + s_logger.error("Error while reconfiguring vm due to: " + e.getMessage()); + } + } + } + + /** + * Search for vm video card iterating through vm device list + * @param vmMo virtual machine mo + * @param svgaVmramSize new svga vram size (in KB) + */ + private void setNewVRamSizeVmVideoCard(VirtualMachineMO vmMo, long svgaVmramSize) throws Exception { + for (VirtualDevice device : vmMo.getAllDeviceList()){ + if (device instanceof VirtualMachineVideoCard){ + VirtualMachineVideoCard videoCard = (VirtualMachineVideoCard) device; + modifyVmVideoCardVRamSize(videoCard, vmMo, svgaVmramSize); + } + } + } + + /** + * Modifies vm vram size if it was set to a different size to the one provided in svga.vramSize (user_vm_details or template_vm_details) + * @param videoCard vm's video card device + * @param vmMo virtual machine mo + * @param svgaVmramSize new svga vram size (in KB) + */ + private void modifyVmVideoCardVRamSize(VirtualMachineVideoCard videoCard, VirtualMachineMO vmMo, long svgaVmramSize) throws Exception { + if (videoCard.getVideoRamSizeInKB().longValue() != svgaVmramSize){ + s_logger.info("Video card memory was set " + videoCard.getVideoRamSizeInKB().longValue() + "kb instead of " + svgaVmramSize + "kb"); + VirtualMachineConfigSpec newSizeSpecs = configSpecVideoCardNewVRamSize(videoCard, svgaVmramSize); + boolean res = vmMo.configureVm(newSizeSpecs); + if (res) { + s_logger.info("Video card memory successfully updated to " + svgaVmramSize + "kb"); + } + } + } + + /** + * Returns a VirtualMachineConfigSpec to edit its svga vram size + * @param videoCard video card device to edit providing the svga vram size + * @param svgaVmramSize new svga vram size (in KB) + */ + private VirtualMachineConfigSpec configSpecVideoCardNewVRamSize(VirtualMachineVideoCard videoCard, long svgaVmramSize){ + videoCard.setVideoRamSizeInKB(svgaVmramSize); + videoCard.setUseAutoDetect(false); + + VirtualDeviceConfigSpec arrayVideoCardConfigSpecs = new VirtualDeviceConfigSpec(); + arrayVideoCardConfigSpecs.setDevice(videoCard); + arrayVideoCardConfigSpecs.setOperation(VirtualDeviceConfigSpecOperation.EDIT); + + VirtualMachineConfigSpec changeVideoCardSpecs = new VirtualMachineConfigSpec(); + changeVideoCardSpecs.getDeviceChange().add(arrayVideoCardConfigSpecs); + return changeVideoCardSpecs; + } + private void tearDownVm(VirtualMachineMO vmMo) throws Exception{ if(vmMo == null) return; @@ -3133,12 +3278,14 @@ protected Answer execute(PrepareForMigrationCommand cmd) { prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false, cmd.getVirtualMachine().getType()); } - String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); + Pair secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId)); + String secStoreUrl = secStoreUrlAndId.first(); + Long secStoreId = secStoreUrlAndId.second(); if (secStoreUrl == null) { String msg = "secondary storage for dc " + _dcId + " is not ready yet?"; throw new Exception(msg); } - mgr.prepareSecondaryStorageStore(secStoreUrl); + mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnHost(secStoreUrl); if (morSecDs == null) { @@ -3349,12 +3496,14 @@ protected Answer execute(MigrateWithStorageCommand cmd) { } // Ensure secondary storage mounted on target host - String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); + Pair secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId)); + String secStoreUrl = secStoreUrlAndId.first(); + Long secStoreId = secStoreUrlAndId.second(); if (secStoreUrl == null) { String msg = "secondary storage for dc " + _dcId + " is not ready yet?"; throw new Exception(msg); } - mgr.prepareSecondaryStorageStore(secStoreUrl); + mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnSpecificHost(secStoreUrl, tgtHyperHost); if (morSecDs == null) { String msg = "Failed to prepare secondary storage on host, secondary store url: " + secStoreUrl; @@ -3445,7 +3594,6 @@ protected Answer execute(MigrateWithStorageCommand cmd) { private Answer execute(MigrateVolumeCommand cmd) { String volumePath = cmd.getVolumePath(); StorageFilerTO poolTo = cmd.getPool(); - Volume.Type volumeType = cmd.getVolumeType(); if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource MigrateVolumeCommand: " + _gson.toJson(cmd)); @@ -3526,7 +3674,6 @@ private Answer execute(MigrateVolumeCommand cmd) { // Consolidate VM disks. // In case of a linked clone VM, if VM's disks are not consolidated, // further volume operations on the ROOT volume such as volume snapshot etc. will result in DB inconsistencies. - String apiVersion = HypervisorHostHelper.getVcenterApiVersion(vmMo.getContext()); if (!vmMo.consolidateVmDisks()) { s_logger.warn("VM disk consolidation failed after storage migration."); } else { @@ -3595,6 +3742,14 @@ protected Answer execute(CreateStoragePoolCommand cmd) { return new Answer(cmd, true, "success"); } + protected Answer execute(ModifyTargetsCommand cmd) { + VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); + + handleTargets(cmd.getAdd(), cmd.getTargets(), (HostMO)hyperHost); + + return new ModifyTargetsAnswer(); + } + protected Answer execute(ModifyStoragePoolCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource ModifyStoragePoolCommand: " + _gson.toJson(cmd)); @@ -3608,34 +3763,53 @@ protected Answer execute(ModifyStoragePoolCommand cmd) { throw new Exception("Unsupported storage pool type " + pool.getType()); } - ManagedObjectReference morDatastore = null; - morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, pool.getUuid()); - if (morDatastore == null) - morDatastore = - hyperHost.mountDatastore(pool.getType() == StoragePoolType.VMFS, pool.getHost(), pool.getPort(), pool.getPath(), pool.getUuid().replace("-", "")); + ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, pool.getUuid()); + + if (morDatastore == null) { + morDatastore = hyperHost.mountDatastore(pool.getType() == StoragePoolType.VMFS, pool.getHost(), pool.getPort(), pool.getPath(), pool.getUuid().replace("-", "")); + } assert (morDatastore != null); + DatastoreSummary summary = new DatastoreMO(getServiceContext(), morDatastore).getSummary(); + long capacity = summary.getCapacity(); long available = summary.getFreeSpace(); + Map tInfo = new HashMap(); ModifyStoragePoolAnswer answer = new ModifyStoragePoolAnswer(cmd, capacity, available, tInfo); + if (cmd.getAdd() && pool.getType() == StoragePoolType.VMFS) { answer.setLocalDatastoreName(morDatastore.getValue()); } + return answer; } catch (Throwable e) { if (e instanceof RemoteException) { s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); + invalidateServiceContext(); } String msg = "ModifyStoragePoolCommand failed due to " + VmwareHelper.getExceptionMessage(e); + s_logger.error(msg, e); + return new Answer(cmd, false, msg); } } + private void handleTargets(boolean add, List> targets, HostMO host) { + if (targets != null && targets.size() > 0) { + try { + _storageProcessor.handleTargetsForHost(add, targets, host); + } + catch (Exception ex) { + s_logger.warn(ex.getMessage()); + } + } + } + protected Answer execute(DeleteStoragePoolCommand cmd) { if (s_logger.isInfoEnabled()) { s_logger.info("Executing resource DeleteStoragePoolCommand: " + _gson.toJson(cmd)); @@ -4619,12 +4793,6 @@ protected HashMap syncHostVmStates() { } } - private boolean isVmInCluster(String vmName) throws Exception { - VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); - - return hyperHost.findVmOnPeerHyperHost(vmName) != null; - } - protected OptionValue[] configureVnc(OptionValue[] optionsToMerge, VmwareHypervisorHost hyperHost, String vmName, String vncPassword, String keyboardLayout) throws Exception { @@ -4861,8 +5029,14 @@ private HashMap getVmStats(List vmNames) throws Ex } String instanceNameCustomField = "value[" + key + "]"; + final String numCpuStr = "summary.config.numCpu"; + final String cpuUseStr = "summary.quickStats.overallCpuUsage"; + final String guestMemUseStr = "summary.quickStats.guestMemoryUsage"; + final String memLimitStr = "resourceConfig.memoryAllocation.limit"; + final String memMbStr = "config.hardware.memoryMB"; + ObjectContent[] ocs = - hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", "summary.config.numCpu", "summary.quickStats.overallCpuUsage", instanceNameCustomField}); + hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", numCpuStr, cpuUseStr ,guestMemUseStr ,memLimitStr ,memMbStr, instanceNameCustomField}); if (ocs != null && ocs.length > 0) { for (ObjectContent oc : ocs) { List objProps = oc.getPropSet(); @@ -4870,6 +5044,9 @@ private HashMap getVmStats(List vmNames) throws Ex String name = null; String numberCPUs = null; String maxCpuUsage = null; + String memlimit = null; + String memkb = null; + String guestMemusage = null; String vmNameOnVcenter = null; String vmInternalCSName = null; for (DynamicProperty objProp : objProps) { @@ -4878,10 +5055,16 @@ private HashMap getVmStats(List vmNames) throws Ex } else if (objProp.getName().contains(instanceNameCustomField)) { if (objProp.getVal() != null) vmInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue(); - } else if (objProp.getName().equals("summary.config.numCpu")) { + }else if(objProp.getName().equals(guestMemusage)){ + guestMemusage = objProp.getVal().toString(); + }else if (objProp.getName().equals(numCpuStr)) { numberCPUs = objProp.getVal().toString(); - } else if (objProp.getName().equals("summary.quickStats.overallCpuUsage")) { + } else if (objProp.getName().equals(cpuUseStr)) { maxCpuUsage = objProp.getVal().toString(); + } else if (objProp.getName().equals(memLimitStr)) { + memlimit = objProp.getVal().toString(); + } else if (objProp.getName().equals(memMbStr)) { + memkb = objProp.getVal().toString(); } } new VirtualMachineMO(hyperHost.getContext(), oc.getObj()); @@ -4950,7 +5133,7 @@ private HashMap getVmStats(List vmNames) throws Ex } } } - vmResponseMap.put(name, new VmStatsEntry(Integer.parseInt(maxCpuUsage), networkReadKBs, networkWriteKBs, Integer.parseInt(numberCPUs), "vm")); + vmResponseMap.put(name, new VmStatsEntry( NumberUtils.toDouble(memkb)*1024,NumberUtils.toDouble(guestMemusage)*1024,NumberUtils.toDouble(memlimit)*1024, NumberUtils.toDouble(maxCpuUsage), networkReadKBs, networkWriteKBs, NumberUtils.toInt(numberCPUs), "vm")); } } } @@ -5190,8 +5373,10 @@ else if (value != null && value.equalsIgnoreCase("ide")) value = (String)params.get("scripts.timeout"); int timeout = NumbersUtil.parseInt(value, 1440) * 1000; - _storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, timeout, this, _shutdownWaitMs, null); - storageHandler = new VmwareStorageSubsystemCommandHandler(_storageProcessor); + + storageNfsVersion = NfsSecondaryStorageResource.retrieveNfsVersionFromParams(params); + _storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, timeout, this, _shutdownWaitMs, null, storageNfsVersion); + storageHandler = new VmwareStorageSubsystemCommandHandler(_storageProcessor, storageNfsVersion); _vrResource = new VirtualRoutingResource(this); if (!_vrResource.configure(name, params)) { diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java index 8e4a0d2a83..fd89cc7bb0 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java @@ -102,7 +102,8 @@ public boolean configure(String name, Map params) throws Configu VmwareSecondaryStorageContextFactory.initFactoryEnvironment(); } - registerHandler(Hypervisor.HypervisorType.VMware, new VmwareSecondaryStorageResourceHandler(this)); + Integer nfsVersion = NfsSecondaryStorageResource.retrieveNfsVersionFromParams(params); + registerHandler(Hypervisor.HypervisorType.VMware, new VmwareSecondaryStorageResourceHandler(this, nfsVersion)); return true; } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java index 8a277991aa..9a8c37a098 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java @@ -66,13 +66,13 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe * private Map _activeHosts = new HashMap(); */ - public VmwareSecondaryStorageResourceHandler(PremiumSecondaryStorageResource resource) { + public VmwareSecondaryStorageResourceHandler(PremiumSecondaryStorageResource resource, Integer nfsVersion) { _resource = resource; - _storageMgr = new VmwareStorageManagerImpl(this); + _storageMgr = new VmwareStorageManagerImpl(this, nfsVersion); _gson = GsonHelper.getGsonLogger(); - VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor(this, true, this, resource.getTimeout(), null, null, _resource); - VmwareStorageSubsystemCommandHandler vmwareStorageSubsystemCommandHandler = new VmwareStorageSubsystemCommandHandler(storageProcessor); + VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor(this, true, this, resource.getTimeout(), null, null, _resource, nfsVersion); + VmwareStorageSubsystemCommandHandler vmwareStorageSubsystemCommandHandler = new VmwareStorageSubsystemCommandHandler(storageProcessor, nfsVersion); vmwareStorageSubsystemCommandHandler.setStorageResource(_resource); vmwareStorageSubsystemCommandHandler.setStorageManager(_storageMgr); storageSubsystemHandler = vmwareStorageSubsystemCommandHandler; @@ -304,7 +304,7 @@ public String getWorkerName(VmwareContext context, Command cmd, int workerSequen } @Override - public String getMountPoint(String storageUrl) { - return _resource.getRootDir(storageUrl); + public String getMountPoint(String storageUrl, Integer nfsVersion) { + return _resource.getRootDir(storageUrl, nfsVersion); } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index 567f8576d7..eb18e0b9a8 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -62,6 +62,8 @@ import org.apache.cloudstack.storage.command.DettachCommand; import org.apache.cloudstack.storage.command.ForgetObjectCmd; import org.apache.cloudstack.storage.command.IntroduceObjectCmd; +import org.apache.cloudstack.storage.command.ResignatureAnswer; +import org.apache.cloudstack.storage.command.ResignatureCommand; import org.apache.cloudstack.storage.command.SnapshotAndCopyAnswer; import org.apache.cloudstack.storage.command.SnapshotAndCopyCommand; import org.apache.cloudstack.storage.to.PrimaryDataStoreTO; @@ -71,6 +73,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.agent.api.to.DataStoreTO; import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; @@ -110,6 +113,7 @@ import com.cloud.vm.VmDetailConstants; public class VmwareStorageProcessor implements StorageProcessor { + private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class); private static final int DEFAULT_NFS_PORT = 2049; @@ -121,9 +125,10 @@ public class VmwareStorageProcessor implements StorageProcessor { protected Integer _shutdownWaitMs; private final Gson _gson; private final StorageLayer _storage = new JavaStorageLayer(); + private Integer _nfsVersion; public VmwareStorageProcessor(VmwareHostService hostService, boolean fullCloneFlag, VmwareStorageMount mountService, Integer timeout, VmwareResource resource, - Integer shutdownWaitMs, PremiumSecondaryStorageResource storageResource) { + Integer shutdownWaitMs, PremiumSecondaryStorageResource storageResource, Integer nfsVersion) { this.hostService = hostService; _fullCloneFlag = fullCloneFlag; this.mountService = mountService; @@ -131,6 +136,7 @@ public VmwareStorageProcessor(VmwareHostService hostService, boolean fullCloneFl this.resource = resource; _shutdownWaitMs = shutdownWaitMs; _gson = GsonHelper.getGsonLogger(); + _nfsVersion = nfsVersion; } @Override @@ -140,6 +146,13 @@ public SnapshotAndCopyAnswer snapshotAndCopy(SnapshotAndCopyCommand cmd) { return new SnapshotAndCopyAnswer(); } + @Override + public ResignatureAnswer resignature(ResignatureCommand cmd) { + s_logger.info("'ResignatureAnswer resignature(ResignatureCommand)' not currently used for VmwareStorageProcessor"); + + return new ResignatureAnswer(); + } + private String getOVFFilePath(String srcOVAFileName) { File file = new File(srcOVAFileName); assert (_storage != null); @@ -156,12 +169,12 @@ private String getOVFFilePath(String srcOVAFileName) { } private VirtualMachineMO copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl, - String templatePathAtSecondaryStorage, String templateName, String templateUuid, boolean createSnapshot) throws Exception { + String templatePathAtSecondaryStorage, String templateName, String templateUuid, boolean createSnapshot, Integer nfsVersion) throws Exception { s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage + ", templateName: " + templateName); - String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, nfsVersion); s_logger.info("Secondary storage mount point: " + secondaryMountPoint); String srcOVAFileName = @@ -317,7 +330,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { if (managed) { VirtualMachineMO vmMo = copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - managedStoragePoolRootVolumeName, false); + managedStoragePoolRootVolumeName, false, _nfsVersion); vmMo.unregisterVm(); @@ -334,7 +347,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { } else { copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - templateUuidName, true); + templateUuidName, true, _nfsVersion); } } else { s_logger.info("Template " + templateInfo.second() + " has already been setup, skip the template setup process in primary storage"); @@ -519,7 +532,7 @@ public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) { } } - private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, String srcVolumePath, DatastoreMO dsMo, String secStorageUrl, long wait) throws Exception { + private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, String srcVolumePath, DatastoreMO dsMo, String secStorageUrl, long wait, Integer nfsVersion) throws Exception { String volumeFolder = null; String volumeName = null; @@ -534,13 +547,13 @@ private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyper } String newVolume = VmwareHelper.getVCenterSafeUuid(); - restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, volumeFolder, volumeName, wait); + restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, volumeFolder, volumeName, wait, nfsVersion); return new Pair(volumeFolder, newVolume); } - private String deleteVolumeDirOnSecondaryStorage(String volumeDir, String secStorageUrl) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + private String deleteVolumeDirOnSecondaryStorage(String volumeDir, String secStorageUrl, Integer nfsVersion) throws Exception { + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String volumeMountRoot = secondaryMountPoint + File.separator + volumeDir; return deleteDir(volumeMountRoot); @@ -579,8 +592,8 @@ public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) { } } - Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000); - deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl()); + Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000, _nfsVersion); + deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl(), _nfsVersion); VolumeObjectTO newVolume = new VolumeObjectTO(); newVolume.setPath(result.second()); return new CopyCmdAnswer(newVolume); @@ -637,7 +650,7 @@ private Pair copyVolumeToSecStorage(VmwareHostService hostServic vmMo.createSnapshot(exportName, "Temporary snapshot for copy-volume command", false, false); - exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, destVolumePath, exportName, hostService.getWorkerName(hyperHost.getContext(), cmd, 1)); + exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, destVolumePath, exportName, hostService.getWorkerName(hyperHost.getContext(), cmd, 1), _nfsVersion); return new Pair(destVolumePath, exportName); } finally { @@ -721,9 +734,9 @@ private void postCreatePrivateTemplate(String installFullPath, long templateId, } private Ternary createTemplateFromVolume(VirtualMachineMO vmMo, String installPath, long templateId, String templateUniqueName, - String secStorageUrl, String volumePath, String workerVmName) throws Exception { + String secStorageUrl, String volumePath, String workerVmName, Integer nfsVersion) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String installFullPath = secondaryMountPoint + "/" + installPath; synchronized (installPath.intern()) { Script command = new Script(false, "mkdir", _timeout, s_logger); @@ -839,7 +852,7 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { Ternary result = createTemplateFromVolume(vmMo, template.getPath(), template.getId(), template.getName(), secondaryStoragePoolURL, volumePath, - hostService.getWorkerName(context, cmd, 0)); + hostService.getWorkerName(context, cmd, 0), _nfsVersion); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -886,7 +899,7 @@ private void writeMetaOvaForTemplate(String installFullPath, String ovfFilename, } private Ternary createTemplateFromSnapshot(String installPath, String templateUniqueName, String secStorageUrl, String snapshotPath, - Long templateId, long wait) throws Exception { + Long templateId, long wait, Integer nfsVersion) throws Exception { //Snapshot path is decoded in this form: /snapshots/account/volumeId/uuid/uuid String backupSSUuid; String snapshotFolder; @@ -900,7 +913,7 @@ private Ternary createTemplateFromSnapshot(String installPat snapshotFolder = StringUtils.join(tokens, File.separator, 0, tokens.length - 1); } - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String installFullPath = secondaryMountPoint + "/" + installPath; String installFullOVAName = installFullPath + "/" + templateUniqueName + ".ova"; //Note: volss for tmpl String snapshotRoot = secondaryMountPoint + "/" + snapshotFolder; @@ -1030,7 +1043,7 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { } NfsTO nfsSvr = (NfsTO)imageStore; - Ternary result = createTemplateFromSnapshot(template.getPath(), uniqeName, nfsSvr.getUrl(), snapshot.getPath(), template.getId(), (long)cmd.getWait() * 1000); + Ternary result = createTemplateFromSnapshot(template.getPath(), uniqeName, nfsSvr.getUrl(), snapshot.getPath(), template.getId(), (long)cmd.getWait() * 1000, _nfsVersion); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -1053,9 +1066,9 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { // return Pair private Pair exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, String secStorageUrl, String secStorageDir, - String exportName, String workerVmName) throws Exception { + String exportName, String workerVmName, Integer nfsVersion) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String exportPath = secondaryMountPoint + "/" + secStorageDir + "/" + exportName; synchronized (exportPath.intern()) { @@ -1097,10 +1110,10 @@ private Pair exportVolumeToSecondaryStroage(VirtualMachineMO v // Ternary private Ternary backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, String installPath, String volumePath, String snapshotUuid, - String secStorageUrl, String prevSnapshotUuid, String prevBackupUuid, String workerVmName) throws Exception { + String secStorageUrl, String prevSnapshotUuid, String prevBackupUuid, String workerVmName, Integer nfsVersion) throws Exception { String backupUuid = UUID.randomUUID().toString(); - Pair snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, installPath, backupUuid, workerVmName); + Pair snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, installPath, backupUuid, workerVmName, nfsVersion); return new Ternary(backupUuid, snapshotInfo.first(), snapshotInfo.second()); } @@ -1175,7 +1188,7 @@ public Answer backupSnapshot(CopyCommand cmd) { backupResult = backupSnapshotToSecondaryStorage(vmMo, destSnapshot.getPath(), srcSnapshot.getVolume().getPath(), snapshotUuid, secondaryStorageUrl, - prevSnapshotUuid, prevBackupUuid, hostService.getWorkerName(context, cmd, 1)); + prevSnapshotUuid, prevBackupUuid, hostService.getWorkerName(context, cmd, 1), _nfsVersion); snapshotBackupUuid = backupResult.first(); success = (snapshotBackupUuid != null); @@ -1187,7 +1200,7 @@ public Answer backupSnapshot(CopyCommand cmd) { // Get snapshot physical size long physicalSize = 0l; - String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, _nfsVersion); String snapshotDir = destSnapshot.getPath() + "/" + snapshotBackupUuid; File[] files = new File(secondaryMountPoint + "/" + snapshotDir).listFiles(); if(files != null) { @@ -1908,14 +1921,77 @@ private static int getMBsFromBytes(long bytes) { return (int)(bytes / (1024L * 1024L)); } - private void addRemoveInternetScsiTargetsToAllHosts(VmwareContext context, final boolean add, final List lstTargets, - List> lstHosts) throws Exception { - ExecutorService executorService = Executors.newFixedThreadPool(lstHosts.size()); + public void handleTargetsForHost(boolean add, List> targets, HostMO host) throws Exception { + List lstTargets = new ArrayList(); - final List exceptions = new ArrayList(); + for (Map mapTarget : targets) { + HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget(); - for (Pair hostPair : lstHosts) { + String targetAddress = mapTarget.get(ModifyTargetsCommand.STORAGE_HOST); + Integer targetPort = Integer.parseInt(mapTarget.get(ModifyTargetsCommand.STORAGE_PORT)); + String iScsiName = trimIqn(mapTarget.get(ModifyTargetsCommand.IQN)); + + target.setAddress(targetAddress); + target.setPort(targetPort); + target.setIScsiName(iScsiName); + + String chapName = mapTarget.get(ModifyTargetsCommand.CHAP_NAME); + String chapSecret = mapTarget.get(ModifyTargetsCommand.CHAP_SECRET); + + if (StringUtils.isNotBlank(chapName) && StringUtils.isNotBlank(chapSecret)) { + HostInternetScsiHbaAuthenticationProperties auth = new HostInternetScsiHbaAuthenticationProperties(); + + String strAuthType = "chapRequired"; + + auth.setChapAuthEnabled(true); + auth.setChapInherited(false); + auth.setChapAuthenticationType(strAuthType); + auth.setChapName(chapName); + auth.setChapSecret(chapSecret); + + String mutualChapName = mapTarget.get(ModifyTargetsCommand.MUTUAL_CHAP_NAME); + String mutualChapSecret = mapTarget.get(ModifyTargetsCommand.MUTUAL_CHAP_SECRET); + + if (StringUtils.isNotBlank(mutualChapName) && StringUtils.isNotBlank(mutualChapSecret)) { + auth.setMutualChapInherited(false); + auth.setMutualChapAuthenticationType(strAuthType); + auth.setMutualChapName(mutualChapName); + auth.setMutualChapSecret(mutualChapSecret); + } + + target.setAuthenticationProperties(auth); + } + + lstTargets.add(target); + } + + List hosts = new ArrayList<>(); + + hosts.add(host); + + addRemoveInternetScsiTargetsToAllHosts(add, lstTargets, hosts); + } + + private void addRemoveInternetScsiTargetsToAllHosts(VmwareContext context, final boolean add, final List targets, + List> hostPairs) throws Exception { + List hosts = new ArrayList<>(); + + for (Pair hostPair : hostPairs) { HostMO host = new HostMO(context, hostPair.first()); + + hosts.add(host); + } + + addRemoveInternetScsiTargetsToAllHosts(add, targets, hosts); + } + + private void addRemoveInternetScsiTargetsToAllHosts(final boolean add, final List targets, + List hosts) throws Exception { + ExecutorService executorService = Executors.newFixedThreadPool(hosts.size()); + + final List exceptions = new ArrayList(); + + for (HostMO host : hosts) { HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO(); boolean iScsiHbaConfigured = false; @@ -1935,9 +2011,9 @@ private void addRemoveInternetScsiTargetsToAllHosts(VmwareContext context, final public void run() { try { if (add) { - hss.addInternetScsiStaticTargets(iScsiHbaDevice, lstTargets); + hss.addInternetScsiStaticTargets(iScsiHbaDevice, targets); } else { - hss.removeInternetScsiStaticTargets(iScsiHbaDevice, lstTargets); + hss.removeInternetScsiStaticTargets(iScsiHbaDevice, targets); } hss.rescanHba(iScsiHbaDevice); @@ -2136,9 +2212,9 @@ private List getManagedIqnsFromVirtualDisks(List virtualDis } private Long restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, String secStorageUrl, String secStorageDir, - String backupName, long wait) throws Exception { + String backupName, long wait, Integer nfsVersion) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); String srcOVAFileName = null; String srcOVFFileName = null; @@ -2240,7 +2316,7 @@ public Answer createVolumeFromSnapshot(CopyCommand cmd) { backedUpSnapshotUuid = backedUpSnapshotUuid.replace(".ovf", ""); } DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs); - restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000); + restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000, _nfsVersion); VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setPath(newVolumeName); @@ -2313,4 +2389,9 @@ private String getControllerFromConfigurationSetting() throws Exception { private String getLegacyVmDataDiskController() throws Exception { return DiskControllerType.lsilogic.toString(); } + + public void setNfsVersion(Integer nfsVersion){ + this._nfsVersion = nfsVersion; + s_logger.debug("VmwareProcessor instance now using NFS version: " + nfsVersion); + } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java index 431286248b..7252f51bf3 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java @@ -21,7 +21,6 @@ import java.io.File; import org.apache.log4j.Logger; - import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.DeleteCommand; @@ -40,9 +39,11 @@ import com.cloud.storage.DataStoreRole; public class VmwareStorageSubsystemCommandHandler extends StorageSubsystemCommandHandlerBase { + private static final Logger s_logger = Logger.getLogger(VmwareStorageSubsystemCommandHandler.class); private VmwareStorageManager storageManager; private PremiumSecondaryStorageResource storageResource; + private Integer _nfsVersion; public PremiumSecondaryStorageResource getStorageResource() { return storageResource; @@ -60,8 +61,26 @@ public void setStorageManager(VmwareStorageManager storageManager) { this.storageManager = storageManager; } - public VmwareStorageSubsystemCommandHandler(StorageProcessor processor) { + public VmwareStorageSubsystemCommandHandler(StorageProcessor processor, Integer nfsVersion) { super(processor); + this._nfsVersion = nfsVersion; + } + + /** + * Reconfigure NFS version for storage operations + * @param nfsVersion NFS version to set + * @return true if NFS version could be configured, false in other case + */ + public boolean reconfigureNfsVersion(Integer nfsVersion){ + try { + VmwareStorageProcessor processor = (VmwareStorageProcessor) this.processor; + processor.setNfsVersion(nfsVersion); + this._nfsVersion = nfsVersion; + return true; + } catch (Exception e){ + s_logger.error("Error while reconfiguring NFS version " + nfsVersion); + return false; + } } @Override @@ -82,7 +101,7 @@ protected Answer execute(CopyCommand cmd) { //need to take extra processing for vmware, such as packing to ova, before sending to S3 if (srcData.getObjectType() == DataObjectType.VOLUME) { NfsTO cacheStore = (NfsTO)srcDataStore; - String parentPath = storageResource.getRootDir(cacheStore.getUrl()); + String parentPath = storageResource.getRootDir(cacheStore.getUrl(), _nfsVersion); VolumeObjectTO vol = (VolumeObjectTO)srcData; String path = vol.getPath(); int index = path.lastIndexOf(File.separator); @@ -95,7 +114,7 @@ protected Answer execute(CopyCommand cmd) { } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT) { // pack ova first // sync snapshot from NFS cache to S3 in NFS migration to S3 case - String parentPath = storageResource.getRootDir(srcDataStore.getUrl()); + String parentPath = storageResource.getRootDir(srcDataStore.getUrl(), _nfsVersion); SnapshotObjectTO snap = (SnapshotObjectTO)srcData; String path = snap.getPath(); int index = path.lastIndexOf(File.separator); @@ -138,7 +157,7 @@ protected Answer execute(CopyCommand cmd) { return answer; } NfsTO cacheStore = (NfsTO)cmd.getCacheTO().getDataStore(); - String parentPath = storageResource.getRootDir(cacheStore.getUrl()); + String parentPath = storageResource.getRootDir(cacheStore.getUrl(), _nfsVersion); SnapshotObjectTO newSnapshot = (SnapshotObjectTO)answer.getNewData(); String path = newSnapshot.getPath(); int index = path.lastIndexOf(File.separator); diff --git a/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java b/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java index 4b77aab617..23b32a3d25 100644 --- a/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java +++ b/plugins/hypervisors/vmware/src/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java @@ -25,9 +25,6 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; @@ -38,6 +35,8 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -87,21 +86,12 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { throw new UnsupportedOperationException(); } @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - CopyCommandResult result = new CopyCommandResult(null, null); - result.setResult("Unsupported operation requested for copying data."); - callback.complete(result); - - return null; - } - - @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { Answer answer = null; String errMsg = null; try { @@ -123,7 +113,6 @@ public Void copyAsync(Map volumeMap, VirtualMachineTO vmT CopyCommandResult result = new CopyCommandResult(null, answer); result.setResult(errMsg); callback.complete(result); - return null; } private Answer migrateVmWithVolumesAcrossCluster(VMInstanceVO vm, VirtualMachineTO to, Host srcHost, Host destHost, Map volumeToPool) diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java index 3b3dd47949..fec2aba40f 100644 --- a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java @@ -25,18 +25,19 @@ import java.util.UUID; import javax.inject.Inject; -import javax.naming.ConfigurationException; import com.cloud.user.User; + import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; @@ -48,12 +49,13 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; - import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.test.utils.SpringUtils; import com.cloud.agent.AgentManager; @@ -86,6 +88,7 @@ import com.cloud.org.Managed.ManagedState; import com.cloud.secstorage.CommandExecLogDao; import com.cloud.server.ConfigurationServer; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.AccountService; @@ -98,6 +101,7 @@ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class) +@PrepareForTest({ComponentContext.class, ApplicationContext.class}) public class VmwareDatacenterApiUnitTest { @Inject @@ -155,10 +159,6 @@ public class VmwareDatacenterApiUnitTest { @Mock private static RemoveVmwareDcCmd removeCmd; - @BeforeClass - public static void setUp() throws ConfigurationException { - } - @Before public void testSetUp() { Mockito.when(_configDao.isPremium()).thenReturn(true); @@ -431,6 +431,22 @@ public DataStoreManager dataStoreManager() { return Mockito.mock(DataStoreManager.class); } + @Bean + public ImageStoreDetailsUtil imageStoreDetailsUtil() { + return Mockito.mock(ImageStoreDetailsUtil.class); + } + + //Mocks for ImageStoreDetailsUtil + @Bean + public ImageStoreDao imageStoreDao() { + return Mockito.mock(ImageStoreDao.class); + } + + @Bean + public ImageStoreDetailsDao imageStoreDetailsDao() { + return Mockito.mock(ImageStoreDetailsDao.class); + } + public static class Library implements TypeFilter { @Override diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java index 2e3d41c048..22388a8a69 100644 --- a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java @@ -19,26 +19,55 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.mock; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.never; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.cloudstack.storage.command.CopyCommand; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import com.vmware.vim25.VirtualDevice; import com.vmware.vim25.VirtualMachineConfigSpec; - +import com.vmware.vim25.VirtualMachineVideoCard; import com.cloud.agent.api.Command; import com.cloud.agent.api.ScaleVmAnswer; import com.cloud.agent.api.ScaleVmCommand; +import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.api.to.NfsTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.cloud.storage.resource.VmwareStorageProcessor; +import com.cloud.storage.resource.VmwareStorageSubsystemCommandHandler; +@RunWith(PowerMockRunner.class) +@PrepareForTest(CopyCommand.class) public class VmwareResourceTest { + @Mock + VmwareStorageProcessor storageProcessor; + @Mock + VmwareStorageSubsystemCommandHandler storageHandler; + @Spy + @InjectMocks VmwareResource _resource = new VmwareResource() { @Override @@ -50,6 +79,7 @@ public ScaleVmAnswer execute(ScaleVmCommand cmd) { public VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd) { return hyperHost; } + }; @Mock @@ -64,12 +94,29 @@ public VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd) { VirtualMachineMO vmMo; @Mock VirtualMachineConfigSpec vmConfigSpec; + @Mock + VirtualMachineMO vmMo3dgpu; + @Mock + VirtualMachineTO vmSpec3dgpu; + @Mock + DataTO srcDataTO; + @Mock + NfsTO srcDataNfsTO; + + CopyCommand storageCmd; + + private static final Integer NFS_VERSION = Integer.valueOf(3); + private static final Integer NFS_VERSION_NOT_PRESENT = null; @Before public void setup() { MockitoAnnotations.initMocks(this); + storageCmd = PowerMockito.mock(CopyCommand.class); doReturn(context).when(_resource).getServiceContext(null); when(cmd.getVirtualMachine()).thenReturn(vmSpec); + when(storageCmd.getSrcTO()).thenReturn(srcDataTO); + when(srcDataTO.getDataStore()).thenReturn(srcDataNfsTO); + when(srcDataNfsTO.getNfsVersion()).thenReturn(NFS_VERSION); } //Test successful scaling up the vm @@ -90,4 +137,77 @@ public void testScaleVMF1() throws Exception { verify(_resource).execute(cmd); } -} + @Test + public void testStartVm3dgpuEnabled() throws Exception{ + Map specDetails = new HashMap(); + specDetails.put("svga.vramSize", "131072"); + when(vmSpec3dgpu.getDetails()).thenReturn(specDetails); + + VirtualMachineVideoCard videoCard = mock(VirtualMachineVideoCard.class); + when(videoCard.getVideoRamSizeInKB()).thenReturn(65536l); + when(vmMo3dgpu.getAllDeviceList()).thenReturn(Arrays.asList((VirtualDevice) videoCard)); + + when(vmMo3dgpu.configureVm(any(VirtualMachineConfigSpec.class))).thenReturn(true); + + _resource.postVideoCardMemoryConfigBeforeStart(vmMo3dgpu, vmSpec3dgpu); + verify(vmMo3dgpu).configureVm(any(VirtualMachineConfigSpec.class)); + } + + // --------------------------------------------------------------------------------------------------- + + @Test + public void testgetNfsVersionFromNfsTONull(){ + assertFalse(_resource.getStorageNfsVersionFromNfsTO(null)); + } + + @Test + public void testgetNfsVersionFromNfsTONfsVersionNull(){ + when(srcDataNfsTO.getNfsVersion()).thenReturn(NFS_VERSION_NOT_PRESENT); + assertFalse(_resource.getStorageNfsVersionFromNfsTO(srcDataNfsTO)); + } + + @Test + public void testgetNfsVersionFromNfsTONfsVersion(){ + assertTrue(_resource.getStorageNfsVersionFromNfsTO(srcDataNfsTO)); + } + + // --------------------------------------------------------------------------------------------------- + + @Test + public void testSetCurrentNfsVersionInProcessorAndHandler(){ + _resource.setCurrentNfsVersionInProcessorAndHandler(); + verify(storageHandler).reconfigureNfsVersion(any(Integer.class)); + } + + // --------------------------------------------------------------------------------------------------- + + @Test + public void testExamineStorageSubSystemCommandNfsVersionNotPresent(){ + when(srcDataNfsTO.getNfsVersion()).thenReturn(NFS_VERSION_NOT_PRESENT); + _resource.examineStorageSubSystemCommandNfsVersion(storageCmd); + verify(_resource, never()).setCurrentNfsVersionInProcessorAndHandler(); + } + + @Test + public void testExamineStorageSubSystemCommandNfsVersion(){ + _resource.examineStorageSubSystemCommandNfsVersion(storageCmd); + verify(_resource).setCurrentNfsVersionInProcessorAndHandler(); + } + + // --------------------------------------------------------------------------------------------------- + + @Test + public void checkStorageProcessorAndHandlerNfsVersionAttributeVersionNotSet(){ + _resource.checkStorageProcessorAndHandlerNfsVersionAttribute(storageCmd); + verify(_resource).examineStorageSubSystemCommandNfsVersion(storageCmd); + assertEquals(NFS_VERSION, _resource.storageNfsVersion); + } + + @Test + public void checkStorageProcessorAndHandlerNfsVersionAttributeVersionSet(){ + _resource.storageNfsVersion = NFS_VERSION; + _resource.checkStorageProcessorAndHandlerNfsVersionAttribute(storageCmd); + verify(_resource, never()).examineStorageSubSystemCommandNfsVersion(storageCmd); + } + +} \ No newline at end of file diff --git a/plugins/hypervisors/xenserver/pom.xml b/plugins/hypervisors/xenserver/pom.xml index 6f86a5c0bc..d03ae541a5 100644 --- a/plugins/hypervisors/xenserver/pom.xml +++ b/plugins/hypervisors/xenserver/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/XenServerGuru.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/XenServerGuru.java index e6ebe555da..9bfcba2596 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/XenServerGuru.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/XenServerGuru.java @@ -18,14 +18,11 @@ import java.util.ArrayList; import java.util.List; -import java.util.Map; import javax.inject.Inject; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; -import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.hypervisor.xenserver.XenserverConfigs; import org.apache.cloudstack.storage.command.CopyCommand; @@ -33,7 +30,7 @@ import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.log4j.Logger; import com.cloud.agent.api.Command; import com.cloud.agent.api.to.DataObjectType; @@ -57,34 +54,27 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.UserVmDao; -import org.apache.log4j.Logger; public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru, Configurable { private final Logger LOGGER = Logger.getLogger(XenServerGuru.class); @Inject - GuestOSDao _guestOsDao; - @Inject - GuestOSHypervisorDao _guestOsHypervisorDao; + private GuestOSDao _guestOsDao; @Inject - EndPointSelector endPointSelector; + private GuestOSHypervisorDao _guestOsHypervisorDao; @Inject - HostDao hostDao; + private HostDao hostDao; @Inject - VolumeDao _volumeDao; + private VolumeDao _volumeDao; @Inject - PrimaryDataStoreDao _storagePoolDao; + private PrimaryDataStoreDao _storagePoolDao; @Inject - VolumeDataFactory _volFactory; + private VolumeDataFactory _volFactory; @Inject - UserVmDao _userVmDao; + private UserVmDao _userVmDao; - static final ConfigKey MaxNumberOfVCPUSPerVM = new ConfigKey("Advanced", Integer.class, "xen.vm.vcpu.max", "16", + private static final ConfigKey MaxNumberOfVCPUSPerVM = new ConfigKey("Advanced", Integer.class, "xen.vm.vcpu.max", "16", "Maximum number of VCPUs that VM can get in XenServer.", true, ConfigKey.Scope.Cluster); - protected XenServerGuru() { - super(); - } - @Override public HypervisorType getHypervisorType() { return HypervisorType.XenServer; @@ -129,11 +119,6 @@ public boolean trackVmHostChange() { return true; } - @Override - public Map getClusterSettings(long vmId) { - return null; - } - @Override public List finalizeExpungeVolumes(VirtualMachine vm) { List commands = new ArrayList(); @@ -189,15 +174,13 @@ public Pair getCommandHostDelegation(long hostId, Command cmd) { DataStoreTO destStore = destData.getDataStore(); if (srcStore instanceof NfsTO && destStore instanceof NfsTO) { HostVO host = hostDao.findById(hostId); - EndPoint ep = endPointSelector.selectHypervisorHost(new ZoneScope(host.getDataCenterId())); - host = hostDao.findById(ep.getId()); hostDao.loadDetails(host); String hypervisorVersion = host.getHypervisorVersion(); String snapshotHotFixVersion = host.getDetail(XenserverConfigs.XS620HotFix); if (hypervisorVersion != null && !hypervisorVersion.equalsIgnoreCase("6.1.0")) { if (!(hypervisorVersion.equalsIgnoreCase("6.2.0") && !(snapshotHotFixVersion != null && snapshotHotFixVersion.equalsIgnoreCase(XenserverConfigs.XSHotFix62ESP1004)))) { - return new Pair(Boolean.TRUE, new Long(ep.getId())); + return new Pair(Boolean.TRUE, new Long(host.getId())); } } } diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java index 63c44853d1..4416c20dd6 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java @@ -113,16 +113,15 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L protected String _guestNic; protected boolean _setupMultipath; protected String _instance; - private String xs620snapshothotfix = "Xenserver-Vdi-Copy-HotFix"; @Inject protected AlertManager _alertMgr; @Inject protected AgentManager _agentMgr; @Inject - VMTemplateDao _tmpltDao; + private VMTemplateDao _tmpltDao; @Inject - HostPodDao _podDao; + private HostPodDao _podDao; protected XcpServerDiscoverer() { } @@ -542,6 +541,10 @@ private void createXsToolsISO() { } } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(com.cloud.host.Host agent, StartupCommand cmd, boolean forRebalance) throws ConnectionException { if (!(cmd instanceof StartupRoutingCommand)) { @@ -629,6 +632,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return false; diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index 7c8bca7f1b..026d0c18cd 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -37,6 +37,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Properties; import java.util.Queue; import java.util.Random; @@ -44,7 +45,6 @@ import java.util.UUID; import java.util.concurrent.TimeoutException; -import javax.ejb.Local; import javax.naming.ConfigurationException; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -164,11 +164,17 @@ * before you do any changes in this code here. * */ -@Local(value = ServerResource.class) public abstract class CitrixResourceBase implements ServerResource, HypervisorResource, VirtualRouterDeployer { - + /** + * used to describe what type of resource a storage device is of + */ public enum SRType { - EXT, FILE, ISCSI, ISO, LVM, LVMOHBA, LVMOISCSI, NFS; + EXT, FILE, ISCSI, ISO, LVM, LVMOHBA, LVMOISCSI, + /** + * used for resigning metadata (like SR UUID and VDI UUID when a + * particular storage manager is installed on a XenServer host (for back-end snapshots to work)) + */ + RELVMOISCSI, NFS; String _str; @@ -186,6 +192,8 @@ public String toString() { } } + private final static int BASE_TO_CONVERT_BYTES_INTO_KILOBYTES = 1024; + protected static final XenServerConnectionPool ConnPool = XenServerConnectionPool.getInstance(); // static min values for guests on xenserver private static final long mem_128m = 134217728L; @@ -1232,7 +1240,7 @@ public VIF createVif(final Connection conn, final String vmName, final VM vm, fi } public VM createVmFromTemplate(final Connection conn, final VirtualMachineTO vmSpec, final Host host) throws XenAPIException, XmlRpcException { - final String guestOsTypeName = getGuestOsType(vmSpec.getOs(), vmSpec.getPlatformEmulator(), vmSpec.getBootloader() == BootloaderType.CD); + final String guestOsTypeName = getGuestOsType(vmSpec.getPlatformEmulator()); final Set templates = VM.getByNameLabel(conn, guestOsTypeName); if (templates == null || templates.isEmpty()) { throw new CloudRuntimeException("Cannot find template " + guestOsTypeName + " on XenServer host"); @@ -1337,7 +1345,7 @@ public VM createVmFromTemplate(final Connection conn, final VirtualMachineTO vmS final TemplateObjectTO iso = (TemplateObjectTO) disk.getData(); final String osType = iso.getGuestOsType(); if (osType != null) { - final String isoGuestOsName = getGuestOsType(osType, vmSpec.getPlatformEmulator(), vmSpec.getBootloader() == BootloaderType.CD); + final String isoGuestOsName = getGuestOsType(vmSpec.getPlatformEmulator()); if (!isoGuestOsName.equals(guestOsTypeName)) { vmSpec.setBootloader(BootloaderType.PyGrub); } @@ -1794,10 +1802,26 @@ protected void fillHostInfo(final Connection conn, final StartupRoutingCommand c cmd.setPod(_pod); cmd.setVersion(CitrixResourceBase.class.getPackage().getImplementationVersion()); + try { + final String cmdLine = "xe sm-list | grep \"resigning of duplicates\""; + + final XenServerUtilitiesHelper xenServerUtilitiesHelper = getXenServerUtilitiesHelper(); + + Pair result = xenServerUtilitiesHelper.executeSshWrapper(_host.getIp(), 22, _username, null, getPwdFromQueue(), cmdLine); + + boolean supportsClonedVolumes = result != null && result.first() != null && result.first() && + result.second() != null && result.second().length() > 0; + + cmd.setSupportsClonedVolumes(supportsClonedVolumes); + } catch (NumberFormatException ex) { + s_logger.warn("Issue sending 'xe sm-list' via SSH to XenServer host: " + ex.getMessage()); + } } catch (final XmlRpcException e) { - throw new CloudRuntimeException("XML RPC Exception" + e.getMessage(), e); + throw new CloudRuntimeException("XML RPC Exception: " + e.getMessage(), e); } catch (final XenAPIException e) { - throw new CloudRuntimeException("XenAPIException" + e.toString(), e); + throw new CloudRuntimeException("XenAPIException: " + e.toString(), e); + } catch (final Exception e) { + throw new CloudRuntimeException("Exception: " + e.toString(), e); } } @@ -2019,8 +2043,8 @@ public HashMap> getGPUGroupDetails(final return null; } - protected String getGuestOsType(final String stdType, String platformEmulator, final boolean bootFromCD) { - if (platformEmulator == null) { + protected String getGuestOsType(String platformEmulator) { + if (org.apache.commons.lang.StringUtils.isBlank(platformEmulator)) { s_logger.debug("no guest OS type, start it as HVM guest"); platformEmulator = "Other install media"; } @@ -2264,6 +2288,11 @@ protected HashMap getHostVmStateReport(final Con public SR getIscsiSR(final Connection conn, final String srNameLabel, final String target, String path, final String chapInitiatorUsername, final String chapInitiatorPassword, final boolean ignoreIntroduceException) { + return getIscsiSR(conn, srNameLabel, target, path, chapInitiatorUsername, chapInitiatorPassword, false, ignoreIntroduceException); + } + + public SR getIscsiSR(final Connection conn, final String srNameLabel, final String target, String path, final String chapInitiatorUsername, + final String chapInitiatorPassword, final boolean resignature, final boolean ignoreIntroduceException) { synchronized (srNameLabel.intern()) { final Map deviceConfig = new HashMap(); try { @@ -2353,17 +2382,52 @@ public SR getIscsiSR(final Connection conn, final String srNameLabel, final Stri throw new CloudRuntimeException(msg, e); } } + deviceConfig.put("SCSIid", scsiid); - final String result = SR.probe(conn, host, deviceConfig, type, smConfig); + String result = SR.probe(conn, host, deviceConfig, type, smConfig); + String pooluuid = null; + if (result.indexOf("") != -1) { pooluuid = result.substring(result.indexOf("") + 6, result.indexOf("")).trim(); } if (pooluuid == null || pooluuid.length() != 36) { sr = SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, type, "user", true, smConfig); - } else { + } + else { + if (resignature) { + try { + SR.create(conn, host, deviceConfig, new Long(0), srNameLabel, srNameLabel, SRType.RELVMOISCSI.toString(), "user", true, smConfig); + + // The successful outcome of SR.create (right above) is to throw an exception of type XenAPIException (with expected + // toString() text) after resigning the metadata (we indicated to perform a resign by passing in SRType.RELVMOISCSI.toString()). + // That being the case, if this CloudRuntimeException statement is executed, there appears to have been some kind + // of failure in the execution of the above SR.create (resign) method. + throw new CloudRuntimeException("Problem resigning the metadata"); + } + catch (XenAPIException ex) { + String msg = ex.toString(); + + if (!msg.contains("successfully resigned")) { + throw ex; + } + + result = SR.probe(conn, host, deviceConfig, type, smConfig); + + pooluuid = null; + + if (result.indexOf("") != -1) { + pooluuid = result.substring(result.indexOf("") + 6, result.indexOf("")).trim(); + } + + if (pooluuid == null || pooluuid.length() != 36) { + throw new CloudRuntimeException("Non-existent or invalid SR UUID"); + } + } + } + try { sr = SR.introduce(conn, pooluuid, srNameLabel, srNameLabel, type, "user", true, smConfig); } catch (final XenAPIException ex) { @@ -2375,11 +2439,15 @@ public SR getIscsiSR(final Connection conn, final String srNameLabel, final Stri } final Set setHosts = Host.getAll(conn); + if (setHosts == null) { - final String msg = "Unable to create Iscsi SR " + deviceConfig + " due to hosts not available."; + final String msg = "Unable to create iSCSI SR " + deviceConfig + " due to hosts not available."; + s_logger.warn(msg); + throw new CloudRuntimeException(msg); } + for (final Host currentHost : setHosts) { final PBD.Record rec = new PBD.Record(); @@ -2392,7 +2460,9 @@ public SR getIscsiSR(final Connection conn, final String srNameLabel, final Stri pbd.plug(conn); } } + sr.scan(conn); + return sr; } catch (final XenAPIException e) { final String msg = "Unable to create Iscsi SR " + deviceConfig + " due to " + e.toString(); @@ -3278,7 +3348,7 @@ public HashMap getVmStats(final Connection conn, final Get final HashMap vmResponseMap = new HashMap(); for (final String vmUUID : vmUUIDs) { - vmResponseMap.put(vmUUID, new VmStatsEntry(0, 0, 0, 0, "vm")); + vmResponseMap.put(vmUUID, new VmStatsEntry(0,0,0,0, 0, 0, 0, "vm")); } final Object[] rrdData = getRRDData(conn, 2); // call rrddata with 2 for @@ -3325,14 +3395,21 @@ public HashMap getVmStats(final Connection conn, final Get vmStatsAnswer.setNumCPUs(vmStatsAnswer.getNumCPUs() + 1); vmStatsAnswer.setCPUUtilization(vmStatsAnswer.getCPUUtilization() + getDataAverage(dataNode, col, numRows)); } else if (param.matches("vif_\\d*_rx")) { - vmStatsAnswer.setNetworkReadKBs(vmStatsAnswer.getNetworkReadKBs() + getDataAverage(dataNode, col, numRows) / 1000); + vmStatsAnswer.setNetworkReadKBs(vmStatsAnswer.getNetworkReadKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); } else if (param.matches("vif_\\d*_tx")) { - vmStatsAnswer.setNetworkWriteKBs(vmStatsAnswer.getNetworkWriteKBs() + getDataAverage(dataNode, col, numRows) / 1000); + vmStatsAnswer.setNetworkWriteKBs(vmStatsAnswer.getNetworkWriteKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); } else if (param.matches("vbd_.*_read")) { - vmStatsAnswer.setDiskReadKBs(vmStatsAnswer.getDiskReadKBs() + getDataAverage(dataNode, col, numRows) / 1000); + vmStatsAnswer.setDiskReadKBs(vmStatsAnswer.getDiskReadKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); } else if (param.matches("vbd_.*_write")) { - vmStatsAnswer.setDiskWriteKBs(vmStatsAnswer.getDiskWriteKBs() + getDataAverage(dataNode, col, numRows) / 1000); + vmStatsAnswer.setDiskWriteKBs(vmStatsAnswer.getDiskWriteKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); + } else if (param.contains("memory_internal_free")) { + vmStatsAnswer.setIntFreeMemoryKBs(vmStatsAnswer.getIntFreeMemoryKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); + } else if (param.contains("memory_target")) { + vmStatsAnswer.setTargetMemoryKBs(vmStatsAnswer.getTargetMemoryKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); + } else if (param.contains("memory")) { + vmStatsAnswer.setMemoryKBs(vmStatsAnswer.getMemoryKBs() + getDataAverage(dataNode, col, numRows) / BASE_TO_CONVERT_BYTES_INTO_KILOBYTES); } + } } @@ -3348,6 +3425,7 @@ public HashMap getVmStats(final Connection conn, final Get s_logger.debug("Vm cpu utilization " + vmStatsAnswer.getCPUUtilization()); } } + return vmResponseMap; } @@ -3961,11 +4039,9 @@ public void prepareISO(final Connection conn, final String vmName, List details = disk.getDetails(); if (details == null) { @@ -3986,7 +4062,7 @@ public VDI prepareManagedDisk(final Connection conn, final DiskTO disk, final St return null; } - final String vdiNameLabel = vmName + "-DATA"; + final String vdiNameLabel = Volume.Type.ROOT.equals(disk.getType()) ? ("ROOT-" + vmId) : (vmName + "-DATA"); return prepareManagedStorage(conn, details, null, vdiNameLabel); } @@ -4016,19 +4092,25 @@ protected VDI prepareManagedStorage(final Connection conn, final Map vdisInSr = sr.getVDIs(conn); + + // If a VDI already exists in the SR (in case we cloned from a template cache), use that. + if (vdisInSr.size() == 1) { + vdi = vdisInSr.iterator().next(); + } + if (vdi == null) { vdi = createVdi(sr, vdiNameLabel, volumeSize); } else { - // if VDI is not null, it must have already been created, so check - // whether a resize of the volume was performed - // if true, resize the VDI to the volume size + // If vdi is not null, it must have already been created, so check whether a resize of the volume was performed. + // If true, resize the VDI to the volume size. - s_logger.info("checking for the resize of the datadisk"); + s_logger.info("Checking for the resize of the datadisk"); final long vdiVirtualSize = vdi.getVirtualSize(conn); if (vdiVirtualSize != volumeSize) { - s_logger.info("resizing the data disk (vdi) from vdiVirtualsize: " + vdiVirtualSize + " to volumeSize: " + volumeSize); + s_logger.info("Resizing the data disk (VDI) from vdiVirtualSize: " + vdiVirtualSize + " to volumeSize: " + volumeSize); try { vdi.resize(conn, volumeSize); @@ -4036,6 +4118,15 @@ protected VDI prepareManagedStorage(final Connection conn, final Map details = cmd.getDetails(); + + final String iScsiName = details.get(DiskTO.IQN); + final String storageHost = details.get(DiskTO.STORAGE_HOST); + final String chapInitiatorUsername = details.get(DiskTO.CHAP_INITIATOR_USERNAME); + final String chapInitiatorSecret = details.get(DiskTO.CHAP_INITIATOR_SECRET); + + newSr = hypervisorResource.getIscsiSR(conn, iScsiName, storageHost, iScsiName, chapInitiatorUsername, chapInitiatorSecret, true, false); + + Set vdis = newSr.getVDIs(conn); + + if (vdis.size() != 1) { + throw new RuntimeException("There were " + vdis.size() + " VDIs in the SR."); + } + + VDI vdi = vdis.iterator().next(); + + final ResignatureAnswer resignatureAnswer = new ResignatureAnswer(); + + resignatureAnswer.setSize(vdi.getVirtualSize(conn)); + resignatureAnswer.setPath(vdi.getUuid(conn)); + resignatureAnswer.setFormat(ImageFormat.VHD); + + return resignatureAnswer; + } + catch (final Exception ex) { + s_logger.warn("Failed to resignature: " + ex.toString(), ex); + + return new ResignatureAnswer(ex.getMessage()); + } + finally { + if (newSr != null) { + hypervisorResource.removeSR(conn, newSr); + } + } + } + @Override public AttachAnswer attachIso(final AttachCommand cmd) { final DiskTO disk = cmd.getDisk(); @@ -763,6 +809,9 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { final DataTO destDataTo = cmd.getDestTO(); final int wait = cmd.getWait(); final DataStoreTO srcDataStoreTo = srcDataTo.getDataStore(); + final Connection conn = hypervisorResource.getConnection(); + SR sr = null; + boolean removeSrAfterCopy = false; try { if (srcDataStoreTo instanceof NfsTO && srcDataTo.getObjectType() == DataObjectType.TEMPLATE) { @@ -796,14 +845,11 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { managedStoragePoolRootVolumeSize = details.get(PrimaryDataStoreTO.VOLUME_SIZE); chapInitiatorUsername = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_USERNAME); chapInitiatorSecret = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_SECRET); + removeSrAfterCopy = Boolean.parseBoolean(details.get(PrimaryDataStoreTO.REMOVE_AFTER_COPY)); } } } - final Connection conn = hypervisorResource.getConnection(); - - final SR sr; - if (managed) { final Map details = new HashMap(); @@ -861,9 +907,11 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { newVol.setUuid(uuidToReturn); newVol.setPath(uuidToReturn); + if (physicalSize != null) { newVol.setSize(physicalSize); } + newVol.setFormat(ImageFormat.VHD); return new CopyCmdAnswer(newVol); @@ -875,6 +923,11 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { return new CopyCmdAnswer(msg); } + finally { + if (removeSrAfterCopy && sr != null) { + hypervisorResource.removeSR(conn, sr); + } + } return new CopyCmdAnswer("not implemented yet"); } diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java index e58bade2c4..02c3197e51 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessor.java @@ -171,6 +171,8 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { final DataStoreTO srcStore = srcData.getDataStore(); final Connection conn = hypervisorResource.getConnection(); SR srcSr = null; + SR destSr = null; + boolean removeSrAfterCopy = false; Task task = null; try { @@ -198,7 +200,8 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { final Set setVdis = srcSr.getVDIs(conn); if (setVdis.size() != 1) { - return new CopyCmdAnswer("Expected 1 VDI template but found " + setVdis.size() + " VDI template(s) on: " + uri.getHost() + ":" + uri.getPath() + "/" + volumeDirectory); + return new CopyCmdAnswer("Expected 1 VDI template, but found " + setVdis.size() + " VDI templates on: " + + uri.getHost() + ":" + uri.getPath() + "/" + volumeDirectory); } final VDI srcVdi = setVdis.iterator().next(); @@ -225,11 +228,10 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { managedStoragePoolRootVolumeSize = details.get(PrimaryDataStoreTO.VOLUME_SIZE); chapInitiatorUsername = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_USERNAME); chapInitiatorSecret = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_SECRET); + removeSrAfterCopy = Boolean.parseBoolean(details.get(PrimaryDataStoreTO.REMOVE_AFTER_COPY)); } } - final SR destSr; - if (managed) { details = new HashMap(); @@ -291,9 +293,11 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { newVol.setUuid(uuidToReturn); newVol.setPath(uuidToReturn); + if (physicalSize != null) { newVol.setSize(physicalSize); } + newVol.setFormat(Storage.ImageFormat.VHD); return new CopyCmdAnswer(newVol); @@ -316,6 +320,10 @@ public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) { if (srcSr != null) { hypervisorResource.removeSR(conn, srcSr); } + + if (removeSrAfterCopy && destSr != null) { + hypervisorResource.removeSR(conn, destSr); + } } return new CopyCmdAnswer("not implemented yet"); diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixModifyStoragePoolCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixModifyStoragePoolCommandWrapper.java index 67d456ff3c..4c7136e28f 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixModifyStoragePoolCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixModifyStoragePoolCommandWrapper.java @@ -49,7 +49,8 @@ public Answer execute(final ModifyStoragePoolCommand command, final CitrixResour final boolean add = command.getAdd(); if (add) { try { - final SR sr = citrixResourceBase.getStorageRepository(conn, pool.getUuid()); + final String srName = command.getStoragePath() != null ? command.getStoragePath() : pool.getUuid(); + final SR sr = citrixResourceBase.getStorageRepository(conn, srName); citrixResourceBase.setupHeartbeatSr(conn, sr, false); final long capacity = sr.getPhysicalSize(conn); final long available = capacity - sr.getPhysicalUtilisation(conn); @@ -81,7 +82,7 @@ public Answer execute(final ModifyStoragePoolCommand command, final CitrixResour if (result == null || !result.split("#")[1].equals("0")) { throw new CloudRuntimeException("Unable to remove heartbeat file entry for SR " + srUuid + " due to " + result); } - return new Answer(command, true, "seccuss"); + return new Answer(command, true, "success"); } catch (final XenAPIException e) { final String msg = "ModifyStoragePoolCommand remove XenAPIException:" + e.toString() + " host:" + citrixResourceBase.getHost().getUuid() + " pool: " + pool.getHost() + pool.getPath(); diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRebootRouterCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRebootRouterCommandWrapper.java index 966df43ed9..236d8db385 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRebootRouterCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRebootRouterCommandWrapper.java @@ -36,7 +36,7 @@ public Answer execute(final RebootRouterCommand command, final CitrixResourceBas final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); - final RebootCommand rebootCommand = new RebootCommand(command.getVmName()); + final RebootCommand rebootCommand = new RebootCommand(command.getVmName(), true); final Answer answer = wrapper.execute(rebootCommand, citrixResourceBase); if (answer.getResult()) { diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixResizeVolumeCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixResizeVolumeCommandWrapper.java index 0206939725..b8e0f565df 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixResizeVolumeCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixResizeVolumeCommandWrapper.java @@ -27,28 +27,80 @@ import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase; import com.cloud.resource.CommandWrapper; import com.cloud.resource.ResourceWrapper; +import com.cloud.utils.exception.CloudRuntimeException; import com.xensource.xenapi.Connection; +import com.xensource.xenapi.PBD; +import com.xensource.xenapi.SR; import com.xensource.xenapi.VDI; +import java.util.HashSet; +import java.util.Set; + @ResourceWrapper(handles = ResizeVolumeCommand.class) public final class CitrixResizeVolumeCommandWrapper extends CommandWrapper { - private static final Logger s_logger = Logger.getLogger(CitrixResizeVolumeCommandWrapper.class); @Override public Answer execute(final ResizeVolumeCommand command, final CitrixResourceBase citrixResourceBase) { - final Connection conn = citrixResourceBase.getConnection(); - final String volid = command.getPath(); - final long newSize = command.getNewSize(); + Connection conn = citrixResourceBase.getConnection(); + + String volId = command.getPath(); + long newSize = command.getNewSize(); try { - final VDI vdi = citrixResourceBase.getVDIbyUuid(conn, volid); + if (command.isManaged()) { + resizeSr(conn, command); + } + + VDI vdi = citrixResourceBase.getVDIbyUuid(conn, volId); + vdi.resize(conn, newSize); + return new ResizeVolumeAnswer(command, true, "success", newSize); - } catch (final Exception e) { - s_logger.warn("Unable to resize volume", e); - final String error = "failed to resize volume:" + e; + } catch (Exception ex) { + s_logger.warn("Unable to resize volume", ex); + + String error = "Failed to resize volume: " + ex; + return new ResizeVolumeAnswer(command, false, error); } } -} \ No newline at end of file + + private void resizeSr(Connection conn, ResizeVolumeCommand command) { + // If this is managed storage, re-size the SR, too. + // The logical unit/volume has already been re-sized, so the SR needs to fill up the new space. + + String iScsiName = command.get_iScsiName(); + + try { + Set srs = SR.getByNameLabel(conn, iScsiName); + Set allPbds = new HashSet<>(); + + for (SR sr : srs) { + if (!CitrixResourceBase.SRType.LVMOISCSI.equals(sr.getType(conn))) { + continue; + } + + Set pbds = sr.getPBDs(conn); + + if (pbds.size() <= 0) { + s_logger.debug("No PBDs found for the following SR: " + sr.getNameLabel(conn)); + } + + allPbds.addAll(pbds); + } + + for (PBD pbd: allPbds) { + PBD.Record pbdr = pbd.getRecord(conn); + + if (pbdr.currentlyAttached) { + pbd.unplug(conn); + pbd.plug(conn); + } + } + } + catch (Throwable ex) { + throw new CloudRuntimeException("Unable to resize volume: " + ex.getMessage()); + } + } +} diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixSecurityGroupRulesCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixSecurityGroupRulesCommandWrapper.java index 0f8e6b5ba8..b189ba076f 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixSecurityGroupRulesCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixSecurityGroupRulesCommandWrapper.java @@ -56,7 +56,7 @@ public Answer execute(final SecurityGroupRulesCmd command, final CitrixResourceB return new SecurityGroupRuleAnswer(command, false, "programming network rules failed"); } else { s_logger.info("Programmed network rules for vm " + command.getVmName() + " guestIp=" + command.getGuestIp() + ", ingress numrules=" - + command.getIngressRuleSet().length + ", egress numrules=" + command.getEgressRuleSet().length); + + command.getIngressRuleSet().size() + ", egress numrules=" + command.getEgressRuleSet().size()); return new SecurityGroupRuleAnswer(command); } } diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java index 241110253c..073f00096b 100644 --- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java @@ -108,11 +108,13 @@ public Answer execute(final StartCommand command, final CitrixResourceBase citri } index++; } + for (DiskTO disk : disks) { - final VDI newVdi = citrixResourceBase.prepareManagedDisk(conn, disk, vmName); + final VDI newVdi = citrixResourceBase.prepareManagedDisk(conn, disk, vmSpec.getId(), vmSpec.getName()); if (newVdi != null) { final String path = newVdi.getUuid(conn); + iqnToPath.put(disk.getDetails().get(DiskTO.IQN), path); } diff --git a/plugins/hypervisors/xenserver/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java b/plugins/hypervisors/xenserver/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java index 36b8ad6ccf..7de96b0a9e 100644 --- a/plugins/hypervisors/xenserver/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java +++ b/plugins/hypervisors/xenserver/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java @@ -24,9 +24,6 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; @@ -37,6 +34,8 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.to.VolumeObjectTO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -92,21 +91,12 @@ public StrategyPriority canHandle(Map volumeMap, Host src } @Override - public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback callback) { throw new UnsupportedOperationException(); } @Override - public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback callback) { - CopyCommandResult result = new CopyCommandResult(null, null); - result.setResult("Unsupported operation requested for copying data."); - callback.complete(result); - - return null; - } - - @Override - public Void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { + public void copyAsync(Map volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback callback) { Answer answer = null; String errMsg = null; try { @@ -128,7 +118,6 @@ public Void copyAsync(Map volumeMap, VirtualMachineTO vmT CopyCommandResult result = new CopyCommandResult(null, answer); result.setResult(errMsg); callback.complete(result); - return null; } private Answer migrateVmWithVolumesAcrossCluster(VMInstanceVO vm, VirtualMachineTO to, Host srcHost, Host destHost, Map volumeToPool) diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java index 353b10683e..67fce92795 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java @@ -19,14 +19,22 @@ import java.util.List; import org.junit.Assert; +import org.junit.Test; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import com.cloud.utils.script.Script; -public abstract class CitrixResourceBaseTest { +public class CitrixResourceBaseTest { - public void testGetPathFilesExeption(CitrixResourceBase citrixResourceBase) { + protected CitrixResourceBase citrixResourceBase = new CitrixResourceBase() { + @Override + protected String getPatchFilePath() { + return null; + } + }; + + public void testGetPathFilesExeption() { String patch = citrixResourceBase.getPatchFilePath(); PowerMockito.mockStatic(Script.class); @@ -36,7 +44,7 @@ public void testGetPathFilesExeption(CitrixResourceBase citrixResourceBase) { } - public void testGetPathFilesListReturned(CitrixResourceBase citrixResourceBase) { + public void testGetPathFilesListReturned() { String patch = citrixResourceBase.getPatchFilePath(); PowerMockito.mockStatic(Script.class); @@ -49,4 +57,39 @@ public void testGetPathFilesListReturned(CitrixResourceBase citrixResourceBase) String receivedPath = files.get(0).getAbsolutePath(); Assert.assertEquals(receivedPath, pathExpected); } + + @Test + public void testGetGuestOsTypeNull() { + String platformEmulator = null; + + String expected = "Other install media"; + String guestOsType = citrixResourceBase.getGuestOsType(platformEmulator); + Assert.assertEquals(expected, guestOsType); + } + + @Test + public void testGetGuestOsTypeEmpty() { + String platformEmulator = ""; + + String expected = "Other install media"; + String guestOsType = citrixResourceBase.getGuestOsType(platformEmulator); + Assert.assertEquals(expected, guestOsType); + } + + @Test + public void testGetGuestOsTypeBlank() { + String platformEmulator = " "; + + String expected = "Other install media"; + String guestOsType = citrixResourceBase.getGuestOsType(platformEmulator); + Assert.assertEquals(expected, guestOsType); + } + + @Test + public void testGetGuestOsTypeOther() { + String platformEmulator = "My Own Linux Distribution Y.M (64-bit)"; + + String guestOsType = citrixResourceBase.getGuestOsType(platformEmulator); + Assert.assertEquals(platformEmulator, guestOsType); + } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java index b0c900c7f6..9266bf915f 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -26,11 +27,14 @@ @RunWith(PowerMockRunner.class) public class XcpOssResourceTest extends CitrixResourceBaseTest{ - private XcpOssResource xcpOssResource = new XcpOssResource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XcpOssResource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xcpOssResource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xcposs/patch"; Assert.assertEquals(patch, patchFilePath); @@ -39,12 +43,12 @@ public void testPatchFilePath() { @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xcpOssResource); + testGetPathFilesExeption(); } @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xcpOssResource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java index ba3d91de2a..5b80a1dc08 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -27,11 +28,14 @@ @RunWith(PowerMockRunner.class) public class XcpServerResourceTest extends CitrixResourceBaseTest{ - private XcpServerResource xcpServerResource = new XcpServerResource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XcpServerResource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xcpServerResource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xcpserver/patch"; Assert.assertEquals(patch, patchFilePath); @@ -40,12 +44,12 @@ public void testPatchFilePath() { @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFilesExeption(){ - testGetPathFilesExeption(xcpServerResource); + testGetPathFilesExeption(); } @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xcpServerResource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java index def51cf0d5..d2edbd4db9 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -23,26 +24,32 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; + @RunWith(PowerMockRunner.class) public class XenServer56FP1ResourceTest extends CitrixResourceBaseTest{ - private XenServer56FP1Resource xenServer56FP1Resource = new XenServer56FP1Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XenServer56FP1Resource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xenServer56FP1Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver56fp1/patch"; Assert.assertEquals(patch, patchFilePath); } + @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xenServer56FP1Resource); + testGetPathFilesExeption(); } + @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer56FP1Resource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java index 960dd7f049..dccdb28175 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -26,11 +27,14 @@ @RunWith(PowerMockRunner.class) public class XenServer56ResourceTest extends CitrixResourceBaseTest { - private XenServer56Resource xenServer56Resource = new XenServer56Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XenServer56Resource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xenServer56Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver56/patch"; Assert.assertEquals(patch, patchFilePath); @@ -39,11 +43,12 @@ public void testPatchFilePath() { @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xenServer56Resource); + testGetPathFilesExeption(); } + @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer56Resource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java index 300f95d6dd..4cc9470538 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -26,23 +27,28 @@ @RunWith(PowerMockRunner.class) public class XenServer56SP2ResourceTest extends CitrixResourceBaseTest{ - private XenServer56SP2Resource xenServer56SP2Resource = new XenServer56SP2Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XenServer56SP2Resource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xenServer56SP2Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver56fp1/patch"; Assert.assertEquals(patch, patchFilePath); } + @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xenServer56SP2Resource); + testGetPathFilesExeption(); } + @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer56SP2Resource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java index 34deeb81f8..d5eba2af38 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -26,23 +27,29 @@ @RunWith(PowerMockRunner.class) public class XenServer600ResourceTest extends CitrixResourceBaseTest{ - private XenServer600Resource xenServer600Resource = new XenServer600Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XenServer600Resource(); + } + @Test public void testPatchFilePath() { - String patchFilePath = xenServer600Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver60/patch"; Assert.assertEquals(patch, patchFilePath); } + @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xenServer600Resource); + testGetPathFilesExeption(); } + @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer600Resource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java index 640ca060a8..9998c2f02b 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -23,26 +24,32 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; + @RunWith(PowerMockRunner.class) -public class XenServer625ResourceTest extends CitrixResourceBaseTest{ +public class XenServer625ResourceTest extends CitrixResourceBaseTest { - private Xenserver625Resource xenServer625Resource = new Xenserver625Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new Xenserver625Resource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xenServer625Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver62/patch"; Assert.assertEquals(patch, patchFilePath); } + @Test(expected = CloudRuntimeException.class) - @PrepareForTest(Script.class ) - public void testGetFiles(){ - testGetPathFilesExeption(xenServer625Resource); + @PrepareForTest(Script.class) + public void testGetFiles() { + testGetPathFilesExeption(); } + @Test - @PrepareForTest(Script.class ) - public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer625Resource); + @PrepareForTest(Script.class) + public void testGetFilesListReturned() { + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java index 148b22def3..5195025de3 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java @@ -16,6 +16,7 @@ package com.cloud.hypervisor.xenserver.resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; @@ -26,11 +27,14 @@ @RunWith(PowerMockRunner.class) public class XenServer650ResourceTest extends CitrixResourceBaseTest{ - private XenServer650Resource xenServer650Resource = new XenServer650Resource(); + @Before + public void beforeTest() { + super.citrixResourceBase = new XenServer650Resource(); + } @Test public void testPatchFilePath() { - String patchFilePath = xenServer650Resource.getPatchFilePath(); + String patchFilePath = citrixResourceBase.getPatchFilePath(); String patch = "scripts/vm/hypervisor/xenserver/xenserver65/patch"; Assert.assertEquals(patch, patchFilePath); @@ -39,11 +43,12 @@ public void testPatchFilePath() { @Test(expected = CloudRuntimeException.class) @PrepareForTest(Script.class ) public void testGetFiles(){ - testGetPathFilesExeption(xenServer650Resource); + testGetPathFilesExeption(); } + @Test @PrepareForTest(Script.class ) public void testGetFilesListReturned(){ - testGetPathFilesListReturned(xenServer650Resource); + testGetPathFilesListReturned(); } } diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java index ca58f35533..66ae2ecd21 100644 --- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java +++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java @@ -33,6 +33,7 @@ import java.util.Hashtable; import java.util.List; import java.util.Map; +import java.util.Vector; import org.apache.cloudstack.storage.command.AttachAnswer; import org.apache.cloudstack.storage.command.AttachCommand; @@ -101,6 +102,7 @@ import com.cloud.agent.api.UpdateHostPasswordCommand; import com.cloud.agent.api.UpgradeSnapshotCommand; import com.cloud.agent.api.VMSnapshotTO; +import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto; import com.cloud.agent.api.check.CheckSshCommand; import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand; import com.cloud.agent.api.proxy.WatchConsoleProxyLoadCommand; @@ -298,7 +300,7 @@ public void testStopCommand() { @Test public void testRebootCommand() { - final RebootCommand rebootCommand = new RebootCommand("Test"); + final RebootCommand rebootCommand = new RebootCommand("Test", true); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); @@ -740,7 +742,17 @@ public void testSecurityGroupRulesCommand() { final Connection conn = Mockito.mock(Connection.class); final XsHost xsHost = Mockito.mock(XsHost.class); - final SecurityGroupRulesCmd sshCommand = new SecurityGroupRulesCmd(); + final String guestIp = "127.0.0.1"; + final String guestMac = "00:00:00:00"; + final String vmName = "Test"; + final Long vmId = 1l; + final String signature = "signature"; + final Long seqNum = 1l; + final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; + final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)}; + final List secIps = new Vector(); + + final SecurityGroupRulesCmd sshCommand = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); diff --git a/plugins/network-elements/bigswitch/pom.xml b/plugins/network-elements/bigswitch/pom.xml index 699c85f4db..05603a61fd 100644 --- a/plugins/network-elements/bigswitch/pom.xml +++ b/plugins/network-elements/bigswitch/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/brocade-vcs/pom.xml b/plugins/network-elements/brocade-vcs/pom.xml index c4d28d8394..c0ed17c144 100644 --- a/plugins/network-elements/brocade-vcs/pom.xml +++ b/plugins/network-elements/brocade-vcs/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/brocade-vcs/src/com/cloud/network/brocade/BrocadeVcsApi.java b/plugins/network-elements/brocade-vcs/src/com/cloud/network/brocade/BrocadeVcsApi.java index dc111fd898..eb03515b5d 100644 --- a/plugins/network-elements/brocade-vcs/src/com/cloud/network/brocade/BrocadeVcsApi.java +++ b/plugins/network-elements/brocade-vcs/src/com/cloud/network/brocade/BrocadeVcsApi.java @@ -30,9 +30,8 @@ import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.HttpStatus; import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.methods.HttpDelete; @@ -64,9 +63,9 @@ public class BrocadeVcsApi { private static final Logger s_logger = Logger.getLogger(BrocadeVcsApi.class); - private String _host; - private String _adminuser; - private String _adminpass; + private final String _host; + private final String _adminuser; + private final String _adminpass; protected DefaultHttpClient _client; @@ -74,7 +73,7 @@ protected HttpRequestBase createMethod(String type, String uri) throws BrocadeVc String url; try { url = new URL(Constants.PROTOCOL, _host, Constants.PORT, uri).toString(); - } catch (MalformedURLException e) { + } catch (final MalformedURLException e) { s_logger.error("Unable to build Brocade Switch API URL", e); throw new BrocadeVcsApiException("Unable to build Brocade Switch API URL", e); } @@ -116,7 +115,7 @@ public boolean createNetwork(int vlanId, long networkId) throws BrocadeVcsApiExc if (createInterfaceVlan(vlanId)) { - PortProfile portProfile = createPortProfile(vlanId, networkId); + final PortProfile portProfile = createPortProfile(vlanId, networkId); if (portProfile != null) { return activatePortProfile(portProfile); @@ -129,9 +128,9 @@ public boolean createNetwork(int vlanId, long networkId) throws BrocadeVcsApiExc * Activates a port-profile. */ private boolean activatePortProfile(PortProfile portProfile) throws BrocadeVcsApiException { - PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); + final PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); portProfile.setVlanProfile(null); - Activate activate = new Activate(); + final Activate activate = new Activate(); portProfile.setActivate(activate); portProfileGlobal.setPortProfile(portProfile); @@ -144,7 +143,7 @@ private boolean activatePortProfile(PortProfile portProfile) throws BrocadeVcsAp */ private PortProfile createPortProfile(int vlanId, long networkId) throws BrocadeVcsApiException { - PortProfile portProfile = new PortProfile(); + final PortProfile portProfile = new PortProfile(); portProfile.setName(Constants.PORT_PROFILE_NAME_PREFIX + networkId); if (executeCreateObject(portProfile, Constants.URI)) { if (createVlanSubProfile(vlanId, portProfile)) { @@ -158,7 +157,7 @@ private PortProfile createPortProfile(int vlanId, long networkId) throws Brocade * Create vlan sub-profile for port-profile */ private boolean createVlanSubProfile(int vlanId, PortProfile portProfile) throws BrocadeVcsApiException { - VlanProfile vlanProfile = new VlanProfile(); + final VlanProfile vlanProfile = new VlanProfile(); portProfile.setVlanProfile(vlanProfile); if (executeUpdateObject(portProfile, Constants.URI)) { return configureVlanSubProfile(vlanId, portProfile); @@ -173,15 +172,15 @@ private boolean createVlanSubProfile(int vlanId, PortProfile portProfile) throws * - configure allowed VLANs for vlan sub-profile */ private boolean configureVlanSubProfile(int vlanId, PortProfile portProfile) throws BrocadeVcsApiException { - SwitchportBasic switchPortBasic = new SwitchportBasic(); - Basic basic = new Basic(); + final SwitchportBasic switchPortBasic = new SwitchportBasic(); + final Basic basic = new Basic(); switchPortBasic.setBasic(basic); portProfile.getVlanProfile().setSwitchportBasic(switchPortBasic); // configure L2 mode for vlan sub-profile if (executeUpdateObject(portProfile, Constants.URI)) { VlanProfile vlanProfile = new VlanProfile(); Switchport switchPort = new Switchport(); - Mode mode = new Mode(); + final Mode mode = new Mode(); mode.setVlanMode("trunk"); switchPort.setMode(mode); vlanProfile.setSwitchport(switchPort); @@ -191,9 +190,9 @@ private boolean configureVlanSubProfile(int vlanId, PortProfile portProfile) thr if (executeUpdateObject(portProfile, Constants.URI)) { vlanProfile = new VlanProfile(); switchPort = new Switchport(); - Trunk trunk = new Trunk(); - Allowed allowed = new Allowed(); - Allowed.Vlan allowedVlan = new Allowed.Vlan(); + final Trunk trunk = new Trunk(); + final Allowed allowed = new Allowed(); + final Allowed.Vlan allowedVlan = new Allowed.Vlan(); allowedVlan.setAdd(vlanId); allowed.setVlan(allowedVlan); trunk.setAllowed(allowed); @@ -214,9 +213,9 @@ private boolean configureVlanSubProfile(int vlanId, PortProfile portProfile) thr * Creates a vlan interface. */ private boolean createInterfaceVlan(int vlanId) throws BrocadeVcsApiException { - InterfaceVlan interfaceVlan = new InterfaceVlan(); - Interface interfaceObj = new Interface(); - Vlan vlan = new Vlan(); + final InterfaceVlan interfaceVlan = new InterfaceVlan(); + final Interface interfaceObj = new Interface(); + final Vlan vlan = new Vlan(); vlan.setName(vlanId); interfaceObj.setVlan(vlan); interfaceVlan.setInterface(interfaceObj); @@ -230,10 +229,10 @@ private boolean createInterfaceVlan(int vlanId) throws BrocadeVcsApiException { */ public boolean associateMacToNetwork(long networkId, String macAddress) throws BrocadeVcsApiException { - PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); - PortProfile portProfile = new PortProfile(); + final PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); + final PortProfile portProfile = new PortProfile(); portProfile.setName(Constants.PORT_PROFILE_NAME_PREFIX + networkId); - Static staticObj = new Static(); + final Static staticObj = new Static(); staticObj.setMacAddress(macAddress); portProfile.setStatic(staticObj); portProfileGlobal.setPortProfile(portProfile); @@ -247,10 +246,10 @@ public boolean associateMacToNetwork(long networkId, String macAddress) throws B */ public boolean disassociateMacFromNetwork(long networkId, String macAddress) throws BrocadeVcsApiException { - PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); - PortProfile portProfile = new PortProfile(); + final PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); + final PortProfile portProfile = new PortProfile(); portProfile.setName(Constants.PORT_PROFILE_NAME_PREFIX + networkId); - Static staticObj = new Static(); + final Static staticObj = new Static(); staticObj.setOperation("delete"); staticObj.setMacAddress(macAddress); portProfile.setStatic(staticObj); @@ -278,9 +277,9 @@ public boolean deleteNetwork(int vlanId, long networkId) throws BrocadeVcsApiExc * Deletes a vlan interface. */ private boolean deleteInterfaceVlan(int vlanId) throws BrocadeVcsApiException { - InterfaceVlan interfaceVlan = new InterfaceVlan(); - Interface interfaceObj = new Interface(); - Vlan vlan = new Vlan(); + final InterfaceVlan interfaceVlan = new InterfaceVlan(); + final Interface interfaceObj = new Interface(); + final Vlan vlan = new Vlan(); vlan.setOperation("delete"); vlan.setName(vlanId); interfaceObj.setVlan(vlan); @@ -294,10 +293,10 @@ private boolean deleteInterfaceVlan(int vlanId) throws BrocadeVcsApiException { * Deactivates a port-profile. */ private boolean deactivatePortProfile(long networkId) throws BrocadeVcsApiException { - PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); - PortProfile portProfile = new PortProfile(); + final PortProfileGlobal portProfileGlobal = new PortProfileGlobal(); + final PortProfile portProfile = new PortProfile(); portProfile.setName(Constants.PORT_PROFILE_NAME_PREFIX + networkId); - Activate activate = new Activate(); + final Activate activate = new Activate(); activate.setOperation("delete"); portProfile.setActivate(activate); portProfileGlobal.setPortProfile(portProfile); @@ -311,7 +310,7 @@ private boolean deactivatePortProfile(long networkId) throws BrocadeVcsApiExcept */ private boolean deletePortProfile(long networkId) throws BrocadeVcsApiException { - PortProfile portProfile = new PortProfile(); + final PortProfile portProfile = new PortProfile(); portProfile.setName(Constants.PORT_PROFILE_NAME_PREFIX + networkId); portProfile.setOperation("delete"); //deletes port-profile @@ -320,25 +319,25 @@ private boolean deletePortProfile(long networkId) throws BrocadeVcsApiException protected boolean executeUpdateObject(T newObject, String uri) throws BrocadeVcsApiException { - boolean result = true; + final boolean result = true; if (_host == null || _host.isEmpty() || _adminuser == null || _adminuser.isEmpty() || _adminpass == null || _adminpass.isEmpty()) { throw new BrocadeVcsApiException("Hostname/credentials are null or empty"); } - HttpPatch pm = (HttpPatch)createMethod("patch", uri); + final HttpPatch pm = (HttpPatch)createMethod("patch", uri); pm.setHeader("Accept", "application/vnd.configuration.resource+xml"); pm.setEntity(new StringEntity(convertToString(newObject), ContentType.APPLICATION_XML)); - HttpResponse response = executeMethod(pm); + final HttpResponse response = executeMethod(pm); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_NO_CONTENT) { String errorMessage; try { errorMessage = responseToErrorMessage(response); - } catch (IOException e) { + } catch (final IOException e) { s_logger.error("Failed to update object : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to update object : " + e.getMessage()); } @@ -363,12 +362,12 @@ protected String convertToString(T object) throws BrocadeVcsApiException { marshaller.marshal(object, stringWriter); - } catch (JAXBException e) { + } catch (final JAXBException e) { s_logger.error("Failed to convert object to string : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to convert object to string : " + e.getMessage()); } - String str = stringWriter.toString(); + final String str = stringWriter.toString(); s_logger.info(str); return str; @@ -379,19 +378,19 @@ protected Output convertToXML(String object) throws BrocadeVcsApiException { Output output = null; try { - JAXBContext context = JAXBContext.newInstance(Output.class); + final JAXBContext context = JAXBContext.newInstance(Output.class); - StringReader reader = new StringReader(object); + final StringReader reader = new StringReader(object); final Unmarshaller unmarshaller = context.createUnmarshaller(); - Object result = unmarshaller.unmarshal(reader); + final Object result = unmarshaller.unmarshal(reader); if (result instanceof Output) { output = (Output)result; s_logger.info(output); } - } catch (JAXBException e) { + } catch (final JAXBException e) { s_logger.error("Failed to convert string to object : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to convert string to object : " + e.getMessage()); } @@ -405,19 +404,19 @@ protected boolean executeCreateObject(T newObject, String uri) throws Brocad throw new BrocadeVcsApiException("Hostname/credentials are null or empty"); } - boolean result = true; - HttpPost pm = (HttpPost)createMethod("post", uri); + final boolean result = true; + final HttpPost pm = (HttpPost)createMethod("post", uri); pm.setHeader("Accept", "application/vnd.configuration.resource+xml"); pm.setEntity(new StringEntity(convertToString(newObject), ContentType.APPLICATION_XML)); - HttpResponse response = executeMethod(pm); + final HttpResponse response = executeMethod(pm); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) { String errorMessage; try { errorMessage = responseToErrorMessage(response); - } catch (IOException e) { + } catch (final IOException e) { s_logger.error("Failed to create object : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to create object : " + e.getMessage()); } @@ -440,18 +439,18 @@ protected Output executeRetreiveStatus(String uri) throws BrocadeVcsApiException String readLine = null; StringBuffer sb = null; - HttpPost pm = (HttpPost)createMethod("post", uri); + final HttpPost pm = (HttpPost)createMethod("post", uri); pm.setHeader("Accept", "application/vnd.operational-state.resource+xml"); pm.setEntity(new StringEntity("", ContentType.APPLICATION_XML)); - HttpResponse response = executeMethod(pm); + final HttpResponse response = executeMethod(pm); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { String errorMessage; try { errorMessage = responseToErrorMessage(response); - } catch (IOException e) { + } catch (final IOException e) { s_logger.error("Failed to retreive status : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to retreive status : " + e.getMessage()); } @@ -464,12 +463,12 @@ protected Output executeRetreiveStatus(String uri) throws BrocadeVcsApiException try (BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), Charset.forName("UTF-8")))) { sb = new StringBuffer(); - while (((readLine = br.readLine()) != null)) { + while ((readLine = br.readLine()) != null) { s_logger.debug(readLine); sb.append(readLine); } - } catch (Exception e) { + } catch (final Exception e) { s_logger.error("Failed to retreive status : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to retreive status : " + e.getMessage()); } @@ -484,17 +483,17 @@ protected void executeDeleteObject(String uri) throws BrocadeVcsApiException { throw new BrocadeVcsApiException("Hostname/credentials are null or empty"); } - HttpDelete dm = (HttpDelete)createMethod("delete", uri); + final HttpDelete dm = (HttpDelete)createMethod("delete", uri); dm.setHeader("Accept", "application/vnd.configuration.resource+xml"); - HttpResponse response = executeMethod(dm); + final HttpResponse response = executeMethod(dm); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_NO_CONTENT) { String errorMessage; try { errorMessage = responseToErrorMessage(response); - } catch (IOException e) { + } catch (final IOException e) { s_logger.error("Failed to delete object : " + e.getMessage()); throw new BrocadeVcsApiException("Failed to delete object : " + e.getMessage()); } @@ -514,11 +513,7 @@ protected HttpResponse executeMethod(HttpRequestBase method) throws BrocadeVcsAp method.releaseConnection(); response = _client.execute(method); } - } catch (HttpException e) { - s_logger.error("HttpException caught while trying to connect to the Brocade Switch", e); - method.releaseConnection(); - throw new BrocadeVcsApiException("API call to Brocade Switch Failed", e); - } catch (IOException e) { + } catch (final IOException e) { s_logger.error("IOException caught while trying to connect to the Brocade Switch", e); method.releaseConnection(); throw new BrocadeVcsApiException("API call to Brocade Switch Failed", e); @@ -533,7 +528,7 @@ private String responseToErrorMessage(HttpResponse response) throws IOException try (BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), Charset.forName("UTF-8")))) { - StringBuffer result = new StringBuffer(); + final StringBuffer result = new StringBuffer(); String line = ""; while ((line = rd.readLine()) != null) { result.append(line); diff --git a/plugins/network-elements/brocade-vcs/test/com/cloud/network/brocade/BrocadeVcsApiTest.java b/plugins/network-elements/brocade-vcs/test/com/cloud/network/brocade/BrocadeVcsApiTest.java index 4223d4cc7b..e84b7caf26 100644 --- a/plugins/network-elements/brocade-vcs/test/com/cloud/network/brocade/BrocadeVcsApiTest.java +++ b/plugins/network-elements/brocade-vcs/test/com/cloud/network/brocade/BrocadeVcsApiTest.java @@ -26,9 +26,9 @@ import static org.mockito.Mockito.when; import java.io.IOException; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.http.StatusLine; import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.StatusLine; import org.apache.http.client.methods.HttpPatch; import org.apache.http.client.methods.HttpPost; @@ -93,7 +93,7 @@ public void testGetSwitchStatus() throws BrocadeVcsApiException, IOException { when(response.getEntity()).thenReturn(new StringEntity(OUTPUT_XML_RESPONSE)); // Execute - Output result = api.getSwitchStatus(); + final Output result = api.getSwitchStatus(); // Assert verify(method, times(1)).releaseConnection(); diff --git a/plugins/network-elements/cisco-vnmc/pom.xml b/plugins/network-elements/cisco-vnmc/pom.xml index 12a994e8ac..2c8bb7f719 100644 --- a/plugins/network-elements/cisco-vnmc/pom.xml +++ b/plugins/network-elements/cisco-vnmc/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/dns-notifier/pom.xml b/plugins/network-elements/dns-notifier/pom.xml index 0f58b883ed..7db075f0aa 100644 --- a/plugins/network-elements/dns-notifier/pom.xml +++ b/plugins/network-elements/dns-notifier/pom.xml @@ -22,7 +22,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml cloud-plugin-example-dns-notifier diff --git a/plugins/network-elements/elastic-loadbalancer/pom.xml b/plugins/network-elements/elastic-loadbalancer/pom.xml index ddb00d31ac..c52cc042de 100644 --- a/plugins/network-elements/elastic-loadbalancer/pom.xml +++ b/plugins/network-elements/elastic-loadbalancer/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/f5/pom.xml b/plugins/network-elements/f5/pom.xml index 571f529685..54533e7aa7 100644 --- a/plugins/network-elements/f5/pom.xml +++ b/plugins/network-elements/f5/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/globodns/pom.xml b/plugins/network-elements/globodns/pom.xml index 73d40d1ac3..9d2c354719 100644 --- a/plugins/network-elements/globodns/pom.xml +++ b/plugins/network-elements/globodns/pom.xml @@ -24,14 +24,14 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml com.globo.globodns globodns-client - 0.0.15 + 0.0.20 diff --git a/plugins/network-elements/globodns/test/resources/db.properties b/plugins/network-elements/globodns/test/resources/db.properties index 6ebe10af5f..6e38a4a6f3 100644 --- a/plugins/network-elements/globodns/test/resources/db.properties +++ b/plugins/network-elements/globodns/test/resources/db.properties @@ -27,6 +27,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -47,6 +48,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -60,6 +63,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/plugins/network-elements/internal-loadbalancer/pom.xml b/plugins/network-elements/internal-loadbalancer/pom.xml index c9d7e7e06a..0eb1523254 100644 --- a/plugins/network-elements/internal-loadbalancer/pom.xml +++ b/plugins/network-elements/internal-loadbalancer/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java index 1e0b2945f1..f3ebeb0bae 100644 --- a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java +++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java @@ -302,50 +302,54 @@ public IpDeployer getIpDeployer(Network network) { @Override public boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException { //1) Get Internal LB VMs to destroy - Set vmsToDestroy = getVmsToDestroy(rules); + Set vmsToDestroy = getVmsToDestroy(network, rules); //2) Get rules to apply Map> rulesToApply = getLbRulesToApply(rules); s_logger.debug("Applying " + rulesToApply.size() + " on element " + getName()); - for (Ip sourceIp : rulesToApply.keySet()) { - if (vmsToDestroy.contains(sourceIp)) { - //2.1 Destroy internal lb vm - List vms = _internalLbMgr.findInternalLbVms(network.getId(), sourceIp); - if (vms.size() > 0) { - //only one internal lb per IP exists - try { - s_logger.debug("Destroying internal lb vm for ip " + sourceIp.addr() + " as all the rules for this vm are in Revoke state"); - return _internalLbMgr.destroyInternalLbVm(vms.get(0).getId(), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM), - _accountMgr.getUserIncludingRemoved(User.UID_SYSTEM).getId()); - } catch (ConcurrentOperationException e) { - s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + " on the element " + getName() + " due to:", e); - return false; - } - } - } else { - //2.2 Start Internal LB vm per IP address - List internalLbVms; + for (Ip sourceIp : vmsToDestroy) { + //2.1 Destroy internal lb vm + List vms = _internalLbMgr.findInternalLbVms(network.getId(), sourceIp); + if (vms.size() > 0) { + //only one internal lb per IP exists try { - DeployDestination dest = new DeployDestination(_entityMgr.findById(DataCenter.class, network.getDataCenterId()), null, null, null); - internalLbVms = _internalLbMgr.deployInternalLbVm(network, sourceIp, dest, _accountMgr.getAccount(network.getAccountId()), null); - } catch (InsufficientCapacityException e) { - s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + "on the element " + getName() + " due to:", e); - return false; + s_logger.debug(String.format("Destroying internal lb vm for ip %s as all the rules for this vm are in Revoke state", sourceIp.addr())); + return _internalLbMgr.destroyInternalLbVm(vms.get(0).getId(), _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM), + _accountMgr.getUserIncludingRemoved(User.UID_SYSTEM).getId()); } catch (ConcurrentOperationException e) { - s_logger.warn("Failed to apply lb rule(s) for ip " + sourceIp.addr() + "on the element " + getName() + " due to:", e); + s_logger.warn(String.format("Failed to apply lb rule(s) for ip %s on the element %s due to: ", sourceIp.addr(), getName()), e); return false; } + } - if (internalLbVms == null || internalLbVms.isEmpty()) { - throw new ResourceUnavailableException("Can't find/deploy internal lb vm to handle LB rules", DataCenter.class, network.getDataCenterId()); - } + rulesToApply.remove(sourceIp); + } - //2.3 Apply Internal LB rules on the VM - if (!_internalLbMgr.applyLoadBalancingRules(network, rulesToApply.get(sourceIp), internalLbVms)) { - throw new CloudRuntimeException("Failed to apply load balancing rules for ip " + sourceIp.addr() + " in network " + network.getId() + " on element " + - getName()); - } + for (Map.Entry> entry : rulesToApply.entrySet()) { + Ip sourceIp = entry.getKey(); + //2.2 Start Internal LB vm per IP address + List internalLbVms; + try { + DeployDestination dest = new DeployDestination(_entityMgr.findById(DataCenter.class, network.getDataCenterId()), null, null, null); + internalLbVms = _internalLbMgr.deployInternalLbVm(network, sourceIp, dest, _accountMgr.getAccount(network.getAccountId()), null); + } catch (InsufficientCapacityException e) { + s_logger.warn(String.format("Failed to apply lb rule(s) for ip %s on the element %s due to: ", sourceIp.addr(), getName()), e); + return false; + } catch (ConcurrentOperationException e) { + s_logger.warn(String.format("Failed to apply lb rule(s) for ip %s on the element %s due to: ", sourceIp.addr(), getName()), e); + return false; + } + + if (internalLbVms == null || internalLbVms.isEmpty()) { + throw new ResourceUnavailableException("Can't find/deploy internal lb vm to handle LB rules", + DataCenter.class, network.getDataCenterId()); + } + + //2.3 Apply Internal LB rules on the VM + if (!_internalLbMgr.applyLoadBalancingRules(network, entry.getValue(), internalLbVms)) { + throw new CloudRuntimeException("Failed to apply load balancing rules for ip " + sourceIp.addr() + + " in network " + network.getId() + " on element " + getName()); } } @@ -359,16 +363,18 @@ protected Map> getLbRulesToApply(List getVmsToDestroy(List rules) { + protected Set getVmsToDestroy(Network network, List rules) { //1) Group rules by the source ip address as NetworkManager always passes the entire network lb config to the element - Map> groupedRules = groupBySourceIp(rules); - + Set lbPublicIps = new HashSet(); Set vmsToDestroy = new HashSet(); - for (Ip sourceIp : groupedRules.keySet()) { + for (LoadBalancingRule rule : rules) { + lbPublicIps.add(rule.getSourceIp()); + } + + for (Ip sourceIp : lbPublicIps) { //2) Check if there are non revoked rules for the source ip address - List rulesToCheck = groupedRules.get(sourceIp); - if (_appLbDao.countBySourceIpAndNotRevoked(sourceIp, rulesToCheck.get(0).getNetworkId()) == 0) { + if (_appLbDao.countBySourceIpAndNotRevoked(sourceIp, network.getId()) == 0) { s_logger.debug("Have to destroy internal lb vm for source ip " + sourceIp + " as it has 0 rules in non-Revoke state"); vmsToDestroy.add(sourceIp); } diff --git a/plugins/network-elements/juniper-contrail/pom.xml b/plugins/network-elements/juniper-contrail/pom.xml index f493b423b8..13a3c5b6e8 100644 --- a/plugins/network-elements/juniper-contrail/pom.xml +++ b/plugins/network-elements/juniper-contrail/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml @@ -109,7 +109,7 @@ org.mockito mockito-all - 1.9.5 + 1.10.19 diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java index b5da604335..e56766aaf4 100644 --- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java +++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java @@ -134,14 +134,14 @@ public User createUser(String arg0, String arg1, String arg2, String arg3, Strin } @Override - public UserAccount createUserAccount(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5, String arg6, short arg7, Long arg8, String arg9, + public UserAccount createUserAccount(String arg0, String arg1, String arg2, String arg3, String arg4, String arg5, String arg6, short arg7, Long roleId, Long arg8, String arg9, Map arg10, String arg11, String arg12) { // TODO Auto-generated method stub return null; } @Override - public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, + public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID, User.Source source) { // TODO Auto-generated method stub return null; @@ -392,8 +392,8 @@ public Account getAccount(long accountId) { } @Override - public Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details, String uuid) { - final AccountVO account = new AccountVO(accountName, domainId, networkDomain, accountType, uuid); + public Account createAccount(String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String uuid) { + final AccountVO account = new AccountVO(accountName, domainId, networkDomain, accountType, roleId, uuid); Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { diff --git a/plugins/network-elements/juniper-contrail/test/resources/db.properties b/plugins/network-elements/juniper-contrail/test/resources/db.properties index 9d250ba8b0..235de85869 100644 --- a/plugins/network-elements/juniper-contrail/test/resources/db.properties +++ b/plugins/network-elements/juniper-contrail/test/resources/db.properties @@ -22,6 +22,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -42,6 +43,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -55,6 +58,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/plugins/network-elements/juniper-srx/pom.xml b/plugins/network-elements/juniper-srx/pom.xml index 9e2833b729..ba3ecd7a95 100644 --- a/plugins/network-elements/juniper-srx/pom.xml +++ b/plugins/network-elements/juniper-srx/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/midonet/pom.xml b/plugins/network-elements/midonet/pom.xml index b57a482655..00ca4aef7c 100644 --- a/plugins/network-elements/midonet/pom.xml +++ b/plugins/network-elements/midonet/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/netscaler/pom.xml b/plugins/network-elements/netscaler/pom.xml index 4bc747dfde..d7b54e92e7 100644 --- a/plugins/network-elements/netscaler/pom.xml +++ b/plugins/network-elements/netscaler/pom.xml @@ -23,19 +23,19 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml com.citrix.netscaler.nitro nitro - 10.1 + ${cs.nitro.version} com.citrix.netscaler.nitro sdx_nitro - 10.1 + ${cs.nitro.version} diff --git a/plugins/network-elements/nicira-nvp/pom.xml b/plugins/network-elements/nicira-nvp/pom.xml index e86fdf10ef..7ed0f235d6 100644 --- a/plugins/network-elements/nicira-nvp/pom.xml +++ b/plugins/network-elements/nicira-nvp/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml @@ -34,7 +34,7 @@ org.apache.cloudstack cloud-utils - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT test-jar test diff --git a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraNvpApiTest.java b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraNvpApiTest.java index 79546a6847..34518cedad 100644 --- a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraNvpApiTest.java +++ b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraNvpApiTest.java @@ -33,9 +33,9 @@ import java.util.List; -import org.apache.commons.httpclient.HttpStatus; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; +import org.apache.http.HttpStatus; import org.apache.http.ProtocolVersion; import org.apache.http.StatusLine; import org.apache.http.client.methods.CloseableHttpResponse; diff --git a/plugins/network-elements/nuage-vsp/pom.xml b/plugins/network-elements/nuage-vsp/pom.xml index b254cbccd3..7369ba5fa7 100644 --- a/plugins/network-elements/nuage-vsp/pom.xml +++ b/plugins/network-elements/nuage-vsp/pom.xml @@ -25,14 +25,20 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml + + + nuage-vsp + http://cs.mv.nuagenetworks.net/releases/ + + - org.apache.commons - commons-lang3 - ${cs.commons-lang3.version} + net.nuage.vsp + nuage-vsp-acs-client + 3.2.8.0 diff --git a/plugins/network-elements/nuage-vsp/resources/META-INF/cloudstack/vsp/spring-vsp-context.xml b/plugins/network-elements/nuage-vsp/resources/META-INF/cloudstack/vsp/spring-vsp-context.xml index c579789e5e..c447c441c9 100644 --- a/plugins/network-elements/nuage-vsp/resources/META-INF/cloudstack/vsp/spring-vsp-context.xml +++ b/plugins/network-elements/nuage-vsp/resources/META-INF/cloudstack/vsp/spring-vsp-context.xml @@ -37,5 +37,5 @@ - + diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceAnswer.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceAnswer.java deleted file mode 100644 index 979dcd315f..0000000000 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceAnswer.java +++ /dev/null @@ -1,60 +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.agent.api; - -public class VspResourceAnswer extends Answer { - - private String _resourceInfo; - - public VspResourceAnswer(Command cmd, String resourceInfo, String details) { - super(cmd, true, details); - this._resourceInfo = resourceInfo; - } - - public VspResourceAnswer(VspResourceCommand cmd, boolean success, String details) { - super(cmd, success, details); - } - - public VspResourceAnswer(VspResourceCommand cmd, Exception e) { - super(cmd, e); - } - - public String getResourceInfo() { - return this._resourceInfo; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - VspResourceAnswer that = (VspResourceAnswer) o; - - if (_resourceInfo != null ? !_resourceInfo.equals(that._resourceInfo) : that._resourceInfo != null) - return false; - - return true; - } - - @Override - public int hashCode() { - return _resourceInfo != null ? _resourceInfo.hashCode() : 0; - } -} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceCommand.java deleted file mode 100644 index 6e03dabc1b..0000000000 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/VspResourceCommand.java +++ /dev/null @@ -1,119 +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.agent.api; - -public class VspResourceCommand extends Command { - - private final String _method; - private final String _resource; - private final String _resourceId; - private final String _childResource; - private final Object _entityDetails; - private final String _resourceFilter; - private final String _proxyUserUuid; - private final String _proxyUserDomainuuid; - - public VspResourceCommand(String method, String resource, String resourceId, String childResource, Object entityDetails, String resourceFilter, String proxyUserUuid, - String proxyUserDomainuuid) { - super(); - this._method = method; - this._resource = resource; - this._resourceId = resourceId; - this._childResource = childResource; - this._entityDetails = entityDetails; - this._resourceFilter = resourceFilter; - this._proxyUserUuid = proxyUserUuid; - this._proxyUserDomainuuid = proxyUserDomainuuid; - } - - public String getRequestType() { - return _method; - } - - public String getResource() { - return _resource; - } - - public String getResourceId() { - return _resourceId; - } - - public String getChildResource() { - return _childResource; - } - - public Object getEntityDetails() { - return _entityDetails; - } - - public String getResourceFilter() { - return _resourceFilter; - } - - public String getProxyUserUuid() { - return _proxyUserUuid; - } - - public String getProxyUserDomainuuid() { - return _proxyUserDomainuuid; - } - - @Override - public boolean executeInSequence() { - return false; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - VspResourceCommand that = (VspResourceCommand) o; - - if (_childResource != null ? !_childResource.equals(that._childResource) : that._childResource != null) - return false; - if (_entityDetails != null ? !_entityDetails.equals(that._entityDetails) : that._entityDetails != null) - return false; - if (_method != null ? !_method.equals(that._method) : that._method != null) return false; - if (_proxyUserDomainuuid != null ? !_proxyUserDomainuuid.equals(that._proxyUserDomainuuid) : that._proxyUserDomainuuid != null) - return false; - if (_proxyUserUuid != null ? !_proxyUserUuid.equals(that._proxyUserUuid) : that._proxyUserUuid != null) - return false; - if (_resource != null ? !_resource.equals(that._resource) : that._resource != null) return false; - if (_resourceFilter != null ? !_resourceFilter.equals(that._resourceFilter) : that._resourceFilter != null) - return false; - if (_resourceId != null ? !_resourceId.equals(that._resourceId) : that._resourceId != null) return false; - - return true; - } - - @Override - public int hashCode() { - int result = _method != null ? _method.hashCode() : 0; - result = 31 * result + (_resource != null ? _resource.hashCode() : 0); - result = 31 * result + (_resourceId != null ? _resourceId.hashCode() : 0); - result = 31 * result + (_childResource != null ? _childResource.hashCode() : 0); - result = 31 * result + (_entityDetails != null ? _entityDetails.hashCode() : 0); - result = 31 * result + (_resourceFilter != null ? _resourceFilter.hashCode() : 0); - result = 31 * result + (_proxyUserUuid != null ? _proxyUserUuid.hashCode() : 0); - result = 31 * result + (_proxyUserDomainuuid != null ? _proxyUserDomainuuid.hashCode() : 0); - return result; - } -} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyAclRuleVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyAclRuleVspCommand.java index 7b1d40bc09..50cace6ffc 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyAclRuleVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyAclRuleVspCommand.java @@ -19,173 +19,43 @@ package com.cloud.agent.api.element; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspNetwork; import java.util.List; -import java.util.Map; public class ApplyAclRuleVspCommand extends Command { - private final boolean _networkAcl; - private final String _networkUuid; - private final String _networkDomainUuid; - private final String _vpcOrSubnetUuid; - private final String _networkName; - private final boolean _isL2Network; - private final List> _aclRules; - private final long _networkId; - private final boolean _egressDefaultPolicy; - private final Boolean _acsIngressAcl; + private final VspAclRule.ACLType _aclType; + private final VspNetwork _network; + private final List _aclRules; private final boolean _networkReset; - private final String _domainTemplateName; - private ApplyAclRuleVspCommand(boolean networkAcl, String networkUuid, String networkDomainUuid, String vpcOrSubnetUuid, String networkName, boolean isL2Network, - List> aclRules, long networkId, boolean egressDefaultPolicy, Boolean acsIngressAcl, boolean networkReset, String domainTemplateName) { + public ApplyAclRuleVspCommand(VspAclRule.ACLType aclType, VspNetwork network, List aclRules, boolean networkReset) { super(); - this._networkAcl = networkAcl; - this._networkUuid = networkUuid; - this._networkDomainUuid = networkDomainUuid; - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - this._networkName = networkName; - this._isL2Network = isL2Network; + this._aclType = aclType; + this._network = network; this._aclRules = aclRules; - this._networkId = networkId; - this._egressDefaultPolicy = egressDefaultPolicy; - this._acsIngressAcl = acsIngressAcl; this._networkReset = networkReset; - this._domainTemplateName = domainTemplateName; } - public boolean isNetworkAcl() { - return _networkAcl; + public VspAclRule.ACLType getAclType() { + return _aclType; } - public String getNetworkUuid() { - return _networkUuid; + public VspNetwork getNetwork() { + return _network; } - public String getNetworkDomainUuid() { - return _networkDomainUuid; - } - - public String getVpcOrSubnetUuid() { - return _vpcOrSubnetUuid; - } - - public String getNetworkName() { - return _networkName; - } - - public boolean isL2Network() { - return _isL2Network; - } - - public List> getAclRules() { + public List getAclRules() { return _aclRules; } - public long getNetworkId() { - return _networkId; - } - - public boolean isEgressDefaultPolicy() { - return _egressDefaultPolicy; - } - - public Boolean getAcsIngressAcl() { - return _acsIngressAcl; - } - public boolean isNetworkReset() { return _networkReset; } - public String getDomainTemplateName() { - return _domainTemplateName; - } - - public static class Builder implements CmdBuilder { - private boolean _networkAcl; - private String _networkUuid; - private String _networkDomainUuid; - private String _vpcOrSubnetUuid; - private String _networkName; - private boolean _isL2Network; - private List> _aclRules; - private long _networkId; - private boolean _egressDefaultPolicy; - private Boolean _acsIngressAcl; - private boolean _networkReset; - private String _domainTemplateName; - - public Builder networkAcl(boolean networkAcl) { - this._networkAcl = networkAcl; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder networkDomainUuid(String networkDomainUuid) { - this._networkDomainUuid = networkDomainUuid; - return this; - } - - public Builder vpcOrSubnetUuid(String vpcOrSubnetUuid) { - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - return this; - } - - public Builder networkName(String networkName) { - this._networkName = networkName; - return this; - } - - public Builder isL2Network(boolean isL2Network) { - this._isL2Network = isL2Network; - return this; - } - - public Builder aclRules(List> aclRules) { - this._aclRules = aclRules; - return this; - } - - public Builder networkId(long networkId) { - this._networkId = networkId; - return this; - } - - public Builder egressDefaultPolicy(boolean egressDefaultPolicy) { - this._egressDefaultPolicy = egressDefaultPolicy; - return this; - } - - public Builder acsIngressAcl(Boolean acsIngressAcl) { - this._acsIngressAcl = acsIngressAcl; - return this; - } - - public Builder networkReset(boolean networkReset) { - this._networkReset = networkReset; - return this; - } - - public Builder domainTemplateName(String domainTemplateName) { - this._domainTemplateName = domainTemplateName; - return this; - } - - @Override - public ApplyAclRuleVspCommand build() { - return new ApplyAclRuleVspCommand(_networkAcl, _networkUuid, _networkDomainUuid, _vpcOrSubnetUuid, _networkName, _isL2Network, _aclRules, - _networkId, _egressDefaultPolicy, _acsIngressAcl, _networkReset, _domainTemplateName); - } - } - @Override public boolean executeInSequence() { return false; @@ -199,22 +69,10 @@ public boolean equals(Object o) { ApplyAclRuleVspCommand that = (ApplyAclRuleVspCommand) o; - if (_egressDefaultPolicy != that._egressDefaultPolicy) return false; - if (_isL2Network != that._isL2Network) return false; - if (_networkAcl != that._networkAcl) return false; - if (_networkId != that._networkId) return false; if (_networkReset != that._networkReset) return false; if (_aclRules != null ? !_aclRules.equals(that._aclRules) : that._aclRules != null) return false; - if (_acsIngressAcl != null ? !_acsIngressAcl.equals(that._acsIngressAcl) : that._acsIngressAcl != null) - return false; - if (_domainTemplateName != null ? !_domainTemplateName.equals(that._domainTemplateName) : that._domainTemplateName != null) - return false; - if (_networkDomainUuid != null ? !_networkDomainUuid.equals(that._networkDomainUuid) : that._networkDomainUuid != null) - return false; - if (_networkName != null ? !_networkName.equals(that._networkName) : that._networkName != null) return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_vpcOrSubnetUuid != null ? !_vpcOrSubnetUuid.equals(that._vpcOrSubnetUuid) : that._vpcOrSubnetUuid != null) - return false; + if (_aclType != that._aclType) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; return true; } @@ -222,18 +80,10 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_networkAcl ? 1 : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_networkDomainUuid != null ? _networkDomainUuid.hashCode() : 0); - result = 31 * result + (_vpcOrSubnetUuid != null ? _vpcOrSubnetUuid.hashCode() : 0); - result = 31 * result + (_networkName != null ? _networkName.hashCode() : 0); - result = 31 * result + (_isL2Network ? 1 : 0); + result = 31 * result + (_aclType != null ? _aclType.hashCode() : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); result = 31 * result + (_aclRules != null ? _aclRules.hashCode() : 0); - result = 31 * result + (int) (_networkId ^ (_networkId >>> 32)); - result = 31 * result + (_egressDefaultPolicy ? 1 : 0); - result = 31 * result + (_acsIngressAcl != null ? _acsIngressAcl.hashCode() : 0); result = 31 * result + (_networkReset ? 1 : 0); - result = 31 * result + (_domainTemplateName != null ? _domainTemplateName.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyStaticNatVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyStaticNatVspCommand.java index cc4e9300c9..500f091919 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyStaticNatVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ApplyStaticNatVspCommand.java @@ -19,100 +19,31 @@ package com.cloud.agent.api.element; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; import java.util.List; -import java.util.Map; public class ApplyStaticNatVspCommand extends Command { - private final String _networkDomainUuid; - private final String _networkUuid; - private final String _vpcOrSubnetUuid; - private final boolean _isL3Network; - private final boolean _isVpc; - private final List> _staticNatDetails; + private final VspNetwork _network; + private final List _staticNatDetails; - private ApplyStaticNatVspCommand(String networkDomainUuid, String networkUuid, String vpcOrSubnetUuid, boolean isL3Network, boolean isVpc, - List> staticNatDetails) { + public ApplyStaticNatVspCommand(VspNetwork network, List staticNatDetails) { super(); - this._networkDomainUuid = networkDomainUuid; - this._networkUuid = networkUuid; - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - this._isL3Network = isL3Network; - this._isVpc = isVpc; + this._network = network; this._staticNatDetails = staticNatDetails; } - public String getNetworkDomainUuid() { - return _networkDomainUuid; + public VspNetwork getNetwork() { + return _network; } - public String getNetworkUuid() { - return _networkUuid; - } - - public String getVpcOrSubnetUuid() { - return _vpcOrSubnetUuid; - } - - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isVpc() { - return _isVpc; - } - - public List> getStaticNatDetails() { + public List getStaticNatDetails() { return _staticNatDetails; } - public static class Builder implements CmdBuilder { - private String _networkDomainUuid; - private String _networkUuid; - private String _vpcOrSubnetUuid; - private boolean _isL3Network; - private boolean _isVpc; - private List> _staticNatDetails; - - public Builder networkDomainUuid(String networkDomainUuid) { - this._networkDomainUuid = networkDomainUuid; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder vpcOrSubnetUuid(String vpcOrSubnetUuid) { - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isVpc(boolean isVpc) { - this._isVpc = isVpc; - return this; - } - - public Builder staticNatDetails(List> staticNatDetails) { - this._staticNatDetails = staticNatDetails; - return this; - } - - @Override - public ApplyStaticNatVspCommand build() { - return new ApplyStaticNatVspCommand(_networkDomainUuid, _networkUuid, _vpcOrSubnetUuid, _isL3Network, _isVpc, _staticNatDetails); - } - } - @Override public boolean executeInSequence() { return false; @@ -126,15 +57,9 @@ public boolean equals(Object o) { ApplyStaticNatVspCommand that = (ApplyStaticNatVspCommand) o; - if (_isL3Network != that._isL3Network) return false; - if (_isVpc != that._isVpc) return false; - if (_networkDomainUuid != null ? !_networkDomainUuid.equals(that._networkDomainUuid) : that._networkDomainUuid != null) - return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; if (_staticNatDetails != null ? !_staticNatDetails.equals(that._staticNatDetails) : that._staticNatDetails != null) return false; - if (_vpcOrSubnetUuid != null ? !_vpcOrSubnetUuid.equals(that._vpcOrSubnetUuid) : that._vpcOrSubnetUuid != null) - return false; return true; } @@ -142,11 +67,7 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_networkDomainUuid != null ? _networkDomainUuid.hashCode() : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_vpcOrSubnetUuid != null ? _vpcOrSubnetUuid.hashCode() : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isVpc ? 1 : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); result = 31 * result + (_staticNatDetails != null ? _staticNatDetails.hashCode() : 0); return result; } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ImplementVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ImplementVspCommand.java index c1de6b9de8..2145f60172 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ImplementVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ImplementVspCommand.java @@ -19,220 +19,48 @@ package com.cloud.agent.api.element; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspNetwork; import java.util.List; -import java.util.Map; public class ImplementVspCommand extends Command { - private final long _networkId; - private final String _networkDomainUuid; - private final String _networkUuid; - private final String _networkName; - private final String _vpcOrSubnetUuid; - private final boolean _isL2Network; - private final boolean _isL3Network; - private final boolean _isVpc; - private final boolean _isShared; - private final String _domainTemplateName; - private final boolean _isFirewallServiceSupported; + private final VspNetwork _network; private final List _dnsServers; - private final List> _ingressFirewallRules; - private final List> _egressFirewallRules; - private final List _acsFipUuid; - private final boolean _egressDefaultPolicy; + private final List _ingressFirewallRules; + private final List _egressFirewallRules; + private final List _floatingIpUuids; - private ImplementVspCommand(long networkId, String networkDomainUuid, String networkUuid, String networkName, String vpcOrSubnetUuid, boolean isL2Network, boolean isL3Network, - boolean isVpc, boolean isShared, String domainTemplateName, boolean isFirewallServiceSupported, List dnsServers, List> ingressFirewallRules, - List> egressFirewallRules, List acsFipUuid, boolean egressDefaultPolicy) { + public ImplementVspCommand(VspNetwork network, List dnsServers, List ingressFirewallRules, + List egressFirewallRules, List floatingIpUuids) { super(); - this._networkId = networkId; - this._networkDomainUuid = networkDomainUuid; - this._networkUuid = networkUuid; - this._networkName = networkName; - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - this._isL2Network = isL2Network; - this._isL3Network = isL3Network; - this._isVpc = isVpc; - this._isShared = isShared; - this._domainTemplateName = domainTemplateName; - this._isFirewallServiceSupported = isFirewallServiceSupported; + this._network = network; this._dnsServers = dnsServers; this._ingressFirewallRules = ingressFirewallRules; this._egressFirewallRules = egressFirewallRules; - this._acsFipUuid = acsFipUuid; - this._egressDefaultPolicy = egressDefaultPolicy; + this._floatingIpUuids = floatingIpUuids; } - public long getNetworkId() { - return _networkId; - } - - public String getNetworkDomainUuid() { - return _networkDomainUuid; - } - - public String getNetworkUuid() { - return _networkUuid; - } - - public String getNetworkName() { - return _networkName; - } - - public String getVpcOrSubnetUuid() { - return _vpcOrSubnetUuid; - } - - public boolean isL2Network() { - return _isL2Network; - } - - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isVpc() { - return _isVpc; - } - - public boolean isShared() { - return _isShared; - } - - public String getDomainTemplateName() { - return _domainTemplateName; - } - - public boolean isFirewallServiceSupported() { - return _isFirewallServiceSupported; + public VspNetwork getNetwork() { + return _network; } public List getDnsServers() { return _dnsServers; } - public List> getIngressFirewallRules() { + public List getIngressFirewallRules() { return _ingressFirewallRules; } - public List> getEgressFirewallRules() { + public List getEgressFirewallRules() { return _egressFirewallRules; } - public List getAcsFipUuid() { - return _acsFipUuid; - } - - public boolean isEgressDefaultPolicy() { - return _egressDefaultPolicy; - } - - public static class Builder implements CmdBuilder { - private long _networkId; - private String _networkDomainUuid; - private String _networkUuid; - private String _networkName; - private String _vpcOrSubnetUuid; - private boolean _isL2Network; - private boolean _isL3Network; - private boolean _isVpc; - private boolean _isShared; - private String _domainTemplateName; - private boolean _isFirewallServiceSupported; - private List _dnsServers; - private List> _ingressFirewallRules; - private List> _egressFirewallRules; - private List _acsFipUuid; - private boolean _egressDefaultPolicy; - - public Builder networkId(long networkId) { - this._networkId = networkId; - return this; - } - - public Builder networkDomainUuid(String networkDomainUuid) { - this._networkDomainUuid = networkDomainUuid; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder networkName(String networkName) { - this._networkName = networkName; - return this; - } - - public Builder vpcOrSubnetUuid(String vpcOrSubnetUuid) { - this._vpcOrSubnetUuid = vpcOrSubnetUuid; - return this; - } - - public Builder isL2Network(boolean isL2Network) { - this._isL2Network = isL2Network; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isVpc(boolean isVpc) { - this._isVpc = isVpc; - return this; - } - - public Builder isShared(boolean isShared) { - this._isShared = isShared; - return this; - } - - public Builder domainTemplateName(String domainTemplateName) { - this._domainTemplateName = domainTemplateName; - return this; - } - - public Builder isFirewallServiceSupported(boolean isFirewallServiceSupported) { - this._isFirewallServiceSupported = isFirewallServiceSupported; - return this; - } - - public Builder dnsServers(List dnsServers) { - this._dnsServers = dnsServers; - return this; - } - - public Builder ingressFirewallRules(List> ingressFirewallRules) { - this._ingressFirewallRules = ingressFirewallRules; - return this; - } - - public Builder egressFirewallRules(List> egressFirewallRules) { - this._egressFirewallRules = egressFirewallRules; - return this; - } - - public Builder acsFipUuid(List acsFipUuid) { - this._acsFipUuid = acsFipUuid; - return this; - } - - public Builder egressDefaultPolicy(boolean egressDefaultPolicy) { - this._egressDefaultPolicy = egressDefaultPolicy; - return this; - } - - @Override - public ImplementVspCommand build() { - return new ImplementVspCommand(_networkId, _networkDomainUuid, _networkUuid, _networkName, _vpcOrSubnetUuid, _isL2Network, _isL3Network, _isVpc, _isShared, - _domainTemplateName, _isFirewallServiceSupported, _dnsServers, _ingressFirewallRules, _egressFirewallRules, _acsFipUuid, _egressDefaultPolicy); - } + public List getFloatingIpUuids() { + return _floatingIpUuids; } @Override @@ -248,27 +76,14 @@ public boolean equals(Object o) { ImplementVspCommand that = (ImplementVspCommand) o; - if (_egressDefaultPolicy != that._egressDefaultPolicy) return false; - if (_isFirewallServiceSupported != that._isFirewallServiceSupported) return false; - if (_isL2Network != that._isL2Network) return false; - if (_isL3Network != that._isL3Network) return false; - if (_isShared != that._isShared) return false; - if (_isVpc != that._isVpc) return false; - if (_networkId != that._networkId) return false; - if (_acsFipUuid != null ? !_acsFipUuid.equals(that._acsFipUuid) : that._acsFipUuid != null) return false; if (_dnsServers != null ? !_dnsServers.equals(that._dnsServers) : that._dnsServers != null) return false; - if (_domainTemplateName != null ? !_domainTemplateName.equals(that._domainTemplateName) : that._domainTemplateName != null) - return false; if (_egressFirewallRules != null ? !_egressFirewallRules.equals(that._egressFirewallRules) : that._egressFirewallRules != null) return false; - if (_ingressFirewallRules != null ? !_ingressFirewallRules.equals(that._ingressFirewallRules) : that._ingressFirewallRules != null) + if (_floatingIpUuids != null ? !_floatingIpUuids.equals(that._floatingIpUuids) : that._floatingIpUuids != null) return false; - if (_networkDomainUuid != null ? !_networkDomainUuid.equals(that._networkDomainUuid) : that._networkDomainUuid != null) - return false; - if (_networkName != null ? !_networkName.equals(that._networkName) : that._networkName != null) return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_vpcOrSubnetUuid != null ? !_vpcOrSubnetUuid.equals(that._vpcOrSubnetUuid) : that._vpcOrSubnetUuid != null) + if (_ingressFirewallRules != null ? !_ingressFirewallRules.equals(that._ingressFirewallRules) : that._ingressFirewallRules != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; return true; } @@ -276,22 +91,11 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (int) (_networkId ^ (_networkId >>> 32)); - result = 31 * result + (_networkDomainUuid != null ? _networkDomainUuid.hashCode() : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_networkName != null ? _networkName.hashCode() : 0); - result = 31 * result + (_vpcOrSubnetUuid != null ? _vpcOrSubnetUuid.hashCode() : 0); - result = 31 * result + (_isL2Network ? 1 : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isVpc ? 1 : 0); - result = 31 * result + (_isShared ? 1 : 0); - result = 31 * result + (_domainTemplateName != null ? _domainTemplateName.hashCode() : 0); - result = 31 * result + (_isFirewallServiceSupported ? 1 : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); result = 31 * result + (_dnsServers != null ? _dnsServers.hashCode() : 0); result = 31 * result + (_ingressFirewallRules != null ? _ingressFirewallRules.hashCode() : 0); result = 31 * result + (_egressFirewallRules != null ? _egressFirewallRules.hashCode() : 0); - result = 31 * result + (_acsFipUuid != null ? _acsFipUuid.hashCode() : 0); - result = 31 * result + (_egressDefaultPolicy ? 1 : 0); + result = 31 * result + (_floatingIpUuids != null ? _floatingIpUuids.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java index 4c41e5140a..6ad4ec6c40 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/element/ShutDownVpcVspCommand.java @@ -19,20 +19,23 @@ package com.cloud.agent.api.element; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import java.util.List; + public class ShutDownVpcVspCommand extends Command { private final String _domainUuid; private final String _vpcUuid; private final String _domainTemplateName; + private final List _domainRouterUuids; - private ShutDownVpcVspCommand(String domainUuid, String vpcUuid, String domainTemplateName) { + public ShutDownVpcVspCommand(String domainUuid, String vpcUuid, String domainTemplateName, List domainRouterUuids) { super(); this._domainUuid = domainUuid; this._vpcUuid = vpcUuid; this._domainTemplateName = domainTemplateName; + this._domainRouterUuids = domainRouterUuids; } public String getDomainUuid() { @@ -47,30 +50,8 @@ public String getDomainTemplateName() { return _domainTemplateName; } - public static class Builder implements CmdBuilder { - private String _domainUuid; - private String _vpcUuid; - private String _domainTemplateName; - - public Builder domainUuid(String domainUuid) { - this._domainUuid = domainUuid; - return this; - } - - public Builder vpcUuid(String vpcUuid) { - this._vpcUuid = vpcUuid; - return this; - } - - public Builder domainTemplateName(String domainTemplateName) { - this._domainTemplateName = domainTemplateName; - return this; - } - - @Override - public ShutDownVpcVspCommand build() { - return new ShutDownVpcVspCommand(_domainUuid, _vpcUuid, _domainTemplateName); - } + public List getDomainRouterUuids() { + return _domainRouterUuids; } @Override @@ -86,6 +67,8 @@ public boolean equals(Object o) { ShutDownVpcVspCommand that = (ShutDownVpcVspCommand) o; + if (_domainRouterUuids != null ? !_domainRouterUuids.equals(that._domainRouterUuids) : that._domainRouterUuids != null) + return false; if (_domainTemplateName != null ? !_domainTemplateName.equals(that._domainTemplateName) : that._domainTemplateName != null) return false; if (_domainUuid != null ? !_domainUuid.equals(that._domainUuid) : that._domainUuid != null) return false; @@ -100,6 +83,7 @@ public int hashCode() { result = 31 * result + (_domainUuid != null ? _domainUuid.hashCode() : 0); result = 31 * result + (_vpcUuid != null ? _vpcUuid.hashCode() : 0); result = 31 * result + (_domainTemplateName != null ? _domainTemplateName.hashCode() : 0); + result = 31 * result + (_domainRouterUuids != null ? _domainRouterUuids.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/DeallocateVmVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/DeallocateVmVspCommand.java index 421fa4c689..10dffccacc 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/DeallocateVmVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/DeallocateVmVspCommand.java @@ -19,156 +19,34 @@ package com.cloud.agent.api.guru; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspVm; public class DeallocateVmVspCommand extends Command { - private final String _networkUuid; - private final String _nicFromDdUuid; - private final String _nicMacAddress; - private final String _nicIp4Address; - private final boolean _isL3Network; - private final boolean _isSharedNetwork; - private final String _vpcUuid; - private final String _networksDomainUuid; - private final String _vmInstanceName; - private final String _vmUuid; - private final boolean _isExpungingState; + private final VspNetwork _network; + private final VspVm _vm; + private final VspNic _nic; - private DeallocateVmVspCommand(String networkUuid, String nicFromDdUuid, String nicMacAddress, String nicIp4Address, boolean isL3Network, boolean isSharedNetwork, String vpcUuid, - String networksDomainUuid, String vmInstanceName, String vmUuid, boolean isExpungingState) { + public DeallocateVmVspCommand(VspNetwork network, VspVm vm, VspNic nic) { super(); - this._networkUuid = networkUuid; - this._nicFromDdUuid = nicFromDdUuid; - this._nicMacAddress = nicMacAddress; - this._nicIp4Address = nicIp4Address; - this._isL3Network = isL3Network; - this._isSharedNetwork = isSharedNetwork; - this._vpcUuid = vpcUuid; - this._networksDomainUuid = networksDomainUuid; - this._vmInstanceName = vmInstanceName; - this._vmUuid = vmUuid; - this._isExpungingState = isExpungingState; + this._network = network; + this._vm = vm; + this._nic = nic; } - public String getNetworkUuid() { - return _networkUuid; + public VspNetwork getNetwork() { + return this._network; } - public String getNicFromDdUuid() { - return _nicFromDdUuid; + public VspVm getVm() { + return this._vm; } - public String getNicMacAddress() { - return _nicMacAddress; - } - - public String getNicIp4Address() { - return _nicIp4Address; - } - - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isSharedNetwork() { - return _isSharedNetwork; - } - - public String getVpcUuid() { - return _vpcUuid; - } - - public String getNetworksDomainUuid() { - return _networksDomainUuid; - } - - public String getVmInstanceName() { - return _vmInstanceName; - } - - public String getVmUuid() { - return _vmUuid; - } - - public boolean isExpungingState() { - return _isExpungingState; - } - - public static class Builder implements CmdBuilder { - private String _networkUuid; - private String _nicFromDdUuid; - private String _nicMacAddress; - private String _nicIp4Address; - private boolean _isL3Network; - private boolean _isSharedNetwork; - private String _vpcUuid; - private String _networksDomainUuid; - private String _vmInstanceName; - private String _vmUuid; - private boolean _isExpungingState; - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder nicFromDbUuid(String nicFromDbUuid) { - this._nicFromDdUuid = nicFromDbUuid; - return this; - } - - public Builder nicMacAddress(String nicMacAddress) { - this._nicMacAddress = nicMacAddress; - return this; - } - - public Builder nicIp4Address(String nicIp4Address) { - this._nicIp4Address = nicIp4Address; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isSharedNetwork(boolean isSharedNetwork) { - this._isSharedNetwork = isSharedNetwork; - return this; - } - - public Builder vpcUuid(String vpcUuid) { - this._vpcUuid = vpcUuid; - return this; - } - - public Builder networksDomainUuid(String networksDomainUuid) { - this._networksDomainUuid = networksDomainUuid; - return this; - } - - public Builder vmInstanceName(String vmInstanceName) { - this._vmInstanceName = vmInstanceName; - return this; - } - - public Builder vmUuid(String vmUuid) { - this._vmUuid = vmUuid; - return this; - } - - public Builder isExpungingState(boolean isExpungingState) { - this._isExpungingState = isExpungingState; - return this; - } - - @Override - public DeallocateVmVspCommand build() { - return new DeallocateVmVspCommand(_networkUuid,_nicFromDdUuid, _nicMacAddress, _nicIp4Address, _isL3Network, _isSharedNetwork, _vpcUuid, - _networksDomainUuid, _vmInstanceName, _vmUuid, _isExpungingState); - } + public VspNic getNic() { + return this._nic; } @Override @@ -184,22 +62,9 @@ public boolean equals(Object o) { DeallocateVmVspCommand that = (DeallocateVmVspCommand) o; - if (_isExpungingState != that._isExpungingState) return false; - if (_isL3Network != that._isL3Network) return false; - if (_isSharedNetwork != that._isSharedNetwork) return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_networksDomainUuid != null ? !_networksDomainUuid.equals(that._networksDomainUuid) : that._networksDomainUuid != null) - return false; - if (_nicFromDdUuid != null ? !_nicFromDdUuid.equals(that._nicFromDdUuid) : that._nicFromDdUuid != null) - return false; - if (_nicIp4Address != null ? !_nicIp4Address.equals(that._nicIp4Address) : that._nicIp4Address != null) - return false; - if (_nicMacAddress != null ? !_nicMacAddress.equals(that._nicMacAddress) : that._nicMacAddress != null) - return false; - if (_vmInstanceName != null ? !_vmInstanceName.equals(that._vmInstanceName) : that._vmInstanceName != null) - return false; - if (_vmUuid != null ? !_vmUuid.equals(that._vmUuid) : that._vmUuid != null) return false; - if (_vpcUuid != null ? !_vpcUuid.equals(that._vpcUuid) : that._vpcUuid != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; + if (_nic != null ? !_nic.equals(that._nic) : that._nic != null) return false; + if (_vm != null ? !_vm.equals(that._vm) : that._vm != null) return false; return true; } @@ -207,17 +72,9 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_nicFromDdUuid != null ? _nicFromDdUuid.hashCode() : 0); - result = 31 * result + (_nicMacAddress != null ? _nicMacAddress.hashCode() : 0); - result = 31 * result + (_nicIp4Address != null ? _nicIp4Address.hashCode() : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isSharedNetwork ? 1 : 0); - result = 31 * result + (_vpcUuid != null ? _vpcUuid.hashCode() : 0); - result = 31 * result + (_networksDomainUuid != null ? _networksDomainUuid.hashCode() : 0); - result = 31 * result + (_vmInstanceName != null ? _vmInstanceName.hashCode() : 0); - result = 31 * result + (_vmUuid != null ? _vmUuid.hashCode() : 0); - result = 31 * result + (_isExpungingState ? 1 : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); + result = 31 * result + (_vm != null ? _vm.hashCode() : 0); + result = 31 * result + (_nic != null ? _nic.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java index 575e57d362..bb3575690d 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ImplementNetworkVspCommand.java @@ -19,272 +19,30 @@ package com.cloud.agent.api.guru; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspNetwork; -import java.util.Collection; import java.util.List; public class ImplementNetworkVspCommand extends Command { - private final String _networkDomainName; - private final String _networkDomainPath; - private final String _networkDomainUuid; - private final String _networkAccountName; - private final String _networkAccountUuid; - private final String _networkName; - private final String _networkCidr; - private final String _networkGateway; - private final Long _networkAclId; + private final VspNetwork _network; private final List _dnsServers; - private final List _gatewaySystemIds; - private final String _networkUuid; - private final boolean _isL3Network; - private final boolean _isVpc; - private final boolean _isSharedNetwork; - private final String _vpcName; - private final String _vpcUuid; - private final boolean _defaultEgressPolicy; - private final List _ipAddressRange; - private final String _domainTemplateName; - private ImplementNetworkVspCommand(String networkDomainName, String networkDomainPath, String networkDomainUuid, String networkAccountName, String networkAccountUuid, - String networkName, String networkCidr, String networkGateway, Long networkAclId, List dnsServers, List gatewaySystemIds, String networkUuid, - boolean isL3Network, boolean isVpc, boolean isSharedNetwork, String vpcName, String vpcUuid, boolean defaultEgressPolicy, List ipAddressRange, - String domainTemplateName) { + public ImplementNetworkVspCommand(VspNetwork network, List dnsServers) { super(); - this._networkDomainName = networkDomainName; - this._networkDomainPath = networkDomainPath; - this._networkDomainUuid = networkDomainUuid; - this._networkAccountName = networkAccountName; - this._networkAccountUuid = networkAccountUuid; - this._networkName = networkName; - this._networkCidr = networkCidr; - this._networkGateway = networkGateway; - this._networkAclId = networkAclId; + this._network = network; this._dnsServers = dnsServers; - this._gatewaySystemIds = gatewaySystemIds; - this._networkUuid = networkUuid; - this._isL3Network = isL3Network; - this._isVpc = isVpc; - this._isSharedNetwork = isSharedNetwork; - this._vpcName = vpcName; - this._vpcUuid = vpcUuid; - this._defaultEgressPolicy = defaultEgressPolicy; - this._ipAddressRange = ipAddressRange; - this._domainTemplateName = domainTemplateName; } - public String getNetworkDomainName() { - return _networkDomainName; - } - - public String getNetworkDomainPath() { - return _networkDomainPath; - } - - public String getNetworkDomainUuid() { - return _networkDomainUuid; - } - - public String getNetworkAccountName() { - return _networkAccountName; - } - - public String getNetworkAccountUuid() { - return _networkAccountUuid; - } - - public String getNetworkName() { - return _networkName; - } - - public String getNetworkCidr() { - return _networkCidr; - } - - public String getNetworkGateway() { - return _networkGateway; - } - - public Long getNetworkAclId() { - return _networkAclId; + public VspNetwork getNetwork() { + return _network; } public List getDnsServers() { return _dnsServers; } - public List getGatewaySystemIds() { - return _gatewaySystemIds; - } - - public String getNetworkUuid() { - return _networkUuid; - } - - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isVpc() { - return _isVpc; - } - - public boolean isSharedNetwork() { - return _isSharedNetwork; - } - - public String getVpcName() { - return _vpcName; - } - - public String getVpcUuid() { - return _vpcUuid; - } - - public boolean isDefaultEgressPolicy() { - return _defaultEgressPolicy; - } - - public Collection getIpAddressRange() { - return _ipAddressRange; - } - - public String getDomainTemplateName() { - return _domainTemplateName; - } - - public static class Builder implements CmdBuilder { - private String _networkDomainName; - private String _networkDomainPath; - private String _networkDomainUuid; - private String _networkAccountName; - private String _networkAccountUuid; - private String _networkName; - private String _networkCidr; - private String _networkGateway; - private Long _networkAclId; - private List _dnsServers; - private List _gatewaySystemIds; - private String _networkUuid; - private boolean _isL3Network; - private boolean _isVpc; - private boolean _isSharedNetwork; - private String _vpcName; - private String _vpcUuid; - private boolean _defaultEgressPolicy; - private List _ipAddressRange; - private String _domainTemplateName; - - public Builder networkDomainName(String networkDomainName) { - this._networkDomainName = networkDomainName; - return this; - } - - public Builder networkDomainPath(String networkDomainPath) { - this._networkDomainPath = networkDomainPath; - return this; - } - - public Builder networkDomainUuid(String networkDomainUuid) { - this._networkDomainUuid = networkDomainUuid; - return this; - } - - public Builder networkAccountName(String networkAccountName) { - this._networkAccountName = networkAccountName; - return this; - } - - public Builder networkAccountUuid(String networkAccountUuid) { - this._networkAccountUuid = networkAccountUuid; - return this; - } - - public Builder networkName(String networkName) { - this._networkName = networkName; - return this; - } - - public Builder networkCidr(String networkCidr) { - this._networkCidr = networkCidr; - return this; - } - - public Builder networkGateway(String networkGateway) { - this._networkGateway = networkGateway; - return this; - } - - public Builder networkAclId(Long networkAclId) { - this._networkAclId = networkAclId; - return this; - } - - public Builder dnsServers(List dnsServers) { - this._dnsServers = dnsServers; - return this; - } - - public Builder gatewaySystemIds(List gatewaySystemIds) { - this._gatewaySystemIds = gatewaySystemIds; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isVpc(boolean isVpc) { - this._isVpc = isVpc; - return this; - } - - public Builder isSharedNetwork(boolean isSharedNetwork) { - this._isSharedNetwork = isSharedNetwork; - return this; - } - - public Builder vpcName(String vpcName) { - this._vpcName = vpcName; - return this; - } - - public Builder vpcUuid(String vpcUuid) { - this._vpcUuid = vpcUuid; - return this; - } - - public Builder defaultEgressPolicy(boolean defaultEgressPolicy) { - this._defaultEgressPolicy = defaultEgressPolicy; - return this; - } - - public Builder ipAddressRange(List ipAddressRange) { - this._ipAddressRange = ipAddressRange; - return this; - } - - public Builder domainTemplateName(String domainTemplateName) { - this._domainTemplateName = domainTemplateName; - return this; - } - - @Override - public ImplementNetworkVspCommand build() { - return new ImplementNetworkVspCommand(_networkDomainName, _networkDomainPath, _networkDomainUuid, _networkAccountName, _networkAccountUuid, _networkName, - _networkCidr, _networkGateway, _networkAclId, _dnsServers, _gatewaySystemIds, _networkUuid, _isL3Network, _isVpc, _isSharedNetwork, _vpcName, _vpcUuid, - _defaultEgressPolicy, _ipAddressRange, _domainTemplateName); - } - } - @Override public boolean executeInSequence() { return false; @@ -298,36 +56,8 @@ public boolean equals(Object o) { ImplementNetworkVspCommand that = (ImplementNetworkVspCommand) o; - if (_defaultEgressPolicy != that._defaultEgressPolicy) return false; - if (_isL3Network != that._isL3Network) return false; - if (_isSharedNetwork != that._isSharedNetwork) return false; - if (_isVpc != that._isVpc) return false; if (_dnsServers != null ? !_dnsServers.equals(that._dnsServers) : that._dnsServers != null) return false; - if (_domainTemplateName != null ? !_domainTemplateName.equals(that._domainTemplateName) : that._domainTemplateName != null) - return false; - if (_gatewaySystemIds != null ? !_gatewaySystemIds.equals(that._gatewaySystemIds) : that._gatewaySystemIds != null) - return false; - if (_ipAddressRange != null ? !_ipAddressRange.equals(that._ipAddressRange) : that._ipAddressRange != null) - return false; - if (_networkAccountName != null ? !_networkAccountName.equals(that._networkAccountName) : that._networkAccountName != null) - return false; - if (_networkAccountUuid != null ? !_networkAccountUuid.equals(that._networkAccountUuid) : that._networkAccountUuid != null) - return false; - if (_networkAclId != null ? !_networkAclId.equals(that._networkAclId) : that._networkAclId != null) - return false; - if (_networkCidr != null ? !_networkCidr.equals(that._networkCidr) : that._networkCidr != null) return false; - if (_networkDomainName != null ? !_networkDomainName.equals(that._networkDomainName) : that._networkDomainName != null) - return false; - if (_networkDomainPath != null ? !_networkDomainPath.equals(that._networkDomainPath) : that._networkDomainPath != null) - return false; - if (_networkDomainUuid != null ? !_networkDomainUuid.equals(that._networkDomainUuid) : that._networkDomainUuid != null) - return false; - if (_networkGateway != null ? !_networkGateway.equals(that._networkGateway) : that._networkGateway != null) - return false; - if (_networkName != null ? !_networkName.equals(that._networkName) : that._networkName != null) return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_vpcName != null ? !_vpcName.equals(that._vpcName) : that._vpcName != null) return false; - if (_vpcUuid != null ? !_vpcUuid.equals(that._vpcUuid) : that._vpcUuid != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; return true; } @@ -335,26 +65,8 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_networkDomainName != null ? _networkDomainName.hashCode() : 0); - result = 31 * result + (_networkDomainPath != null ? _networkDomainPath.hashCode() : 0); - result = 31 * result + (_networkDomainUuid != null ? _networkDomainUuid.hashCode() : 0); - result = 31 * result + (_networkAccountName != null ? _networkAccountName.hashCode() : 0); - result = 31 * result + (_networkAccountUuid != null ? _networkAccountUuid.hashCode() : 0); - result = 31 * result + (_networkName != null ? _networkName.hashCode() : 0); - result = 31 * result + (_networkCidr != null ? _networkCidr.hashCode() : 0); - result = 31 * result + (_networkGateway != null ? _networkGateway.hashCode() : 0); - result = 31 * result + (_networkAclId != null ? _networkAclId.hashCode() : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); result = 31 * result + (_dnsServers != null ? _dnsServers.hashCode() : 0); - result = 31 * result + (_gatewaySystemIds != null ? _gatewaySystemIds.hashCode() : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isVpc ? 1 : 0); - result = 31 * result + (_isSharedNetwork ? 1 : 0); - result = 31 * result + (_vpcName != null ? _vpcName.hashCode() : 0); - result = 31 * result + (_vpcUuid != null ? _vpcUuid.hashCode() : 0); - result = 31 * result + (_defaultEgressPolicy ? 1 : 0); - result = 31 * result + (_ipAddressRange != null ? _ipAddressRange.hashCode() : 0); - result = 31 * result + (_domainTemplateName != null ? _domainTemplateName.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ReserveVmInterfaceVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ReserveVmInterfaceVspCommand.java index abcd0f2c69..299b9a6ec7 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ReserveVmInterfaceVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/ReserveVmInterfaceVspCommand.java @@ -19,303 +19,41 @@ package com.cloud.agent.api.guru; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; public class ReserveVmInterfaceVspCommand extends Command { - private final String _nicUuid; - private final String _nicMacAddress; - private final String _networkUuid; - private final boolean _isL3Network; - private final boolean _isSharedNetwork; - private final String _vpcUuid; - private final String _networkDomainUuid; - private final String _networksAccountUuid; - private final boolean _isDomainRouter; - private final String _domainRouterIp; - private final String _vmInstanceName; - private final String _vmUuid; - private final String _vmUserName; - private final String _vmUserDomainName; - private final boolean _useStaticIp; - private final String _staticIp; - private final String _staticNatIpUuid; - private final String _staticNatIpAddress; - private final boolean _isStaticNatIpAllocated; - private final boolean _isOneToOneNat; - private final String _staticNatVlanUuid; - private final String _staticNatVlanGateway; - private final String _staticNatVlanNetmask; + private final VspNetwork _network; + private final VspVm _vm; + private final VspNic _nic; + private final VspStaticNat _staticNat; - private ReserveVmInterfaceVspCommand(String nicUuid, String nicMacAddress, String networkUuid, boolean isL3Network, boolean isSharedNetwork, String vpcUuid, String networkDomainUuid, - String networksAccountUuid, boolean isDomainRouter, String domainRouterIp, String vmInstanceName, String vmUuid, String vmUserName, String vmUserDomainName, - boolean useStaticIp, String staticIp, String staticNatIpUuid, String staticNatIpAddress, boolean isStaticNatIpAllocated, boolean isOneToOneNat, String staticNatVlanUuid, - String staticNatVlanGateway, String staticNatVlanNetmask) { + public ReserveVmInterfaceVspCommand(VspNetwork network, VspVm vm, VspNic nic, VspStaticNat staticNat) { super(); - this._nicUuid = nicUuid; - this._nicMacAddress = nicMacAddress; - this._networkUuid = networkUuid; - this._isL3Network = isL3Network; - this._isSharedNetwork = isSharedNetwork; - this._vpcUuid = vpcUuid; - this._networkDomainUuid = networkDomainUuid; - this._networksAccountUuid = networksAccountUuid; - this._isDomainRouter = isDomainRouter; - this._domainRouterIp = domainRouterIp; - this._vmInstanceName = vmInstanceName; - this._vmUuid = vmUuid; - this._vmUserName = vmUserName; - this._vmUserDomainName = vmUserDomainName; - this._useStaticIp = useStaticIp; - this._staticIp = staticIp; - this._staticNatIpUuid = staticNatIpUuid; - this._staticNatIpAddress = staticNatIpAddress; - this._isStaticNatIpAllocated = isStaticNatIpAllocated; - this._isOneToOneNat = isOneToOneNat; - this._staticNatVlanUuid = staticNatVlanUuid; - this._staticNatVlanGateway = staticNatVlanGateway; - this._staticNatVlanNetmask = staticNatVlanNetmask; + this._network = network; + this._vm = vm; + this._nic = nic; + this._staticNat = staticNat; } - public String getNicUuid() { - return _nicUuid; + public VspNetwork getNetwork() { + return _network; } - public String getNicMacAddress() { - return _nicMacAddress; + public VspVm getVm() { + return _vm; } - public String getNetworkUuid() { - return _networkUuid; + public VspNic getNic() { + return _nic; } - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isSharedNetwork() { - return _isSharedNetwork; - } - - public String getVpcUuid() { - return _vpcUuid; - } - - public String getNetworkDomainUuid() { - return _networkDomainUuid; - } - - public String getNetworksAccountUuid() { - return _networksAccountUuid; - } - - public boolean isDomainRouter() { - return _isDomainRouter; - } - - public String getDomainRouterIp() { - return _domainRouterIp; - } - - public String getVmInstanceName() { - return _vmInstanceName; - } - - public String getVmUuid() { - return _vmUuid; - } - - public String getVmUserName() { - return _vmUserName; - } - - public String getVmUserDomainName() { - return _vmUserDomainName; - } - - public boolean useStaticIp() { - return _useStaticIp; - } - - public String getStaticIp() { - return _staticIp; - } - - public String getStaticNatIpUuid() { - return _staticNatIpUuid; - } - - public String getStaticNatIpAddress() { - return _staticNatIpAddress; - } - - public boolean isStaticNatIpAllocated() { - return _isStaticNatIpAllocated; - } - - public boolean isOneToOneNat() { - return _isOneToOneNat; - } - - public String getStaticNatVlanUuid() { - return _staticNatVlanUuid; - } - - public String getStaticNatVlanGateway() { - return _staticNatVlanGateway; - } - - public String getStaticNatVlanNetmask() { - return _staticNatVlanNetmask; - } - - public static class Builder implements CmdBuilder { - private String _nicUuid; - private String _nicMacAddress; - private String _networkUuid; - private boolean _isL3Network; - private boolean _isSharedNetwork; - private String _vpcUuid; - private String _networkDomainUuid; - private String _networksAccountUuid; - private boolean _isDomainRouter; - private String _domainRouterIp; - private String _vmInstanceName; - private String _vmUuid; - private String _vmUserName; - private String _vmUserDomainName; - private boolean _useStaticIp; - private String _staticIp; - private String _staticNatIpUuid; - private String _staticNatIpAddress; - private boolean _isStaticNatIpAllocated; - private boolean _isOneToOneNat; - private String _staticNatVlanUuid; - private String _staticNatVlanGateway; - private String _staticNatVlanNetmask; - - public Builder nicUuid(String nicUuid) { - this._nicUuid = nicUuid; - return this; - } - - public Builder nicMacAddress(String nicMacAddress) { - this._nicMacAddress = nicMacAddress; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isSharedNetwork(boolean isSharedNetwork) { - this._isSharedNetwork = isSharedNetwork; - return this; - } - - public Builder vpcUuid(String vpcUuid) { - this._vpcUuid = vpcUuid; - return this; - } - - public Builder networkDomainUuid(String networkDomainUuid) { - this._networkDomainUuid = networkDomainUuid; - return this; - } - - public Builder networksAccountUuid(String networksAccountUuid) { - this._networksAccountUuid = networksAccountUuid; - return this; - } - - public Builder isDomainRouter(boolean isDomainRouter) { - this._isDomainRouter = isDomainRouter; - return this; - } - - public Builder domainRouterIp(String domainRouterIp) { - this._domainRouterIp = domainRouterIp; - return this; - } - - public Builder vmInstanceName(String vmInstanceName) { - this._vmInstanceName = vmInstanceName; - return this; - } - - public Builder vmUuid(String vmUuid) { - this._vmUuid = vmUuid; - return this; - } - - public Builder vmUserName(String vmUserName) { - this._vmUserName = vmUserName; - return this; - } - - public Builder vmUserDomainName(String vmUserDomainName) { - this._vmUserDomainName = vmUserDomainName; - return this; - } - - public Builder useStaticIp(boolean useStaticIp) { - this._useStaticIp = useStaticIp; - return this; - } - - public Builder staticIp(String staticIp) { - this._staticIp = staticIp; - return this; - } - - public Builder staticNatIpUuid(String staticNatIpUuid) { - this._staticNatIpUuid = staticNatIpUuid; - return this; - } - - public Builder staticNatIpAddress(String staticNatIpAddress) { - this._staticNatIpAddress = staticNatIpAddress; - return this; - } - - public Builder isStaticNatIpAllocated(boolean isStaticNatIpAllocated) { - this._isStaticNatIpAllocated = isStaticNatIpAllocated; - return this; - } - - public Builder isOneToOneNat(boolean isOneToOneNat) { - this._isOneToOneNat = isOneToOneNat; - return this; - } - - public Builder staticNatVlanUuid(String staticNatVlanUuid) { - this._staticNatVlanUuid = staticNatVlanUuid; - return this; - } - - public Builder staticNatVlanGateway(String staticNatVlanGateway) { - this._staticNatVlanGateway = staticNatVlanGateway; - return this; - } - - public Builder staticNatVlanNetmask(String staticNatVlanNetmask) { - this._staticNatVlanNetmask = staticNatVlanNetmask; - return this; - } - - @Override - public ReserveVmInterfaceVspCommand build() { - return new ReserveVmInterfaceVspCommand(_nicUuid, _nicMacAddress, _networkUuid, _isL3Network, _isSharedNetwork, _vpcUuid, _networkDomainUuid, _networksAccountUuid, - _isDomainRouter, _domainRouterIp, _vmInstanceName, _vmUuid, _vmUserName, _vmUserDomainName, _useStaticIp, _staticIp, _staticNatIpUuid, _staticNatIpAddress, - _isStaticNatIpAllocated, _isOneToOneNat, _staticNatVlanUuid, _staticNatVlanGateway, _staticNatVlanNetmask); - } + public VspStaticNat getStaticNat() { + return _staticNat; } @Override @@ -331,40 +69,10 @@ public boolean equals(Object o) { ReserveVmInterfaceVspCommand that = (ReserveVmInterfaceVspCommand) o; - if (_isDomainRouter != that._isDomainRouter) return false; - if (_isL3Network != that._isL3Network) return false; - if (_isOneToOneNat != that._isOneToOneNat) return false; - if (_isSharedNetwork != that._isSharedNetwork) return false; - if (_isStaticNatIpAllocated != that._isStaticNatIpAllocated) return false; - if (_useStaticIp != that._useStaticIp) return false; - if (_domainRouterIp != null ? !_domainRouterIp.equals(that._domainRouterIp) : that._domainRouterIp != null) - return false; - if (_networkDomainUuid != null ? !_networkDomainUuid.equals(that._networkDomainUuid) : that._networkDomainUuid != null) - return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_networksAccountUuid != null ? !_networksAccountUuid.equals(that._networksAccountUuid) : that._networksAccountUuid != null) - return false; - if (_nicMacAddress != null ? !_nicMacAddress.equals(that._nicMacAddress) : that._nicMacAddress != null) - return false; - if (_nicUuid != null ? !_nicUuid.equals(that._nicUuid) : that._nicUuid != null) return false; - if (_staticIp != null ? !_staticIp.equals(that._staticIp) : that._staticIp != null) return false; - if (_staticNatIpAddress != null ? !_staticNatIpAddress.equals(that._staticNatIpAddress) : that._staticNatIpAddress != null) - return false; - if (_staticNatIpUuid != null ? !_staticNatIpUuid.equals(that._staticNatIpUuid) : that._staticNatIpUuid != null) - return false; - if (_staticNatVlanGateway != null ? !_staticNatVlanGateway.equals(that._staticNatVlanGateway) : that._staticNatVlanGateway != null) - return false; - if (_staticNatVlanNetmask != null ? !_staticNatVlanNetmask.equals(that._staticNatVlanNetmask) : that._staticNatVlanNetmask != null) - return false; - if (_staticNatVlanUuid != null ? !_staticNatVlanUuid.equals(that._staticNatVlanUuid) : that._staticNatVlanUuid != null) - return false; - if (_vmInstanceName != null ? !_vmInstanceName.equals(that._vmInstanceName) : that._vmInstanceName != null) - return false; - if (_vmUserDomainName != null ? !_vmUserDomainName.equals(that._vmUserDomainName) : that._vmUserDomainName != null) - return false; - if (_vmUserName != null ? !_vmUserName.equals(that._vmUserName) : that._vmUserName != null) return false; - if (_vmUuid != null ? !_vmUuid.equals(that._vmUuid) : that._vmUuid != null) return false; - if (_vpcUuid != null ? !_vpcUuid.equals(that._vpcUuid) : that._vpcUuid != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; + if (_nic != null ? !_nic.equals(that._nic) : that._nic != null) return false; + if (_staticNat != null ? !_staticNat.equals(that._staticNat) : that._staticNat != null) return false; + if (_vm != null ? !_vm.equals(that._vm) : that._vm != null) return false; return true; } @@ -372,29 +80,10 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_nicUuid != null ? _nicUuid.hashCode() : 0); - result = 31 * result + (_nicMacAddress != null ? _nicMacAddress.hashCode() : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isSharedNetwork ? 1 : 0); - result = 31 * result + (_vpcUuid != null ? _vpcUuid.hashCode() : 0); - result = 31 * result + (_networkDomainUuid != null ? _networkDomainUuid.hashCode() : 0); - result = 31 * result + (_networksAccountUuid != null ? _networksAccountUuid.hashCode() : 0); - result = 31 * result + (_isDomainRouter ? 1 : 0); - result = 31 * result + (_domainRouterIp != null ? _domainRouterIp.hashCode() : 0); - result = 31 * result + (_vmInstanceName != null ? _vmInstanceName.hashCode() : 0); - result = 31 * result + (_vmUuid != null ? _vmUuid.hashCode() : 0); - result = 31 * result + (_vmUserName != null ? _vmUserName.hashCode() : 0); - result = 31 * result + (_vmUserDomainName != null ? _vmUserDomainName.hashCode() : 0); - result = 31 * result + (_useStaticIp ? 1 : 0); - result = 31 * result + (_staticIp != null ? _staticIp.hashCode() : 0); - result = 31 * result + (_staticNatIpUuid != null ? _staticNatIpUuid.hashCode() : 0); - result = 31 * result + (_staticNatIpAddress != null ? _staticNatIpAddress.hashCode() : 0); - result = 31 * result + (_isStaticNatIpAllocated ? 1 : 0); - result = 31 * result + (_isOneToOneNat ? 1 : 0); - result = 31 * result + (_staticNatVlanUuid != null ? _staticNatVlanUuid.hashCode() : 0); - result = 31 * result + (_staticNatVlanGateway != null ? _staticNatVlanGateway.hashCode() : 0); - result = 31 * result + (_staticNatVlanNetmask != null ? _staticNatVlanNetmask.hashCode() : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); + result = 31 * result + (_vm != null ? _vm.hashCode() : 0); + result = 31 * result + (_nic != null ? _nic.hashCode() : 0); + result = 31 * result + (_staticNat != null ? _staticNat.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/TrashNetworkVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/TrashNetworkVspCommand.java index 4a01fdcc3d..b3f8f8e012 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/TrashNetworkVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/guru/TrashNetworkVspCommand.java @@ -19,94 +19,20 @@ package com.cloud.agent.api.guru; -import com.cloud.agent.api.CmdBuilder; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspNetwork; public class TrashNetworkVspCommand extends Command { - private final String _domainUuid; - private final String _networkUuid; - private final boolean _isL3Network; - private final boolean _isSharedNetwork; - private final String _vpcUuid; - private final String _domainTemplateName; + private final VspNetwork _network; - private TrashNetworkVspCommand(String domainUuid, String networkUuid, boolean isL3Network, boolean isSharedNetwork, String vpcUuid, String domainTemplateName) { + public TrashNetworkVspCommand(VspNetwork network) { super(); - this._domainUuid = domainUuid; - this._networkUuid = networkUuid; - this._isL3Network = isL3Network; - this._isSharedNetwork = isSharedNetwork; - this._vpcUuid = vpcUuid; - this._domainTemplateName = domainTemplateName; + this._network = network; } - public String getDomainUuid() { - return _domainUuid; - } - - public String getNetworkUuid() { - return _networkUuid; - } - - public boolean isL3Network() { - return _isL3Network; - } - - public boolean isSharedNetwork() { - return _isSharedNetwork; - } - - public String getVpcUuid() { - return _vpcUuid; - } - - public String getDomainTemplateName() { - return _domainTemplateName; - } - - public static class Builder implements CmdBuilder { - private String _domainUuid; - private String _networkUuid; - private boolean _isL3Network; - private boolean _isSharedNetwork; - private String _vpcUuid; - private String _domainTemplateName; - - public Builder domainUuid(String domainUuid) { - this._domainUuid = domainUuid; - return this; - } - - public Builder networkUuid(String networkUuid) { - this._networkUuid = networkUuid; - return this; - } - - public Builder isL3Network(boolean isL3Network) { - this._isL3Network = isL3Network; - return this; - } - - public Builder isSharedNetwork(boolean isSharedNetwork) { - this._isSharedNetwork = isSharedNetwork; - return this; - } - - public Builder vpcUuid(String vpcUuid) { - this._vpcUuid = vpcUuid; - return this; - } - - public Builder domainTemplateName(String domainTemplateName) { - this._domainTemplateName = domainTemplateName; - return this; - } - - @Override - public TrashNetworkVspCommand build() { - return new TrashNetworkVspCommand(_domainUuid, _networkUuid, _isL3Network, _isSharedNetwork, _vpcUuid, _domainTemplateName); - } + public VspNetwork getNetwork() { + return _network; } @Override @@ -122,13 +48,7 @@ public boolean equals(Object o) { TrashNetworkVspCommand that = (TrashNetworkVspCommand) o; - if (_isL3Network != that._isL3Network) return false; - if (_isSharedNetwork != that._isSharedNetwork) return false; - if (_domainTemplateName != null ? !_domainTemplateName.equals(that._domainTemplateName) : that._domainTemplateName != null) - return false; - if (_domainUuid != null ? !_domainUuid.equals(that._domainUuid) : that._domainUuid != null) return false; - if (_networkUuid != null ? !_networkUuid.equals(that._networkUuid) : that._networkUuid != null) return false; - if (_vpcUuid != null ? !_vpcUuid.equals(that._vpcUuid) : that._vpcUuid != null) return false; + if (_network != null ? !_network.equals(that._network) : that._network != null) return false; return true; } @@ -136,12 +56,7 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_domainUuid != null ? _domainUuid.hashCode() : 0); - result = 31 * result + (_networkUuid != null ? _networkUuid.hashCode() : 0); - result = 31 * result + (_isL3Network ? 1 : 0); - result = 31 * result + (_isSharedNetwork ? 1 : 0); - result = 31 * result + (_vpcUuid != null ? _vpcUuid.hashCode() : 0); - result = 31 * result + (_domainTemplateName != null ? _domainTemplateName.hashCode() : 0); + result = 31 * result + (_network != null ? _network.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsAnswer.java similarity index 56% rename from plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncVspCommand.java rename to plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsAnswer.java index cfcfb870cd..c02eef1699 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncVspCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsAnswer.java @@ -17,38 +17,37 @@ // under the License. // -package com.cloud.agent.api.sync; +package com.cloud.agent.api.manager; -import com.cloud.agent.api.Command; +import com.cloud.agent.api.Answer; +import net.nuage.vsp.acs.client.api.model.VspApiDefaults; -public class SyncVspCommand extends Command { +public class GetApiDefaultsAnswer extends Answer { - private final String _nuageVspEntity; + private VspApiDefaults _apiDefaults; - public SyncVspCommand(String nuageVspEntity) { - super(); - this._nuageVspEntity = nuageVspEntity; + public GetApiDefaultsAnswer(GetApiDefaultsCommand cmd, VspApiDefaults defaults) { + super(cmd); + this._apiDefaults = defaults; } - @Override - public boolean executeInSequence() { - return false; + public GetApiDefaultsAnswer(GetApiDefaultsCommand cmd, Exception e) { + super(cmd, e); } - public String getNuageVspEntity() { - return _nuageVspEntity; + public VspApiDefaults getApiDefaults() { + return _apiDefaults; } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof SyncVspCommand)) return false; + if (!(o instanceof GetApiDefaultsAnswer)) return false; if (!super.equals(o)) return false; - SyncVspCommand that = (SyncVspCommand) o; + GetApiDefaultsAnswer that = (GetApiDefaultsAnswer) o; - if (_nuageVspEntity != null ? !_nuageVspEntity.equals(that._nuageVspEntity) : that._nuageVspEntity != null) - return false; + if (_apiDefaults != null ? !_apiDefaults.equals(that._apiDefaults) : that._apiDefaults != null) return false; return true; } @@ -56,7 +55,7 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_nuageVspEntity != null ? _nuageVspEntity.hashCode() : 0); + result = 31 * result + (_apiDefaults != null ? _apiDefaults.hashCode() : 0); return result; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsCommand.java similarity index 92% rename from plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsCommand.java rename to plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsCommand.java index 2ffbe04ea4..3fca16a242 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsCommand.java @@ -25,9 +25,9 @@ * The super class implementations for equals and hashCode are acceptable because this class does not track any state * in addition to the super class. */ -public class GetClientDefaultsCommand extends Command { +public class GetApiDefaultsCommand extends Command { - public GetClientDefaultsCommand() { + public GetApiDefaultsCommand() { super(); } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsAnswer.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsAnswer.java deleted file mode 100644 index f748e1cbb4..0000000000 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsAnswer.java +++ /dev/null @@ -1,81 +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.agent.api.manager; - -import com.cloud.agent.api.Answer; - -import java.util.Map; - -public class GetClientDefaultsAnswer extends Answer { - - private String _currentApiVersion; - private Integer _apiRetryCount; - private Long _apiRetryInterval; - - public GetClientDefaultsAnswer(GetClientDefaultsCommand cmd, Map defaults) { - super(cmd); - this._currentApiVersion = (String) defaults.get("CURRENT_API_VERSION"); - this._apiRetryCount = (Integer) defaults.get("DEFAULT_API_RETRY_COUNT"); - this._apiRetryInterval = (Long) defaults.get("DEFAULT_API_RETRY_INTERVAL"); - } - - public GetClientDefaultsAnswer(GetClientDefaultsCommand cmd, Exception e) { - super(cmd, e); - } - - public String getCurrentApiVersion() { - return _currentApiVersion; - } - - public Integer getApiRetryCount() { - return _apiRetryCount; - } - - public Long getApiRetryInterval() { - return _apiRetryInterval; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof GetClientDefaultsAnswer)) return false; - if (!super.equals(o)) return false; - - GetClientDefaultsAnswer that = (GetClientDefaultsAnswer) o; - - if (_apiRetryCount != null ? !_apiRetryCount.equals(that._apiRetryCount) : that._apiRetryCount != null) - return false; - if (_apiRetryInterval != null ? !_apiRetryInterval.equals(that._apiRetryInterval) : that._apiRetryInterval != null) - return false; - if (_currentApiVersion != null ? !_currentApiVersion.equals(that._currentApiVersion) : that._currentApiVersion != null) - return false; - - return true; - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (_currentApiVersion != null ? _currentApiVersion.hashCode() : 0); - result = 31 * result + (_apiRetryCount != null ? _apiRetryCount.hashCode() : 0); - result = 31 * result + (_apiRetryInterval != null ? _apiRetryInterval.hashCode() : 0); - return result; - } -} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncDomainCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncDomainCommand.java index 7ae474f2d1..90a30a4b3a 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncDomainCommand.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncDomainCommand.java @@ -20,34 +20,23 @@ package com.cloud.agent.api.sync; import com.cloud.agent.api.Command; +import net.nuage.vsp.acs.client.api.model.VspDomain; public class SyncDomainCommand extends Command { - private final String _domainUuid; - private final String _domainName; - private final String _domainPath; + private final VspDomain _domain; private final boolean _toAdd; private final boolean _toRemove; - public SyncDomainCommand(String domainUuid, String domainName, String domainPath, boolean toAdd, boolean toRemove) { + public SyncDomainCommand(VspDomain domain, boolean toAdd, boolean toRemove) { super(); - this._domainUuid = domainUuid; - this._domainName = domainName; - this._domainPath = domainPath; + this._domain = domain; this._toAdd = toAdd; this._toRemove = toRemove; } - public String getDomainUuid() { - return _domainUuid; - } - - public String getDomainName() { - return _domainName; - } - - public String getDomainPath() { - return _domainPath; + public VspDomain getDomain() { + return _domain; } public boolean isToAdd() { @@ -73,9 +62,7 @@ public boolean equals(Object o) { if (_toAdd != that._toAdd) return false; if (_toRemove != that._toRemove) return false; - if (_domainName != null ? !_domainName.equals(that._domainName) : that._domainName != null) return false; - if (_domainPath != null ? !_domainPath.equals(that._domainPath) : that._domainPath != null) return false; - if (_domainUuid != null ? !_domainUuid.equals(that._domainUuid) : that._domainUuid != null) return false; + if (_domain != null ? !_domain.equals(that._domain) : that._domain != null) return false; return true; } @@ -83,9 +70,7 @@ public boolean equals(Object o) { @Override public int hashCode() { int result = super.hashCode(); - result = 31 * result + (_domainUuid != null ? _domainUuid.hashCode() : 0); - result = 31 * result + (_domainName != null ? _domainName.hashCode() : 0); - result = 31 * result + (_domainPath != null ? _domainPath.hashCode() : 0); + result = 31 * result + (_domain != null ? _domain.hashCode() : 0); result = 31 * result + (_toAdd ? 1 : 0); result = 31 * result + (_toRemove ? 1 : 0); return result; diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/AddNuageVspDeviceCmd.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/AddNuageVspDeviceCmd.java index 7590901a5f..62a15ea5a7 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/AddNuageVspDeviceCmd.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/AddNuageVspDeviceCmd.java @@ -29,6 +29,7 @@ import com.cloud.network.NuageVspDeviceVO; import com.cloud.network.manager.NuageVspManager; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -41,9 +42,12 @@ import javax.inject.Inject; -@APICommand(name = "addNuageVspDevice", responseObject = NuageVspDeviceResponse.class, description = "Adds a Nuage VSP device", since = "4.5") +@APICommand(name = AddNuageVspDeviceCmd.APINAME, description = "Adds a Nuage VSP device", responseObject = NuageVspDeviceResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.5", + authorized = {RoleType.Admin}) public class AddNuageVspDeviceCmd extends BaseAsyncCmd { - private static final String s_name = "addnuagevspdeviceresponse"; + public static final String APINAME = "addNuageVspDevice"; @Inject NuageVspManager _nuageVspManager; @@ -68,14 +72,14 @@ public class AddNuageVspDeviceCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, required = true, description = "the password of CMS user in Nuage VSD") private String password; - @Parameter(name = VspConstants.NUAGE_VSP_API_VERSION, type = CommandType.STRING, required = true, description = "the version of the API to use to communicate to Nuage VSD") + @Parameter(name = VspConstants.NUAGE_VSP_API_VERSION, type = CommandType.STRING, description = "the version of the API to use to communicate to Nuage VSD") private String apiVersion; - @Parameter(name = VspConstants.NUAGE_VSP_API_RETRY_COUNT, type = CommandType.INTEGER, required = true, description = "the number of retries on failure to communicate to Nuage VSD") - private int apiRetryCount; + @Parameter(name = VspConstants.NUAGE_VSP_API_RETRY_COUNT, type = CommandType.INTEGER, description = "the number of retries on failure to communicate to Nuage VSD") + private Integer apiRetryCount; - @Parameter(name = VspConstants.NUAGE_VSP_API_RETRY_INTERVAL, type = CommandType.LONG, required = true, description = "the time to wait after failure before retrying to communicate to Nuage VSD") - private long apiRetryInterval; + @Parameter(name = VspConstants.NUAGE_VSP_API_RETRY_INTERVAL, type = CommandType.LONG, description = "the time to wait after failure before retrying to communicate to Nuage VSD") + private Long apiRetryInterval; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -117,7 +121,7 @@ public void setApiVersion(String apiVersion) { this.apiVersion = apiVersion; } - public int getApiRetryCount() { + public Integer getApiRetryCount() { return apiRetryCount; } @@ -125,7 +129,7 @@ public void setApiRetryCount(int apiRetryCount) { this.apiRetryCount = apiRetryCount; } - public long getApiRetryInterval() { + public Long getApiRetryInterval() { return apiRetryInterval; } @@ -158,7 +162,7 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE @Override public String getCommandName() { - return s_name; + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; } @Override diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/DeleteNuageVspDeviceCmd.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/DeleteNuageVspDeviceCmd.java index 971f9c93f4..05a17d6734 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/DeleteNuageVspDeviceCmd.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/DeleteNuageVspDeviceCmd.java @@ -28,9 +28,11 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.manager.NuageVspManager; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.SuccessResponse; @@ -38,9 +40,13 @@ import javax.inject.Inject; -@APICommand(name = "deleteNuageVspDevice", responseObject = SuccessResponse.class, description = "delete a nuage vsp device", since = "4.5") +@APICommand(name = DeleteNuageVspDeviceCmd.APINAME, description = "delete a nuage vsp device", responseObject = SuccessResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.5", + authorized = {RoleType.Admin}) public class DeleteNuageVspDeviceCmd extends BaseAsyncCmd { - private static final String s_name = "deletenuagevspdeviceresponse"; + public static final String APINAME = "deleteNuageVspDevice"; + @Inject NuageVspManager _nuageVspManager; @@ -83,7 +89,7 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE @Override public String getCommandName() { - return s_name; + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; } @Override diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/IssueNuageVspResourceRequestCmd.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/IssueNuageVspResourceRequestCmd.java deleted file mode 100644 index 559b30d40a..0000000000 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/IssueNuageVspResourceRequestCmd.java +++ /dev/null @@ -1,213 +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.api.commands; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.VspResourceAnswer; -import com.cloud.agent.api.VspResourceCommand; -import com.cloud.api.response.NuageVspResourceResponse; -import com.cloud.domain.dao.DomainDao; -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.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.network.NuageVspDeviceVO; -import com.cloud.network.dao.NuageVspDao; -import com.cloud.offering.NetworkOffering; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.ServerApiException; -import org.apache.cloudstack.api.response.NetworkOfferingResponse; -import org.apache.cloudstack.api.response.PhysicalNetworkResponse; -import org.apache.cloudstack.api.response.ZoneResponse; -import org.apache.cloudstack.context.CallContext; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; - -import javax.inject.Inject; -import java.util.List; - -@APICommand(name = "issueNuageVspResourceRequest", responseObject = NuageVspResourceResponse.class, description = "Issues a Nuage VSP REST API resource request", since = "4.5") -public class IssueNuageVspResourceRequestCmd extends BaseCmd { - private static final Logger s_logger = Logger.getLogger(IssueNuageVspResourceRequestCmd.class.getName()); - private static final String s_name = "nuagevspresourceresponse"; - - @Inject - protected AccountManager _accountMgr; - @Inject - protected DomainDao _domainDao; - @Inject - protected NuageVspDao _nuageConfigDao; - @Inject - HostDao _hostDao; - @Inject - AgentManager _agentMgr; - - ///////////////////////////////////////////////////// - //////////////// API parameters ///////////////////// - ///////////////////////////////////////////////////// - - @Parameter(name = ApiConstants.NETWORK_OFFERING_ID, type = CommandType.UUID, entityType = NetworkOfferingResponse.class, required = true, description = "the network offering id") - private Long networkOfferingId; - - @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, description = "the Zone ID for the network") - private Long zoneId; - - @Parameter(name = ApiConstants.PHYSICAL_NETWORK_ID, type = CommandType.UUID, entityType = PhysicalNetworkResponse.class, description = "the ID of the physical network in to which Nuage VSP Controller is added") - private Long physicalNetworkId; - - @Parameter(name = VspConstants.NUAGE_VSP_API_METHOD, type = CommandType.STRING, required = true, description = "the Nuage VSP REST API method type") - private String method; - - @Parameter(name = VspConstants.NUAGE_VSP_API_RESOURCE, type = CommandType.STRING, required = true, description = "the resource in Nuage VSP") - private String resource; - - @Parameter(name = VspConstants.NUAGE_VSP_API_RESOURCE_ID, type = CommandType.STRING, description = "the ID of the resource in Nuage VSP") - private String resourceId; - - @Parameter(name = VspConstants.NUAGE_VSP_API_CHILD_RESOURCE, type = CommandType.STRING, description = "the child resource in Nuage VSP") - private String childResource; - - @Parameter(name = VspConstants.NUAGE_VSP_API_RESOURCE_FILTER, type = CommandType.STRING, description = "the resource filter in Nuage VSP") - private String resourceFilter; - - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// - - public Long getNetworkOfferingId() { - return networkOfferingId; - } - - public Long getZoneId() { - Long physicalNetworkId = getPhysicalNetworkId(); - - if (physicalNetworkId == null && zoneId == null) { - throw new InvalidParameterValueException("Zone id is required"); - } - - return zoneId; - } - - public Long getPhysicalNetworkId() { - if (physicalNetworkId != null) { - return physicalNetworkId; - } - - NetworkOffering offering = _entityMgr.findById(NetworkOffering.class, networkOfferingId); - if (offering == null) { - throw new InvalidParameterValueException("Unable to find network offering by id " + networkOfferingId); - } - - if (zoneId == null) { - throw new InvalidParameterValueException("ZoneId is required as physicalNetworkId is null"); - } - return _networkService.findPhysicalNetworkId(zoneId, offering.getTags(), offering.getTrafficType()); - } - - public String getMethod() { - return method; - } - - public void setMethod(String method) { - this.method = method; - } - - public String getResource() { - return resource; - } - - public void setResource(String resource) { - this.resource = resource; - } - - public String getResourceId() { - return resourceId; - } - - public void setResourceId(String resourceId) { - this.resourceId = resourceId; - } - - public String getChildResource() { - return childResource; - } - - public void setChildResource(String childResource) { - this.childResource = childResource; - } - - public String getResourceFilter() { - return resourceFilter; - } - - public void setResourceFilter(String resourceFilter) { - this.resourceFilter = resourceFilter; - } - - @Override - public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { - long accountId = CallContext.current().getCallingAccount().getAccountId(); - Account account = _accountMgr.getAccount(accountId); - - List nuageVspDevices = _nuageConfigDao.listByPhysicalNetwork(getPhysicalNetworkId()); - if (nuageVspDevices != null && (!nuageVspDevices.isEmpty())) { - NuageVspDeviceVO config = nuageVspDevices.iterator().next(); - HostVO nuageVspHost = _hostDao.findById(config.getHostId()); - VspResourceCommand cmd = new VspResourceCommand(method, resource, resourceId, childResource, null, resourceFilter, null, null); - VspResourceAnswer answer = (VspResourceAnswer)_agentMgr.easySend(nuageVspHost.getId(), cmd); - if (answer == null || !answer.getResult()) { - s_logger.error("VspResourceCommand failed"); - if ((null != answer) && (null != answer.getDetails())) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, answer.getDetails()); - } - } else { - NuageVspResourceResponse response = new NuageVspResourceResponse(); - response.setResourceInfo(StringUtils.isBlank(answer.getResourceInfo()) ? "" : answer.getResourceInfo()); - response.setObjectName("nuagevspresource"); - response.setResponseName(getCommandName()); - this.setResponseObject(response); - } - } else { - String errorMessage = "No Nuage VSP Controller configured on physical network " + getPhysicalNetworkId(); - s_logger.error(errorMessage); - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMessage); - } - } - - @Override - public String getCommandName() { - return s_name; - } - - @Override - public long getEntityOwnerId() { - return CallContext.current().getCallingAccount().getId(); - } - -} \ No newline at end of file diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/ListNuageVspDevicesCmd.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/ListNuageVspDevicesCmd.java index 2d08e12e3d..d9f80e7856 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/ListNuageVspDevicesCmd.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/ListNuageVspDevicesCmd.java @@ -28,9 +28,11 @@ import com.cloud.network.NuageVspDeviceVO; import com.cloud.network.manager.NuageVspManager; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; @@ -41,9 +43,13 @@ import java.util.ArrayList; import java.util.List; -@APICommand(name = "listNuageVspDevices", responseObject = NuageVspDeviceResponse.class, description = "Lists Nuage VSP devices", since = "4.5") +@APICommand(name = ListNuageVspDevicesCmd.APINAME, description = "Lists Nuage VSP devices", responseObject = NuageVspDeviceResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.5", + authorized = {RoleType.Admin}) public class ListNuageVspDevicesCmd extends BaseListCmd { - private static final String s_name = "listnuagevspdeviceresponse"; + public static final String APINAME = "listNuageVspDevices"; + @Inject NuageVspManager _nuageVspManager; @@ -99,7 +105,7 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE @Override public String getCommandName() { - return s_name; + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/UpdateNuageVspDeviceCmd.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/UpdateNuageVspDeviceCmd.java index d235b2b595..4197bd65a7 100755 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/UpdateNuageVspDeviceCmd.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/UpdateNuageVspDeviceCmd.java @@ -29,6 +29,7 @@ import com.cloud.network.NuageVspDeviceVO; import com.cloud.network.manager.NuageVspManager; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -38,14 +39,15 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import org.apache.cloudstack.context.CallContext; -import org.apache.log4j.Logger; import javax.inject.Inject; -@APICommand(name = "updateNuageVspDevice", responseObject = NuageVspDeviceResponse.class, description = "Update a Nuage VSP device", since = "4.6") +@APICommand(name = UpdateNuageVspDeviceCmd.APINAME, description = "Update a Nuage VSP device", responseObject = NuageVspDeviceResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + since = "4.6", + authorized = {RoleType.Admin}) public class UpdateNuageVspDeviceCmd extends BaseAsyncCmd { - private static final Logger s_logger = Logger.getLogger(UpdateNuageVspDeviceCmd.class); - private static final String s_name = "updatenuagevspdeviceresponse"; + public static final String APINAME = "updateNuageVspDevice"; @Inject NuageVspManager _nuageVspManager; @@ -160,7 +162,7 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE @Override public String getCommandName() { - return s_name; + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; } @Override diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/VspConstants.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/VspConstants.java index 237289064a..7abcdfb8d0 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/VspConstants.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/commands/VspConstants.java @@ -32,4 +32,5 @@ public class VspConstants { public static final String NUAGE_VSP_API_CHILD_RESOURCE = "childresource"; public static final String NUAGE_VSP_API_RESOURCE_FILTER = "resourcefilter"; public static final String NUAGE_VSP_API_RESOURCE_INFO = "resourceinfo"; + public static final String NUAGE_VSP_CMS_ID = "cmsid"; } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/api/response/NuageVspDeviceResponse.java b/plugins/network-elements/nuage-vsp/src/com/cloud/api/response/NuageVspDeviceResponse.java index 136a465e79..346e28823f 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/api/response/NuageVspDeviceResponse.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/api/response/NuageVspDeviceResponse.java @@ -65,6 +65,10 @@ public class NuageVspDeviceResponse extends BaseResponse { @Param(description = "the time to wait after failure before retrying to communicate to Nuage VSD") private long apiRetryInterval; + @SerializedName(VspConstants.NUAGE_VSP_CMS_ID) + @Param(description = "the CMS ID generated by the Nuage VSD") + private String cmsId; + public void setId(String vspDetailsId) { this.id = vspDetailsId; } @@ -101,4 +105,7 @@ public void setApiRetryInterval(long apiRetryInterval) { this.apiRetryInterval = apiRetryInterval; } + public void setCmsId(String cmsId) { + this.cmsId = cmsId; + } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java index cb0d698c2b..1f36ae0c3d 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/element/NuageVspElement.java @@ -59,6 +59,7 @@ import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.manager.NuageVspManager; +import com.cloud.network.manager.NuageVspManagerImpl; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.FirewallRuleType; import com.cloud.network.rules.FirewallRuleVO; @@ -69,30 +70,40 @@ import com.cloud.network.vpc.PrivateGateway; import com.cloud.network.vpc.StaticRouteProfile; import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcOfferingServiceMapVO; import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; import com.cloud.offering.NetworkOffering; -import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; -import com.cloud.util.NuageVspUtil; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.DomainRouterVO; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; import com.google.common.base.Function; import com.google.common.collect.Lists; +import com.cloud.util.NuageVspEntityBuilder; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; import org.apache.cloudstack.api.InternalIdentity; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.network.ExternalNetworkDeviceManager; +import org.apache.cloudstack.resourcedetail.VpcDetailVO; +import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; +import javax.annotation.Nullable; import javax.inject.Inject; import javax.naming.ConfigurationException; import java.util.ArrayList; @@ -123,9 +134,9 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider @Inject NetworkDao _networkDao; @Inject - protected DomainDao _domainDao; + DomainDao _domainDao; @Inject - protected DataCenterDao _dcDao; + DataCenterDao _dcDao; @Inject IPAddressDao _ipAddressDao; @Inject @@ -135,6 +146,8 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider @Inject VpcDao _vpcDao; @Inject + VpcOfferingServiceMapDao _vpcOfferingSrvcDao; + @Inject NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao; @Inject AgentManager _agentMgr; @@ -152,6 +165,12 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider PhysicalNetworkDao _physicalNetworkDao; @Inject NetworkACLItemDao _networkACLItemDao; + @Inject + NuageVspEntityBuilder _nuageVspEntityBuilder; + @Inject + VpcDetailsDao _vpcDetailsDao; + @Inject + DomainRouterDao _routerDao; @Override public boolean applyIps(Network network, List ipAddress, Set service) throws ResourceUnavailableException { @@ -237,53 +256,21 @@ public boolean implement(Network network, NetworkOffering offering, DeployDestin return false; } - boolean egressDefaultPolicy = offering.getEgressDefaultPolicy(); - Domain networkDomain = _domainDao.findById(network.getDomainId()); - boolean isFirewallServiceSupported = _networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Service.Firewall); - List dnsServers = _nuageVspManager.getDnsDetails(network); - boolean isL2Network = false, isL3Network = false, isShared = false; - String subnetUuid = network.getUuid(); - if (offering.getGuestType() == Network.GuestType.Shared) { - isShared = true; - subnetUuid = networkDomain.getUuid(); - } else if (_ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offering.getId(), Service.SourceNat) - || _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offering.getId(), Service.StaticNat) - || _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offering.getId(), Service.Connectivity)) { - isL3Network = true; - } else { - isL2Network = true; - } - - String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configDao, network, offering); - List> ingressFirewallRules = getFirewallRulesToApply(network.getId(), FirewallRule.TrafficType.Ingress, egressDefaultPolicy); - List> egressFirewallRules = getFirewallRulesToApply(network.getId(), FirewallRule.TrafficType.Egress, egressDefaultPolicy); + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false); + List dnsServers = _nuageVspManager.getDnsDetails(network); + List ingressFirewallRules = getFirewallRulesToApply(network, FirewallRule.TrafficType.Ingress); + List egressFirewallRules = getFirewallRulesToApply(network, FirewallRule.TrafficType.Egress); List ips = _ipAddressDao.listStaticNatPublicIps(network.getId()); - List acsFipUuid = new ArrayList(); + List floatingIpUuids = new ArrayList(); for (IPAddressVO ip : ips) { - acsFipUuid.add(ip.getUuid()); + floatingIpUuids.add(ip.getUuid()); } HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); - ImplementVspCommand.Builder cmdBuilder = new ImplementVspCommand.Builder() - .networkId(network.getId()) - .networkDomainUuid(networkDomain.getUuid()) - .networkUuid(network.getUuid()) - .networkName(network.getName()) - .vpcOrSubnetUuid(subnetUuid) - .isL2Network(isL2Network) - .isL3Network(isL3Network) - .isVpc(false) - .isShared(isShared) - .domainTemplateName(preConfiguredDomainTemplateName) - .isFirewallServiceSupported(isFirewallServiceSupported) - .dnsServers(dnsServers) - .ingressFirewallRules(ingressFirewallRules) - .egressFirewallRules(egressFirewallRules) - .acsFipUuid(acsFipUuid) - .egressDefaultPolicy(egressDefaultPolicy); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + ImplementVspCommand cmd = new ImplementVspCommand(vspNetwork, dnsServers, ingressFirewallRules, egressFirewallRules, floatingIpUuids); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ImplementVspCommand for network " + network.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); if ((null != answer) && (null != answer.getDetails())) { @@ -297,23 +284,21 @@ public boolean implement(Network network, NetworkOffering offering, DeployDestin private boolean applyACLRulesForVpc(Network network, NetworkOffering offering) throws ResourceUnavailableException { List rules = _networkACLItemDao.listByACL(network.getNetworkACLId()); if (_networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Network.Service.NetworkACL)) { - applyACLRules(network, rules, true, null, false); + applyACLRules(network, rules, true, false); } return true; } - private List> getFirewallRulesToApply(long networkId, FirewallRule.TrafficType trafficType, final boolean egressDefaultPolicy) { - List firewallRulesToApply = _firewallRulesDao.listByNetworkPurposeTrafficType(networkId, FirewallRule.Purpose.Firewall, trafficType); + private List getFirewallRulesToApply(final Network network, FirewallRule.TrafficType trafficType) { + List firewallRulesToApply = _firewallRulesDao.listByNetworkPurposeTrafficType(network.getId(), FirewallRule.Purpose.Firewall, trafficType); + List vspAclRulesToApply = Lists.newArrayListWithExpectedSize(firewallRulesToApply.size()); + for (FirewallRuleVO rule : firewallRulesToApply) { - // load cidrs if any rule.setSourceCidrList(_firewallRulesCidrsDao.getSourceCidrs(rule.getId())); + VspAclRule vspAclRule = _nuageVspEntityBuilder.buildVspAclRule(rule, network); + vspAclRulesToApply.add(vspAclRule); } - return Lists.transform(firewallRulesToApply, new Function>() { - @Override - public Map apply(FirewallRuleVO firewallRuleVO) { - return getACLRuleDetails(firewallRuleVO, egressDefaultPolicy); - } - }); + return vspAclRulesToApply; } @Override @@ -426,6 +411,16 @@ protected boolean canHandle(Network network, Service service) { } } + if (network.getVpcId() != null) { + NetworkOffering networkOffering = _ntwkOfferingDao.findById(network.getNetworkOfferingId()); + if (!networkOffering.getIsPersistent()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("NuageVsp can't handle VPC tiers which use a network offering which are not persistent"); + } + return false; + } + } + return true; } @@ -448,48 +443,19 @@ public boolean removeDhcpSupportForSubnet(Network network) throws ResourceUnavai @Override public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { - //Check if the network is associated to a VPC - Long vpcId = config.getVpcId(); - String vpcOrSubnetUuid = null; - if (vpcId != null) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcOrSubnetUuid = vpcObj.getUuid(); - } else { - vpcOrSubnetUuid = config.getUuid(); - } - Domain networkDomain = _domainDao.findById(config.getDomainId()); - - long networkOfferingId = _ntwkOfferingDao.findById(config.getNetworkOfferingId()).getId(); - boolean isL3Network = isL3Network(networkOfferingId); - - List> sourceNatDetails = new ArrayList>(); + List vspStaticNatDetails = new ArrayList(); for (StaticNat staticNat : rules) { - Map sourceNatDetail = new HashMap(); IPAddressVO sourceNatIp = _ipAddressDao.findById(staticNat.getSourceIpAddressId()); - VlanVO sourceNatVan = _vlanDao.findById(sourceNatIp.getVlanId()); + VlanVO sourceNatVlan = _vlanDao.findById(sourceNatIp.getVlanId()); NicVO nicVO = _nicDao.findByIp4AddressAndNetworkId(staticNat.getDestIpAddress(), staticNat.getNetworkId()); - //Just get all the information about the sourceNat which will be used by NuageVsp - //client to process the request - sourceNatDetail.put("sourceNatIpUuid", sourceNatIp.getUuid()); - sourceNatDetail.put("sourceNatIpAddress", sourceNatIp.getAddress().addr()); - sourceNatDetail.put("nicUuid", nicVO == null ? null : nicVO.getUuid()); - sourceNatDetail.put("nicMacAddress", nicVO == null ? null : nicVO.getMacAddress()); - sourceNatDetail.put("isRevoke", staticNat.isForRevoke()); - sourceNatDetail.put("sourceNatVlanUuid", sourceNatVan.getUuid()); - sourceNatDetail.put("sourceNatVlanGateway", sourceNatVan.getVlanGateway()); - sourceNatDetail.put("sourceNatVlanNetmask", sourceNatVan.getVlanNetmask()); - sourceNatDetails.add(sourceNatDetail); + VspStaticNat vspStaticNat = _nuageVspEntityBuilder.buildVspStaticNat(staticNat.isForRevoke(), sourceNatIp, sourceNatVlan, nicVO); + vspStaticNatDetails.add(vspStaticNat); } + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(config, false); HostVO nuageVspHost = getNuageVspHost(config.getPhysicalNetworkId()); - ApplyStaticNatVspCommand.Builder cmdBuilder = new ApplyStaticNatVspCommand.Builder() - .networkDomainUuid(networkDomain.getUuid()) - .networkUuid(config.getUuid()) - .vpcOrSubnetUuid(vpcOrSubnetUuid) - .isL3Network(isL3Network) - .isVpc(vpcId != null) - .staticNatDetails(sourceNatDetails); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + ApplyStaticNatVspCommand cmd = new ApplyStaticNatVspCommand(vspNetwork, vspStaticNatDetails); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ApplyStaticNatNuageVspCommand for network " + config.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); if ((null != answer) && (null != answer.getDetails())) { @@ -519,44 +485,27 @@ public boolean applyFWRules(Network network, List rules) } s_logger.info("Applying " + rules.size() + " Firewall Rules for network " + network.getName()); - return applyACLRules(network, rules, false, rules.iterator().next().getTrafficType().equals(FirewallRule.TrafficType.Ingress), false); + return applyACLRules(network, rules, false, false); } - protected boolean applyACLRules(Network network, List rules, boolean isNetworkAcl, Boolean isAcsIngressAcl, boolean networkReset) + protected boolean applyACLRules(final Network network, List rules, boolean isNetworkAcl, boolean networkReset) throws ResourceUnavailableException { - Domain networksDomain = _domainDao.findById(network.getDomainId()); - NetworkOfferingVO networkOfferingVO = _ntwkOfferingDao.findById(network.getNetworkOfferingId()); - Long vpcId = network.getVpcId(); - String vpcOrSubnetUuid = null; - if (vpcId != null) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcOrSubnetUuid = vpcObj.getUuid(); - } else { - vpcOrSubnetUuid = network.getUuid(); - } - boolean egressDefaultPolicy = networkOfferingVO.getEgressDefaultPolicy(); - List> aclRules = new ArrayList>(); - for (InternalIdentity acl : rules) { - aclRules.add(getACLRuleDetails(acl, egressDefaultPolicy)); - } + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false); + List vspAclRules = Lists.transform(rules, new Function() { + @Nullable + @Override + public VspAclRule apply(@Nullable InternalIdentity input) { + if (input instanceof FirewallRule) { + return _nuageVspEntityBuilder.buildVspAclRule((FirewallRule) input, network); + } + return _nuageVspEntityBuilder.buildVspAclRule((NetworkACLItem) input); + } + }); - boolean isL3Network = isL3Network(network.getNetworkOfferingId()); HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); - String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configDao, network, networkOfferingVO); - ApplyAclRuleVspCommand.Builder cmdBuilder = new ApplyAclRuleVspCommand.Builder() - .networkAcl(isNetworkAcl) - .networkUuid(network.getUuid()) - .networkDomainUuid(networksDomain.getUuid()) - .vpcOrSubnetUuid(vpcOrSubnetUuid) - .networkName(network.getName()) - .isL2Network(!isL3Network) - .aclRules(aclRules) - .networkId(network.getId()) - .egressDefaultPolicy(networkOfferingVO.getEgressDefaultPolicy()) - .acsIngressAcl(isAcsIngressAcl) - .networkReset(networkReset) - .domainTemplateName(preConfiguredDomainTemplateName); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + VspAclRule.ACLType vspAclType = isNetworkAcl ? VspAclRule.ACLType.NetworkACL : VspAclRule.ACLType.Firewall; + ApplyAclRuleVspCommand cmd = new ApplyAclRuleVspCommand(vspAclType, vspNetwork, vspAclRules, networkReset); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ApplyAclRuleNuageVspCommand for network " + network.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); if ((null != answer) && (null != answer.getDetails())) { @@ -579,27 +528,61 @@ public boolean applyNetworkACLs(Network config, List r } if (rules != null) { s_logger.info("Applying " + rules.size() + " Network ACLs for network " + config.getName()); - applyACLRules(config, rules, true, null, rules.isEmpty()); + applyACLRules(config, rules, true, rules.isEmpty()); } return true; } @Override public boolean implementVpc(Vpc vpc, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + List vpcOfferingServices = _vpcOfferingSrvcDao.listByVpcOffId(vpc.getVpcOfferingId()); + Map> supportedVpcServices = NuageVspManagerImpl.NUAGE_VSP_VPC_SERVICE_MAP; + for (VpcOfferingServiceMapVO vpcOfferingService : vpcOfferingServices) { + Network.Service service = Network.Service.getService(vpcOfferingService.getService()); + if (!supportedVpcServices.containsKey(service)) { + s_logger.warn(String.format("NuageVsp doesn't support service %s for VPCs", service.getName())); + return false; + } + + Network.Provider provider = Network.Provider.getProvider(vpcOfferingService.getProvider()); + if (!supportedVpcServices.get(service).contains(provider)) { + s_logger.warn(String.format("NuageVsp doesn't support provider %s for service %s for VPCs", provider.getName(), service.getName())); + return false; + } + } + return true; } @Override public boolean shutdownVpc(Vpc vpc, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { if (vpc.getState().equals(Vpc.State.Inactive)) { + List routers = _routerDao.listByVpcId(vpc.getId()); + if (CollectionUtils.isEmpty(routers)) { + routers = _routerDao.listIncludingRemovedByVpcId(vpc.getId()); + } + + List domainRouterUuids = Lists.transform(routers, new Function() { + @Nullable + @Override + public String apply(@Nullable DomainRouterVO input) { + return input != null ? input.getUuid() : null; + } + }); + Domain vpcDomain = _domainDao.findById(vpc.getDomainId()); HostVO nuageVspHost = getNuageVspHost(getPhysicalNetworkId(vpc.getZoneId())); - String preConfiguredDomainTemplateName = _configDao.getValue(NuageVspManager.NuageVspVpcDomainTemplateName.key()); - ShutDownVpcVspCommand.Builder cmdBuilder = new ShutDownVpcVspCommand.Builder() - .domainUuid(vpcDomain.getUuid()) - .vpcUuid(vpc.getUuid()) - .domainTemplateName(preConfiguredDomainTemplateName); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + + String preConfiguredDomainTemplateName; + VpcDetailVO domainTemplateNameDetail = _vpcDetailsDao.findDetail(vpc.getId(), NuageVspManager.nuageDomainTemplateDetailName); + if (domainTemplateNameDetail != null) { + preConfiguredDomainTemplateName = domainTemplateNameDetail.getValue(); + } else { + preConfiguredDomainTemplateName = _configDao.getValue(NuageVspManager.NuageVspVpcDomainTemplateName.key()); + } + + ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand(vpcDomain.getUuid(), vpc.getUuid(), preConfiguredDomainTemplateName, domainRouterUuids); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ShutDownVpcVspCommand for VPC " + vpc.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); if ((null != answer) && (null != answer.getDetails())) { @@ -676,50 +659,4 @@ private HostVO getNuageVspHost(Long physicalNetworkId) { } return nuageVspHost; } - - protected boolean isL3Network(Long offeringId) { - return _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offeringId, Service.SourceNat) - || _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offeringId, Service.StaticNat); - } - - private Map getACLRuleDetails(Object aclRule, boolean egressDefaultPolicy) { - Map aclDetails = new HashMap(); - if (aclRule instanceof FirewallRule) { - FirewallRule firewallRule = (FirewallRule)aclRule; - aclDetails.put("sourceCidrList", firewallRule.getSourceCidrList()); - aclDetails.put("uuid", firewallRule.getUuid()); - aclDetails.put("protocol", firewallRule.getProtocol()); - aclDetails.put("startPort", firewallRule.getSourcePortStart()); - aclDetails.put("endPort", firewallRule.getSourcePortEnd()); - aclDetails.put("state", firewallRule.getState().name()); - aclDetails.put("trafficType", firewallRule.getTrafficType().name()); - if (firewallRule.getSourceIpAddressId() != null) { - //add the source IP - IPAddressVO ipaddress = _ipAddressDao.findById(((FirewallRule)aclRule).getSourceIpAddressId()); - aclDetails.put("sourceIpAddress", ipaddress != null ? ipaddress.getVmIp() + "/32" : null); - } - if (firewallRule.getTrafficType().equals(FirewallRule.TrafficType.Egress) && egressDefaultPolicy) { - aclDetails.put("action", "Deny"); - } else { - aclDetails.put("action", "Allow"); - } - aclDetails.put("priority", -1); - aclDetails.put("type", "Firewall"); - } else { - NetworkACLItem networkAcl = (NetworkACLItem)aclRule; - aclDetails.put("sourceCidrList", networkAcl.getSourceCidrList()); - aclDetails.put("uuid", networkAcl.getUuid()); - aclDetails.put("protocol", networkAcl.getProtocol()); - aclDetails.put("startPort", networkAcl.getSourcePortStart()); - aclDetails.put("endPort", networkAcl.getSourcePortEnd()); - aclDetails.put("state", networkAcl.getState().name()); - aclDetails.put("trafficType", networkAcl.getTrafficType().name()); - //Set sourceIP to null as it is not applicable - aclDetails.put("sourceIpAddress", null); - aclDetails.put("action", networkAcl.getAction().name()); - aclDetails.put("priority", networkAcl.getNumber()); - aclDetails.put("type", "NetworkACL"); - } - return aclDetails; - } } \ No newline at end of file diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java index 5f69a2139a..a6c17e3517 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/guru/NuageVspGuestNetworkGuru.java @@ -25,23 +25,20 @@ import com.cloud.agent.api.guru.ImplementNetworkVspCommand; import com.cloud.agent.api.guru.ReserveVmInterfaceVspCommand; import com.cloud.agent.api.guru.TrashNetworkVspCommand; +import com.cloud.configuration.ConfigurationManager; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.VlanVO; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; -import com.cloud.domain.Domain; -import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapacityException; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; -import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.GuestType; -import com.cloud.network.Network.Service; import com.cloud.network.Network.State; import com.cloud.network.NetworkProfile; import com.cloud.network.Networks; @@ -49,11 +46,12 @@ import com.cloud.network.PhysicalNetwork; import com.cloud.network.PhysicalNetwork.IsolationMethod; import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkDetailVO; +import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.NuageVspDao; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.manager.NuageVspManager; -import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -61,28 +59,25 @@ import com.cloud.user.Account; import com.cloud.user.AccountVO; import com.cloud.user.dao.AccountDao; -import com.cloud.util.NuageVspUtil; +import com.cloud.utils.StringUtils; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.net.NetUtils; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; -import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.google.common.base.Strings; -import org.apache.commons.lang.StringUtils; +import com.cloud.util.NuageVspEntityBuilder; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; +import org.apache.cloudstack.resourcedetail.VpcDetailVO; +import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; import org.apache.log4j.Logger; import javax.inject.Inject; -import java.net.URI; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; import java.util.List; -import java.util.Set; -import java.util.TreeSet; public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { public static final Logger s_logger = Logger.getLogger(NuageVspGuestNetworkGuru.class); @@ -105,6 +100,14 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru { AgentManager _agentMgr; @Inject NuageVspManager _nuageVspManager; + @Inject + ConfigurationManager _configMgr; + @Inject + NuageVspEntityBuilder _nuageVspEntityBuilder; + @Inject + NetworkDetailsDao _networkDetailsDao; + @Inject + VpcDetailsDao _vpcDetailsDao; public NuageVspGuestNetworkGuru() { super(); @@ -145,6 +148,15 @@ public Network implement(Network network, NetworkOffering offering, DeployDestin throw new IllegalStateException("Network " + networkId + " is not in expected state Implementing, but is in state " + network.getState()); } + //Get the Account details and find the type + AccountVO networksAccount = _accountDao.findById(network.getAccountId()); + if (networksAccount.getType() == Account.ACCOUNT_TYPE_PROJECT) { + String errorMessage = "Networks created by account " + networksAccount.getAccountName() + " of type Project (" + Account.ACCOUNT_TYPE_PROJECT + ") " + + "are not yet supported by NuageVsp provider"; + s_logger.error(errorMessage); + throw new InsufficientVirtualNetworkCapacityException(errorMessage, Account.class, network.getAccountId()); + } + long dcId = dest.getDataCenter().getId(); //Get physical network id Long physicalNetworkId = network.getPhysicalNetworkId(); @@ -152,80 +164,29 @@ public Network implement(Network network, NetworkOffering offering, DeployDestin if (physicalNetworkId == null) { physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType()); } - implemented = new NetworkVO(network.getTrafficType(), network.getMode(), network.getBroadcastDomainType(), network.getNetworkOfferingId(), State.Allocated, - network.getDataCenterId(), physicalNetworkId, offering.getRedundantRouter()); + + implemented = new NetworkVO(network.getId(), network, network.getNetworkOfferingId(), network.getGuruName(), network.getDomainId(), network.getAccountId(), + network.getRelated(), network.getName(), network.getDisplayText(), network.getNetworkDomain(), network.getGuestType(), network.getDataCenterId(), + physicalNetworkId, network.getAclType(), network.getSpecifyIpRanges(), network.getVpcId(), offering.getRedundantRouter()); + implemented.setUuid(network.getUuid()); + implemented.setState(State.Allocated); if (network.getGateway() != null) { implemented.setGateway(network.getGateway()); } if (network.getCidr() != null) { implemented.setCidr(network.getCidr()); } - List ipAddressRanges = new ArrayList(); - String virtualRouterIp = getVirtualRouterIP(network, ipAddressRanges); - String networkUuid = implemented.getUuid(); + + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(implemented, true); String tenantId = context.getDomain().getName() + "-" + context.getAccount().getAccountId(); - String broadcastUriStr = networkUuid + "/" + virtualRouterIp; + String broadcastUriStr = implemented.getUuid() + "/" + vspNetwork.getVirtualRouterIp(); implemented.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr)); implemented.setBroadcastDomainType(Networks.BroadcastDomainType.Vsp); - //Check if the network is associated to a VPC - Long vpcId = network.getVpcId(); - boolean isVpc = (vpcId != null); - //Check owner of the Network - Domain networksDomain = _domainDao.findById(network.getDomainId()); - //Get the Account details and find the type - AccountVO networksAccount = _accountDao.findById(network.getAccountId()); - if (networksAccount.getType() == Account.ACCOUNT_TYPE_PROJECT) { - String errorMessage = "Networks created by account " + networksAccount.getAccountName() + " of type Project (" + Account.ACCOUNT_TYPE_PROJECT + ") " + - "are not yet supported by NuageVsp provider"; - s_logger.error(errorMessage); - throw new InsufficientVirtualNetworkCapacityException(errorMessage, Account.class, network.getAccountId()); - } - String vpcName = null; - String vpcUuid = null; - String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configDao, network, offering); - boolean isSharedNetwork = offering.getGuestType() == GuestType.Shared; - boolean isL3Network = !isVpc && (isSharedNetwork || isL3Network(network)); - - if (isVpc) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcName = vpcObj.getName(); - vpcUuid = vpcObj.getUuid(); - } - - if (isSharedNetwork) { - List vlans = _vlanDao.listVlansByNetworkId(network.getId()); - for (VlanVO vlan : vlans) { - boolean isIpv4 = StringUtils.isNotBlank(vlan.getIpRange()); - String[] range = isIpv4 ? vlan.getIpRange().split("-") : vlan.getIp6Range().split("-"); - ipAddressRanges.add(range); - } - } HostVO nuageVspHost = getNuageVspHost(physicalNetworkId); List dnsServers = _nuageVspManager.getDnsDetails(network); - List gatewaySystemIds = _nuageVspManager.getGatewaySystemIds(); - ImplementNetworkVspCommand.Builder cmdBuilder = new ImplementNetworkVspCommand.Builder() - .networkDomainName(networksDomain.getName()) - .networkDomainPath(networksDomain.getPath()) - .networkDomainUuid(networksDomain.getUuid()) - .networkAccountName(networksAccount.getAccountName()) - .networkAccountUuid(networksAccount.getUuid()) - .networkName(network.getName()) - .networkCidr(network.getCidr()) - .networkGateway(network.getGateway()) - .networkAclId(network.getNetworkACLId()) - .dnsServers(dnsServers) - .gatewaySystemIds(gatewaySystemIds) - .networkUuid(network.getUuid()) - .isL3Network(isL3Network) - .isVpc(isVpc) - .isSharedNetwork(isSharedNetwork) - .vpcName(vpcName) - .vpcUuid(vpcUuid) - .defaultEgressPolicy(offering.getEgressDefaultPolicy()) - .ipAddressRange(ipAddressRanges) - .domainTemplateName(preConfiguredDomainTemplateName); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + ImplementNetworkVspCommand cmd = new ImplementNetworkVspCommand(vspNetwork, dnsServers); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("ImplementNetworkVspCommand for network " + network.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); @@ -234,7 +195,18 @@ public Network implement(Network network, NetworkOffering offering, DeployDestin } return null; } - s_logger.info("Implemented OK, network " + networkUuid + " in tenant " + tenantId + " linked to " + implemented.getBroadcastUri()); + + if (StringUtils.isNotBlank(vspNetwork.getDomainTemplateName())) { + if (network.getVpcId() != null) { + VpcDetailVO vpcDetail = new VpcDetailVO(network.getVpcId(), NuageVspManager.nuageDomainTemplateDetailName, vspNetwork.getDomainTemplateName(), false); + _vpcDetailsDao.persist(vpcDetail); + } else { + NetworkDetailVO networkDetail = new NetworkDetailVO(implemented.getId(), NuageVspManager.nuageDomainTemplateDetailName, vspNetwork.getDomainTemplateName(), false); + _networkDetailsDao.persist(networkDetail); + } + } + + s_logger.info("Implemented OK, network " + implemented.getUuid() + " in tenant " + tenantId + " linked to " + implemented.getBroadcastUri()); } finally { _networkDao.releaseFromLockTable(network.getId()); } @@ -259,68 +231,38 @@ public void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, D if (s_logger.isDebugEnabled()) { s_logger.debug("Handling reserve() call back to with Create a new VM or add an interface to existing VM in network " + network.getName()); } - nic.setBroadcastUri(network.getBroadcastUri()); - nic.setIsolationUri(network.getBroadcastUri()); + DataCenter dc = _dcDao.findById(network.getDataCenterId()); - Account networksAccount = _accountDao.findById(network.getAccountId()); - DomainVO networksDomain = _domainDao.findById(network.getDomainId()); - //Get the Account details and find the type - long networkOwnedBy = network.getAccountId(); - AccountVO neworkAccountDetails = _accountDao.findById(networkOwnedBy); + AccountVO neworkAccountDetails = _accountDao.findById(network.getAccountId()); if (neworkAccountDetails.getType() == Account.ACCOUNT_TYPE_PROJECT) { throw new InsufficientVirtualNetworkCapacityException("CS project support is not yet implemented in NuageVsp", DataCenter.class, dc.getId()); } - //NicProfile does not contain the NIC UUID. We need this information to set it in the VMInterface and VPort - //that we create in VSP - NicVO nicFrmDB = _nicDao.findById(nic.getId()); - NetworkOffering networkOffering = _ntwkOfferingDao.findById(network.getNetworkOfferingId()); - boolean isDomainRouter = vm.getType().equals(VirtualMachine.Type.DomainRouter); - URI broadcastUri = network.getBroadcastUri(); - if (Strings.isNullOrEmpty(broadcastUri.getPath()) || !broadcastUri.getPath().startsWith("/")) { + if (Strings.isNullOrEmpty(network.getBroadcastUri().getPath()) || !network.getBroadcastUri().getPath().startsWith("/")) { throw new IllegalStateException("The broadcast URI path " + network.getBroadcastUri() + " is empty or in an incorrect format."); } - String domainRouterIp = network.getBroadcastUri().getPath().substring(1); - boolean isL3Network = isL3Network(network); - boolean isSharedNetwork = networkOffering.getGuestType() == GuestType.Shared; - Long vpcId = network.getVpcId(); - String vpcUuid = null; - if (vpcId != null) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcUuid = vpcObj.getUuid(); - } - HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); + + nic.setBroadcastUri(network.getBroadcastUri()); + nic.setIsolationUri(network.getBroadcastUri()); + + //NicProfile does not contain the NIC UUID. We need this information to set it in the VMInterface and VPort + //that we create in VSP + NicVO nicFromDb = _nicDao.findById(nic.getId()); IPAddressVO staticNatIp = _ipAddressDao.findByVmIdAndNetworkId(network.getId(), vm.getId()); - ReserveVmInterfaceVspCommand.Builder cmdBuilder = new ReserveVmInterfaceVspCommand.Builder() - .nicUuid(nicFrmDB.getUuid()) - .nicMacAddress(nic.getMacAddress()) - .networkUuid(network.getUuid()) - .isL3Network(isL3Network) - .isSharedNetwork(isSharedNetwork) - .vpcUuid(vpcUuid) - .networkDomainUuid(networksDomain.getUuid()) - .networksAccountUuid(networksAccount.getUuid()) - .isDomainRouter(isDomainRouter) - .domainRouterIp(domainRouterIp) - .vmInstanceName(vm.getInstanceName()) - .vmUuid(vm.getUuid()) - .vmUserName(networksDomain.getUuid()) - .vmUserDomainName(networksAccount.getUuid()) - .useStaticIp(true) - .staticIp(nic.getIPv4Address()); + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false); + VspVm vspVm = _nuageVspEntityBuilder.buildVspVm(vm.getVirtualMachine(), network); + VspNic vspNic = _nuageVspEntityBuilder.buildVspNic(nicFromDb.getUuid(), nic); + VspStaticNat vspStaticNat = null; if (staticNatIp != null) { VlanVO staticNatVlan = _vlanDao.findById(staticNatIp.getVlanId()); - cmdBuilder = cmdBuilder.staticNatIpUuid(staticNatIp.getUuid()) - .staticNatIpAddress(staticNatIp.getAddress().addr()) - .isStaticNatIpAllocated(staticNatIp.getState().equals(IpAddress.State.Allocated)) - .isOneToOneNat(staticNatIp.isOneToOneNat()) - .staticNatVlanUuid(staticNatVlan.getUuid()) - .staticNatVlanGateway(staticNatVlan.getVlanGateway()) - .staticNatVlanNetmask(staticNatVlan.getVlanNetmask()); + vspStaticNat = _nuageVspEntityBuilder.buildVspStaticNat(null, staticNatIp, staticNatVlan, null); } - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); + ReserveVmInterfaceVspCommand cmd = new ReserveVmInterfaceVspCommand(vspNetwork, vspVm, vspNic, vspStaticNat); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); + if (answer == null || !answer.getResult()) { s_logger.error("ReserveVmInterfaceNuageVspCommand failed for NIC " + nic.getId() + " attached to VM " + vm.getId() + " in network " + network.getId()); if ((null != answer) && (null != answer.getDetails())) { @@ -329,8 +271,8 @@ public void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, D throw new InsufficientVirtualNetworkCapacityException("Failed to reserve VM in Nuage VSP.", Network.class, network.getId()); } - if (isDomainRouter) { - nic.setIPv4Address(domainRouterIp); + if (vspVm.getDomainRouter() == Boolean.TRUE) { + nic.setIPv4Address(vspVm.getDomainRouterIp()); } } finally { @@ -347,6 +289,12 @@ public void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, D protected boolean canHandle(NetworkOffering offering, final NetworkType networkType, final PhysicalNetwork physicalNetwork) { if (networkType == NetworkType.Advanced && isMyTrafficType(offering.getTrafficType()) && (offering.getGuestType() == Network.GuestType.Isolated || offering.getGuestType() == Network.GuestType.Shared) && isMyIsolationMethod(physicalNetwork)) { + if (_configMgr.isOfferingForVpc(offering) && !offering.getIsPersistent()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("NuageVsp can't handle VPC tiers which use a network offering which are not persistent"); + } + return false; + } return true; } else { if (s_logger.isTraceEnabled()) { @@ -369,32 +317,16 @@ public void deallocate(Network network, NicProfile nic, VirtualMachineProfile vm s_logger.debug("Handling deallocate() call back, which is called when a VM is destroyed or interface is removed, " + "to delete VM Interface with IP " + nic.getIPv4Address() + " from a VM " + vm.getInstanceName() + " with state " + vm.getVirtualMachine().getState()); } - DomainVO networksDomain = _domainDao.findById(network.getDomainId()); - NicVO nicFrmDd = _nicDao.findById(nic.getId()); - NetworkOffering networkOffering = _ntwkOfferingDao.findById(network.getNetworkOfferingId()); - boolean isL3Network = isL3Network(network); - boolean isSharedNetwork = networkOffering.getGuestType() == GuestType.Shared; - boolean isExpunging = vm.getVirtualMachine().getState() == VirtualMachine.State.Expunging; - Long vpcId = network.getVpcId(); - String vpcUuid = null; - if (vpcId != null) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcUuid = vpcObj.getUuid(); - } + + NicVO nicFromDb = _nicDao.findById(nic.getId()); + + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false); + VspVm vspVm = _nuageVspEntityBuilder.buildVspVm(vm.getVirtualMachine(), network); + VspNic vspNic = _nuageVspEntityBuilder.buildVspNic(nicFromDb.getUuid(), nic); HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); - DeallocateVmVspCommand.Builder cmdBuilder = new DeallocateVmVspCommand.Builder() - .networkUuid(network.getUuid()) - .nicFromDbUuid(nicFrmDd.getUuid()) - .nicMacAddress(nic.getMacAddress()) - .nicIp4Address(nic.getIPv4Address()) - .isL3Network(isL3Network) - .isSharedNetwork(isSharedNetwork) - .vpcUuid(vpcUuid) - .networksDomainUuid(networksDomain.getUuid()) - .vmInstanceName(vm.getInstanceName()) - .vmUuid(vm.getUuid()) - .isExpungingState(isExpunging); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + + DeallocateVmVspCommand cmd = new DeallocateVmVspCommand(vspNetwork, vspVm, vspNic); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("DeallocateVmNuageVspCommand for VM " + vm.getUuid() + " failed on Nuage VSD " + nuageVspHost.getDetail("hostname")); if ((null != answer) && (null != answer.getDetails())) { @@ -442,27 +374,10 @@ public boolean trash(Network network, NetworkOffering offering) { if (s_logger.isDebugEnabled()) { s_logger.debug("Handling trash() call back to delete the network " + network.getName() + " with uuid " + network.getUuid() + " from VSP"); } - long domainId = network.getDomainId(); - Domain domain = _domainDao.findById(domainId); - boolean isL3Network = isL3Network(network); - boolean isSharedNetwork = offering.getGuestType() == GuestType.Shared; - Long vpcId = network.getVpcId(); - String vpcUuid = null; - if (vpcId != null) { - Vpc vpcObj = _vpcDao.findById(vpcId); - vpcUuid = vpcObj.getUuid(); - } - - String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configDao, network, offering); + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false); HostVO nuageVspHost = getNuageVspHost(network.getPhysicalNetworkId()); - TrashNetworkVspCommand.Builder cmdBuilder = new TrashNetworkVspCommand.Builder() - .domainUuid(domain.getUuid()) - .networkUuid(network.getUuid()) - .isL3Network(isL3Network) - .isSharedNetwork(isSharedNetwork) - .vpcUuid(vpcUuid) - .domainTemplateName(preConfiguredDomainTemplateName); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmdBuilder.build()); + TrashNetworkVspCommand cmd = new TrashNetworkVspCommand(vspNetwork); + Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); if (answer == null || !answer.getResult()) { s_logger.error("TrashNetworkNuageVspCommand for network " + network.getUuid() + " failed"); if ((null != answer) && (null != answer.getDetails())) { @@ -476,51 +391,6 @@ public boolean trash(Network network, NetworkOffering offering) { return super.trash(network, offering); } - private String getVirtualRouterIP(Network network, Collection ipAddressRanges) throws InsufficientVirtualNetworkCapacityException { - String virtualRouterIp; - //Check if the subnet has minimum 5 host in it. - String subnet = NetUtils.getCidrSubNet(network.getCidr()); - String netmask = NetUtils.getCidrNetmask(network.getCidr()); - long cidrSize = NetUtils.getCidrSize(netmask); - - Set allIPsInCidr = NetUtils.getAllIpsFromCidr(subnet, cidrSize, new HashSet()); - if (allIPsInCidr == null || !(allIPsInCidr instanceof TreeSet)) { - throw new IllegalStateException("The IPs in CIDR for subnet " + subnet + " where null or returned in a non-ordered set."); - } - - if (allIPsInCidr.size() > 3) { - //get the second IP and see if it the networks GatewayIP - Iterator ipIterator = allIPsInCidr.iterator(); - long vip = ipIterator.next(); - if (NetUtils.ip2Long(network.getGateway()) == vip) { - vip = ipIterator.next(); - virtualRouterIp = NetUtils.long2Ip(vip); - if (s_logger.isDebugEnabled()) { - s_logger.debug("1st IP is used as gateway IP. Reserving " + virtualRouterIp + " for the Virtual Router IP for Network(" + network.getName() + ")"); - } - } else { - virtualRouterIp = NetUtils.long2Ip(vip); - if (s_logger.isDebugEnabled()) { - s_logger.debug("1st IP is not used as the gateway IP. Reserving" + virtualRouterIp + " for the Virtual Router IP for Network(" + network.getName() + ")"); - } - } - ipAddressRanges.add(new String[] { - NetUtils.long2Ip(ipIterator.next()), - NetUtils.getIpRangeEndIpFromCidr(subnet, cidrSize) - }); - return virtualRouterIp; - } - - throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " So, subnet should have atleast minimum 4 hosts ", Network.class, - network.getId()); - } - - private boolean isL3Network(Network network) { - return _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Service.SourceNat) - || _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Service.StaticNat) - || network.getGuestType() == GuestType.Shared; - } - private HostVO getNuageVspHost(long physicalNetworkId) { HostVO nuageVspHost; List nuageVspDevices = _nuageVspDao.listByPhysicalNetwork(physicalNetworkId); diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java index 0aae22ccce..4861fb240d 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManager.java @@ -40,6 +40,8 @@ public interface NuageVspManager extends PluggableService { static final String nuageVPCOfferingDisplayText = "Nuage VSP VPC Offering"; + static final String nuageDomainTemplateDetailName = "domainTemplateName"; + static final ConfigKey NuageVspConfigDns = new ConfigKey(Boolean.class, "nuagevsp.configure.dns", "Advanced", "true", "Defines if NuageVsp plugin needs to configure DNS setting for a VM or not. True will configure the DNS and false will not configure the DNS settings", true, Scope.Global, null); diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java index ce2a363631..04b1ccc9f9 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/manager/NuageVspManagerImpl.java @@ -27,8 +27,8 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.PingNuageVspCommand; import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.manager.GetClientDefaultsAnswer; -import com.cloud.agent.api.manager.GetClientDefaultsCommand; +import com.cloud.agent.api.manager.GetApiDefaultsAnswer; +import com.cloud.agent.api.manager.GetApiDefaultsCommand; import com.cloud.agent.api.manager.SupportedApiVersionCommand; import com.cloud.agent.api.sync.SyncDomainAnswer; import com.cloud.agent.api.sync.SyncDomainCommand; @@ -37,7 +37,6 @@ import com.cloud.api.ApiDBUtils; import com.cloud.api.commands.AddNuageVspDeviceCmd; import com.cloud.api.commands.DeleteNuageVspDeviceCmd; -import com.cloud.api.commands.IssueNuageVspResourceRequestCmd; import com.cloud.api.commands.ListNuageVspDevicesCmd; import com.cloud.api.commands.UpdateNuageVspDeviceCmd; import com.cloud.api.response.NuageVspDeviceResponse; @@ -70,7 +69,6 @@ import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.resource.NuageVspResource; -import com.cloud.network.sync.NuageVspSync; import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.VpcOffering; import com.cloud.network.vpc.VpcOfferingServiceMapVO; @@ -105,7 +103,11 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.cloud.util.NuageVspEntityBuilder; import net.nuage.vsp.acs.NuageVspPluginClientLoader; +import net.nuage.vsp.acs.client.api.model.VspApiDefaults; +import net.nuage.vsp.acs.client.api.model.VspDomain; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -120,14 +122,12 @@ import javax.naming.ConfigurationException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ScheduledExecutorService; import static com.cloud.agent.api.sync.SyncNuageVspCmsIdCommand.SyncType; @@ -135,10 +135,7 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager, private static final Logger s_logger = Logger.getLogger(NuageVspManagerImpl.class); - private static final int ONE_MINUTE_MULTIPLIER = 60 * 1000; - - private static final Set NUAGE_VSP_PROVIDERS; - private static final Map> NUAGE_VSP_VPC_SERVICE_MAP; + public static final Map> NUAGE_VSP_VPC_SERVICE_MAP; private static final ConfigKey[] NUAGE_VSP_CONFIG_KEYS = new ConfigKey[] { NuageVspConfigDns, NuageVspDnsExternal, NuageVspConfigGateway, NuageVspSharedNetworkDomainTemplateName, NuageVspVpcDomainTemplateName, NuageVspIsolatedNetworkDomainTemplateName }; @@ -165,8 +162,6 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager, @Inject NuageVspDao _nuageVspDao; @Inject - NuageVspSync _nuageVspSync; - @Inject DataCenterDao _dataCenterDao; @Inject ConfigurationDao _configDao; @@ -188,27 +183,32 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager, NetworkOfferingDao _networkOfferingDao; @Inject NetworkOfferingServiceMapDao _networkOfferingServiceMapDao; - - private ScheduledExecutorService scheduler; + @Inject + NuageVspEntityBuilder _nuageVspEntityBuilder; @Inject MessageBus _messageBus; static { - NUAGE_VSP_PROVIDERS = ImmutableSet.of(Network.Provider.NuageVsp); + Set nuageVspProviders = ImmutableSet.of(Network.Provider.NuageVsp); + Set userDataProviders = ImmutableSet.of(Network.Provider.VPCVirtualRouter); + Set lbProviders = ImmutableSet.of(Network.Provider.InternalLbVm); NUAGE_VSP_VPC_SERVICE_MAP = ImmutableMap.>builder() - .put(Network.Service.Connectivity, NUAGE_VSP_PROVIDERS) - .put(Network.Service.Dhcp, NUAGE_VSP_PROVIDERS) - .put(Network.Service.StaticNat, NUAGE_VSP_PROVIDERS) - .put(Network.Service.SourceNat, NUAGE_VSP_PROVIDERS) - .put(Network.Service.NetworkACL, NUAGE_VSP_PROVIDERS) + .put(Network.Service.Connectivity, nuageVspProviders) + .put(Network.Service.Gateway, nuageVspProviders) + .put(Network.Service.Dhcp, nuageVspProviders) + .put(Network.Service.StaticNat, nuageVspProviders) + .put(Network.Service.SourceNat, nuageVspProviders) + .put(Network.Service.NetworkACL, nuageVspProviders) + .put(Network.Service.UserData, userDataProviders) + .put(Network.Service.Lb, lbProviders) .build(); } @Override public List> getCommands() { return Lists.>newArrayList(AddNuageVspDeviceCmd.class, DeleteNuageVspDeviceCmd.class, ListNuageVspDevicesCmd.class, - IssueNuageVspResourceRequestCmd.class, UpdateNuageVspDeviceCmd.class); + UpdateNuageVspDeviceCmd.class); } @Override @@ -238,21 +238,21 @@ public NuageVspDeviceVO addNuageVspDevice(AddNuageVspDeviceCmd cmd) { } try { - NuageVspPluginClientLoader clientLoader = NuageVspPluginClientLoader.getClientLoader(null, null, 1, 1, null); + NuageVspPluginClientLoader clientLoader = NuageVspPluginClientLoader.getClientLoader(null, null, null, null, 1, 1, null); - Map clientDefaults = clientLoader.getNuageVspManagerClient().getClientDefaults(); - String apiVersion = MoreObjects.firstNonNull(cmd.getApiVersion(), (String) clientDefaults.get("CURRENT_API_VERSION")); + VspApiDefaults apiDefaults = clientLoader.getNuageVspManagerClient().getApiDefaults(); + String apiVersion = MoreObjects.firstNonNull(cmd.getApiVersion(), apiDefaults.getVersion()); if (!clientLoader.getNuageVspManagerClient().isSupportedApiVersion(apiVersion)) { throw new CloudRuntimeException("Unsupported API version : " + apiVersion); } int port = cmd.getPort(); if (0 == port) { - port = 8443; + port = 443; } String cmsUserPasswordBase64 = NuageVspUtil.encodePassword(cmd.getPassword()); - String retryCount = String.valueOf(MoreObjects.firstNonNull(cmd.getApiRetryCount(), clientDefaults.get("DEFAULT_API_RETRY_COUNT"))); - String retryInterval = String.valueOf(MoreObjects.firstNonNull(cmd.getApiRetryInterval(), clientDefaults.get("DEFAULT_API_RETRY_INTERVAL"))); + String retryCount = String.valueOf(MoreObjects.firstNonNull(cmd.getApiRetryCount(), apiDefaults.getRetryCount())); + String retryInterval = String.valueOf(MoreObjects.firstNonNull(cmd.getApiRetryInterval(), apiDefaults.getRetryInterval())); NuageVspResource.Configuration resourceConfiguration = new NuageVspResource.Configuration() .name("Nuage VSD - " + cmd.getHostName()) .guid(UUID.randomUUID().toString()) @@ -280,22 +280,33 @@ public NuageVspDeviceVO addNuageVspDevice(AddNuageVspDeviceCmd cmd) { _hostDetailsDao.persist(detail); ConfigurationVO cmsIdConfig = _configDao.findByName("nuagevsp.cms.id"); + NuageVspDeviceVO matchingNuageVspDevice = findMatchingNuageVspDevice(nuageVspDevice); + String cmsId; + if (matchingNuageVspDevice != null) { + cmsId = findNuageVspCmsIdForDevice(matchingNuageVspDevice.getId(), cmsIdConfig); + } else { + SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(SyncType.REGISTER, null); + SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd); + if (answer != null && answer.getSuccess()) { + cmsId = answer.getNuageVspCmsId(); + } else { + throw new CloudRuntimeException("Failed to register CMS ID"); + } + } + host = findNuageVspHost(nuageVspDevice.getHostId()); - SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(SyncType.REGISTER, null); - SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd); - if (answer != null && answer.getSuccess()) { - registerNewNuageVspDevice(cmsIdConfig, nuageVspDevice.getId() + ":" + answer.getNuageVspCmsId()); + registerNewNuageVspDevice(cmsIdConfig, nuageVspDevice.getId() + ":" + cmsId); - detail = new DetailVO(host.getId(), "nuagevspcmsid", answer.getNuageVspCmsId()); - _hostDetailsDao.persist(detail); + detail = new DetailVO(host.getId(), "nuagevspcmsid", cmsId); + _hostDetailsDao.persist(detail); - resourceConfiguration.nuageVspCmsId(answer.getNuageVspCmsId()); - resource.configure(cmd.getHostName(), Maps.newHashMap(resourceConfiguration.build())); + resourceConfiguration.nuageVspCmsId(cmsId); + resource.configure(cmd.getHostName(), Maps.newHashMap(resourceConfiguration.build())); + if (matchingNuageVspDevice == null) { auditDomainsOnVsp((HostVO) host, true, false); - } else { - throw new CloudRuntimeException("Failed to register CMS ID"); } + return nuageVspDevice; } catch (ConfigurationException e) { s_logger.error("Failed to configure Nuage VSD resource " + cmd.getHostName(), e); @@ -368,13 +379,13 @@ public NuageVspDeviceVO updateNuageVspDevice(UpdateNuageVspDeviceCmd command) { updateRequired = true; } - GetClientDefaultsCommand getClientDefaultsCmd = new GetClientDefaultsCommand(); - GetClientDefaultsAnswer getClientDefaultsAnswer = (GetClientDefaultsAnswer) _agentMgr.easySend(nuageVspHost.getId(), getClientDefaultsCmd); + GetApiDefaultsCommand apiDefaultsCmd = new GetApiDefaultsCommand(); + GetApiDefaultsAnswer apiDefaultsAnswer = (GetApiDefaultsAnswer) _agentMgr.easySend(nuageVspHost.getId(), apiDefaultsCmd); String apiVersion = MoreObjects.firstNonNull(command.getApiVersion(), resourceConfiguration.apiVersion()); SupportedApiVersionCommand supportedApiVersionCmd = new SupportedApiVersionCommand(apiVersion); Answer supportedApiVersionAnswer = _agentMgr.easySend(nuageVspHost.getId(), supportedApiVersionCmd); if (!supportedApiVersionAnswer.getResult()) { - throw new CloudRuntimeException("Incorrect API version: Nuage plugin only supports " + getClientDefaultsAnswer.getCurrentApiVersion()); + throw new CloudRuntimeException("Incorrect API version: Nuage plugin only supports " + apiDefaultsAnswer.getApiDefaults().getVersion()); } String apiRelativePath = "/nuage/api/" + apiVersion; @@ -424,6 +435,7 @@ public NuageVspDeviceResponse createNuageVspDeviceResponse(NuageVspDeviceVO nuag HostVO nuageVspHost = _hostDao.findById(nuageVspDeviceVO.getHostId()); _hostDao.loadDetails(nuageVspHost); + NuageVspResource.Configuration resourceConfiguration = NuageVspResource.Configuration.fromConfiguration(nuageVspHost.getDetails()); NuageVspDeviceResponse response = new NuageVspDeviceResponse(); response.setDeviceName(nuageVspDeviceVO.getDeviceName()); PhysicalNetwork pnw = ApiDBUtils.findPhysicalNetworkById(nuageVspDeviceVO.getPhysicalNetworkId()); @@ -432,12 +444,13 @@ public NuageVspDeviceResponse createNuageVspDeviceResponse(NuageVspDeviceVO nuag } response.setId(nuageVspDeviceVO.getUuid()); response.setProviderName(nuageVspDeviceVO.getProviderName()); - response.setHostName(nuageVspHost.getDetail("hostname")); - response.setPort(Integer.parseInt(nuageVspHost.getDetail("port"))); - String apiRelativePath = nuageVspHost.getDetail("apirelativepath"); + response.setHostName(resourceConfiguration.hostName()); + response.setPort(Integer.parseInt(resourceConfiguration.port())); + String apiRelativePath = resourceConfiguration.apiRelativePath(); response.setApiVersion(apiRelativePath.substring(apiRelativePath.lastIndexOf('/') + 1)); - response.setApiRetryCount(Integer.parseInt(nuageVspHost.getDetail("retrycount"))); - response.setApiRetryInterval(Long.parseLong(nuageVspHost.getDetail("retryinterval"))); + response.setApiRetryCount(Integer.parseInt(resourceConfiguration.retryCount())); + response.setApiRetryInterval(Long.parseLong(resourceConfiguration.retryInterval())); + response.setCmsId(resourceConfiguration.nuageVspCmsId()); response.setObjectName("nuagevspdevice"); return response; } @@ -468,25 +481,31 @@ public boolean deleteNuageVspDevice(DeleteNuageVspDeviceCmd cmd) { } } + NuageVspDeviceVO matchingNuageVspDevice = findMatchingNuageVspDevice(nuageVspDevice); ConfigurationVO cmsIdConfig = _configDao.findByName("nuagevsp.cms.id"); HostVO host = findNuageVspHost(nuageVspDevice.getHostId()); - if (!auditDomainsOnVsp(host, false, true)) { - return false; - } - String nuageVspCmsId = findNuageVspCmsIdForDevice(nuageVspDevice.getId(), cmsIdConfig); - SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(SyncType.UNREGISTER, nuageVspCmsId); - SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd); - if (answer != null && answer.getSuccess()) { - String currentValue = cmsIdConfig.getValue(); - String newValue = currentValue.replace(nuageVspDevice.getId() + ":" + answer.getNuageVspCmsId(), ""); - if (!Strings.isNullOrEmpty(newValue) && newValue.startsWith(";")) { - newValue = newValue.substring(1); + if (matchingNuageVspDevice == null) { + if (!auditDomainsOnVsp(host, false, true)) { + return false; } - _configDao.update("nuagevsp.cms.id", newValue); - } else { - return false; + + SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(SyncType.UNREGISTER, nuageVspCmsId); + SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd); + if (answer == null || !answer.getSuccess()) { + return false; + } + } + + String newValue = cmsIdConfig.getValue().replace(nuageVspDevice.getId() + ":" + nuageVspCmsId, ""); + if (newValue.startsWith(";")) { + newValue = newValue.substring(1); } + if (newValue.endsWith(";")) { + newValue = newValue.substring(0, newValue.length() - 1); + } + newValue = newValue.replaceAll(";+", ";"); + _configDao.update("nuagevsp.cms.id", newValue); HostVO nuageHost = _hostDao.findById(nuageVspDevice.getHostId()); Long hostId = nuageHost.getId(); @@ -499,6 +518,22 @@ public boolean deleteNuageVspDevice(DeleteNuageVspDeviceCmd cmd) { return true; } + private NuageVspDeviceVO findMatchingNuageVspDevice(NuageVspDeviceVO nuageVspDevice) { + List otherNuageVspDevices = _nuageVspDao.listAll(); + for (NuageVspDeviceVO otherNuageVspDevice : otherNuageVspDevices) { + if (otherNuageVspDevice.getId() == nuageVspDevice.getId()) continue; + + HostVO nuageVspDeviceHost = findNuageVspHost(nuageVspDevice.getHostId()); + HostVO otherNuageVspDeviceHost = findNuageVspHost(otherNuageVspDevice.getHostId()); + String nuageVspDeviceHostName = nuageVspDeviceHost.getDetail("hostname"); + String otherNuageVspDeviceHostName = otherNuageVspDeviceHost.getDetail("hostname"); + if (otherNuageVspDeviceHostName != null && otherNuageVspDeviceHostName.equals(nuageVspDeviceHostName)) { + return otherNuageVspDevice; + } + } + return null; + } + @Override public List listNuageVspDevices(ListNuageVspDevicesCmd cmd) { Long physicalNetworkId = cmd.getPhysicalNetworkId(); @@ -545,6 +580,8 @@ private void registerNewNuageVspDevice(ConfigurationVO currentConfig, String reg } private void auditHost(HostVO host) { + if (host == null) return; + _hostDao.loadDetails(host); boolean validateDomains = true; @@ -579,7 +616,8 @@ private boolean auditDomainsOnVsp(HostVO host, boolean add, boolean remove) { _hostDao.loadDetails(host); List allDomains = _domainDao.listAll(); for (DomainVO domain : allDomains) { - SyncDomainCommand cmd = new SyncDomainCommand(domain.getUuid(), domain.getName(), domain.getPath(), add, remove); + VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(domain); + SyncDomainCommand cmd = new SyncDomainCommand(vspDomain, add, remove); SyncDomainAnswer answer = (SyncDomainAnswer) _agentMgr.easySend(host.getId(), cmd); return answer.getSuccess(); } @@ -677,7 +715,8 @@ public void onPublishMessage(String senderAddress, String subject, Object args) List nuageVspDevices = _nuageVspDao.listAll(); for (NuageVspDeviceVO nuageVspDevice : nuageVspDevices) { HostVO host = findNuageVspHost(nuageVspDevice.getHostId()); - SyncDomainCommand cmd = new SyncDomainCommand(domain.getUuid(), domain.getName(), domain.getPath(), true, false); + VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(domain); + SyncDomainCommand cmd = new SyncDomainCommand(vspDomain, true, false); _agentMgr.easySend(host.getId(), cmd); } } finally { @@ -694,7 +733,8 @@ public void onPublishMessage(String senderAddress, String subject, Object args) List nuageVspDevices = _nuageVspDao.listAll(); for (NuageVspDeviceVO nuageVspDevice : nuageVspDevices) { HostVO host = findNuageVspHost(nuageVspDevice.getHostId()); - SyncDomainCommand cmd = new SyncDomainCommand(domain.getUuid(), domain.getName(), domain.getPath(), false, true); + VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(domain); + SyncDomainCommand cmd = new SyncDomainCommand(vspDomain, false, true); _agentMgr.easySend(host.getId(), cmd); } } @@ -729,6 +769,11 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { @@ -739,6 +784,16 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + + } + @Override public boolean isRecurring() { return false; @@ -770,7 +825,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) { defaultNuageVspSharedSGNetworkOffering.setState(NetworkOffering.State.Enabled); defaultNuageVspSharedSGNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNuageVspSharedSGNetworkOffering); - Map defaultNuageVspSharedSGNetworkOfferingProviders = new HashMap<>(); + Map defaultNuageVspSharedSGNetworkOfferingProviders = new HashMap(); defaultNuageVspSharedSGNetworkOfferingProviders.put(Network.Service.Dhcp, Network.Provider.NuageVsp); defaultNuageVspSharedSGNetworkOfferingProviders.put(Network.Service.SecurityGroup, Network.Provider.NuageVsp); defaultNuageVspSharedSGNetworkOfferingProviders.put(Network.Service.Connectivity, Network.Provider.NuageVsp); @@ -794,16 +849,15 @@ private void initNuageVspVpcOffering() { Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { - if (_vpcOffDao.findByUniqueName(nuageVPCOfferingName) == null) { + VpcOffering offering = _vpcOffDao.findByUniqueName(nuageVPCOfferingName); + if (offering == null) { if (s_logger.isDebugEnabled()) { s_logger.debug("Creating default Nuage VPC offering " + nuageVPCOfferingName); } - Map> svcProviderMap = Maps.newHashMap(NUAGE_VSP_VPC_SERVICE_MAP); - Set userDataProviders = Collections.singleton(Network.Provider.VPCVirtualRouter); - svcProviderMap.put(Network.Service.UserData, userDataProviders); - - createVpcOffering(nuageVPCOfferingName, nuageVPCOfferingDisplayText, svcProviderMap, true, VpcOffering.State.Enabled, null); + createVpcOffering(nuageVPCOfferingName, nuageVPCOfferingDisplayText, NUAGE_VSP_VPC_SERVICE_MAP, true, VpcOffering.State.Enabled, null); + } else { + updateVpcOffering(offering, NUAGE_VSP_VPC_SERVICE_MAP); } } }); @@ -822,7 +876,7 @@ public VpcOffering doInTransaction(TransactionStatus status) { offering.setState(state); } if (s_logger.isDebugEnabled()) { - s_logger.debug("Adding vpc offering " + offering); + s_logger.debug(String.format("Adding vpc offering %s", offering)); } offering = _vpcOffDao.persist(offering); // populate services and providers @@ -834,11 +888,49 @@ public VpcOffering doInTransaction(TransactionStatus status) { VpcOfferingServiceMapVO offService = new VpcOfferingServiceMapVO(offering.getId(), service, provider); _vpcOffSvcMapDao.persist(offService); if (s_logger.isTraceEnabled()) { - s_logger.trace("Added service for the vpc offering: " + offService + " with provider " + provider.getName()); + s_logger.trace(String.format("Added service for the vpc offering: %s with provider %s", offService, provider.getName())); } } } else { - throw new InvalidParameterValueException("Provider is missing for the VPC offering service " + service.getName()); + throw new InvalidParameterValueException(String.format("Provider is missing for the VPC offering service %s", service.getName())); + } + } + } + return offering; + } + }); + } + + @DB + protected void updateVpcOffering(final VpcOffering offering, final Map> svcProviderMap) { + Transaction.execute(new TransactionCallback() { + @Override + public VpcOffering doInTransaction(TransactionStatus status) { + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("Updating vpc offering %s", offering)); + } + + List currentVpcOfferingServices = _vpcOffSvcMapDao.listByVpcOffId(offering.getId()); + Map> currentSvcProviderMap = Maps.newHashMap(); + for (VpcOfferingServiceMapVO vpcOfferingService : currentVpcOfferingServices) { + Network.Service service = Network.Service.getService(vpcOfferingService.getService()); + Network.Provider provider = Network.Provider.getProvider(vpcOfferingService.getProvider()); + + if (!currentSvcProviderMap.containsKey(service)) { + currentSvcProviderMap.put(service, Sets.newHashSet(provider)); + } else if (!currentSvcProviderMap.get(service).contains(provider)) { + currentSvcProviderMap.get(service).add(provider); + } + } + + for (Network.Service service : svcProviderMap.keySet()) { + for (Network.Provider provider : svcProviderMap.get(service)) { + if (currentSvcProviderMap.get(service) == null || !currentSvcProviderMap.get(service).contains(provider)) { + VpcOfferingServiceMapVO offService = new VpcOfferingServiceMapVO(offering.getId(), service, provider); + _vpcOffSvcMapDao.persist(offService); + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("Added service for the vpc offering: %s", offService)); + } } } } diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java index 8e142372d6..bdcb481a01 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/network/resource/NuageVspResource.java @@ -30,8 +30,6 @@ import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupVspCommand; -import com.cloud.agent.api.VspResourceAnswer; -import com.cloud.agent.api.VspResourceCommand; import com.cloud.agent.api.element.ApplyAclRuleVspCommand; import com.cloud.agent.api.element.ApplyStaticNatVspCommand; import com.cloud.agent.api.element.ImplementVspCommand; @@ -40,14 +38,13 @@ import com.cloud.agent.api.guru.ImplementNetworkVspCommand; import com.cloud.agent.api.guru.ReserveVmInterfaceVspCommand; import com.cloud.agent.api.guru.TrashNetworkVspCommand; -import com.cloud.agent.api.manager.GetClientDefaultsAnswer; -import com.cloud.agent.api.manager.GetClientDefaultsCommand; +import com.cloud.agent.api.manager.GetApiDefaultsAnswer; +import com.cloud.agent.api.manager.GetApiDefaultsCommand; import com.cloud.agent.api.manager.SupportedApiVersionCommand; import com.cloud.agent.api.sync.SyncDomainAnswer; import com.cloud.agent.api.sync.SyncDomainCommand; import com.cloud.agent.api.sync.SyncNuageVspCmsIdAnswer; import com.cloud.agent.api.sync.SyncNuageVspCmsIdCommand; -import com.cloud.agent.api.sync.SyncVspCommand; import com.cloud.host.Host; import com.cloud.resource.ServerResource; import com.cloud.util.NuageVspUtil; @@ -56,12 +53,11 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.google.common.base.Strings; import net.nuage.vsp.acs.NuageVspPluginClientLoader; -import net.nuage.vsp.acs.client.NuageVspApiClient; -import net.nuage.vsp.acs.client.NuageVspElementClient; -import net.nuage.vsp.acs.client.NuageVspGuruClient; -import net.nuage.vsp.acs.client.NuageVspManagerClient; -import net.nuage.vsp.acs.client.NuageVspSyncClient; -import org.apache.commons.lang3.tuple.Pair; +import net.nuage.vsp.acs.client.api.NuageVspApiClient; +import net.nuage.vsp.acs.client.api.NuageVspElementClient; +import net.nuage.vsp.acs.client.api.NuageVspGuruClient; +import net.nuage.vsp.acs.client.api.NuageVspManagerClient; +import net.nuage.vsp.acs.client.common.model.Pair; import org.apache.log4j.Logger; import javax.naming.ConfigurationException; @@ -91,7 +87,8 @@ public class NuageVspResource extends ManagerBase implements ServerResource { private String _name; private String _guid; private String _zoneId; - private String[] _cmsUserInfo; + private String _cmsUserLogin; + private String _cmsUserPassword; private String _hostName; private String _relativePath; private int _numRetries; @@ -102,7 +99,6 @@ public class NuageVspResource extends ManagerBase implements ServerResource { protected NuageVspApiClient _nuageVspApiClient; protected NuageVspGuruClient _nuageVspGuruClient; protected NuageVspElementClient _nuageVspElementClient; - protected NuageVspSyncClient _nuageVspSyncClient; protected NuageVspManagerClient _nuageVspManagerClient; protected boolean _isNuageVspClientLoaded; @@ -190,7 +186,8 @@ public boolean configure(String name, Map params) throws Configu _relativePath = new StringBuffer().append("https://").append(_hostName).append(":").append(port).append(apiRelativePath).toString(); String cmsUserPass = NuageVspUtil.decodePassword(cmsUserPassBase64); - _cmsUserInfo = new String[] {CMS_USER_ENTEPRISE_NAME, cmsUser, cmsUserPass}; + _cmsUserLogin = cmsUser; + _cmsUserPassword = cmsUserPass; _nuageVspCmsId = (String)params.get(NUAGE_VSP_CMS_ID); @@ -199,8 +196,8 @@ public boolean configure(String name, Map params) throws Configu try { login(); } catch (ExecutionException | ConfigurationException e) { - s_logger.error("Failed to login to Nuage VSD on " + name + " as user " + cmsUser, e); - throw new CloudRuntimeException("Failed to login to Nuage VSD on " + name + " as user " + cmsUser, e); + s_logger.error(e.getMessage(), e); + throw new CloudRuntimeException(e.getMessage(), e); } return true; @@ -211,23 +208,14 @@ protected void login() throws ConfigurationException, ExecutionException { _nuageVspApiClient.login(); } - protected void loadNuageClient() { - - try { - NuageVspPluginClientLoader clientLoader = NuageVspPluginClientLoader.getClientLoader(_relativePath, _cmsUserInfo, _numRetries, _retryInterval, _nuageVspCmsId); - _nuageVspApiClient = clientLoader.getNuageVspApiClient(); - _nuageVspSyncClient = clientLoader.getNuageVspSyncClient(); - _nuageVspGuruClient = clientLoader.getNuageVspGuruClient(); - _nuageVspElementClient = clientLoader.getNuageVspElementClient(); - _nuageVspManagerClient = clientLoader.getNuageVspManagerClient(); - _isNuageVspClientLoaded = true; - } catch (ConfigurationException e) { - _isNuageVspClientLoaded = false; - String errorMessage = "Nuage Vsp Plugin client is not yet installed. Please install NuageVsp plugin client to use NuageVsp plugin in Cloudstack. "; - s_logger.error(errorMessage, e); - throw new CloudRuntimeException(errorMessage, e); - } - + protected void loadNuageClient() { + NuageVspPluginClientLoader clientLoader = NuageVspPluginClientLoader.getClientLoader(_relativePath, CMS_USER_ENTEPRISE_NAME, + _cmsUserLogin, _cmsUserPassword, _numRetries, _retryInterval, _nuageVspCmsId); + _nuageVspApiClient = clientLoader.getNuageVspApiClient(); + _nuageVspGuruClient = clientLoader.getNuageVspGuruClient(); + _nuageVspElementClient = clientLoader.getNuageVspElementClient(); + _nuageVspManagerClient = clientLoader.getNuageVspManagerClient(); + _isNuageVspClientLoaded = true; } @Override @@ -265,12 +253,12 @@ public StartupCommand[] initialize() { @Override public PingCommand getCurrentStatus(long id) { - if (_relativePath == null || _relativePath.isEmpty()) { + if (Strings.isNullOrEmpty(_relativePath)) { s_logger.error("Refusing to ping Nuage VSD because the resource configuration is missing the relative path information"); _shouldAudit = true; return null; } - if (_cmsUserInfo == null || _cmsUserInfo.length < 2) { + if (Strings.isNullOrEmpty(_cmsUserLogin) || Strings.isNullOrEmpty(_cmsUserPassword)) { s_logger.error("Refusing to ping Nuage VSD because the resource configuration is missing the CMS user information"); _shouldAudit = true; return null; @@ -278,7 +266,7 @@ public PingCommand getCurrentStatus(long id) { try { login(); } catch (ExecutionException | ConfigurationException e) { - s_logger.error("Failed to ping to Nuage VSD on " + _name + " as user " + _cmsUserInfo[1], e); + s_logger.error("Failed to ping to Nuage VSD on " + _name + " as user " + _cmsUserLogin, e); _shouldAudit = true; return null; } @@ -293,8 +281,6 @@ public Answer executeRequest(Command cmd) { return executeRequest((ReadyCommand)cmd); } else if (cmd instanceof MaintainCommand) { return executeRequest((MaintainCommand)cmd); - } else if (cmd instanceof VspResourceCommand) { - return executeRequest((VspResourceCommand)cmd); } //Guru commands else if (cmd instanceof ImplementNetworkVspCommand) { @@ -317,16 +303,14 @@ else if (cmd instanceof ImplementVspCommand) { return executeRequest((ShutDownVpcVspCommand)cmd); } //Sync Commands - else if (cmd instanceof SyncVspCommand) { - return executeRequest((SyncVspCommand)cmd); - } else if (cmd instanceof SyncNuageVspCmsIdCommand) { + else if (cmd instanceof SyncNuageVspCmsIdCommand) { return executeRequest((SyncNuageVspCmsIdCommand)cmd); } else if (cmd instanceof SyncDomainCommand) { return executeRequest((SyncDomainCommand)cmd); } //Other commands - else if (cmd instanceof GetClientDefaultsCommand) { - return executeRequest((GetClientDefaultsCommand)cmd); + else if (cmd instanceof GetApiDefaultsCommand) { + return executeRequest((GetApiDefaultsCommand)cmd); } else if (cmd instanceof SupportedApiVersionCommand) { return executeRequest((SupportedApiVersionCommand)cmd); } @@ -357,29 +341,11 @@ private Answer executeRequest(MaintainCommand cmd) { return new MaintainAnswer(cmd); } - private Answer executeRequest(VspResourceCommand cmd) { - try { - isNuageVspApiLoaded(); - if (cmd.getRequestType().equalsIgnoreCase("GETALL") || cmd.getRequestType().equalsIgnoreCase("GET") || cmd.getRequestType().equalsIgnoreCase("GETRELATED")) { - String resourceInfo = _nuageVspApiClient.executeRestApi(cmd.getRequestType(), cmd.getResource(), cmd.getResourceId(), cmd.getChildResource(), - cmd.getEntityDetails(), cmd.getResourceFilter(), cmd.getProxyUserUuid(), cmd.getProxyUserDomainuuid()); - return new VspResourceAnswer(cmd, resourceInfo, "Executed Issue Resource command"); - } - return new VspResourceAnswer(cmd, false, cmd.getRequestType() + " is not yet supported"); - } catch (ExecutionException | ConfigurationException e) { - s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); - return new VspResourceAnswer(cmd, e); - } - } - private Answer executeRequest(ImplementNetworkVspCommand cmd) { try { isNuageVspGuruLoaded(); - _nuageVspGuruClient.implement(cmd.getNetworkDomainName(), cmd.getNetworkDomainPath(), cmd.getNetworkDomainUuid(), cmd.getNetworkAccountName(), - cmd.getNetworkAccountUuid(), cmd.getNetworkName(), cmd.getNetworkCidr(), cmd.getNetworkGateway(), cmd.getNetworkAclId(), cmd.getDnsServers(), - cmd.getGatewaySystemIds(), cmd.isL3Network(), cmd.isVpc(), cmd.isSharedNetwork(), cmd.getNetworkUuid(), cmd.getVpcName(), cmd.getVpcUuid(), - cmd.isDefaultEgressPolicy(), cmd.getIpAddressRange(), cmd.getDomainTemplateName()); - return new Answer(cmd, true, "Created network mapping to " + cmd.getNetworkName() + " on Nuage VSD " + _hostName); + _nuageVspGuruClient.implement(cmd.getNetwork(), cmd.getDnsServers()); + return new Answer(cmd, true, "Created network mapping to " + cmd.getNetwork().getName() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -389,11 +355,8 @@ private Answer executeRequest(ImplementNetworkVspCommand cmd) { private Answer executeRequest(ReserveVmInterfaceVspCommand cmd) { try { isNuageVspGuruLoaded(); - _nuageVspGuruClient.reserve(cmd.getNicUuid(), cmd.getNicMacAddress(), cmd.getNetworkUuid(), cmd.isL3Network(), - cmd.isSharedNetwork(), cmd.getVpcUuid(), cmd.getNetworkDomainUuid(), cmd.getNetworksAccountUuid(), cmd.isDomainRouter(), cmd.getDomainRouterIp(), - cmd.getVmInstanceName(), cmd.getVmUuid(), cmd.useStaticIp(), cmd.getStaticIp(), cmd.getStaticNatIpUuid(), cmd.getStaticNatIpAddress(), cmd.isStaticNatIpAllocated(), - cmd.isOneToOneNat(), cmd.getStaticNatVlanUuid(), cmd.getStaticNatVlanGateway(), cmd.getStaticNatVlanNetmask()); - return new Answer(cmd, true, "Created NIC that maps to nicUuid" + cmd.getNicUuid() + " on Nuage VSD " + _hostName); + _nuageVspGuruClient.reserve(cmd.getNetwork(), cmd.getVm(), cmd.getNic(), cmd.getStaticNat()); + return new Answer(cmd, true, "Created NIC that maps to nicUuid" + cmd.getNic().getUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -403,9 +366,9 @@ private Answer executeRequest(ReserveVmInterfaceVspCommand cmd) { private Answer executeRequest(DeallocateVmVspCommand cmd) { try { isNuageVspGuruLoaded(); - _nuageVspGuruClient.deallocate(cmd.getNetworkUuid(), cmd.getNicFromDdUuid(), cmd.getNicMacAddress(), cmd.getNicIp4Address(), cmd.isL3Network(), cmd.isSharedNetwork(), - cmd.getVpcUuid(), cmd.getNetworksDomainUuid(), cmd.getVmInstanceName(), cmd.getVmUuid(), cmd.isExpungingState()); - return new Answer(cmd, true, "Deallocated VM " + cmd.getVmInstanceName() + " on Nuage VSD " + _hostName); + + _nuageVspGuruClient.deallocate(cmd.getNetwork(), cmd.getVm(), cmd.getNic()); + return new Answer(cmd, true, "Deallocated VM " + cmd.getVm().getName() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -415,8 +378,8 @@ private Answer executeRequest(DeallocateVmVspCommand cmd) { private Answer executeRequest(TrashNetworkVspCommand cmd) { try { isNuageVspGuruLoaded(); - _nuageVspGuruClient.trash(cmd.getDomainUuid(), cmd.getNetworkUuid(), cmd.isL3Network(), cmd.isSharedNetwork(), cmd.getVpcUuid(), cmd.getDomainTemplateName()); - return new Answer(cmd, true, "Deleted network mapping to " + cmd.getNetworkUuid() + " on Nuage VSD " + _hostName); + _nuageVspGuruClient.trash(cmd.getNetwork()); + return new Answer(cmd, true, "Deleted network mapping to " + cmd.getNetwork().getUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -426,9 +389,8 @@ private Answer executeRequest(TrashNetworkVspCommand cmd) { private Answer executeRequest(ApplyStaticNatVspCommand cmd) { try { isNuageVspElementLoaded(); - _nuageVspElementClient.applyStaticNats(cmd.getNetworkDomainUuid(), cmd.getNetworkUuid(), cmd.getVpcOrSubnetUuid(), cmd.isL3Network(), - cmd.isVpc(), cmd.getStaticNatDetails()); - return new Answer(cmd, true, "Applied Static NAT to network mapping " + cmd.getVpcOrSubnetUuid() + " on Nuage VSD " + _hostName); + _nuageVspElementClient.applyStaticNats(cmd.getNetwork(), cmd.getStaticNatDetails()); + return new Answer(cmd, true, "Applied Static NAT to network mapping " + cmd.getNetwork().getUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -438,10 +400,9 @@ private Answer executeRequest(ApplyStaticNatVspCommand cmd) { private Answer executeRequest(ImplementVspCommand cmd) { try { isNuageVspElementLoaded(); - boolean success = _nuageVspElementClient.implement(cmd.getNetworkId(), cmd.getNetworkDomainUuid(), cmd.getNetworkUuid(), cmd.getNetworkName(), cmd.getVpcOrSubnetUuid(), cmd.isL2Network(), - cmd.isL3Network(), cmd.isVpc(), cmd.isShared(), cmd.getDomainTemplateName(), cmd.isFirewallServiceSupported(), cmd.getDnsServers(), cmd.getIngressFirewallRules(), - cmd.getEgressFirewallRules(), cmd.getAcsFipUuid(), cmd.isEgressDefaultPolicy()); - return new Answer(cmd, success, "Implemented network " + cmd.getNetworkUuid() + " on Nuage VSD " + _hostName); + boolean success = _nuageVspElementClient.implement(cmd.getNetwork(), cmd.getDnsServers(), cmd.getIngressFirewallRules(), + cmd.getEgressFirewallRules(), cmd.getFloatingIpUuids()); + return new Answer(cmd, success, "Implemented network " + cmd.getNetwork().getUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -451,9 +412,8 @@ private Answer executeRequest(ImplementVspCommand cmd) { private Answer executeRequest(ApplyAclRuleVspCommand cmd) { try { isNuageVspElementLoaded(); - _nuageVspElementClient.applyAclRules(cmd.isNetworkAcl(), cmd.getNetworkUuid(), cmd.getNetworkDomainUuid(), cmd.getVpcOrSubnetUuid(), cmd.getNetworkName(), - cmd.isL2Network(), cmd.getAclRules(), cmd.getNetworkId(), cmd.isEgressDefaultPolicy(), cmd.getAcsIngressAcl(), cmd.isNetworkReset(), cmd.getDomainTemplateName()); - return new Answer(cmd, true, "Applied ACL Rule to network mapping " + cmd.getVpcOrSubnetUuid() + " on Nuage VSD " + _hostName); + _nuageVspElementClient.applyAclRules(cmd.getAclType(), cmd.getNetwork(), cmd.getAclRules(), cmd.isNetworkReset()); + return new Answer(cmd, true, "Applied ACL Rule to network mapping " + cmd.getNetwork().getUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); return new Answer(cmd, e); @@ -463,7 +423,7 @@ private Answer executeRequest(ApplyAclRuleVspCommand cmd) { private Answer executeRequest(ShutDownVpcVspCommand cmd) { try { isNuageVspElementLoaded(); - _nuageVspElementClient.shutdownVpc(cmd.getDomainUuid(), cmd.getVpcUuid(), cmd.getDomainTemplateName()); + _nuageVspElementClient.shutdownVpc(cmd.getDomainUuid(), cmd.getVpcUuid(), cmd.getDomainTemplateName(), cmd.getDomainRouterUuids()); return new Answer(cmd, true, "Shutdown VPC " + cmd.getVpcUuid() + " on Nuage VSD " + _hostName); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); @@ -471,17 +431,6 @@ private Answer executeRequest(ShutDownVpcVspCommand cmd) { } } - private Answer executeRequest(SyncVspCommand cmd) { - try { - isNuageVspSyncLoaded(); - _nuageVspSyncClient.syncWithNuageVsp(cmd.getNuageVspEntity()); - return new Answer(cmd, true, "Synced " + cmd.getNuageVspEntity() + " on Nuage VSD " + _hostName); - } catch (ExecutionException | ConfigurationException e) { - s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); - return new Answer(cmd, e); - } - } - private Answer executeRequest(SyncNuageVspCmsIdCommand cmd) { try { isNuageVspManagerLoaded(); @@ -504,7 +453,7 @@ private Answer executeRequest(SyncNuageVspCmsIdCommand cmd) { private Answer executeRequest(SyncDomainCommand cmd) { try { isNuageVspManagerLoaded(); - boolean success = _nuageVspManagerClient.syncDomainWithNuageVsp(cmd.getDomainUuid(), cmd.getDomainName(), cmd.getDomainPath(), cmd.isToAdd(), cmd.isToRemove()); + boolean success = _nuageVspManagerClient.syncDomainWithNuageVsp(cmd.getDomain(), cmd.isToAdd(), cmd.isToRemove()); return new SyncDomainAnswer(success); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); @@ -512,14 +461,13 @@ private Answer executeRequest(SyncDomainCommand cmd) { } } - private Answer executeRequest(GetClientDefaultsCommand cmd) { + private Answer executeRequest(GetApiDefaultsCommand cmd) { try { isNuageVspManagerLoaded(); - Map clientDefaults = _nuageVspManagerClient.getClientDefaults(); - return new GetClientDefaultsAnswer(cmd, clientDefaults); + return new GetApiDefaultsAnswer(cmd, _nuageVspManagerClient.getApiDefaults()); } catch (ExecutionException | ConfigurationException e) { s_logger.error("Failure during " + cmd + " on Nuage VSD " + _hostName, e); - return new GetClientDefaultsAnswer(cmd, e); + return new GetApiDefaultsAnswer(cmd, e); } } @@ -552,12 +500,6 @@ protected void isNuageVspElementLoaded() throws ConfigurationException { } } - protected void isNuageVspSyncLoaded() throws ConfigurationException { - if (!_isNuageVspClientLoaded || _nuageVspSyncClient == null) { - throw new ConfigurationException(NUAGE_VSP_PLUGIN_ERROR_MESSAGE); - } - } - protected void isNuageVspManagerLoaded() throws ConfigurationException { if (!_isNuageVspClientLoaded || _nuageVspManagerClient == null) { throw new ConfigurationException(NUAGE_VSP_PLUGIN_ERROR_MESSAGE); diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSyncImpl.java b/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSyncImpl.java deleted file mode 100644 index 9180c17909..0000000000 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSyncImpl.java +++ /dev/null @@ -1,65 +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.network.sync; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.sync.SyncVspCommand; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.network.NuageVspDeviceVO; -import com.cloud.network.dao.NuageVspDao; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import javax.inject.Inject; -import java.util.List; - -@Component -public class NuageVspSyncImpl implements NuageVspSync { - - private static final Logger s_logger = Logger.getLogger(NuageVspSyncImpl.class); - - @Inject - NuageVspDao _nuageVspDao; - @Inject - HostDao _hostDao; - @Inject - AgentManager _agentMgr; - - public void syncWithNuageVsp(String nuageVspEntity) { - //Get the NuageVspDevice and get the host information. - //This information is used to query VSP and synch the corresponding - //entities - List nuageVspDevices = _nuageVspDao.listAll(); - for (NuageVspDeviceVO nuageVspDevice : nuageVspDevices) { - HostVO nuageVspHost = _hostDao.findById(nuageVspDevice.getHostId()); - _hostDao.loadDetails(nuageVspHost); - SyncVspCommand cmd = new SyncVspCommand(nuageVspEntity); - Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd); - if (answer == null || !answer.getResult()) { - s_logger.error("SyncNuageVspCommand for Nuage VSP Host " + nuageVspHost.getUuid() + " failed"); - if ((null != answer) && (null != answer.getDetails())) { - s_logger.error(answer.getDetails()); - } - } - } - } -} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java new file mode 100644 index 0000000000..8757ad0212 --- /dev/null +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspEntityBuilder.java @@ -0,0 +1,370 @@ +// +// 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.util; + +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.VlanDao; +import com.cloud.domain.Domain; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.InsufficientVirtualNetworkCapacityException; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkDetailsDao; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.VirtualMachine; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspDomain; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; +import net.nuage.vsp.acs.client.common.model.Pair; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +public class NuageVspEntityBuilder { + private static final Logger s_logger = Logger.getLogger(NuageVspEntityBuilder.class); + + @Inject + VpcDao _vpcDao; + @Inject + DomainDao _domainDao; + @Inject + AccountDao _accountDao; + @Inject + NetworkOfferingDao _networkOfferingDao; + @Inject + NetworkOfferingServiceMapDao _networkOfferingServiceMapDao; + @Inject + NetworkModel _networkModel; + @Inject + VlanDao _vlanDao; + @Inject + ConfigurationDao _configurationDao; + @Inject + IPAddressDao _ipAddressDao; + @Inject + NetworkDetailsDao _networkDetailsDao; + + public VspDomain buildVspDomain(Domain domain) { + return new VspDomain.Builder() + .uuid(domain.getUuid()) + .name(domain.getName()) + .path(domain.getPath()) + .build(); + } + + public VspNetwork buildVspNetwork(Network network, boolean fillAddressRange) { + VspNetwork.Builder vspNetworkBuilder = new VspNetwork.Builder() + .id(network.getId()) + .uuid(network.getUuid()) + .name(network.getName()) + .cidr(network.getCidr()) + .gateway(network.getGateway()); + + DomainVO domain = _domainDao.findById(network.getDomainId()); + VspDomain vspDomain = buildVspDomain(domain); + vspNetworkBuilder.domain(vspDomain); + + AccountVO account = _accountDao.findById(network.getAccountId()); + if (account != null) { + vspNetworkBuilder.accountUuid(account.getUuid()).accountName(account.getAccountName()); + } + + NetworkOfferingVO networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + vspNetworkBuilder.egressDefaultPolicy(networkOffering.getEgressDefaultPolicy()); + + if (network.getVpcId() != null) { + VpcVO vpc = _vpcDao.findById(network.getVpcId()); + vspNetworkBuilder.vpcUuid(vpc.getUuid()) + .vpcName(vpc.getName()) + .networkType(VspNetwork.NetworkType.Vpc); + } else { + if (networkOffering.getGuestType() == Network.GuestType.Shared) { + vspNetworkBuilder.networkType(VspNetwork.NetworkType.Shared); + } else if (_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Network.Service.SourceNat) + || _networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Network.Service.StaticNat)) { + vspNetworkBuilder.networkType(VspNetwork.NetworkType.L3); + } else { + vspNetworkBuilder.networkType(VspNetwork.NetworkType.L2); + } + } + + boolean firewallServiceSupported = _networkModel.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Network.Service.Firewall); + vspNetworkBuilder.firewallServiceSupported(firewallServiceSupported); + + String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configurationDao, _networkDetailsDao, network, networkOffering); + vspNetworkBuilder.domainTemplateName(preConfiguredDomainTemplateName); + + if (fillAddressRange) { + try { + List> ipAddressRanges = getIpAddressRanges(networkOffering, network); + vspNetworkBuilder.ipAddressRanges(ipAddressRanges); + + String virtualRouterIp = getVirtualRouterIP(network, ipAddressRanges); + vspNetworkBuilder.virtualRouterIp(virtualRouterIp); + } catch (InsufficientVirtualNetworkCapacityException ex) { + s_logger.error("There is an insufficient network capacity in network " + network.getId(), ex); + throw new CloudRuntimeException("There is an insufficient network capacity in network " + network.getId(), ex); + } + } + + return vspNetworkBuilder.build(); + } + + private List> getIpAddressRanges(NetworkOfferingVO networkOffering, Network network) { + List> ipAddressRanges = Lists.newArrayList(); + if (networkOffering.getGuestType() == Network.GuestType.Shared) { + List vlans = _vlanDao.listVlansByNetworkId(network.getId()); + ipAddressRanges = Lists.newArrayList(); + for (VlanVO vlan : vlans) { + boolean isIpv4 = StringUtils.isNotBlank(vlan.getIpRange()); + String[] range = isIpv4 ? vlan.getIpRange().split("-") : vlan.getIp6Range().split("-"); + if (range.length == 2) { + ipAddressRanges.add(Pair.of(range[0], range[1])); + } + } + return ipAddressRanges; + } + + String subnet = NetUtils.getCidrSubNet(network.getCidr()); + String netmask = NetUtils.getCidrNetmask(network.getCidr()); + long cidrSize = NetUtils.getCidrSize(netmask); + Set allIPsInCidr = NetUtils.getAllIpsFromCidr(subnet, cidrSize, new HashSet()); + if (allIPsInCidr == null || !(allIPsInCidr instanceof TreeSet)) { + throw new IllegalStateException("The IPs in CIDR for subnet " + subnet + " where null or returned in a non-ordered set."); + } + + Iterator ipIterator = allIPsInCidr.iterator(); + long ip = ipIterator.next(); + if (NetUtils.ip2Long(network.getGateway()) == ip) { + ip = ipIterator.next(); + } + ipAddressRanges.add(Pair.of(NetUtils.long2Ip(ip), NetUtils.getIpRangeEndIpFromCidr(subnet, cidrSize))); + return ipAddressRanges; + } + + private String getVirtualRouterIP(Network network, List> ipAddressRanges) throws InsufficientVirtualNetworkCapacityException { + Pair lowestIpAddressRange = null; + if (ipAddressRanges.size() == 1) { + lowestIpAddressRange = Iterables.getOnlyElement(ipAddressRanges); + } else { + for (Pair ipAddressRange : ipAddressRanges) { + if (lowestIpAddressRange == null || NetUtils.ip2Long(ipAddressRange.getLeft()) < NetUtils.ip2Long(lowestIpAddressRange.getLeft())) { + lowestIpAddressRange = ipAddressRange; + } + } + } + + if (lowestIpAddressRange == null) { + throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " But no ip address ranges are specified", Network.class, + network.getId()); + } else if (NetUtils.ip2Long(lowestIpAddressRange.getRight()) - NetUtils.ip2Long(lowestIpAddressRange.getLeft()) < 2) { + throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " So, subnet should have atleast minimum 3 hosts", Network.class, + network.getId()); + } + + String virtualRouterIp = lowestIpAddressRange.getLeft(); + long lowestIp = NetUtils.ip2Long(lowestIpAddressRange.getLeft()); + lowestIp = lowestIp + 1; + lowestIpAddressRange.setLeft(NetUtils.long2Ip(lowestIp)); + return virtualRouterIp; + } + + public VspVm buildVspVm(VirtualMachine vm, Network network) { + VspVm.Builder vspVmBuilder = new VspVm.Builder() + .uuid(vm.getUuid()) + .name(vm.getInstanceName()); + + switch (vm.getState()) { + case Starting: + vspVmBuilder.state(VspVm.State.Starting); break; + case Running: + vspVmBuilder.state(VspVm.State.Running); break; + case Stopping: + vspVmBuilder.state(VspVm.State.Stopping); break; + case Stopped: + vspVmBuilder.state(VspVm.State.Stopped); break; + case Destroyed: + vspVmBuilder.state(VspVm.State.Destroyed); break; + case Expunging: + vspVmBuilder.state(VspVm.State.Expunging); break; + case Migrating: + vspVmBuilder.state(VspVm.State.Migrating); break; + case Error: + vspVmBuilder.state(VspVm.State.Error); break; + case Shutdowned: + vspVmBuilder.state(VspVm.State.Shutdowned); break; + default: + vspVmBuilder.state(VspVm.State.Unknown); + } + + boolean isDomainRouter = vm.getType().equals(VirtualMachine.Type.DomainRouter); + vspVmBuilder.domainRouter(isDomainRouter); + + if (network.getBroadcastUri() != null) { + String domainRouterIp = network.getBroadcastUri().getPath().substring(1); + vspVmBuilder.domainRouterIp(domainRouterIp); + } + + return vspVmBuilder.build(); + } + + public VspNic buildVspNic(String nicUuid, NicProfile nicProfile) { + VspNic.Builder vspNicBuilder = new VspNic.Builder() + .uuid(nicUuid) + .macAddress(nicProfile.getMacAddress()) + .useStaticIp(true) + .ip(nicProfile.getIPv4Address()); + return vspNicBuilder.build(); + } + + public VspNic buildVspNic(NicVO nic) { + VspNic.Builder vspNicBuilder = new VspNic.Builder() + .uuid(nic.getUuid()) + .macAddress(nic.getMacAddress()) + .useStaticIp(true) + .ip(nic.getIPv4Address()); + return vspNicBuilder.build(); + } + + public VspStaticNat buildVspStaticNat(Boolean forRevoke, IPAddressVO staticNatIp, VlanVO staticNatVlan, NicVO nic) { + VspStaticNat.Builder vspStaticNatBuilder = new VspStaticNat.Builder() + .ipUuid(staticNatIp.getUuid()) + .ipAddress(staticNatIp.getAddress().addr()) + .revoke(forRevoke) + .oneToOneNat(staticNatIp.isOneToOneNat()) + .vlanUuid(staticNatVlan.getUuid()) + .vlanGateway(staticNatVlan.getVlanGateway()) + .vlanNetmask(staticNatVlan.getVlanNetmask()); + + if (nic != null) { + VspNic vspNic = buildVspNic(nic); + vspStaticNatBuilder.nic(vspNic); + } + + return vspStaticNatBuilder.build(); + } + + public VspAclRule buildVspAclRule(FirewallRule firewallRule, Network network) { + VspAclRule.Builder vspAclRuleBuilder = new VspAclRule.Builder() + .uuid(firewallRule.getUuid()) + .protocol(firewallRule.getProtocol()) + .startPort(firewallRule.getSourcePortStart()) + .endPort(firewallRule.getSourcePortEnd()) + .sourceCidrList(firewallRule.getSourceCidrList()) + .priority(-1) + .type(VspAclRule.ACLType.Firewall); + + switch (firewallRule.getState()) { + case Active: + vspAclRuleBuilder.state(VspAclRule.ACLState.Active); break; + case Add: + vspAclRuleBuilder.state(VspAclRule.ACLState.Add); break; + case Revoke: + vspAclRuleBuilder.state(VspAclRule.ACLState.Revoke); + } + + switch (firewallRule.getTrafficType()) { + case Ingress: + vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Ingress); break; + case Egress: + vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Egress); + } + + NetworkOfferingVO networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + if (firewallRule.getTrafficType() == FirewallRule.TrafficType.Egress && networkOffering.getEgressDefaultPolicy()) { + vspAclRuleBuilder.action(VspAclRule.ACLAction.Deny); + } else { + vspAclRuleBuilder.action(VspAclRule.ACLAction.Allow); + } + + if (firewallRule.getSourceIpAddressId() != null) { + IPAddressVO ipAddress = _ipAddressDao.findById(firewallRule.getSourceIpAddressId()); + if (ipAddress != null) { + vspAclRuleBuilder.sourceIpAddress(ipAddress.getVmIp() + "/32"); + } + } + + return vspAclRuleBuilder.build(); + } + + public VspAclRule buildVspAclRule(NetworkACLItem networkAcl) { + VspAclRule.Builder vspAclRuleBuilder = new VspAclRule.Builder() + .uuid(networkAcl.getUuid()) + .protocol(networkAcl.getProtocol()) + .startPort(networkAcl.getSourcePortStart()) + .endPort(networkAcl.getSourcePortEnd()) + .sourceIpAddress(null) + .sourceCidrList(networkAcl.getSourceCidrList()) + .priority(networkAcl.getNumber()) + .type(VspAclRule.ACLType.NetworkACL); + + switch (networkAcl.getState()) { + case Active: + vspAclRuleBuilder.state(VspAclRule.ACLState.Active); break; + case Add: + vspAclRuleBuilder.state(VspAclRule.ACLState.Add); break; + case Revoke: + vspAclRuleBuilder.state(VspAclRule.ACLState.Revoke); + } + + switch (networkAcl.getTrafficType()) { + case Ingress: + vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Ingress); break; + case Egress: + vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Egress); + } + + switch (networkAcl.getAction()) { + case Allow: + vspAclRuleBuilder.action(VspAclRule.ACLAction.Allow); break; + case Deny: + vspAclRuleBuilder.action(VspAclRule.ACLAction.Deny); + } + + return vspAclRuleBuilder.build(); + } +} diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspUtil.java b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspUtil.java index 23002892ce..fedf048db3 100644 --- a/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspUtil.java +++ b/plugins/network-elements/nuage-vsp/src/com/cloud/util/NuageVspUtil.java @@ -20,6 +20,8 @@ package com.cloud.util; import com.cloud.network.Network; +import com.cloud.network.dao.NetworkDetailVO; +import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.manager.NuageVspManager; import com.cloud.offering.NetworkOffering; import com.cloud.utils.StringUtils; @@ -28,7 +30,12 @@ public class NuageVspUtil { - public static String getPreConfiguredDomainTemplateName(ConfigurationDao configDao, Network network, NetworkOffering networkOffering) { + public static String getPreConfiguredDomainTemplateName(ConfigurationDao configDao, NetworkDetailsDao networkDetailsDao, Network network, NetworkOffering networkOffering) { + NetworkDetailVO domainTemplateNetworkDetail = networkDetailsDao.findDetail(network.getId(), NuageVspManager.nuageDomainTemplateDetailName); + if (domainTemplateNetworkDetail != null) { + return domainTemplateNetworkDetail.getValue(); + } + String configKey; if (network.getVpcId() != null) { configKey = NuageVspManager.NuageVspVpcDomainTemplateName.key(); diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/NuageVspPluginClientLoader.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/NuageVspPluginClientLoader.java index 57935b9f05..72ce2909e2 100644 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/NuageVspPluginClientLoader.java +++ b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/NuageVspPluginClientLoader.java @@ -19,82 +19,53 @@ package net.nuage.vsp.acs; -import net.nuage.vsp.acs.client.NuageVspApiClient; -import net.nuage.vsp.acs.client.NuageVspElementClient; -import net.nuage.vsp.acs.client.NuageVspGuruClient; -import net.nuage.vsp.acs.client.NuageVspManagerClient; -import net.nuage.vsp.acs.client.NuageVspSyncClient; +import net.nuage.vsp.acs.client.api.NuageVspApiClient; +import net.nuage.vsp.acs.client.api.NuageVspElementClient; +import net.nuage.vsp.acs.client.api.NuageVspGuruClient; +import net.nuage.vsp.acs.client.api.NuageVspManagerClient; +import net.nuage.vsp.acs.client.api.impl.NuageVspApiClientImpl; +import net.nuage.vsp.acs.client.api.impl.NuageVspElementClientImpl; +import net.nuage.vsp.acs.client.api.impl.NuageVspGuruClientImpl; +import net.nuage.vsp.acs.client.api.impl.NuageVspManagerClientImpl; +import net.nuage.vsp.acs.client.api.model.VspHost; import org.apache.log4j.Logger; -import javax.naming.ConfigurationException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; public class NuageVspPluginClientLoader { - private ClassLoader _loader = null; private static final Logger s_logger = Logger.getLogger(NuageVspPluginClientLoader.class); private NuageVspApiClient _nuageVspApiClient; private NuageVspElementClient _nuageVspElementClient; private NuageVspGuruClient _nuageVspGuruClient; private NuageVspManagerClient _nuageVspManagerClient; - private NuageVspSyncClient _nuageVspSyncClient; - private static final String NUAGE_PLUGIN_CLIENT_JAR_FILE = "/usr/share/nuagevsp/lib/nuage-vsp-acs-client.jar"; - private static final String NUAGE_VSP_API_CLIENT_IMPL = "net.nuage.vsp.acs.client.impl.NuageVspApiClientImpl"; - private static final String NUAGE_VSP_SYNC_CLIENT_IMPL = "net.nuage.vsp.acs.client.impl.NuageVspSyncClientImpl"; - private static final String NUAGE_VSP_ELEMENT_CLIENT_IMPL = "net.nuage.vsp.acs.client.impl.NuageVspElementClientImpl"; - private static final String NUAGE_VSP_GURU_CLIENT_IMPL = "net.nuage.vsp.acs.client.impl.NuageVspGuruClientImpl"; - private static final String NUAGE_VSP_MANAGER_CLIENT_IMPL = "net.nuage.vsp.acs.client.impl.NuageVspManagerClientImpl"; + private NuageVspPluginClientLoader() { - private NuageVspPluginClientLoader(String nuagePluginClientJarLocation) { - try { - _loader = URLClassLoader.newInstance(new URL[] {new URL("jar:file:" + nuagePluginClientJarLocation + "!/")}, - getClass().getClassLoader()); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(e); - } } - public static NuageVspPluginClientLoader getClientLoader(String relativePath, String[] cmsUserInfo, int numRetries, int retryInterval, - String nuageVspCmsId) throws ConfigurationException { - NuageVspPluginClientLoader nuageVspPluginClientClassloader = new NuageVspPluginClientLoader(NUAGE_PLUGIN_CLIENT_JAR_FILE); - nuageVspPluginClientClassloader.loadClasses(relativePath, cmsUserInfo, numRetries, retryInterval, nuageVspCmsId); + public static NuageVspPluginClientLoader getClientLoader(String relativePath, String cmsUserEnterprise, String cmsUserLogin, + String cmsUserPassword, int numRetries, int retryInterval, String nuageVspCmsId) { + NuageVspPluginClientLoader nuageVspPluginClientClassloader = new NuageVspPluginClientLoader(); + nuageVspPluginClientClassloader.loadClasses(relativePath, cmsUserEnterprise, cmsUserLogin, cmsUserPassword, numRetries, retryInterval, nuageVspCmsId); return nuageVspPluginClientClassloader; } - private void loadClasses(String relativePath, String[] cmsUserInfo, int numRetries, int retryInterval, String nuageVspCmsId) throws ConfigurationException { - try { - Class nuageVspApiClientClass = Class.forName(NUAGE_VSP_API_CLIENT_IMPL, true, _loader); - Class nuageVspSyncClientClass = Class.forName(NUAGE_VSP_SYNC_CLIENT_IMPL, true, _loader); - Class nuageVspGuruClientClass = Class.forName(NUAGE_VSP_GURU_CLIENT_IMPL, true, _loader); - Class nuageVspElementClientClass = Class.forName(NUAGE_VSP_ELEMENT_CLIENT_IMPL, true, _loader); - Class nuageVspManagerClientClass = Class.forName(NUAGE_VSP_MANAGER_CLIENT_IMPL, true, _loader); - - //Instantiate the instances - _nuageVspApiClient = (NuageVspApiClient)nuageVspApiClientClass.newInstance(); - _nuageVspApiClient.setNuageVspHost(relativePath, cmsUserInfo, numRetries, retryInterval, nuageVspCmsId); - _nuageVspSyncClient = (NuageVspSyncClient)nuageVspSyncClientClass.newInstance(); - _nuageVspSyncClient.setNuageVspApiClient(_nuageVspApiClient); - _nuageVspGuruClient = (NuageVspGuruClient)nuageVspGuruClientClass.newInstance(); - _nuageVspGuruClient.setNuageVspApiClient(_nuageVspApiClient); - _nuageVspElementClient = (NuageVspElementClient)nuageVspElementClientClass.newInstance(); - _nuageVspElementClient.setNuageVspApiClient(_nuageVspApiClient); - _nuageVspManagerClient = (NuageVspManagerClient)nuageVspManagerClientClass.newInstance(); - _nuageVspManagerClient.setNuageVspApiClient(_nuageVspApiClient); - } catch (ClassNotFoundException cnfe) { - s_logger.error("Error while loading classes of Nuage VSP client", cnfe); - throw new ConfigurationException("Error while loading classes of Nuage VSP client"); - } catch (InstantiationException ie) { - s_logger.error("Error while initializing classes of Nuage VSP client", ie); - throw new ConfigurationException("Error while initializing classes of Nuage VSP client"); - } catch (IllegalAccessException iae) { - s_logger.error("Error while accessing classes of Nuage VSP client", iae); - throw new ConfigurationException("Error while accessing classes of Nuage VSP client"); - } - + private void loadClasses(String relativePath, String cmsUserEnterprise, String cmsUserLogin, String cmsUserPassword, int numRetries, + int retryInterval, String nuageVspCmsId) { + VspHost vspHost = new VspHost.Builder() + .restRelativePath(relativePath) + .cmsUserEnterprise(cmsUserEnterprise) + .cmsUserLogin(cmsUserLogin) + .cmsUserPassword(cmsUserPassword) + .noofRetry(numRetries) + .retryInterval(retryInterval) + .nuageVspCmsId(nuageVspCmsId) + .build(); + _nuageVspApiClient = new NuageVspApiClientImpl(vspHost); + _nuageVspElementClient = new NuageVspElementClientImpl(_nuageVspApiClient); + _nuageVspGuruClient = new NuageVspGuruClientImpl(_nuageVspApiClient); + _nuageVspManagerClient = new NuageVspManagerClientImpl(_nuageVspApiClient); } public NuageVspApiClient getNuageVspApiClient() { @@ -112,8 +83,4 @@ public NuageVspGuruClient getNuageVspGuruClient() { public NuageVspManagerClient getNuageVspManagerClient() { return _nuageVspManagerClient; } - - public NuageVspSyncClient getNuageVspSyncClient() { - return _nuageVspSyncClient; - } } diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspElementClient.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspElementClient.java deleted file mode 100644 index acd4256a50..0000000000 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspElementClient.java +++ /dev/null @@ -1,42 +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 net.nuage.vsp.acs.client; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; - -public interface NuageVspElementClient { - - boolean implement(long networkId, String networkDomainUuid, String networkUuid, String networkName, String vpcOrSubnetUuid, boolean isL2Network, boolean isL3Network, - boolean isVpc, boolean isShared, String domainTemplateName, boolean isFirewallServiceSupported, List dnsServers, List> ingressFirewallRules, - List> egressFirewallRules, List acsFipUuid, boolean egressDefaultPolicy) throws ExecutionException; - - void applyStaticNats(String networkDomainUuid, String networkUuid, String vpcOrSubnetUuid, boolean isL3Network, boolean isVpc, - List> staticNatDetails) throws ExecutionException; - - void applyAclRules(boolean isNetworkAcl, String networkUuid, String networkDomainUuid, String vpcOrSubnetUuid, String networkName, boolean isL2Network, - List> rules, long networkId, boolean egressDefaultPolicy, Boolean isAcsIngressAcl, boolean networkReset, String domainTemplateName) throws ExecutionException; - - void shutdownVpc(String domainUuid, String vpcUuid, String domainTemplateName) throws ExecutionException; - - void setNuageVspApiClient(NuageVspApiClient nuageVspApiClient); - -} diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspGuruClient.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspGuruClient.java deleted file mode 100644 index 2b3a63a263..0000000000 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspGuruClient.java +++ /dev/null @@ -1,43 +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 net.nuage.vsp.acs.client; - -import java.util.Collection; -import java.util.List; -import java.util.concurrent.ExecutionException; - -public interface NuageVspGuruClient { - - void implement(String networkDomainName, String networkDomainPath, String networkDomainUuid, String networkAccountName, String networkAccountUuid, String networkName, - String networkCidr, String networkGateway, Long networkAclId, List dnsServers, List gatewaySystemIds, boolean isL3Network, boolean isVpc, boolean isSharedNetwork, - String networkUuid, String vpcName, String vpcUuid, boolean defaultEgressPolicy, Collection ipAddressRange, String domainTemplateName) throws ExecutionException; - - void reserve(String nicUuid, String nicMacAddress, String networkUuid, boolean isL3Network, boolean isSharedNetwork, String vpcUuid, String networkDomainUuid, - String networksAccountUuid, boolean isDomainRouter, String domainRouterIp, String vmInstanceName, String vmUuid, boolean useStaticIp, String staticIp, String staticNatIpUuid, - String staticNatIpAddress, boolean isStaticNatIpAllocated, boolean isOneToOneNat, String staticNatVlanUuid, String staticNatVlanGateway, String staticNatVlanNetmask) throws ExecutionException; - - void deallocate(String networkUuid, String nicFrmDdUuid, String nicMacAddress, String nicIp4Address, boolean isL3Network, boolean isSharedNetwork, - String vpcUuid, String networksDomainUuid, String vmInstanceName, String vmUuid, boolean isExpungingState) throws ExecutionException; - - void trash(String domainUuid, String networkUuid, boolean isL3Network, boolean isSharedNetwork, String vpcUuid, String domainTemplateName) throws ExecutionException; - - void setNuageVspApiClient(NuageVspApiClient nuageVspApiClient); - -} diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspManagerClient.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspManagerClient.java deleted file mode 100644 index f134111bf7..0000000000 --- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspManagerClient.java +++ /dev/null @@ -1,42 +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 net.nuage.vsp.acs.client; - -import org.apache.commons.lang3.tuple.Pair; - -import java.util.Map; -import java.util.concurrent.ExecutionException; - -public interface NuageVspManagerClient { - - Pair auditNuageVspCmsId(String nuageVspCmsId, boolean auditOnly) throws ExecutionException; - - String registerNuageVspCmsId() throws ExecutionException; - - boolean unregisterNuageVspCmsId(String nuageVspCmsId) throws ExecutionException; - - boolean isSupportedApiVersion(String version); - - Map getClientDefaults() throws ExecutionException; - - boolean syncDomainWithNuageVsp(String domainUuid, String domainName, String domainPath, boolean add, boolean remove) throws ExecutionException; - - void setNuageVspApiClient(NuageVspApiClient nuageVspApiClient); -} diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java new file mode 100644 index 0000000000..845a8be04f --- /dev/null +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/NuageTest.java @@ -0,0 +1,157 @@ +// +// 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; + +import com.cloud.dc.VlanVO; +import com.cloud.domain.Domain; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.util.NuageVspEntityBuilder; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.VirtualMachine; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspDomain; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; +import net.nuage.vsp.acs.client.common.model.Pair; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.junit.Before; + +import java.util.ArrayList; + +import static com.cloud.network.manager.NuageVspManager.NuageVspIsolatedNetworkDomainTemplateName; +import static com.cloud.network.manager.NuageVspManager.NuageVspSharedNetworkDomainTemplateName; +import static com.cloud.network.manager.NuageVspManager.NuageVspVpcDomainTemplateName; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class NuageTest { + + protected static final long NETWORK_ID = 42L; + protected NetworkModel _networkModel = mock(NetworkModel.class); + protected ConfigurationDao _configurationDao = mock(ConfigurationDao.class); + protected NuageVspEntityBuilder _nuageVspEntityBuilder = mock(NuageVspEntityBuilder.class); + + @Before + public void setUp() throws Exception { + // Standard responses + when(_networkModel.isProviderForNetwork(Network.Provider.NuageVsp, NETWORK_ID)).thenReturn(true); + when(_configurationDao.getValue(NuageVspIsolatedNetworkDomainTemplateName.key())).thenReturn("IsolatedDomainTemplate"); + when(_configurationDao.getValue(NuageVspVpcDomainTemplateName.key())).thenReturn("VpcDomainTemplate"); + when(_configurationDao.getValue(NuageVspSharedNetworkDomainTemplateName.key())).thenReturn("SharedDomainTemplate"); + + when(_nuageVspEntityBuilder.buildVspDomain(any(Domain.class))).thenReturn(buildVspDomain()); + when(_nuageVspEntityBuilder.buildVspNetwork(any(Network.class), anyBoolean())).thenReturn(buildVspNetwork()); + when(_nuageVspEntityBuilder.buildVspVm(any(VirtualMachine.class), any(Network.class))).thenReturn(buildVspVm()); + when(_nuageVspEntityBuilder.buildVspNic(anyString(), any(NicProfile.class))).thenReturn(buildVspNic()); + when(_nuageVspEntityBuilder.buildVspNic(any(NicVO.class))).thenReturn(buildVspNic()); + when(_nuageVspEntityBuilder.buildVspStaticNat(anyBoolean(), any(IPAddressVO.class), any(VlanVO.class), any(NicVO.class))).thenReturn(buildVspStaticNat()); + when(_nuageVspEntityBuilder.buildVspAclRule(any(FirewallRule.class), any(Network.class))).thenReturn(buildVspAclRule()); + when(_nuageVspEntityBuilder.buildVspAclRule(any(NetworkACLItem.class))).thenReturn(buildVspAclRule()); + } + + protected VspDomain buildVspDomain() { + return new VspDomain.Builder() + .uuid("domainUuid") + .name("domainName") + .path("domainPath") + .build(); + } + + protected VspNetwork buildVspNetwork() { + return new VspNetwork.Builder() + .id(NETWORK_ID) + .uuid("networkUuid") + .name("networkName") + .domain(buildVspDomain()) + .accountUuid("networkAccountUuid") + .accountName("networkAccountName") + .vpcUuid("vpcUuid") + .vpcName("vpcName") + .networkType(VspNetwork.NetworkType.L3) + .firewallServiceSupported(true) + .egressDefaultPolicy(true) + .domainTemplateName("domainTemplateName") + .cidr("networkCidr") + .gateway("networkGateway") + .virtualRouterIp("virtualRouterIp") + .ipAddressRanges(new ArrayList>()) + .build(); + } + + protected VspVm buildVspVm() { + return new VspVm.Builder() + .state(VspVm.State.Running) + .uuid("vmUuid") + .name("vmName") + .domainRouter(true) + .domainRouterIp("domainRouterIp") + .build(); + } + + protected VspNic buildVspNic() { + return new VspNic.Builder() + .uuid("nicUuid") + .macAddress("macAddress") + .useStaticIp(true) + .ip("ip") + .build(); + } + + protected VspStaticNat buildVspStaticNat() { + return new VspStaticNat.Builder() + .state(VspStaticNat.State.Allocating) + .ipUuid("ipUuid") + .ipAddress("ipAddress") + .nic(buildVspNic()) + .revoke(false) + .oneToOneNat(true) + .vlanUuid("vlanUuid") + .vlanGateway("vlanGateway") + .vlanNetmask("vlanNetmask") + .build(); + } + + protected VspAclRule buildVspAclRule() { + return new VspAclRule.Builder() + .uuid("aclRuleUuid") + .protocol("protcol") + .startPort(1) + .endPort(9) + .state(VspAclRule.ACLState.Add) + .trafficType(VspAclRule.ACLTrafficType.Ingress) + .action(VspAclRule.ACLAction.Allow) + .sourceIpAddress("sourceIpAddress") + .sourceCidrList(new ArrayList()) + .priority(1) + .type(VspAclRule.ACLType.NetworkACL) + .build(); + } + +} diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/agent/api/CommandsTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/agent/api/CommandsTest.java index 817ab7a3bc..2a0b07ad99 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/agent/api/CommandsTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/agent/api/CommandsTest.java @@ -30,43 +30,41 @@ import com.cloud.agent.api.manager.SupportedApiVersionCommand; import com.cloud.agent.api.sync.SyncDomainCommand; import com.cloud.agent.api.sync.SyncNuageVspCmsIdCommand; -import com.cloud.agent.api.sync.SyncVspCommand; import com.google.common.collect.Maps; import com.google.common.testing.EqualsTester; import org.junit.Test; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.Map; public class CommandsTest { @Test public void testCommandEquals() throws IllegalAccessException, InvocationTargetException, InstantiationException { - ApplyAclRuleVspCommand applyAclRuleVspCommand = fillBuilderObject(new ApplyAclRuleVspCommand.Builder()).build(); - ApplyAclRuleVspCommand otherApplyAclRuleVspCommand = fillBuilderObject(new ApplyAclRuleVspCommand.Builder()).build(); + ApplyAclRuleVspCommand applyAclRuleVspCommand = fillObject(ApplyAclRuleVspCommand.class); + ApplyAclRuleVspCommand otherApplyAclRuleVspCommand = fillObject(ApplyAclRuleVspCommand.class); - ApplyStaticNatVspCommand applyStaticNatVspCommand = fillBuilderObject(new ApplyStaticNatVspCommand.Builder()).build(); - ApplyStaticNatVspCommand otherApplyStaticNatVspCommand = fillBuilderObject(new ApplyStaticNatVspCommand.Builder()).build(); + ApplyStaticNatVspCommand applyStaticNatVspCommand = fillObject(ApplyStaticNatVspCommand.class); + ApplyStaticNatVspCommand otherApplyStaticNatVspCommand = fillObject(ApplyStaticNatVspCommand.class); - ImplementVspCommand implementVspCommand = fillBuilderObject(new ImplementVspCommand.Builder()).build(); - ImplementVspCommand otherImplementVspCommand = fillBuilderObject(new ImplementVspCommand.Builder()).build(); + ImplementVspCommand implementVspCommand = fillObject(ImplementVspCommand.class); + ImplementVspCommand otherImplementVspCommand = fillObject(ImplementVspCommand.class); - ShutDownVpcVspCommand shutDownVpcVspCommand = fillBuilderObject(new ShutDownVpcVspCommand.Builder()).build(); - ShutDownVpcVspCommand otherShutDownVpcVspCommand = fillBuilderObject(new ShutDownVpcVspCommand.Builder()).build(); + ShutDownVpcVspCommand shutDownVpcVspCommand = fillObject(ShutDownVpcVspCommand.class); + ShutDownVpcVspCommand otherShutDownVpcVspCommand = fillObject(ShutDownVpcVspCommand.class); - DeallocateVmVspCommand deallocateVmVspCommand = fillBuilderObject(new DeallocateVmVspCommand.Builder()).build(); - DeallocateVmVspCommand otherDeallocateVmVspCommand = fillBuilderObject(new DeallocateVmVspCommand.Builder()).build(); + DeallocateVmVspCommand deallocateVmVspCommand = fillObject(DeallocateVmVspCommand.class); + DeallocateVmVspCommand otherDeallocateVmVspCommand = fillObject(DeallocateVmVspCommand.class); - ImplementNetworkVspCommand implementNetworkVspCommand = fillBuilderObject(new ImplementNetworkVspCommand.Builder()).build(); - ImplementNetworkVspCommand otherImplementNetworkVspCommand = fillBuilderObject(new ImplementNetworkVspCommand.Builder()).build(); + ImplementNetworkVspCommand implementNetworkVspCommand = fillObject(ImplementNetworkVspCommand.class); + ImplementNetworkVspCommand otherImplementNetworkVspCommand = fillObject(ImplementNetworkVspCommand.class); - ReserveVmInterfaceVspCommand reserveVmInterfaceVspCommand = fillBuilderObject(new ReserveVmInterfaceVspCommand.Builder()).build(); - ReserveVmInterfaceVspCommand otherReserveVmInterfaceVspCommand = fillBuilderObject(new ReserveVmInterfaceVspCommand.Builder()).build(); + ReserveVmInterfaceVspCommand reserveVmInterfaceVspCommand = fillObject(ReserveVmInterfaceVspCommand.class); + ReserveVmInterfaceVspCommand otherReserveVmInterfaceVspCommand = fillObject(ReserveVmInterfaceVspCommand.class); - TrashNetworkVspCommand trashNetworkVspCommand = fillBuilderObject(new TrashNetworkVspCommand.Builder()).build(); - TrashNetworkVspCommand otherTrashNetworkVspCommand = fillBuilderObject(new TrashNetworkVspCommand.Builder()).build(); + TrashNetworkVspCommand trashNetworkVspCommand = fillObject(TrashNetworkVspCommand.class); + TrashNetworkVspCommand otherTrashNetworkVspCommand = fillObject(TrashNetworkVspCommand.class); SupportedApiVersionCommand supportedApiVersionCommand = new SupportedApiVersionCommand("3.2"); SupportedApiVersionCommand otherSupportedApiVersionCommand = new SupportedApiVersionCommand("3.2"); @@ -77,15 +75,9 @@ public void testCommandEquals() throws IllegalAccessException, InvocationTargetE SyncNuageVspCmsIdCommand syncNuageVspCmsIdCommand = fillObject(SyncNuageVspCmsIdCommand.class); SyncNuageVspCmsIdCommand otherSyncNuageVspCmsIdCommand = fillObject(SyncNuageVspCmsIdCommand.class); - SyncVspCommand syncVspCommand = fillObject(SyncVspCommand.class); - SyncVspCommand otherSyncVspCommand = fillObject(SyncVspCommand.class); - PingNuageVspCommand pingNuageVspCommand = fillObject(PingNuageVspCommand.class); PingNuageVspCommand otherPingNuageVspCommand = fillObject(PingNuageVspCommand.class); - VspResourceCommand vspResourceCommand = fillObject(VspResourceCommand.class); - VspResourceCommand otherVspResourceCommand = fillObject(VspResourceCommand.class); - new EqualsTester() .addEqualityGroup(applyAclRuleVspCommand, otherApplyAclRuleVspCommand) .addEqualityGroup(applyStaticNatVspCommand, otherApplyStaticNatVspCommand) @@ -98,33 +90,10 @@ public void testCommandEquals() throws IllegalAccessException, InvocationTargetE .addEqualityGroup(supportedApiVersionCommand, otherSupportedApiVersionCommand) .addEqualityGroup(syncDomainCommand, otherSyncDomainCommand) .addEqualityGroup(syncNuageVspCmsIdCommand, otherSyncNuageVspCmsIdCommand) - .addEqualityGroup(syncVspCommand, otherSyncVspCommand) .addEqualityGroup(pingNuageVspCommand, otherPingNuageVspCommand) - .addEqualityGroup(vspResourceCommand, otherVspResourceCommand) .testEquals(); } - private T fillBuilderObject(T obj) throws IllegalAccessException, InvocationTargetException { - Class clazz = obj.getClass(); - for (Method method : clazz.getDeclaredMethods()) { - if (method.getParameterTypes().length == 1) { - Class paramType = method.getParameterTypes()[0]; - if (isNumericType(paramType)) { - if (Long.class.isAssignableFrom(paramType)) { - method.invoke(obj, Long.valueOf(method.getName().length())); - } else { - method.invoke(obj, method.getName().length()); - } - } else if (String.class.isAssignableFrom(paramType)) { - method.invoke(obj, method.getName()); - } else if (Boolean.class.isAssignableFrom(paramType) || boolean.class.isAssignableFrom(paramType)) { - method.invoke(obj, method.getName().length() % 2 == 0); - } - } - } - return obj; - } - private T fillObject(Class clazz) throws IllegalAccessException, InvocationTargetException, InstantiationException { Constructor constructor = clazz.getDeclaredConstructors()[0]; Object[] constructorArgs = new Object[constructor.getParameterTypes().length]; diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java index bbdf764ed8..85cbb361c9 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/element/NuageVspElementTest.java @@ -19,6 +19,7 @@ package com.cloud.network.element; +import com.cloud.NuageTest; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; @@ -35,7 +36,6 @@ import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -import com.cloud.network.NetworkModel; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.NuageVspDeviceVO; @@ -59,15 +59,15 @@ import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.resource.ResourceManager; import com.cloud.user.Account; +import com.cloud.util.NuageVspEntityBuilder; +import com.cloud.vm.DomainRouterVO; import com.cloud.vm.ReservationContext; +import com.cloud.vm.dao.DomainRouterDao; import com.google.common.collect.Lists; -import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; import org.junit.Before; import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import javax.naming.ConfigurationException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; @@ -76,9 +76,6 @@ import java.util.HashSet; import java.util.Set; -import static com.cloud.network.manager.NuageVspManager.NuageVspIsolatedNetworkDomainTemplateName; -import static com.cloud.network.manager.NuageVspManager.NuageVspSharedNetworkDomainTemplateName; -import static com.cloud.network.manager.NuageVspManager.NuageVspVpcDomainTemplateName; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; @@ -86,55 +83,48 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class NuageVspElementTest { - - private static final long NETWORK_ID = 42L; - NuageVspElement element = new NuageVspElement(); - NetworkOrchestrationService networkManager = mock(NetworkOrchestrationService.class); - NetworkModel networkModel = mock(NetworkModel.class); - NetworkServiceMapDao ntwkSrvcDao = mock(NetworkServiceMapDao.class); - AgentManager agentManager = mock(AgentManager.class); - HostDao hostDao = mock(HostDao.class); - NuageVspDao nuageVspDao = mock(NuageVspDao.class); - DomainDao domainDao = mock(DomainDao.class); - NetworkOfferingDao ntwkOfferingDao = mock(NetworkOfferingDao.class); - NetworkOfferingServiceMapDao ntwkOfferingSrvcDao = mock(NetworkOfferingServiceMapDao.class); - ConfigurationDao configDao = mock(ConfigurationDao.class); - NuageVspManager nuageVspManager = mock(NuageVspManager.class); - FirewallRulesDao firewallRulesDao = mock(FirewallRulesDao.class); - IPAddressDao ipAddressDao = mock(IPAddressDao.class); - PhysicalNetworkDao physNetDao = mock(PhysicalNetworkDao.class); - - org.mockito.stubbing.Answer genericAnswer = new org.mockito.stubbing.Answer() { - public Object answer(InvocationOnMock invocation) { - return null; - } - }; +public class NuageVspElementTest extends NuageTest { + + private NuageVspElement _nuageVspElement = new NuageVspElement(); + + private NetworkServiceMapDao _networkServiceMapDao = mock(NetworkServiceMapDao.class); + private AgentManager _agentManager = mock(AgentManager.class); + private HostDao _hostDao = mock(HostDao.class); + private NuageVspDao _nuageVspDao = mock(NuageVspDao.class); + private DomainDao _domainDao = mock(DomainDao.class); + private NetworkOfferingDao _networkOfferingDao = mock(NetworkOfferingDao.class); + private NetworkOfferingServiceMapDao _networkOfferingServiceMapDao = mock(NetworkOfferingServiceMapDao.class); + private NuageVspManager _nuageVspManager = mock(NuageVspManager.class); + private FirewallRulesDao _firewallRulesDao = mock(FirewallRulesDao.class); + private IPAddressDao _ipAddressDao = mock(IPAddressDao.class); + private PhysicalNetworkDao _physicalNetworkDao = mock(PhysicalNetworkDao.class); + private NuageVspEntityBuilder _nuageVspEntityBuilder = mock(NuageVspEntityBuilder.class); + private VpcDetailsDao _vpcDetailsDao = mock(VpcDetailsDao.class); + private DomainRouterDao _domainRouterDao = mock(DomainRouterDao.class); @Before - public void setUp() throws ConfigurationException { - element._resourceMgr = mock(ResourceManager.class); - element._ntwkSrvcDao = ntwkSrvcDao; - element._networkModel = networkModel; - element._agentMgr = agentManager; - element._hostDao = hostDao; - element._nuageVspDao = nuageVspDao; - element._ntwkOfferingSrvcDao = ntwkOfferingSrvcDao; - element._domainDao = domainDao; - element._ntwkOfferingDao = ntwkOfferingDao; - element._configDao = configDao; - element._nuageVspManager = nuageVspManager; - element._firewallRulesDao = firewallRulesDao; - element._ipAddressDao = ipAddressDao; - element._physicalNetworkDao = physNetDao; - - // Standard responses - when(networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true); - when(configDao.getValue(NuageVspIsolatedNetworkDomainTemplateName.key())).thenReturn("IsolatedDomainTemplate"); - when(configDao.getValue(NuageVspVpcDomainTemplateName.key())).thenReturn("VpcDomainTemplate"); - when(configDao.getValue(NuageVspSharedNetworkDomainTemplateName.key())).thenReturn("SharedDomainTemplate"); - - element.configure("NuageVspTestElement", Collections. emptyMap()); + public void setUp() throws Exception { + super.setUp(); + + _nuageVspElement._resourceMgr = mock(ResourceManager.class); + _nuageVspElement._ntwkSrvcDao = _networkServiceMapDao; + _nuageVspElement._networkModel = _networkModel; + _nuageVspElement._agentMgr = _agentManager; + _nuageVspElement._hostDao = _hostDao; + _nuageVspElement._nuageVspDao = _nuageVspDao; + _nuageVspElement._ntwkOfferingSrvcDao = _networkOfferingServiceMapDao; + _nuageVspElement._domainDao = _domainDao; + _nuageVspElement._ntwkOfferingDao = _networkOfferingDao; + _nuageVspElement._configDao = _configurationDao; + _nuageVspElement._nuageVspManager = _nuageVspManager; + _nuageVspElement._firewallRulesDao = _firewallRulesDao; + _nuageVspElement._ipAddressDao = _ipAddressDao; + _nuageVspElement._physicalNetworkDao = _physicalNetworkDao; + _nuageVspElement._nuageVspEntityBuilder = _nuageVspEntityBuilder; + _nuageVspElement._vpcDetailsDao = _vpcDetailsDao; + _nuageVspElement._routerDao = _domainRouterDao; + + _nuageVspElement.configure("NuageVspTestElement", Collections.emptyMap()); } @Test @@ -142,28 +132,34 @@ public void testCanHandle() { final Network net = mock(Network.class); when(net.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vsp); when(net.getId()).thenReturn(NETWORK_ID); + when(net.getNetworkOfferingId()).thenReturn(NETWORK_ID); - when(ntwkSrvcDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); + final NetworkOfferingVO ntwkoffer = mock(NetworkOfferingVO.class); + when(ntwkoffer.getId()).thenReturn(NETWORK_ID); + when(ntwkoffer.getIsPersistent()).thenReturn(true); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); + + when(_networkServiceMapDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); // Golden path - assertTrue(element.canHandle(net, Service.Connectivity)); + assertTrue(_nuageVspElement.canHandle(net, Service.Connectivity)); when(net.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vlan); // Only broadcastdomaintype Vsp is supported - assertFalse(element.canHandle(net, Service.Connectivity)); + assertFalse(_nuageVspElement.canHandle(net, Service.Connectivity)); when(net.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vsp); - when(ntwkSrvcDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(false); + when(_networkServiceMapDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(false); // No NuageVsp provider in the network - assertFalse(element.canHandle(net, Service.Connectivity)); + assertFalse(_nuageVspElement.canHandle(net, Service.Connectivity)); - when(networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(false); - when(ntwkSrvcDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); + when(_networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(false); + when(_networkServiceMapDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); // NusageVsp provider does not provide Connectivity for this network - assertFalse(element.canHandle(net, Service.Connectivity)); + assertFalse(_nuageVspElement.canHandle(net, Service.Connectivity)); - when(networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true); + when(_networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true); // Only service Connectivity is supported - assertFalse(element.canHandle(net, Service.Dhcp)); + assertFalse(_nuageVspElement.canHandle(net, Service.Dhcp)); } @@ -176,8 +172,8 @@ public void testImplement() throws ConcurrentOperationException, ResourceUnavail when(network.getBroadcastUri()).thenReturn(new URI("")); when(network.getPhysicalNetworkId()).thenReturn(NETWORK_ID); when(network.getDomainId()).thenReturn(NETWORK_ID); - when(networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true); - when(ntwkSrvcDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); + when(_networkModel.isProviderForNetwork(Provider.NuageVsp, NETWORK_ID)).thenReturn(true); + when(_networkServiceMapDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true); final NetworkOffering offering = mock(NetworkOffering.class); when(offering.getId()).thenReturn(NETWORK_ID); @@ -188,7 +184,7 @@ public void testImplement() throws ConcurrentOperationException, ResourceUnavail final DomainVO dom = mock(DomainVO.class); when(dom.getName()).thenReturn("domain"); - when(domainDao.findById(NETWORK_ID)).thenReturn(dom); + when(_domainDao.findById(NETWORK_ID)).thenReturn(dom); final Account acc = mock(Account.class); when(acc.getAccountName()).thenReturn("accountname"); final ReservationContext context = mock(ReservationContext.class); @@ -199,15 +195,15 @@ public void testImplement() throws ConcurrentOperationException, ResourceUnavail when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); - when(firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress)).thenReturn(new ArrayList()); - when(firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Egress)).thenReturn(new ArrayList()); - when(ipAddressDao.listStaticNatPublicIps(NETWORK_ID)).thenReturn(new ArrayList()); - when(nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); + when(_firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress)).thenReturn(new ArrayList()); + when(_firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Egress)).thenReturn(new ArrayList()); + when(_ipAddressDao.listStaticNatPublicIps(NETWORK_ID)).thenReturn(new ArrayList()); + when(_nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); - assertTrue(element.implement(network, offering, deployDest, context)); + assertTrue(_nuageVspElement.implement(network, offering, deployDest, context)); } @Test @@ -218,14 +214,14 @@ public void testVerifyServiceCombination() { services.add(Service.SourceNat); services.add(Service.Connectivity); services.add(Service.Firewall); - assertTrue(element.verifyServicesCombination(services)); + assertTrue(_nuageVspElement.verifyServicesCombination(services)); services = new HashSet(); services.add(Service.Dhcp); services.add(Service.StaticNat); services.add(Service.Connectivity); services.add(Service.Firewall); - assertFalse(element.verifyServicesCombination(services)); + assertFalse(_nuageVspElement.verifyServicesCombination(services)); } @Test @@ -238,25 +234,24 @@ public void testApplyStaticNats() throws CloudException { when(network.getDomainId()).thenReturn(NETWORK_ID); final DomainVO domVo = mock(DomainVO.class); - when(domainDao.findById(41l)).thenReturn(domVo); + when(_domainDao.findById(41l)).thenReturn(domVo); final NetworkOfferingVO ntwkoffer = mock(NetworkOfferingVO.class); when(ntwkoffer.getId()).thenReturn(NETWORK_ID); - when(ntwkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); - when(element.isL3Network(NETWORK_ID)).thenReturn(true); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); - when(domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); + when(_domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - assertTrue(element.applyStaticNats(network, new ArrayList())); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + assertTrue(_nuageVspElement.applyStaticNats(network, new ArrayList())); } @Test @@ -271,21 +266,21 @@ public void testApplyFWRules() throws Exception { final NetworkOfferingVO ntwkoffer = mock(NetworkOfferingVO.class); when(ntwkoffer.getId()).thenReturn(NETWORK_ID); when(ntwkoffer.getEgressDefaultPolicy()).thenReturn(true); - when(ntwkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); - when(domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); + when(_domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - assertTrue(element.applyFWRules(network, new ArrayList())); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + assertTrue(_nuageVspElement.applyFWRules(network, new ArrayList())); } @Test @@ -300,20 +295,20 @@ public void testApplyNetworkACL() throws Exception { final NetworkOfferingVO ntwkoffer = mock(NetworkOfferingVO.class); when(ntwkoffer.getId()).thenReturn(NETWORK_ID); when(ntwkoffer.getEgressDefaultPolicy()).thenReturn(true); - when(ntwkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffer); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); - when(domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); + when(_domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - assertTrue(element.applyNetworkACLs(network, new ArrayList())); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + assertTrue(_nuageVspElement.applyNetworkACLs(network, new ArrayList())); } @Test @@ -323,10 +318,11 @@ public void testShutdownVpc() throws Exception { when(vpc.getState()).thenReturn(Vpc.State.Inactive); when(vpc.getDomainId()).thenReturn(NETWORK_ID); when(vpc.getZoneId()).thenReturn(NETWORK_ID); + when(vpc.getId()).thenReturn(NETWORK_ID); final DomainVO dom = mock(DomainVO.class); when(dom.getName()).thenReturn("domain"); - when(domainDao.findById(NETWORK_ID)).thenReturn(dom); + when(_domainDao.findById(NETWORK_ID)).thenReturn(dom); final Account acc = mock(Account.class); when(acc.getAccountName()).thenReturn("accountname"); final ReservationContext context = mock(ReservationContext.class); @@ -336,18 +332,22 @@ public void testShutdownVpc() throws Exception { PhysicalNetworkVO physNet = mock(PhysicalNetworkVO.class); when(physNet.getIsolationMethods()).thenReturn(Lists.newArrayList(PhysicalNetwork.IsolationMethod.VSP.name())); when(physNet.getId()).thenReturn(NETWORK_ID); - when(physNetDao.listByZone(NETWORK_ID)).thenReturn(Lists.newArrayList(physNet)); + when(_physicalNetworkDao.listByZone(NETWORK_ID)).thenReturn(Lists.newArrayList(physNet)); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Lists.newArrayList(nuageVspDevice)); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); + + DomainRouterVO domainRouter = mock(DomainRouterVO.class); + when(domainRouter.getUuid()).thenReturn("aaaaaa"); + when(_domainRouterDao.listByVpcId(NETWORK_ID)).thenReturn(Lists.newArrayList(domainRouter)); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - assertTrue(element.shutdownVpc(vpc, context)); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + assertTrue(_nuageVspElement.shutdownVpc(vpc, context)); } } \ No newline at end of file diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java index 18c088f684..f101e1e1a2 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/guru/NuageVspGuestNetworkGuruTest.java @@ -19,9 +19,11 @@ package com.cloud.network.guru; +import com.cloud.NuageTest; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.configuration.ConfigurationManager; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; @@ -45,6 +47,7 @@ import com.cloud.network.NuageVspDeviceVO; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.NuageVspDao; import com.cloud.network.dao.PhysicalNetworkDao; @@ -63,7 +66,6 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.NicDao; -import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.junit.Before; import org.junit.Test; @@ -78,64 +80,68 @@ import static com.cloud.network.manager.NuageVspManager.NuageVspSharedNetworkDomainTemplateName; import static com.cloud.network.manager.NuageVspManager.NuageVspVpcDomainTemplateName; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class NuageVspGuestNetworkGuruTest { +public class NuageVspGuestNetworkGuruTest extends NuageTest { private static final long NETWORK_ID = 42L; - PhysicalNetworkDao physnetdao = mock(PhysicalNetworkDao.class); - DataCenterDao dcdao = mock(DataCenterDao.class); - NetworkOfferingServiceMapDao nosd = mock(NetworkOfferingServiceMapDao.class); - AgentManager agentManager = mock(AgentManager.class); - NetworkOrchestrationService netmgr = mock(NetworkOrchestrationService.class); - NetworkModel networkModel = mock(NetworkModel.class); - AccountDao accountDao = mock(AccountDao.class); - DomainDao domainDao = mock(DomainDao.class); - NicDao nicDao = mock(NicDao.class); - NetworkOfferingDao ntwkOfferDao = mock(NetworkOfferingDao.class); - NuageVspDao nuageVspDao = mock(NuageVspDao.class); - HostDao hostDao = mock(HostDao.class); - NetworkDao networkDao = mock(NetworkDao.class); - ConfigurationDao configDao = mock(ConfigurationDao.class); - IPAddressDao ipAddressDao = mock(IPAddressDao.class); - NuageVspManager nuageVspManager = mock(NuageVspManager.class); - - NetworkDao netdao = mock(NetworkDao.class); - NuageVspGuestNetworkGuru guru; + private PhysicalNetworkDao _physicalNetworkDao = mock(PhysicalNetworkDao.class); + private DataCenterDao _dataCenterDao = mock(DataCenterDao.class); + private NetworkOfferingServiceMapDao _networkOfferingServiceMapDao = mock(NetworkOfferingServiceMapDao.class); + private AgentManager _agentManager = mock(AgentManager.class); + private NetworkModel _networkModel = mock(NetworkModel.class); + private AccountDao _accountDao = mock(AccountDao.class); + private DomainDao _domainDao = mock(DomainDao.class); + private NicDao _nicDao = mock(NicDao.class); + private NetworkOfferingDao _networkOfferingDao = mock(NetworkOfferingDao.class); + private NuageVspDao _nuageVspDao = mock(NuageVspDao.class); + private HostDao _hostDao = mock(HostDao.class); + private NetworkDao _networkDao = mock(NetworkDao.class); + private ConfigurationDao _configurationDao = mock(ConfigurationDao.class); + private IPAddressDao _ipAddressDao = mock(IPAddressDao.class); + private NuageVspManager _nuageVspManager = mock(NuageVspManager.class); + private ConfigurationManager _configurationManager = mock(ConfigurationManager.class); + private NetworkDetailsDao _networkDetailsDao = mock(NetworkDetailsDao.class); + private NuageVspGuestNetworkGuru _nuageVspGuestNetworkGuru; @Before - public void setUp() { - guru = new NuageVspGuestNetworkGuru(); - guru._physicalNetworkDao = physnetdao; - guru._physicalNetworkDao = physnetdao; - guru._nuageVspDao = nuageVspDao; - guru._dcDao = dcdao; - guru._ntwkOfferingSrvcDao = nosd; - guru._networkModel = networkModel; - guru._hostDao = hostDao; - guru._agentMgr = agentManager; - guru._networkDao = netdao; - guru._networkDao = networkDao; - guru._accountDao = accountDao; - guru._domainDao = domainDao; - guru._nicDao = nicDao; - guru._ntwkOfferingDao = ntwkOfferDao; - guru._configDao = configDao; - guru._ipAddressDao = ipAddressDao; - guru._nuageVspManager = nuageVspManager; + public void setUp() throws Exception { + super.setUp(); + + _nuageVspGuestNetworkGuru = new NuageVspGuestNetworkGuru(); + _nuageVspGuestNetworkGuru._physicalNetworkDao = _physicalNetworkDao; + _nuageVspGuestNetworkGuru._physicalNetworkDao = _physicalNetworkDao; + _nuageVspGuestNetworkGuru._nuageVspDao = _nuageVspDao; + _nuageVspGuestNetworkGuru._dcDao = _dataCenterDao; + _nuageVspGuestNetworkGuru._ntwkOfferingSrvcDao = _networkOfferingServiceMapDao; + _nuageVspGuestNetworkGuru._networkModel = _networkModel; + _nuageVspGuestNetworkGuru._hostDao = _hostDao; + _nuageVspGuestNetworkGuru._agentMgr = _agentManager; + _nuageVspGuestNetworkGuru._networkDao = _networkDao; + _nuageVspGuestNetworkGuru._accountDao = _accountDao; + _nuageVspGuestNetworkGuru._domainDao = _domainDao; + _nuageVspGuestNetworkGuru._nicDao = _nicDao; + _nuageVspGuestNetworkGuru._ntwkOfferingDao = _networkOfferingDao; + _nuageVspGuestNetworkGuru._configDao = _configurationDao; + _nuageVspGuestNetworkGuru._ipAddressDao = _ipAddressDao; + _nuageVspGuestNetworkGuru._nuageVspManager = _nuageVspManager; + _nuageVspGuestNetworkGuru._configMgr = _configurationManager; + _nuageVspGuestNetworkGuru._nuageVspEntityBuilder = _nuageVspEntityBuilder; + _nuageVspGuestNetworkGuru._networkDetailsDao = _networkDetailsDao; final DataCenterVO dc = mock(DataCenterVO.class); when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); when(dc.getGuestNetworkCidr()).thenReturn("10.1.1.1/24"); - when(dcdao.findById((Long)any())).thenReturn(dc); + when(_dataCenterDao.findById((Long)any())).thenReturn(dc); - when(configDao.getValue(NuageVspIsolatedNetworkDomainTemplateName.key())).thenReturn("IsolatedDomainTemplate"); - when(configDao.getValue(NuageVspVpcDomainTemplateName.key())).thenReturn("VpcDomainTemplate"); - when(configDao.getValue(NuageVspSharedNetworkDomainTemplateName.key())).thenReturn("SharedDomainTemplate"); + when(_configurationDao.getValue(NuageVspIsolatedNetworkDomainTemplateName.key())).thenReturn("IsolatedDomainTemplate"); + when(_configurationDao.getValue(NuageVspVpcDomainTemplateName.key())).thenReturn("VpcDomainTemplate"); + when(_configurationDao.getValue(NuageVspSharedNetworkDomainTemplateName.key())).thenReturn("SharedDomainTemplate"); } @Test @@ -144,70 +150,81 @@ public void testCanHandle() { when(offering.getId()).thenReturn(NETWORK_ID); when(offering.getTrafficType()).thenReturn(TrafficType.Guest); when(offering.getGuestType()).thenReturn(GuestType.Isolated); + when(offering.getIsPersistent()).thenReturn(false); + when(_configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(false); final PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class); when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"VSP"})); when(physnet.getId()).thenReturn(NETWORK_ID); - when(nosd.areServicesSupportedByNetworkOffering(NETWORK_ID, Service.Connectivity)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(NETWORK_ID, Service.Connectivity)).thenReturn(true); - assertTrue(guru.canHandle(offering, NetworkType.Advanced, physnet) == true); + assertTrue(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Advanced, physnet) == true); // Not supported TrafficType != Guest when(offering.getTrafficType()).thenReturn(TrafficType.Management); - assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet) == true); + assertFalse(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Advanced, physnet) == true); // Supported: GuestType Shared when(offering.getTrafficType()).thenReturn(TrafficType.Guest); when(offering.getGuestType()).thenReturn(GuestType.Shared); - assertTrue(guru.canHandle(offering, NetworkType.Advanced, physnet) == true); + assertTrue(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Advanced, physnet) == true); // Not supported: Basic networking when(offering.getGuestType()).thenReturn(GuestType.Isolated); - assertFalse(guru.canHandle(offering, NetworkType.Basic, physnet) == true); + assertFalse(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Basic, physnet) == true); // Not supported: IsolationMethod != STT when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"VLAN"})); - assertFalse(guru.canHandle(offering, NetworkType.Advanced, physnet) == true); + assertFalse(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Advanced, physnet) == true); + // Not supported: Non-persistent VPC tier + when(_configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(true); + assertFalse(_nuageVspGuestNetworkGuru.canHandle(offering, NetworkType.Advanced, physnet)); } @Test public void testDesign() { final PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class); - when(physnetdao.findById((Long)any())).thenReturn(physnet); + when(_physicalNetworkDao.findById((Long)any())).thenReturn(physnet); when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"VSP"})); when(physnet.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO device = mock(NuageVspDeviceVO.class); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {device})); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{device})); when(device.getId()).thenReturn(1L); final NetworkOffering offering = mock(NetworkOffering.class); when(offering.getId()).thenReturn(NETWORK_ID); when(offering.getTrafficType()).thenReturn(TrafficType.Guest); when(offering.getGuestType()).thenReturn(GuestType.Isolated); + when(offering.getIsPersistent()).thenReturn(false); + when(_configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(false); - when(nosd.areServicesSupportedByNetworkOffering(NETWORK_ID, Service.Connectivity)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(NETWORK_ID, Service.Connectivity)).thenReturn(true); final DeploymentPlan plan = mock(DeploymentPlan.class); final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = _nuageVspGuestNetworkGuru.design(offering, plan, network, account); assertTrue(designednetwork != null); assertTrue(designednetwork.getBroadcastDomainType() == BroadcastDomainType.Vsp); + + // Can't design non-persistent VPC tier + when(_configurationManager.isOfferingForVpc(any(NetworkOffering.class))).thenReturn(true); + assertNull(_nuageVspGuestNetworkGuru.design(offering, plan, network, account)); } @Test public void testDesignNoElementOnPhysicalNetwork() { final PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class); - when(physnetdao.findById((Long)any())).thenReturn(physnet); + when(_physicalNetworkDao.findById((Long)any())).thenReturn(physnet); when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"STT"})); when(physnet.getId()).thenReturn(NETWORK_ID); mock(NuageVspDeviceVO.class); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Collections. emptyList()); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Collections.emptyList()); final NetworkOffering offering = mock(NetworkOffering.class); when(offering.getId()).thenReturn(NETWORK_ID); @@ -218,19 +235,19 @@ public void testDesignNoElementOnPhysicalNetwork() { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = _nuageVspGuestNetworkGuru.design(offering, plan, network, account); assertTrue(designednetwork == null); } @Test public void testDesignNoIsolationMethodVSP() { final PhysicalNetworkVO physnet = mock(PhysicalNetworkVO.class); - when(physnetdao.findById((Long)any())).thenReturn(physnet); + when(_physicalNetworkDao.findById((Long)any())).thenReturn(physnet); when(physnet.getIsolationMethods()).thenReturn(Arrays.asList(new String[] {"VLAN"})); when(physnet.getId()).thenReturn(NETWORK_ID); mock(NuageVspDeviceVO.class); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Collections. emptyList()); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Collections.emptyList()); final NetworkOffering offering = mock(NetworkOffering.class); when(offering.getId()).thenReturn(NETWORK_ID); @@ -241,7 +258,7 @@ public void testDesignNoIsolationMethodVSP() { final Network network = mock(Network.class); final Account account = mock(Account.class); - final Network designednetwork = guru.design(offering, plan, network, account); + final Network designednetwork = _nuageVspGuestNetworkGuru.design(offering, plan, network, account); assertTrue(designednetwork == null); } @@ -259,20 +276,20 @@ public void testReserve() throws InsufficientVirtualNetworkCapacityException, In when(network.getBroadcastUri()).thenReturn(new URI("vsp://aaaaaa-aavvv/10.1.1.1")); final DataCenterVO dataCenter = mock(DataCenterVO.class); - when(dcdao.findById(NETWORK_ID)).thenReturn(dataCenter); + when(_dataCenterDao.findById(NETWORK_ID)).thenReturn(dataCenter); final AccountVO networksAccount = mock(AccountVO.class); when(networksAccount.getUuid()).thenReturn("aaaa-abbbb"); when(networksAccount.getType()).thenReturn(Account.ACCOUNT_TYPE_NORMAL); - when(accountDao.findById(NETWORK_ID)).thenReturn(networksAccount); + when(_accountDao.findById(NETWORK_ID)).thenReturn(networksAccount); final DomainVO networksDomain = mock(DomainVO.class); when(networksDomain.getUuid()).thenReturn("aaaaa-bbbbb"); - when(domainDao.findById(NETWORK_ID)).thenReturn(networksDomain); + when(_domainDao.findById(NETWORK_ID)).thenReturn(networksDomain); final NicVO nicvo = mock(NicVO.class); when(nicvo.getId()).thenReturn(NETWORK_ID); when(nicvo.getMacAddress()).thenReturn("aa-aa-aa-aa-aa-aa"); when(nicvo.getUuid()).thenReturn("aaaa-fffff"); - when(nicDao.findById(NETWORK_ID)).thenReturn(nicvo); + when(_nicDao.findById(NETWORK_ID)).thenReturn(nicvo); final VirtualMachine vm = mock(VirtualMachine.class); when(vm.getId()).thenReturn(NETWORK_ID); @@ -291,24 +308,24 @@ public void testReserve() throws InsufficientVirtualNetworkCapacityException, In final NetworkOfferingVO ntwkoffering = mock(NetworkOfferingVO.class); when(ntwkoffering.getId()).thenReturn(NETWORK_ID); - when(ntwkOfferDao.findById(NETWORK_ID)).thenReturn(ntwkoffering); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(ntwkoffering); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); - when(networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); - when(ipAddressDao.findByVmIdAndNetworkId(NETWORK_ID, NETWORK_ID)).thenReturn(null); - when(domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); + when(_networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); + when(_ipAddressDao.findByVmIdAndNetworkId(NETWORK_ID, NETWORK_ID)).thenReturn(null); + when(_domainDao.findById(NETWORK_ID)).thenReturn(mock(DomainVO.class)); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - guru.reserve(nicProfile, network, vmProfile, mock(DeployDestination.class), mock(ReservationContext.class)); + _nuageVspGuestNetworkGuru.reserve(nicProfile, network, vmProfile, mock(DeployDestination.class), mock(ReservationContext.class)); } @Test @@ -337,7 +354,7 @@ public void testImplementNetwork() throws URISyntaxException, InsufficientVirtua when(offering.getTags()).thenReturn("aaaa"); when(offering.getEgressDefaultPolicy()).thenReturn(true); - when(networkModel.findPhysicalNetworkId(NETWORK_ID, "aaa", TrafficType.Guest)).thenReturn(NETWORK_ID); + when(_networkModel.findPhysicalNetworkId(NETWORK_ID, "aaa", TrafficType.Guest)).thenReturn(NETWORK_ID); final ReservationContext reserveContext = mock(ReservationContext.class); final Domain domain = mock(Domain.class); @@ -347,29 +364,29 @@ public void testImplementNetwork() throws URISyntaxException, InsufficientVirtua when(account.getAccountId()).thenReturn(NETWORK_ID); when(reserveContext.getAccount()).thenReturn(account); final DomainVO domainVo = mock(DomainVO.class); - when(domainDao.findById(NETWORK_ID)).thenReturn(domainVo); + when(_domainDao.findById(NETWORK_ID)).thenReturn(domainVo); final AccountVO accountVo = mock(AccountVO.class); - when(accountDao.findById(NETWORK_ID)).thenReturn(accountVo); + when(_accountDao.findById(NETWORK_ID)).thenReturn(accountVo); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); - when(networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); - when(nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); - when(nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList()); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); + when(_nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); + when(_nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList()); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); final DataCenter dc = mock(DataCenter.class); when(dc.getId()).thenReturn(NETWORK_ID); final DeployDestination deployDest = mock(DeployDestination.class); when(deployDest.getDataCenter()).thenReturn(dc); - guru.implement(network, offering, deployDest, reserveContext); + _nuageVspGuestNetworkGuru.implement(network, offering, deployDest, reserveContext); } @Test @@ -381,22 +398,22 @@ public void testDeallocate() throws Exception { when(network.getPhysicalNetworkId()).thenReturn(NETWORK_ID); when(network.getVpcId()).thenReturn(null); when(network.getDomainId()).thenReturn(NETWORK_ID); - when(networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); + when(_networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); final NetworkOfferingVO offering = mock(NetworkOfferingVO.class); when(offering.getId()).thenReturn(NETWORK_ID); when(offering.getTrafficType()).thenReturn(TrafficType.Guest); - when(ntwkOfferDao.findById(NETWORK_ID)).thenReturn(offering); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(offering); final DomainVO domain = mock(DomainVO.class); when(domain.getUuid()).thenReturn("aaaaaa"); - when(domainDao.findById(NETWORK_ID)).thenReturn(domain); + when(_domainDao.findById(NETWORK_ID)).thenReturn(domain); final NicVO nic = mock(NicVO.class); when(nic.getId()).thenReturn(NETWORK_ID); when(nic.getIPv4Address()).thenReturn("10.10.10.10"); when(nic.getMacAddress()).thenReturn("c8:60:00:56:e5:58"); - when(nicDao.findById(NETWORK_ID)).thenReturn(nic); + when(_nicDao.findById(NETWORK_ID)).thenReturn(nic); final NicProfile nicProfile = mock(NicProfile.class); when(nicProfile.getId()).thenReturn(NETWORK_ID); @@ -416,14 +433,14 @@ public void testDeallocate() throws Exception { when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - guru.deallocate(network, nicProfile, vmProfile); + _nuageVspGuestNetworkGuru.deallocate(network, nicProfile, vmProfile); } @Test @@ -436,31 +453,31 @@ public void testTrash() throws Exception { when(network.getNetworkOfferingId()).thenReturn(NETWORK_ID); when(network.getPhysicalNetworkId()).thenReturn(NETWORK_ID); when(network.getVpcId()).thenReturn(null); - when(networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); + when(_networkDao.acquireInLockTable(NETWORK_ID, 1200)).thenReturn(network); final NetworkOfferingVO offering = mock(NetworkOfferingVO.class); when(offering.getId()).thenReturn(NETWORK_ID); when(offering.getTrafficType()).thenReturn(TrafficType.Guest); - when(ntwkOfferDao.findById(NETWORK_ID)).thenReturn(offering); + when(_networkOfferingDao.findById(NETWORK_ID)).thenReturn(offering); final DomainVO domain = mock(DomainVO.class); when(domain.getUuid()).thenReturn("aaaaaa"); - when(domainDao.findById(NETWORK_ID)).thenReturn(domain); + when(_domainDao.findById(NETWORK_ID)).thenReturn(domain); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); - when(nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); - when(nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList()); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Arrays.asList(new NuageVspDeviceVO[]{nuageVspDevice})); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList()); + when(_nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList()); final Answer answer = mock(Answer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - assertTrue(guru.trash(network, offering)); + assertTrue(_nuageVspGuestNetworkGuru.trash(network, offering)); } } diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/manager/NuageVspManagerTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/manager/NuageVspManagerTest.java index a29e3d7894..ec16a974d0 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/manager/NuageVspManagerTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/manager/NuageVspManagerTest.java @@ -19,6 +19,7 @@ package com.cloud.network.manager; +import com.cloud.NuageTest; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Command; import com.cloud.agent.api.sync.SyncNuageVspCmsIdAnswer; @@ -35,6 +36,7 @@ import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.resource.ResourceManager; +import com.cloud.util.NuageVspEntityBuilder; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.impl.ConfigurationVO; import org.junit.Before; @@ -48,34 +50,37 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -public class NuageVspManagerTest { +public class NuageVspManagerTest extends NuageTest { private static final long NETWORK_ID = 42L; - PhysicalNetworkDao physicalNetworkDao = mock(PhysicalNetworkDao.class); - PhysicalNetworkServiceProviderDao physicalNetworkServiceProviderDao = mock(PhysicalNetworkServiceProviderDao.class); - ResourceManager resourceMgr = mock(ResourceManager.class); - HostDetailsDao hostDetailsDao = mock(HostDetailsDao.class); - NuageVspDao nuageVspDao = mock(NuageVspDao.class); - NetworkDao networkDao = mock(NetworkDao.class); - HostDao hostDao = mock(HostDao.class); - AgentManager agentManager = mock(AgentManager.class); - ConfigurationDao configDao = mock(ConfigurationDao.class); - - NuageVspManagerImpl manager; + private PhysicalNetworkDao _physicalNetworkDao = mock(PhysicalNetworkDao.class); + private PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao = mock(PhysicalNetworkServiceProviderDao.class); + private ResourceManager _resourceManager = mock(ResourceManager.class); + private HostDetailsDao _hostDetailsDao = mock(HostDetailsDao.class); + private NuageVspDao _nuageVspDao = mock(NuageVspDao.class); + private NetworkDao _networkDao = mock(NetworkDao.class); + private HostDao _hostDao = mock(HostDao.class); + private AgentManager _agentManager = mock(AgentManager.class); + private ConfigurationDao _configurationDao = mock(ConfigurationDao.class); + private NuageVspEntityBuilder _nuageVspEntityBuilder = mock(NuageVspEntityBuilder.class); + private NuageVspManagerImpl _nuageVspManager; @Before - public void setUp() { - manager = new NuageVspManagerImpl(); - - manager._physicalNetworkServiceProviderDao = physicalNetworkServiceProviderDao; - manager._physicalNetworkDao = physicalNetworkDao; - manager._resourceMgr = resourceMgr; - manager._hostDetailsDao = hostDetailsDao; - manager._nuageVspDao = nuageVspDao; - manager._networkDao = networkDao; - manager._hostDao = hostDao; - manager._agentMgr = agentManager; - manager._configDao = configDao; + public void setUp() throws Exception { + super.setUp(); + + _nuageVspManager = new NuageVspManagerImpl(); + + _nuageVspManager._physicalNetworkServiceProviderDao = _physicalNetworkServiceProviderDao; + _nuageVspManager._physicalNetworkDao = _physicalNetworkDao; + _nuageVspManager._resourceMgr = _resourceManager; + _nuageVspManager._hostDetailsDao = _hostDetailsDao; + _nuageVspManager._nuageVspDao = _nuageVspDao; + _nuageVspManager._networkDao = _networkDao; + _nuageVspManager._hostDao = _hostDao; + _nuageVspManager._agentMgr = _agentManager; + _nuageVspManager._configDao = _configurationDao; + _nuageVspManager._nuageVspEntityBuilder = _nuageVspEntityBuilder; } @Test @@ -84,31 +89,31 @@ public void testDeleteNuageVspDevice() throws ConfigurationException { final PhysicalNetworkVO physicalNetwork = mock(PhysicalNetworkVO.class); when(physicalNetwork.getDataCenterId()).thenReturn(NETWORK_ID); when(physicalNetwork.getId()).thenReturn(NETWORK_ID); - when(physicalNetworkDao.findById(NETWORK_ID)).thenReturn(physicalNetwork); + when(_physicalNetworkDao.findById(NETWORK_ID)).thenReturn(physicalNetwork); final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); when(nuageVspDevice.getPhysicalNetworkId()).thenReturn(NETWORK_ID); when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDao.findById(NETWORK_ID)).thenReturn(nuageVspDevice); + when(_nuageVspDao.findById(NETWORK_ID)).thenReturn(nuageVspDevice); - when(networkDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(new ArrayList()); + when(_networkDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(new ArrayList()); final HostVO host = mock(HostVO.class); when(host.getId()).thenReturn(NETWORK_ID); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); + when(_hostDao.findById(NETWORK_ID)).thenReturn(host); final DeleteNuageVspDeviceCmd cmd = mock(DeleteNuageVspDeviceCmd.class); when(cmd.getNuageVspDeviceId()).thenReturn(NETWORK_ID); ConfigurationVO cmsIdConfig = mock(ConfigurationVO.class); when(cmsIdConfig.getValue()).thenReturn("1:1"); - when(configDao.findByName("nuagevsp.cms.id")).thenReturn(cmsIdConfig); + when(_configurationDao.findByName("nuagevsp.cms.id")).thenReturn(cmsIdConfig); final SyncNuageVspCmsIdAnswer answer = mock(SyncNuageVspCmsIdAnswer.class); when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); + when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - manager.deleteNuageVspDevice(cmd); + _nuageVspManager.deleteNuageVspDevice(cmd); } @Test @@ -117,12 +122,12 @@ public void testListNuageVspDevices() { when(nuageVspDevice.getPhysicalNetworkId()).thenReturn(NETWORK_ID); final PhysicalNetworkVO phyNtwkVO = mock(PhysicalNetworkVO.class); - when(physicalNetworkDao.findById(NETWORK_ID)).thenReturn(phyNtwkVO); - when(nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(new ArrayList()); + when(_physicalNetworkDao.findById(NETWORK_ID)).thenReturn(phyNtwkVO); + when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(new ArrayList()); final ListNuageVspDevicesCmd cmd = mock(ListNuageVspDevicesCmd.class); when(cmd.getPhysicalNetworkId()).thenReturn(NETWORK_ID); when(cmd.getNuageVspDeviceId()).thenReturn(null); - manager.listNuageVspDevices(cmd); + _nuageVspManager.listNuageVspDevices(cmd); } } diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java index 770e13f0dc..66d26323aa 100644 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/network/resource/NuageVspResourceTest.java @@ -19,6 +19,7 @@ package com.cloud.network.resource; +import com.cloud.NuageTest; import com.cloud.agent.api.Answer; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.StartupCommand; @@ -29,13 +30,17 @@ import com.cloud.agent.api.guru.ImplementNetworkVspCommand; import com.cloud.agent.api.guru.ReserveVmInterfaceVspCommand; import com.cloud.agent.api.guru.TrashNetworkVspCommand; -import com.cloud.agent.api.sync.SyncVspCommand; import com.cloud.host.Host; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import net.nuage.vsp.acs.client.NuageVspApiClient; -import net.nuage.vsp.acs.client.NuageVspElementClient; -import net.nuage.vsp.acs.client.NuageVspGuruClient; -import net.nuage.vsp.acs.client.NuageVspSyncClient; +import net.nuage.vsp.acs.client.api.NuageVspApiClient; +import net.nuage.vsp.acs.client.api.NuageVspElementClient; +import net.nuage.vsp.acs.client.api.NuageVspGuruClient; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; import org.junit.Before; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; @@ -43,20 +48,20 @@ import javax.naming.ConfigurationException; import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Map; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; -public class NuageVspResourceTest { - NuageVspResource _resource; - NuageVspApiClient _mockNuageVspApiClient = mock(NuageVspApiClient.class); - NuageVspElementClient _mockNuageVspElementClient = mock(NuageVspElementClient.class); - NuageVspGuruClient _mockNuageVspGuruClient = mock(NuageVspGuruClient.class); - NuageVspSyncClient _mockNuageVspSyncClient = mock(NuageVspSyncClient.class); - NuageVspResource.Configuration _resourceConfiguration; - Map _hostDetails; +public class NuageVspResourceTest extends NuageTest { + private NuageVspResource _resource; + private NuageVspApiClient _mockNuageVspApiClient = mock(NuageVspApiClient.class); + private NuageVspElementClient _mockNuageVspElementClient = mock(NuageVspElementClient.class); + private NuageVspGuruClient _mockNuageVspGuruClient = mock(NuageVspGuruClient.class); + private NuageVspResource.Configuration _resourceConfiguration; + private Map _hostDetails; org.mockito.stubbing.Answer genericAnswer = new org.mockito.stubbing.Answer() { public Object answer(InvocationOnMock invocation) { @@ -66,6 +71,8 @@ public Object answer(InvocationOnMock invocation) { @Before public void setUp() throws Exception { + super.setUp(); + _resource = new NuageVspResource() { @Override @@ -74,8 +81,6 @@ protected void loadNuageClient() { _nuageVspApiClient = _mockNuageVspApiClient; _nuageVspElementClient = _mockNuageVspElementClient; _nuageVspGuruClient = _mockNuageVspGuruClient; - _nuageVspSyncClient = _mockNuageVspSyncClient; - } protected void isNuageVspApiLoaded() throws ConfigurationException { @@ -87,9 +92,6 @@ protected void isNuageVspGuruLoaded() throws ConfigurationException { protected void isNuageVspElementLoaded() throws ConfigurationException { } - protected void isNuageVspSyncLoaded() throws ConfigurationException { - } - protected void login() throws ConfigurationException { } @@ -148,15 +150,10 @@ public void testPingCommandStatus() throws Exception { public void testImplementNetworkVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ImplementNetworkVspCommand.Builder cmdBuilder = new ImplementNetworkVspCommand.Builder().networkDomainName("networkDomainName").networkDomainPath("networkDomainPath") - .networkDomainUuid("networkDomainUuid").networkAccountName("networkAccountName").networkAccountUuid("networkAccountUuid").networkName("networkName") - .networkCidr("networkCidr").networkGateway("networkGateway").networkAclId(0L).dnsServers(new ArrayList()).gatewaySystemIds(new ArrayList()) - .networkUuid("networkUuid").isL3Network(true).isVpc(true).isSharedNetwork(true).vpcName("vpcName").vpcUuid("vpcUuid").defaultEgressPolicy(true) - .ipAddressRange(new ArrayList()).domainTemplateName("domainTemplateName"); - doAnswer(genericAnswer).when(_mockNuageVspGuruClient).implement("networkDomainName", "networkDomainPath", "networkDomainUuid", "networkAccountName", - "networkAccountUuid", "networkName", "networkCidr", "networkGateway", 0L, new ArrayList(), new ArrayList(), true, true, true, "networkUuid", - "vpcName", "vpcUuid", true, new ArrayList(), "domainTemplateName"); - com.cloud.agent.api.Answer implNtwkAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + ImplementNetworkVspCommand cmd = new ImplementNetworkVspCommand(vspNetwork, new ArrayList()); + doAnswer(genericAnswer).when(_mockNuageVspGuruClient).implement(vspNetwork, new ArrayList()); + com.cloud.agent.api.Answer implNtwkAns = _resource.executeRequest(cmd); assertTrue(implNtwkAns.getResult()); } @@ -164,16 +161,13 @@ public void testImplementNetworkVspCommand() throws Exception { public void testReserveVmInterfaceVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ReserveVmInterfaceVspCommand.Builder cmdBuilder = new ReserveVmInterfaceVspCommand.Builder().nicUuid("nicUuid").nicMacAddress("nicMacAddress") - .networkUuid("networkUuid").isL3Network(true).isSharedNetwork(true).vpcUuid("vpcUuid").networkDomainUuid("networkDomainUuid") - .networksAccountUuid("networksAccountUuid").isDomainRouter(false).domainRouterIp("domainRouterIp").vmInstanceName("vmInstanceName").vmUuid("vmUuid") - .vmUserName("vmUserName").vmUserDomainName("vmUserDomainName").useStaticIp(true).staticIp("staticIp").staticNatIpUuid("staticNatIpUuid") - .staticNatIpAddress("staticNatIpAddress").isStaticNatIpAllocated(true).isOneToOneNat(true).staticNatVlanUuid("staticNatVlanUuid") - .staticNatVlanGateway("staticNatVlanGateway").staticNatVlanNetmask("staticNatVlanNetmask"); - doAnswer(genericAnswer).when(_mockNuageVspGuruClient).reserve("nicUuid", "nicMacAddress", "networkUuid", true, true, "vpcUuid", "networkDomainUuid", - "networksAccountUuid", false, "domainRouterIp", "vmInstanceName", "vmUuid", true, "staticIp", "staticNatIpUuid", "staticNatIpAddress", - true, true, "staticNatVlanUuid", "staticNatVlanGateway", "staticNatVlanNetmask"); - Answer rsrvVmInfAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + VspVm vspVm = buildVspVm(); + VspNic vspNic = buildVspNic(); + VspStaticNat vspStaticNat = buildVspStaticNat(); + ReserveVmInterfaceVspCommand cmd = new ReserveVmInterfaceVspCommand(vspNetwork, vspVm, vspNic, vspStaticNat); + doAnswer(genericAnswer).when(_mockNuageVspGuruClient).reserve(vspNetwork, vspVm, vspNic, vspStaticNat); + Answer rsrvVmInfAns = _resource.executeRequest(cmd); assertTrue(rsrvVmInfAns.getResult()); } @@ -181,12 +175,12 @@ public void testReserveVmInterfaceVspCommand() throws Exception { public void testDeallocateVmVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - DeallocateVmVspCommand.Builder cmdBuilder = new DeallocateVmVspCommand.Builder().networkUuid("networkUuid").nicFromDbUuid("nicFromDbUuid") - .nicMacAddress("nicMacAddress").nicIp4Address("nicIp4Address").isL3Network(true).isSharedNetwork(true).vpcUuid("vpcUuid") - .networksDomainUuid("networksDomainUuid").vmInstanceName("vmInstanceName").vmUuid("vmUuid").isExpungingState(true); - doAnswer(genericAnswer).when(_mockNuageVspGuruClient).deallocate("networkUuid", "nicFrmDdUuid", "nicMacAddress", "nicIp4Address", true, true, "vpcUuid", "networksDomainUuid", - "vmInstanceName", "vmUuid", true); - Answer dellocateVmAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + VspVm vspVm = buildVspVm(); + VspNic vspNic = buildVspNic(); + DeallocateVmVspCommand cmd = new DeallocateVmVspCommand(vspNetwork, vspVm, vspNic); + doAnswer(genericAnswer).when(_mockNuageVspGuruClient).deallocate(vspNetwork, vspVm, vspNic); + Answer dellocateVmAns = _resource.executeRequest(cmd); assertTrue(dellocateVmAns.getResult()); } @@ -194,10 +188,10 @@ public void testDeallocateVmVspCommand() throws Exception { public void testTrashNetworkVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - TrashNetworkVspCommand.Builder cmdBuilder = new TrashNetworkVspCommand.Builder().domainUuid("domainUuid").networkUuid("networkUuid") - .isL3Network(true).isSharedNetwork(true).vpcUuid("vpcUuid").domainTemplateName("domainTemplateName"); - doAnswer(genericAnswer).when(_mockNuageVspGuruClient).trash("domainUuid", "networkUuid", true, true, "vpcUuid", "domainTemplateName"); - Answer trashNtwkAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + TrashNetworkVspCommand cmd = new TrashNetworkVspCommand(vspNetwork); + doAnswer(genericAnswer).when(_mockNuageVspGuruClient).trash(vspNetwork); + Answer trashNtwkAns = _resource.executeRequest(cmd); assertTrue(trashNtwkAns.getResult()); } @@ -205,10 +199,11 @@ public void testTrashNetworkVspCommand() throws Exception { public void testApplyStaticNatVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ApplyStaticNatVspCommand.Builder cmdBuilder = new ApplyStaticNatVspCommand.Builder().networkDomainUuid("networkDomainUuid").networkUuid("networkUuid") - .vpcOrSubnetUuid("vpcOrSubnetUuid").isL3Network(true).isVpc(true).staticNatDetails(new ArrayList>()); - doAnswer(genericAnswer).when(_mockNuageVspElementClient).applyStaticNats("networkDomainUuid", "networkUuid", "vpcOrSubnetUuid", true, true, new ArrayList>()); - Answer applyNatAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + List vspStaticNatDetails = Lists.newArrayList(buildVspStaticNat()); + ApplyStaticNatVspCommand cmd = new ApplyStaticNatVspCommand(vspNetwork, vspStaticNatDetails); + doAnswer(genericAnswer).when(_mockNuageVspElementClient).applyStaticNats(vspNetwork, vspStaticNatDetails); + Answer applyNatAns = _resource.executeRequest(cmd); assertTrue(applyNatAns.getResult()); } @@ -216,12 +211,11 @@ public void testApplyStaticNatVspCommand() throws Exception { public void testApplyAclRuleVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ApplyAclRuleVspCommand.Builder cmdBuilder = new ApplyAclRuleVspCommand.Builder().networkAcl(true).networkUuid("networkUuid").networkDomainUuid("networkDomainUuid") - .vpcOrSubnetUuid("vpcOrSubnetUuid").networkName("networkName").isL2Network(true).aclRules(new ArrayList>()).networkId(100) - .egressDefaultPolicy(false).acsIngressAcl(true).networkReset(true).domainTemplateName("domainTemplateName"); - doAnswer(genericAnswer).when(_mockNuageVspElementClient).applyAclRules(true, "networkUuid", "networkDomainUuid", "vpcOrSubnetUuid", "networkName", true, - new ArrayList>(), 100, false, true, true, "domainTemplateName"); - Answer applyAclAns = _resource.executeRequest(cmdBuilder.build()); + VspNetwork vspNetwork = buildVspNetwork(); + List vspAclRules = Lists.newArrayList(buildVspAclRule()); + ApplyAclRuleVspCommand cmd = new ApplyAclRuleVspCommand(VspAclRule.ACLType.NetworkACL, vspNetwork, vspAclRules, false); + doAnswer(genericAnswer).when(_mockNuageVspElementClient).applyAclRules(VspAclRule.ACLType.NetworkACL, vspNetwork, vspAclRules, false); + Answer applyAclAns = _resource.executeRequest(cmd); assertTrue(applyAclAns.getResult()); } @@ -229,19 +223,9 @@ public void testApplyAclRuleVspCommand() throws Exception { public void testShutDownVpcVspCommand() throws Exception { _resource.configure("NuageVspResource", _hostDetails); - ShutDownVpcVspCommand.Builder cmdBuilder = new ShutDownVpcVspCommand.Builder().domainUuid("domainUuid").vpcUuid("vpcUuid").domainTemplateName("domainTemplateName"); - doAnswer(genericAnswer).when(_mockNuageVspElementClient).shutdownVpc("domainUuid", "vpcUuid", "domainTemplateName"); - Answer shutVpcAns = _resource.executeRequest(cmdBuilder.build()); - assertTrue(shutVpcAns.getResult()); - } - - @Test - public void testSyncVspCommand() throws Exception { - _resource.configure("NuageVspResource", _hostDetails); - - SyncVspCommand shutVpcCmd = new SyncVspCommand("nuageVspEntity"); - doAnswer(genericAnswer).when(_mockNuageVspSyncClient).syncWithNuageVsp("nuageVspEntity"); - Answer shutVpcAns = _resource.executeRequest(shutVpcCmd); + ShutDownVpcVspCommand cmd = new ShutDownVpcVspCommand("domainUuid", "vpcUuid", "domainTemplateName", Lists.newArrayList()); + doAnswer(genericAnswer).when(_mockNuageVspElementClient).shutdownVpc("domainUuid", "vpcUuid", "domainTemplateName", Lists.newArrayList()); + Answer shutVpcAns = _resource.executeRequest(cmd); assertTrue(shutVpcAns.getResult()); } } diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/network/sync/NuageVspSyncTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/network/sync/NuageVspSyncTest.java deleted file mode 100644 index 23430d4685..0000000000 --- a/plugins/network-elements/nuage-vsp/test/com/cloud/network/sync/NuageVspSyncTest.java +++ /dev/null @@ -1,72 +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.network.sync; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.network.NuageVspDeviceVO; -import com.cloud.network.dao.NuageVspDao; -import org.junit.Before; -import org.junit.Test; - -import java.util.Arrays; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class NuageVspSyncTest { - private static final long NETWORK_ID = 42L; - NuageVspDao nuageVspDao = mock(NuageVspDao.class); - AgentManager agentManager = mock(AgentManager.class); - HostDao hostDao = mock(HostDao.class); - - NuageVspSyncImpl sync; - - @Before - public void setUp() { - sync = new NuageVspSyncImpl(); - sync._nuageVspDao = nuageVspDao; - sync._agentMgr = agentManager; - sync._hostDao = hostDao; - } - - @Test - public void testSyncWithNuageVsp() { - final NuageVspDeviceVO nuageVspDevice = mock(NuageVspDeviceVO.class); - when(nuageVspDevice.getHostId()).thenReturn(NETWORK_ID); - when(nuageVspDevice.getId()).thenReturn(NETWORK_ID); - when(nuageVspDao.listAll()).thenReturn(Arrays.asList(new NuageVspDeviceVO[] {nuageVspDevice})); - - final HostVO host = mock(HostVO.class); - when(host.getId()).thenReturn(NETWORK_ID); - when(hostDao.findById(NETWORK_ID)).thenReturn(host); - - final Answer answer = mock(Answer.class); - when(answer.getResult()).thenReturn(true); - when(agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer); - - sync.syncWithNuageVsp("users"); - } -} diff --git a/plugins/network-elements/nuage-vsp/test/com/cloud/util/NuageVspEntityBuilderTest.java b/plugins/network-elements/nuage-vsp/test/com/cloud/util/NuageVspEntityBuilderTest.java new file mode 100644 index 0000000000..1ddc106877 --- /dev/null +++ b/plugins/network-elements/nuage-vsp/test/com/cloud/util/NuageVspEntityBuilderTest.java @@ -0,0 +1,412 @@ +// +// 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.util; + +import com.cloud.NuageTest; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.VlanDao; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.network.Network; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkDetailsDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.net.Ip; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.VirtualMachine; +import com.google.common.collect.Lists; +import net.nuage.vsp.acs.client.api.model.VspAclRule; +import net.nuage.vsp.acs.client.api.model.VspDomain; +import net.nuage.vsp.acs.client.api.model.VspNetwork; +import net.nuage.vsp.acs.client.api.model.VspNic; +import net.nuage.vsp.acs.client.api.model.VspStaticNat; +import net.nuage.vsp.acs.client.api.model.VspVm; +import net.nuage.vsp.acs.client.common.model.Pair; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class NuageVspEntityBuilderTest extends NuageTest { + + private static final long DOMAIN_ID = 1L; + private static final long ACCOUNT_ID = 1L; + private static final long NETWORK_OFFERING_ID = 1L; + private static final long SHARED_NETWORK_OFFERING_ID = 2L; + private static final long L2_NETWORK_OFFERING_ID = 3L; + private static final long VPC_ID = 1L; + private static final long SOURCE_IP_ADDRESS_ID = 1L; + + private VpcDao _vpcDao = mock(VpcDao.class); + private DomainDao _domainDao = mock(DomainDao.class); + private AccountDao _accountDao = mock(AccountDao.class); + private NetworkOfferingDao _networkOfferingDao = mock(NetworkOfferingDao.class); + private NetworkOfferingServiceMapDao _networkOfferingServiceMapDao = mock(NetworkOfferingServiceMapDao.class); + private VlanDao _vlanDao = mock(VlanDao.class); + private IPAddressDao _ipAddressDao = mock(IPAddressDao.class); + private NetworkDetailsDao _networkDetailsDao = mock(NetworkDetailsDao.class); + private NuageVspEntityBuilder _nuageVspEntityBuilder = new NuageVspEntityBuilder(); + + private DomainVO _mockedDomain = mock(DomainVO.class); + private AccountVO _mockedAccount = mock(AccountVO.class); + private NetworkOfferingVO _mockedNetworkOffering = mock(NetworkOfferingVO.class); + private NetworkOfferingVO _mockedSharedNetworkOffering = mock(NetworkOfferingVO.class); + private NetworkOfferingVO _mockedL2NetworkOffering = mock(NetworkOfferingVO.class); + private VlanVO _mockedVlan = mock(VlanVO.class); + private VpcVO _mockedVpc = mock(VpcVO.class); + private NetworkVO _mockedNetwork = mock(NetworkVO.class); + private NetworkVO _mockedVpcNetwork = mock(NetworkVO.class); + private NetworkVO _mockedSharedNetwork = mock(NetworkVO.class); + private NetworkVO _mockedL2Network = mock(NetworkVO.class); + private VirtualMachine _mockedUserVirtualMachine = mock(VirtualMachine.class); + private VirtualMachine _mockedDomainRouterVirtualMachine = mock(VirtualMachine.class); + private NicProfile _mockedNicProfile = mock(NicProfile.class); + private NicVO _mockedNic = mock(NicVO.class); + private IPAddressVO _mockedStaticNatIp = mock(IPAddressVO.class); + private VlanVO _mockedStaticNatVlan = mock(VlanVO.class); + private FirewallRule _mockedFirewallRule = mock(FirewallRule.class); + private NetworkACLItem _mockedNetworkAclItem = mock(NetworkACLItem.class); + + @Before + public void setUp() throws Exception { + super.setUp(); + + _nuageVspEntityBuilder._vpcDao = _vpcDao; + _nuageVspEntityBuilder._domainDao = _domainDao; + _nuageVspEntityBuilder._accountDao = _accountDao; + _nuageVspEntityBuilder._networkOfferingDao = _networkOfferingDao; + _nuageVspEntityBuilder._networkOfferingServiceMapDao = _networkOfferingServiceMapDao; + _nuageVspEntityBuilder._vlanDao = _vlanDao; + _nuageVspEntityBuilder._configurationDao = _configurationDao; + _nuageVspEntityBuilder._ipAddressDao = _ipAddressDao; + _nuageVspEntityBuilder._networkModel = _networkModel; + _nuageVspEntityBuilder._networkDetailsDao = _networkDetailsDao; + + setUpMockedDomain(); + setUpMockedAccount(); + setUpMockedNetworkOffering(_mockedNetworkOffering, Network.GuestType.Isolated); + setUpMockedNetworkOffering(_mockedSharedNetworkOffering, Network.GuestType.Shared); + setUpMockedNetworkOffering(_mockedL2NetworkOffering, Network.GuestType.Isolated); + setUpMockedVlan(); + setUpMockedVpc(); + setUpMockedNetwork(_mockedNetwork, NETWORK_OFFERING_ID, null); + setUpMockedNetwork(_mockedVpcNetwork, NETWORK_OFFERING_ID, VPC_ID); + setUpMockedNetwork(_mockedSharedNetwork, SHARED_NETWORK_OFFERING_ID, null); + setUpMockedNetwork(_mockedL2Network, L2_NETWORK_OFFERING_ID, null); + setUpMockedVirtualMachine(_mockedUserVirtualMachine, false); + setUpMockedVirtualMachine(_mockedDomainRouterVirtualMachine, true); + setUpMockedNicProfile(); + setUpMockedNic(); + setUpMockedStaticNatIp(); + setUpMockedStaticNatVlan(); + setUpMockedFirewallRule(); + setUpMockedNetworkAclItem(); + setUpMockedDaoCalls(); + } + + @Test + public void testBuildVspDomain() { + VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(_mockedDomain); + validateVspDomain(vspDomain); + } + + @Test + public void testBuildVspNetwork() { + VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedL2Network, true); + validateVspNetwork(vspNetwork, true, false, false, false, "IsolatedDomainTemplate", true); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedL2Network, false); + validateVspNetwork(vspNetwork, true, false, false, false, "IsolatedDomainTemplate", false); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedNetwork, true); + validateVspNetwork(vspNetwork, false, true, false, false, "IsolatedDomainTemplate", true); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedNetwork, false); + validateVspNetwork(vspNetwork, false, true, false, false, "IsolatedDomainTemplate", false); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedVpcNetwork, true); + validateVspNetwork(vspNetwork, false, false, true, false, "VpcDomainTemplate", true); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedVpcNetwork, false); + validateVspNetwork(vspNetwork, false, false, true, false, "VpcDomainTemplate", false); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedSharedNetwork, true); + validateVspNetwork(vspNetwork, false, false, false, true, "SharedDomainTemplate", true); + + vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(_mockedSharedNetwork, false); + validateVspNetwork(vspNetwork, false, false, false, true, "SharedDomainTemplate", false); + } + + @Test + public void testBuildVspVm() { + VspVm vspVm = _nuageVspEntityBuilder.buildVspVm(_mockedUserVirtualMachine, _mockedNetwork); + validateVspVm(vspVm, false); + + vspVm = _nuageVspEntityBuilder.buildVspVm(_mockedDomainRouterVirtualMachine, _mockedNetwork); + validateVspVm(vspVm, true); + } + + @Test + public void testBuildVspNic() { + VspNic vspNic = _nuageVspEntityBuilder.buildVspNic("nicUuid", _mockedNicProfile); + validateVspNic(vspNic); + + vspNic = _nuageVspEntityBuilder.buildVspNic(_mockedNic); + validateVspNic(vspNic); + } + + @Test + public void testBuildVspStaticNat() { + VspStaticNat vspStaticNat = _nuageVspEntityBuilder.buildVspStaticNat(true, _mockedStaticNatIp, _mockedStaticNatVlan, _mockedNic); + validateVspStaticNat(vspStaticNat, true); + } + + @Test + public void testBuildVspAclRule() { + VspAclRule vspAclRule = _nuageVspEntityBuilder.buildVspAclRule(_mockedFirewallRule, _mockedNetwork); + validateVspAclRule(vspAclRule, true); + + vspAclRule = _nuageVspEntityBuilder.buildVspAclRule(_mockedNetworkAclItem); + validateVspAclRule(vspAclRule, false); + } + + private void validateVspDomain(VspDomain vspDomain) { + assertEquals("domainUuid", vspDomain.getUuid()); + assertEquals("domainName", vspDomain.getName()); + assertEquals("domainPath", vspDomain.getPath()); + } + + private void validateVspNetwork(VspNetwork vspNetwork, boolean isL2, boolean isL3, boolean isVpc, boolean isShared, + String domainTemplateName, boolean hasAddressRanges) { + assertEquals(NETWORK_ID, vspNetwork.getId()); + assertEquals("networkUuid", vspNetwork.getUuid()); + assertEquals("networkName", vspNetwork.getName()); + assertNotNull(vspNetwork.getVspDomain()); + validateVspDomain(vspNetwork.getVspDomain()); + assertEquals("accountName", vspNetwork.getAccountName()); + assertEquals("accountUuid", vspNetwork.getAccountUuid()); + + if (isVpc) { + assertEquals("vpcUuid", vspNetwork.getVpcUuid()); + assertEquals("vpcName", vspNetwork.getVpcName()); + } else { + assertNull(vspNetwork.getVpcUuid()); + assertNull(vspNetwork.getVpcName()); + } + + assertEquals(isL2, vspNetwork.isL2()); + assertEquals(isL3, vspNetwork.isL3()); + assertEquals(isVpc, vspNetwork.isVpc()); + assertEquals(isShared, vspNetwork.isShared()); + assertEquals(true, vspNetwork.isFirewallServiceSupported()); + assertEquals(true, vspNetwork.isEgressDefaultPolicy()); + assertEquals(domainTemplateName, vspNetwork.getDomainTemplateName()); + assertEquals("10.10.10.0/24", vspNetwork.getCidr()); + assertEquals("10.10.10.1", vspNetwork.getGateway()); + + if (hasAddressRanges) { + if (isShared) { + assertEquals("192.168.2.2", vspNetwork.getVirtualRouterIp()); + } else { + assertEquals("10.10.10.2", vspNetwork.getVirtualRouterIp()); + } + + List> ipAddressRanges; + if (isShared) { + ipAddressRanges = Lists.newArrayList(Pair.of("192.168.2.3", "192.168.2.200")); + } else { + ipAddressRanges = Lists.newArrayList(Pair.of("10.10.10.3", "10.10.10.254")); + } + assertEquals(ipAddressRanges, vspNetwork.getIpAddressRanges()); + } + } + + private void validateVspVm(VspVm vspVm, boolean isDomainRouter) { + assertEquals("virtualMachineUuid", vspVm.getUuid()); + assertEquals("virtualMachineInstanceName", vspVm.getName()); + assertEquals(VspVm.State.Running, vspVm.getState()); + assertEquals(isDomainRouter, vspVm.getDomainRouter()); + } + + private void validateVspNic(VspNic vspNic) { + assertEquals("nicUuid", vspNic.getUuid()); + assertEquals("macAddress", vspNic.getMacAddress()); + assertEquals(true, vspNic.getUseStaticIp()); + assertEquals("10.10.10.2", vspNic.getIp()); + } + + private void validateVspStaticNat(VspStaticNat vspStaticNat, Boolean forRevoke) { + assertEquals("staticNatIpUuid", vspStaticNat.getIpUuid()); + assertEquals("10.10.10.2", vspStaticNat.getIpAddress()); + assertEquals(forRevoke, vspStaticNat.getRevoke()); + assertEquals(true, vspStaticNat.getOneToOneNat()); + assertEquals("staticNatVlanUuid", vspStaticNat.getVlanUuid()); + assertEquals("10.10.10.1", vspStaticNat.getVlanGateway()); + assertEquals("255.255.255.0", vspStaticNat.getVlanNetmask()); + } + + private void validateVspAclRule(VspAclRule vspAclRule, boolean isFirewall) { + assertEquals("aclUuid", vspAclRule.getUuid()); + assertEquals("aclProtocol", vspAclRule.getProtocol()); + assertEquals(new Integer(1), vspAclRule.getStartPort()); + assertEquals(new Integer(20), vspAclRule.getEndPort()); + assertEquals(Lists.newArrayList("10.10.0.0/16"), vspAclRule.getSourceCidrList()); + assertEquals(VspAclRule.ACLState.Active, vspAclRule.getState()); + assertEquals(VspAclRule.ACLTrafficType.Egress, vspAclRule.getTrafficType()); + + if (isFirewall) { + assertEquals(VspAclRule.ACLType.Firewall, vspAclRule.getType()); + assertEquals("192.168.0.24/32", vspAclRule.getSourceIpAddress()); + assertEquals(VspAclRule.ACLAction.Deny, vspAclRule.getAction()); + } else { + assertEquals(VspAclRule.ACLType.NetworkACL, vspAclRule.getType()); + assertNull(vspAclRule.getSourceIpAddress()); + assertEquals(VspAclRule.ACLAction.Allow, vspAclRule.getAction()); + } + } + + private void setUpMockedDomain() { + when(_mockedDomain.getUuid()).thenReturn("domainUuid"); + when(_mockedDomain.getName()).thenReturn("domainName"); + when(_mockedDomain.getPath()).thenReturn("domainPath"); + } + + private void setUpMockedAccount() { + when(_mockedAccount.getUuid()).thenReturn("accountUuid"); + when(_mockedAccount.getAccountName()).thenReturn("accountName"); + } + + private void setUpMockedNetworkOffering(NetworkOfferingVO networkOfferingToMock, Network.GuestType guestType) { + when(networkOfferingToMock.getEgressDefaultPolicy()).thenReturn(true); + when(networkOfferingToMock.getGuestType()).thenReturn(guestType); + } + + private void setUpMockedVlan() { + when(_mockedVlan.getIpRange()).thenReturn("192.168.2.2-192.168.2.200"); + } + + private void setUpMockedVpc() { + when(_mockedVpc.getUuid()).thenReturn("vpcUuid"); + when(_mockedVpc.getName()).thenReturn("vpcName"); + } + + private void setUpMockedNetwork(NetworkVO networkToMock, long networkOfferingId, Long vpcId) { + when(networkToMock.getId()).thenReturn(NETWORK_ID); + when(networkToMock.getUuid()).thenReturn("networkUuid"); + when(networkToMock.getName()).thenReturn("networkName"); + when(networkToMock.getCidr()).thenReturn("10.10.10.0/24"); + when(networkToMock.getGateway()).thenReturn("10.10.10.1"); + when(networkToMock.getDomainId()).thenReturn(DOMAIN_ID); + when(networkToMock.getAccountId()).thenReturn(ACCOUNT_ID); + when(networkToMock.getNetworkOfferingId()).thenReturn(networkOfferingId); + when(networkToMock.getVpcId()).thenReturn(vpcId != null ? vpcId : null); + } + + private void setUpMockedVirtualMachine(VirtualMachine virtualMachineToMock, boolean isDomainRouter) { + when(virtualMachineToMock.getUuid()).thenReturn("virtualMachineUuid"); + when(virtualMachineToMock.getInstanceName()).thenReturn("virtualMachineInstanceName"); + when(virtualMachineToMock.getState()).thenReturn(VirtualMachine.State.Running); + when(virtualMachineToMock.getType()).thenReturn(isDomainRouter ? VirtualMachine.Type.DomainRouter : VirtualMachine.Type.User); + } + + private void setUpMockedNicProfile() { + when(_mockedNicProfile.getMacAddress()).thenReturn("macAddress"); + when(_mockedNicProfile.getIPv4Address()).thenReturn("10.10.10.2"); + } + + private void setUpMockedNic() { + when(_mockedNic.getUuid()).thenReturn("nicUuid"); + when(_mockedNic.getMacAddress()).thenReturn("macAddress"); + when(_mockedNic.getIPv4Address()).thenReturn("10.10.10.2"); + } + + private void setUpMockedStaticNatIp() { + when(_mockedStaticNatIp.getUuid()).thenReturn("staticNatIpUuid"); + when(_mockedStaticNatIp.getAddress()).thenReturn(new Ip("10.10.10.2")); + when(_mockedStaticNatIp.isOneToOneNat()).thenReturn(true); + when(_mockedStaticNatIp.getVmIp()).thenReturn("192.168.0.24"); + } + + private void setUpMockedStaticNatVlan() { + when(_mockedStaticNatVlan.getUuid()).thenReturn("staticNatVlanUuid"); + when(_mockedStaticNatVlan.getVlanGateway()).thenReturn("10.10.10.1"); + when(_mockedStaticNatVlan.getVlanNetmask()).thenReturn("255.255.255.0"); + } + + private void setUpMockedFirewallRule() { + when(_mockedFirewallRule.getUuid()).thenReturn("aclUuid"); + when(_mockedFirewallRule.getProtocol()).thenReturn("aclProtocol"); + when(_mockedFirewallRule.getSourcePortStart()).thenReturn(1); + when(_mockedFirewallRule.getSourcePortEnd()).thenReturn(20); + when(_mockedFirewallRule.getSourceCidrList()).thenReturn(Lists.newArrayList("10.10.0.0/16")); + when(_mockedFirewallRule.getState()).thenReturn(FirewallRule.State.Active); + when(_mockedFirewallRule.getTrafficType()).thenReturn(FirewallRule.TrafficType.Egress); + when(_mockedFirewallRule.getSourceIpAddressId()).thenReturn(SOURCE_IP_ADDRESS_ID); + } + + private void setUpMockedNetworkAclItem() { + when(_mockedNetworkAclItem.getUuid()).thenReturn("aclUuid"); + when(_mockedNetworkAclItem.getProtocol()).thenReturn("aclProtocol"); + when(_mockedNetworkAclItem.getSourcePortStart()).thenReturn(1); + when(_mockedNetworkAclItem.getSourcePortEnd()).thenReturn(20); + when(_mockedNetworkAclItem.getSourceCidrList()).thenReturn(Lists.newArrayList("10.10.0.0/16")); + when(_mockedNetworkAclItem.getNumber()).thenReturn(1337); + when(_mockedNetworkAclItem.getState()).thenReturn(NetworkACLItem.State.Active); + when(_mockedNetworkAclItem.getTrafficType()).thenReturn(NetworkACLItem.TrafficType.Egress); + when(_mockedNetworkAclItem.getAction()).thenReturn(NetworkACLItem.Action.Allow); + } + + private void setUpMockedDaoCalls() { + when(_domainDao.findById(DOMAIN_ID)).thenReturn(_mockedDomain); + when(_accountDao.findById(ACCOUNT_ID)).thenReturn(_mockedAccount); + when(_networkOfferingDao.findById(NETWORK_OFFERING_ID)).thenReturn(_mockedNetworkOffering); + when(_networkOfferingDao.findById(SHARED_NETWORK_OFFERING_ID)).thenReturn(_mockedSharedNetworkOffering); + when(_networkOfferingDao.findById(L2_NETWORK_OFFERING_ID)).thenReturn(_mockedL2NetworkOffering); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(NETWORK_OFFERING_ID, Network.Service.SourceNat)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(NETWORK_OFFERING_ID, Network.Service.StaticNat)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(SHARED_NETWORK_OFFERING_ID, Network.Service.SourceNat)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(SHARED_NETWORK_OFFERING_ID, Network.Service.StaticNat)).thenReturn(true); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(L2_NETWORK_OFFERING_ID, Network.Service.SourceNat)).thenReturn(false); + when(_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(L2_NETWORK_OFFERING_ID, Network.Service.StaticNat)).thenReturn(false); + when(_networkModel.areServicesSupportedByNetworkOffering(NETWORK_OFFERING_ID, Network.Service.Firewall)).thenReturn(true); + when(_networkModel.areServicesSupportedByNetworkOffering(SHARED_NETWORK_OFFERING_ID, Network.Service.Firewall)).thenReturn(true); + when(_networkModel.areServicesSupportedByNetworkOffering(L2_NETWORK_OFFERING_ID, Network.Service.Firewall)).thenReturn(true); + when(_vlanDao.listVlansByNetworkId(NETWORK_ID)).thenReturn(Lists.newArrayList(_mockedVlan)); + when(_vpcDao.findById(VPC_ID)).thenReturn(_mockedVpc); + when(_ipAddressDao.findById(SOURCE_IP_ADDRESS_ID)).thenReturn(_mockedStaticNatIp); + } +} diff --git a/plugins/network-elements/opendaylight/pom.xml b/plugins/network-elements/opendaylight/pom.xml index 167375a2ca..a5f2a26781 100644 --- a/plugins/network-elements/opendaylight/pom.xml +++ b/plugins/network-elements/opendaylight/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/ovs/pom.xml b/plugins/network-elements/ovs/pom.xml index 26f9873268..4f5adf9d65 100644 --- a/plugins/network-elements/ovs/pom.xml +++ b/plugins/network-elements/ovs/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/palo-alto/pom.xml b/plugins/network-elements/palo-alto/pom.xml index 5719acfbe3..555ef7ab3f 100644 --- a/plugins/network-elements/palo-alto/pom.xml +++ b/plugins/network-elements/palo-alto/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/stratosphere-ssp/pom.xml b/plugins/network-elements/stratosphere-ssp/pom.xml index 6d57670d55..89e84db27b 100644 --- a/plugins/network-elements/stratosphere-ssp/pom.xml +++ b/plugins/network-elements/stratosphere-ssp/pom.xml @@ -25,7 +25,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/network-elements/vxlan/pom.xml b/plugins/network-elements/vxlan/pom.xml index c31b72f792..46e5af03ed 100644 --- a/plugins/network-elements/vxlan/pom.xml +++ b/plugins/network-elements/vxlan/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/outofbandmanagement-drivers/ipmitool/pom.xml b/plugins/outofbandmanagement-drivers/ipmitool/pom.xml new file mode 100644 index 0000000000..be4cd86bef --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + cloud-plugin-outofbandmanagement-driver-ipmitool + Apache CloudStack Plugin - Power Management Driver ipmitool + + org.apache.cloudstack + cloudstack-plugins + 4.9.0-SNAPSHOT + ../../pom.xml + + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + org.apache.cloudstack + cloud-api + ${project.version} + + + diff --git a/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/module.properties b/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/module.properties new file mode 100644 index 0000000000..f6499d746b --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/module.properties @@ -0,0 +1,18 @@ +# 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. +name=ipmitool +parent=outofbandmanagement diff --git a/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/spring-ipmitool-context.xml b/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/spring-ipmitool-context.xml new file mode 100644 index 0000000000..49baa90da3 --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/spring-ipmitool-context.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolOutOfBandManagementDriver.java b/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolOutOfBandManagementDriver.java new file mode 100644 index 0000000000..bad3cb61ac --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolOutOfBandManagementDriver.java @@ -0,0 +1,167 @@ +// 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.outofbandmanagement.driver.ipmitool; + +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementDriver; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverChangePasswordCommand; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverCommand; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverPowerCommand; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; +import org.apache.log4j.Logger; +import org.joda.time.Duration; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public final class IpmitoolOutOfBandManagementDriver extends AdapterBase implements OutOfBandManagementDriver, Configurable { + public static final Logger LOG = Logger.getLogger(IpmitoolOutOfBandManagementDriver.class); + + private static volatile boolean isDriverEnabled = false; + private static boolean isIpmiToolBinAvailable = false; + + private final ExecutorService ipmitoolExecutor = Executors.newFixedThreadPool(OutOfBandManagementService.SyncThreadPoolSize.value(), new NamedThreadFactory("IpmiToolDriver")); + private final IpmitoolWrapper IPMITOOL = new IpmitoolWrapper(ipmitoolExecutor); + + public final ConfigKey IpmiToolPath = new ConfigKey("Advanced", String.class, "outofbandmanagement.ipmitool.path", "/usr/bin/ipmitool", + "The out of band management ipmitool path used by the IpmiTool driver. Default: /usr/bin/ipmitool.", true, ConfigKey.Scope.Global); + + public final ConfigKey IpmiToolInterface = new ConfigKey("Advanced", String.class, "outofbandmanagement.ipmitool.interface", "lanplus", + "The out of band management IpmiTool driver interface to use. Default: lanplus. Valid values are: lan, lanplus, open etc.", true, ConfigKey.Scope.Global); + + public final ConfigKey IpmiToolRetries = new ConfigKey("Advanced", String.class, "outofbandmanagement.ipmitool.retries", "1", + "The out of band management IpmiTool driver retries option -R. Default 1.", true, ConfigKey.Scope.Global); + + private String getIpmiUserId(ImmutableMap options, final Duration timeOut) { + final String username = options.get(OutOfBandManagement.Option.USERNAME); + if (Strings.isNullOrEmpty(username)) { + throw new CloudRuntimeException("Empty IPMI user configured, cannot proceed to find user's ID"); + } + + final List ipmiToolCommands = IPMITOOL.getIpmiToolCommandArgs(IpmiToolPath.value(), + IpmiToolInterface.value(), + IpmiToolRetries.value(), + options, "user", "list"); + final OutOfBandManagementDriverResponse output = IPMITOOL.executeCommands(ipmiToolCommands, timeOut); + if (!output.isSuccess()) { + throw new CloudRuntimeException("Failed to find IPMI user to change password, error: " + output.getError()); + } + + final String userId = IPMITOOL.findIpmiUser(output.getResult(), username); + if (Strings.isNullOrEmpty(userId)) { + throw new CloudRuntimeException("No IPMI user ID found for the username: " + username); + } + return userId; + } + + public OutOfBandManagementDriverResponse execute(final OutOfBandManagementDriverCommand cmd) { + if (!isIpmiToolBinAvailable) { + initDriver(); + if (!isIpmiToolBinAvailable) { + return new OutOfBandManagementDriverResponse(null, "Aborting operation due to ipmitool binary not available for execution", false); + } + } + + OutOfBandManagementDriverResponse response = new OutOfBandManagementDriverResponse(null, "Unsupported Command", false); + if (!isDriverEnabled) { + response.setError("Driver not enabled or shutdown"); + return response; + } + if (cmd instanceof OutOfBandManagementDriverPowerCommand) { + response = execute((OutOfBandManagementDriverPowerCommand) cmd); + } else if (cmd instanceof OutOfBandManagementDriverChangePasswordCommand) { + response = execute((OutOfBandManagementDriverChangePasswordCommand) cmd); + } + + if (response != null && !response.isSuccess() && response.getError().contains("RAKP 2 HMAC is invalid")) { + response.setAuthFailure(true); + } + return response; + } + + private OutOfBandManagementDriverResponse execute(final OutOfBandManagementDriverPowerCommand cmd) { + List ipmiToolCommands = IPMITOOL.getIpmiToolCommandArgs(IpmiToolPath.value(), + IpmiToolInterface.value(), + IpmiToolRetries.value(), + cmd.getOptions(), "chassis", "power", IPMITOOL.parsePowerCommand(cmd.getPowerOperation())); + + final OutOfBandManagementDriverResponse response = IPMITOOL.executeCommands(ipmiToolCommands, cmd.getTimeout()); + + if (response.isSuccess() && cmd.getPowerOperation().equals(OutOfBandManagement.PowerOperation.STATUS)) { + response.setPowerState(IPMITOOL.parsePowerState(response.getResult().trim())); + } + return response; + } + + private OutOfBandManagementDriverResponse execute(final OutOfBandManagementDriverChangePasswordCommand cmd) { + final String outOfBandManagementUserId = getIpmiUserId(cmd.getOptions(), cmd.getTimeout()); + + final List ipmiToolCommands = IPMITOOL.getIpmiToolCommandArgs(IpmiToolPath.value(), + IpmiToolInterface.value(), IpmiToolRetries.value(), + cmd.getOptions(), "user", "set", "password", outOfBandManagementUserId, cmd.getNewPassword()); + return IPMITOOL.executeCommands(ipmiToolCommands, cmd.getTimeout()); + } + + private void initDriver() { + isDriverEnabled = true; + final OutOfBandManagementDriverResponse output = IPMITOOL.executeCommands(Arrays.asList(IpmiToolPath.value(), "-V")); + if (output.isSuccess() && output.getResult().startsWith("ipmitool version")) { + isIpmiToolBinAvailable = true; + LOG.debug("OutOfBandManagementDriver ipmitool initialized: " + output.getResult()); + } else { + isIpmiToolBinAvailable = false; + LOG.error("OutOfBandManagementDriver ipmitool failed initialization with error: " + output.getError() + "; standard output: " + output.getResult()); + } + } + + private void stopDriver() { + isDriverEnabled = false; + } + + @Override + public boolean start() { + initDriver(); + return true; + } + + @Override + public boolean stop() { + ipmitoolExecutor.shutdown(); + stopDriver(); + return true; + } + + @Override + public String getConfigComponentName() { + return IpmitoolOutOfBandManagementDriver.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[] {IpmiToolPath, IpmiToolInterface, IpmiToolRetries}; + } +} diff --git a/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapper.java b/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapper.java new file mode 100644 index 0000000000..f5896b2073 --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/src/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapper.java @@ -0,0 +1,181 @@ +// 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.outofbandmanagement.driver.ipmitool; + +import com.cloud.utils.StringUtils; +import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; +import org.apache.cloudstack.utils.process.ProcessResult; +import org.apache.cloudstack.utils.process.ProcessRunner; +import org.apache.log4j.Logger; +import org.joda.time.Duration; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; + +public final class IpmitoolWrapper { + public static final Logger LOG = Logger.getLogger(IpmitoolWrapper.class); + + private final ProcessRunner RUNNER; + + public IpmitoolWrapper(ExecutorService executor) { + this.RUNNER = new ProcessRunner(executor); + } + + public String parsePowerCommand(OutOfBandManagement.PowerOperation operation) { + if (operation == null) { + throw new IllegalStateException("Invalid power operation requested"); + } + switch (operation) { + case ON: + case OFF: + case CYCLE: + case RESET: + case SOFT: + case STATUS: + break; + default: + throw new IllegalStateException("Invalid power operation requested"); + } + return operation.toString().toLowerCase(); + } + + public OutOfBandManagement.PowerState parsePowerState(final String standardOutput) { + if (Strings.isNullOrEmpty(standardOutput)) { + return OutOfBandManagement.PowerState.Unknown; + } + if (standardOutput.equals("Chassis Power is on")) { + return OutOfBandManagement.PowerState.On; + } else if (standardOutput.equals("Chassis Power is off")) { + return OutOfBandManagement.PowerState.Off; + } + return OutOfBandManagement.PowerState.Unknown; + } + + public List getIpmiToolCommandArgs(final String ipmiToolPath, final String ipmiInterface, final String retries, + final ImmutableMap options, String... commands) { + + final ImmutableList.Builder ipmiToolCommands = ImmutableList.builder() + .add(ipmiToolPath) + .add("-I") + .add(ipmiInterface) + .add("-R") + .add(retries) + .add("-v"); + + if (options != null) { + for (ImmutableMap.Entry option : options.entrySet()) { + switch (option.getKey()) { + case ADDRESS: + ipmiToolCommands.add("-H"); + break; + case PORT: + ipmiToolCommands.add("-p"); + break; + case USERNAME: + ipmiToolCommands.add("-U"); + break; + case PASSWORD: + ipmiToolCommands.add("-P"); + break; + default: + continue; + } + ipmiToolCommands.add(option.getValue()); + } + } + for (String command : commands) { + ipmiToolCommands.add(command); + } + return ipmiToolCommands.build(); + } + + public String findIpmiUser(final String usersList, final String username) { + /** + * Expected usersList string contains legends on first line and users on rest + * ID Name Callin Link Auth IPMI Msg Channel Priv Limit + * 1 admin true true true ADMINISTRATOR + */ + + // Assuming user 'ID' index on 1st position + int idIndex = 0; + + // Assuming user 'Name' index on 2nd position + int usernameIndex = 1; + + final String[] lines = usersList.split("\\r?\\n"); + if (lines.length < 2) { + throw new CloudRuntimeException("Error parsing user ID from ipmi user listing"); + } + // Find user and name indexes from the 1st line if not on default position + final String[] legends = lines[0].split(" +"); + for (int idx = 0; idx < legends.length; idx++) { + if (legends[idx].equals("ID")) { + idIndex = idx; + } + if (legends[idx].equals("Name")) { + usernameIndex = idx; + } + } + // Find user 'ID' based on provided username and ID/Name positions + String userId = null; + for (int idx = 1; idx < lines.length; idx++) { + final String[] words = lines[idx].split(" +"); + if (usernameIndex < words.length && idIndex < words.length) { + if (words[usernameIndex].equals(username)) { + userId = words[idIndex]; + } + } + } + return userId; + } + + public OutOfBandManagementDriverResponse executeCommands(final List commands) { + return executeCommands(commands, ProcessRunner.DEFAULT_MAX_TIMEOUT); + } + + public OutOfBandManagementDriverResponse executeCommands(final List commands, final Duration timeOut) { + final ProcessResult result = RUNNER.executeCommands(commands, timeOut); + if (LOG.isTraceEnabled()) { + List cleanedCommands = new ArrayList(); + int maskNextCommand = 0; + for (String command : commands) { + if (maskNextCommand > 0) { + cleanedCommands.add("**** "); + maskNextCommand--; + continue; + } + if (command.equalsIgnoreCase("-P")) { + maskNextCommand = 1; + } else if (command.toLowerCase().endsWith("password")) { + maskNextCommand = 2; + } + cleanedCommands.add(command); + } + LOG.trace("Executed ipmitool process with commands: " + StringUtils.join(cleanedCommands, ", ") + + "\nIpmitool execution standard output: " + result.getStdOutput() + + "\nIpmitool execution error output: " + result.getStdError()); + } + return new OutOfBandManagementDriverResponse(result.getStdOutput(), result.getStdError(), result.isSuccess()); + } +} \ No newline at end of file diff --git a/plugins/outofbandmanagement-drivers/ipmitool/test/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapperTest.java b/plugins/outofbandmanagement-drivers/ipmitool/test/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapperTest.java new file mode 100644 index 0000000000..26115f7a8c --- /dev/null +++ b/plugins/outofbandmanagement-drivers/ipmitool/test/org/apache/cloudstack/outofbandmanagement/driver/ipmitool/IpmitoolWrapperTest.java @@ -0,0 +1,106 @@ +// +// 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.outofbandmanagement.driver.ipmitool; + +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@RunWith(MockitoJUnitRunner.class) +public class IpmitoolWrapperTest { + + private static final ExecutorService ipmitoolExecutor = Executors.newFixedThreadPool(20, new NamedThreadFactory("IpmiToolDriverTest")); + private static final IpmitoolWrapper IPMITOOL = new IpmitoolWrapper(ipmitoolExecutor); + + @Test + public void testParsePowerCommandValid() { + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.ON), "on"); + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.OFF), "off"); + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.CYCLE), "cycle"); + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.RESET), "reset"); + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.SOFT), "soft"); + Assert.assertEquals(IPMITOOL.parsePowerCommand(OutOfBandManagement.PowerOperation.STATUS), "status"); + } + + @Test(expected = IllegalStateException.class) + public void testParsePowerCommandInvalid() { + IPMITOOL.parsePowerCommand(null); + Assert.fail("IpmitoolWrapper.parsePowerCommand failed to throw exception on invalid power state"); + } + + @Test + public void testParsePowerState() { + Assert.assertEquals(IPMITOOL.parsePowerState(null), OutOfBandManagement.PowerState.Unknown); + Assert.assertEquals(IPMITOOL.parsePowerState(""), OutOfBandManagement.PowerState.Unknown); + Assert.assertEquals(IPMITOOL.parsePowerState(" "), OutOfBandManagement.PowerState.Unknown); + Assert.assertEquals(IPMITOOL.parsePowerState("invalid data"), OutOfBandManagement.PowerState.Unknown); + Assert.assertEquals(IPMITOOL.parsePowerState("Chassis Power is on"), OutOfBandManagement.PowerState.On); + Assert.assertEquals(IPMITOOL.parsePowerState("Chassis Power is off"), OutOfBandManagement.PowerState.Off); + } + + @Test + public void testGetIpmiToolCommandArgs() { + List args = IPMITOOL.getIpmiToolCommandArgs("binpath", "intf", "1", null); + assert args != null; + Assert.assertEquals(args.size(), 6); + Assert.assertArrayEquals(args.toArray(), new String[]{"binpath", "-I", "intf", "-R", "1", "-v"}); + + ImmutableMap.Builder argMap = new ImmutableMap.Builder<>(); + argMap.put(OutOfBandManagement.Option.DRIVER, "ipmitool"); + argMap.put(OutOfBandManagement.Option.ADDRESS, "127.0.0.1"); + List argsWithOpts = IPMITOOL.getIpmiToolCommandArgs("binpath", "intf", "1", argMap.build(), "user", "list"); + assert argsWithOpts != null; + Assert.assertEquals(argsWithOpts.size(), 10); + Assert.assertArrayEquals(argsWithOpts.toArray(), new String[]{"binpath", "-I", "intf", "-R", "1", "-v", "-H", "127.0.0.1", "user", "list"}); + } + + @Test(expected = CloudRuntimeException.class) + public void testFindIpmiUserInvalid() { + IPMITOOL.findIpmiUser("some invalid string\n", "admin"); + Assert.fail("IpmitoolWrapper.findIpmiUser failed to throw exception on invalid data"); + + Assert.assertEquals(IPMITOOL.findIpmiUser("some\ninvalid\ndata\n", "admin"), null); + } + + @Test + public void testFindIpmiUserNull() { + Assert.assertEquals(IPMITOOL.findIpmiUser("some\ninvalid\ndata\n", "admin"), null); + } + + @Test + public void testFindIpmiUserValid() { + String usersList = "ID Name\t Callin Link Auth\tIPMI Msg Channel Priv Limit\n" + + "1 admin true true true ADMINISTRATOR\n" + + "2 operator true false false OPERATOR\n" + + "3 user true true true USER\n"; + Assert.assertEquals(IPMITOOL.findIpmiUser(usersList, "admin"), "1"); + Assert.assertEquals(IPMITOOL.findIpmiUser(usersList, "operator"), "2"); + Assert.assertEquals(IPMITOOL.findIpmiUser(usersList, "user"), "3"); + } +} diff --git a/plugins/pom.xml b/plugins/pom.xml index 530245c546..d05e630411 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT @@ -50,6 +50,7 @@ api/solidfire-intg-test api/discovery acl/static-role-based + acl/dynamic-role-based affinity-group-processors/host-anti-affinity affinity-group-processors/explicit-dedication deployment-planners/user-concentrated-pod @@ -74,11 +75,13 @@ network-elements/palo-alto network-elements/netscaler network-elements/nicira-nvp + network-elements/nuage-vsp network-elements/bigswitch network-elements/brocade-vcs network-elements/midonet network-elements/stratosphere-ssp network-elements/opendaylight + outofbandmanagement-drivers/ipmitool storage-allocators/random user-authenticators/ldap user-authenticators/md5 @@ -168,17 +171,6 @@ network-elements/juniper-srx - - nuagevsp - - - noredist - - - - network-elements/nuage-vsp - - vmware diff --git a/plugins/storage-allocators/random/pom.xml b/plugins/storage-allocators/random/pom.xml index 960aa1f0cd..87cd5b582c 100644 --- a/plugins/storage-allocators/random/pom.xml +++ b/plugins/storage-allocators/random/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/storage/image/default/pom.xml b/plugins/storage/image/default/pom.xml index 48a544ae38..b9c641cfd9 100644 --- a/plugins/storage/image/default/pom.xml +++ b/plugins/storage/image/default/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java index 05222c81f1..b8b5226261 100644 --- a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java +++ b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java @@ -32,7 +32,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.storage.image.BaseImageStoreDriverImpl; +import org.apache.cloudstack.storage.image.NfsImageStoreDriverImpl; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; import org.apache.cloudstack.storage.image.store.ImageStoreImpl; @@ -44,7 +44,7 @@ import com.cloud.storage.Storage.ImageFormat; import com.cloud.utils.exception.CloudRuntimeException; -public class CloudStackImageStoreDriverImpl extends BaseImageStoreDriverImpl { +public class CloudStackImageStoreDriverImpl extends NfsImageStoreDriverImpl { private static final Logger s_logger = Logger.getLogger(CloudStackImageStoreDriverImpl.class); @Inject @@ -60,6 +60,7 @@ public DataStoreTO getStoreTO(DataStore store) { NfsTO nfsTO = new NfsTO(); nfsTO.setRole(store.getRole()); nfsTO.setUrl(nfsStore.getUri()); + nfsTO.setNfsVersion(getNfsVersion(nfsStore.getId())); return nfsTO; } diff --git a/plugins/storage/image/s3/pom.xml b/plugins/storage/image/s3/pom.xml index d7f8d4f448..d7ee4372d0 100644 --- a/plugins/storage/image/s3/pom.xml +++ b/plugins/storage/image/s3/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/image/sample/pom.xml b/plugins/storage/image/sample/pom.xml index 961a36750d..c63929e79a 100644 --- a/plugins/storage/image/sample/pom.xml +++ b/plugins/storage/image/sample/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/image/swift/pom.xml b/plugins/storage/image/swift/pom.xml index 3365e7775d..a6c7dd1164 100644 --- a/plugins/storage/image/swift/pom.xml +++ b/plugins/storage/image/swift/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/cloudbyte/pom.xml b/plugins/storage/volume/cloudbyte/pom.xml index a762cec109..5372ab8013 100755 --- a/plugins/storage/volume/cloudbyte/pom.xml +++ b/plugins/storage/volume/cloudbyte/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml @@ -54,7 +54,7 @@ com.sun.jersey jersey-bundle - 1.18.3 + 1.19.1 diff --git a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java index b7ae4d43ff..74fbde5273 100644 --- a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java +++ b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/driver/ElastistorPrimaryDataStoreDriver.java @@ -53,7 +53,6 @@ import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; import com.cloud.storage.VolumeDetailVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; @@ -110,7 +109,7 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet String volumeName = volumeInfo.getName(); Long Iops = volumeInfo.getMaxIops(); // quota size of the cloudbyte volume will be increased with the given HypervisorSnapshotReserve - Long quotaSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId)); + Long quotaSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId)); StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId()); VolumeVO volume = _volumeDao.findById(volumeInfo.getId()); @@ -337,7 +336,8 @@ public void updateVolumeDetails(VolumeVO volume, FileSystem esvolume) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + VolumeInfo volume = (VolumeInfo)dataObject; long volumeSize = volume.getSize(); Integer hypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve(); @@ -353,7 +353,7 @@ public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, Stora } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + public ChapInfo getChapInfo(DataObject dataObject) { return null; } diff --git a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/provider/ElastistorHostListener.java b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/provider/ElastistorHostListener.java index c2624eaa25..b40e60ecf7 100644 --- a/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/provider/ElastistorHostListener.java +++ b/plugins/storage/volume/cloudbyte/src/org/apache/cloudstack/storage/datastore/provider/ElastistorHostListener.java @@ -76,6 +76,11 @@ public class ElastistorHostListener implements HypervisorHostListener { @Inject HostDao _hostDao; + @Override + public boolean hostAdded(long hostId) { + return true; + } + @Override public boolean hostConnect(long hostId, long poolId) { StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary); @@ -126,4 +131,13 @@ public boolean hostDisconnected(long hostId, long poolId) { return false; } + @Override + public boolean hostAboutToBeRemoved(long hostId) { + return true; + } + + @Override + public boolean hostRemoved(long hostId, long clusterId) { + return true; + } } diff --git a/plugins/storage/volume/default/pom.xml b/plugins/storage/volume/default/pom.xml index 17500d7cb6..1cba838939 100644 --- a/plugins/storage/volume/default/pom.xml +++ b/plugins/storage/volume/default/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java index e92e8f6e04..b5aee543e4 100644 --- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java @@ -38,6 +38,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.StorageAction; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -70,7 +71,6 @@ import com.cloud.storage.Storage; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.VMTemplateDao; @@ -145,7 +145,7 @@ public Answer createVolume(VolumeInfo volume) throws StorageUnavailableException } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + public ChapInfo getChapInfo(DataObject dataObject) { return null; } @@ -169,8 +169,13 @@ public long getUsedIops(StoragePool storagePool) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { - return volume.getSize(); + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + return dataObject.getSize(); + } + + @Override + public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) { + return 0; } @Override diff --git a/plugins/storage/volume/nexenta/pom.xml b/plugins/storage/volume/nexenta/pom.xml index 04556c1b8a..e4d8ebe069 100644 --- a/plugins/storage/volume/nexenta/pom.xml +++ b/plugins/storage/volume/nexenta/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java index 752470316d..c6ae3ed7f6 100644 --- a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java +++ b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/driver/NexentaPrimaryDataStoreDriver.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.command.CommandResult; @@ -49,7 +50,6 @@ import com.cloud.host.Host; import com.cloud.storage.Storage; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VolumeDao; import com.cloud.user.dao.AccountDao; @@ -78,8 +78,13 @@ public long getUsedIops(StoragePool storagePool) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { - return 0; //To change body of implemented methods use File | Settings | File Templates. + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + return 0; + } + + @Override + public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) { + return 0; } @Inject @@ -97,7 +102,7 @@ public Map getCapabilities() { } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + public ChapInfo getChapInfo(DataObject dataObject) { return null; } diff --git a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/provider/NexentaHostListener.java b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/provider/NexentaHostListener.java index 950325288f..5fe759902b 100644 --- a/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/provider/NexentaHostListener.java +++ b/plugins/storage/volume/nexenta/src/org/apache/cloudstack/storage/datastore/provider/NexentaHostListener.java @@ -23,13 +23,40 @@ import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; public class NexentaHostListener implements HypervisorHostListener { - private static final Logger logger = Logger.getLogger(NexentaHostListener.class); + private static final Logger s_logger = Logger.getLogger(NexentaHostListener.class); + @Override + public boolean hostAdded(long hostId) { + s_logger.trace("hostAdded(long) invoked"); + + return true; + } + + @Override public boolean hostConnect(long hostId, long poolId) { + s_logger.trace("hostConnect(long, long) invoked"); + return true; } + @Override public boolean hostDisconnected(long hostId, long poolId) { + s_logger.trace("hostDisconnected(long, long) invoked"); + + return true; + } + + @Override + public boolean hostAboutToBeRemoved(long hostId) { + s_logger.trace("hostAboutToBeRemoved(long) invoked"); + + return true; + } + + @Override + public boolean hostRemoved(long hostId, long clusterId) { + s_logger.trace("hostRemoved(long) invoked"); + return true; } } diff --git a/plugins/storage/volume/sample/pom.xml b/plugins/storage/volume/sample/pom.xml index c26d574142..d649df248d 100644 --- a/plugins/storage/volume/sample/pom.xml +++ b/plugins/storage/volume/sample/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java index 0a4cfd6c08..343b08a11a 100644 --- a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java @@ -31,7 +31,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncRpcContext; @@ -44,7 +44,6 @@ import com.cloud.agent.api.to.DataTO; import com.cloud.host.Host; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.utils.exception.CloudRuntimeException; @@ -77,7 +76,7 @@ public DataStoreTO getStoreTO(DataStore store) { } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + public ChapInfo getChapInfo(DataObject dataObject) { return null; } @@ -98,16 +97,18 @@ public long getUsedIops(StoragePool storagePool) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { - return volume.getSize(); + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + return dataObject.getSize(); } - private class CreateVolumeContext extends AsyncRpcContext { - private final DataObject volume; + @Override + public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) { + return 0; + } + private class CreateVolumeContext extends AsyncRpcContext { public CreateVolumeContext(AsyncCompletionCallback callback, DataObject volume) { super(callback); - this.volume = volume; } } diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml index fb7ecdf74d..21b3636ddb 100644 --- a/plugins/storage/volume/solidfire/pom.xml +++ b/plugins/storage/volume/solidfire/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../../pom.xml diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java index 61e199c74c..af969e168a 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidFirePrimaryDataStoreDriver.java @@ -17,32 +17,13 @@ package org.apache.cloudstack.storage.datastore.driver; import java.text.NumberFormat; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; -import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; -import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; -import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; -import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.command.CommandResult; -import org.apache.cloudstack.storage.command.CreateObjectAnswer; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; -import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; -import org.apache.cloudstack.storage.to.SnapshotObjectTO; -import org.apache.log4j.Logger; - import com.cloud.agent.api.Answer; import com.cloud.agent.api.to.DataObjectType; import com.cloud.agent.api.to.DataStoreTO; @@ -55,16 +36,19 @@ import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; -import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.DataStoreRole; import com.cloud.storage.ResizeVolumePayload; +import com.cloud.storage.Snapshot.State; +import com.cloud.storage.SnapshotVO; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; +import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VolumeDetailVO; import com.cloud.storage.VolumeVO; -import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.SnapshotDetailsDao; import com.cloud.storage.dao.SnapshotDetailsVO; +import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeDetailsDao; import com.cloud.user.AccountDetailVO; @@ -74,28 +58,64 @@ import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.base.Preconditions; + +import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.command.CommandResult; +import org.apache.cloudstack.storage.command.CreateObjectAnswer; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; +import org.apache.cloudstack.storage.to.SnapshotObjectTO; +import org.apache.log4j.Logger; + public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { - private static final Logger s_logger = Logger.getLogger(SolidFirePrimaryDataStoreDriver.class); - private static final int s_lockTimeInSeconds = 300; - private static final int s_lowestHypervisorSnapshotReserve = 10; - - @Inject private AccountDao _accountDao; - @Inject private AccountDetailsDao _accountDetailsDao; - @Inject private ClusterDao _clusterDao; - @Inject private ClusterDetailsDao _clusterDetailsDao; - @Inject private HostDao _hostDao; - @Inject private SnapshotDao _snapshotDao; - @Inject private SnapshotDetailsDao _snapshotDetailsDao; - @Inject private PrimaryDataStoreDao _storagePoolDao; - @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; - @Inject private VolumeDao _volumeDao; - @Inject private VolumeDetailsDao _volumeDetailsDao; + private static final Logger LOGGER = Logger.getLogger(SolidFirePrimaryDataStoreDriver.class); + private static final int LOCK_TIME_IN_SECONDS = 300; + private static final int LOWEST_HYPERVISOR_SNAPSHOT_RESERVE = 10; + private static final long MIN_IOPS_FOR_TEMPLATE_VOLUME = 100L; + private static final long MAX_IOPS_FOR_TEMPLATE_VOLUME = 20000L; + private static final long MIN_IOPS_FOR_TEMP_VOLUME = 100L; + private static final long MAX_IOPS_FOR_TEMP_VOLUME = 20000L; + private static final long MIN_IOPS_FOR_SNAPSHOT_VOLUME = 100L; + private static final long MAX_IOPS_FOR_SNAPSHOT_VOLUME = 20000L; + + @Inject private AccountDao accountDao; + @Inject private AccountDetailsDao accountDetailsDao; + @Inject private ClusterDao clusterDao; + @Inject private ClusterDetailsDao clusterDetailsDao; + @Inject private DataStoreManager dataStoreMgr; + @Inject private HostDao hostDao; + @Inject private SnapshotDao snapshotDao; + @Inject private SnapshotDetailsDao snapshotDetailsDao; + @Inject private PrimaryDataStoreDao storagePoolDao; + @Inject private StoragePoolDetailsDao storagePoolDetailsDao; + @Inject private VMTemplatePoolDao tmpltPoolDao; + @Inject private VolumeDao volumeDao; + @Inject private VolumeDetailsDao volumeDetailsDao; + @Inject private VolumeDataFactory volumeFactory; @Override public Map getCapabilities() { - Map mapCapabilities = new HashMap(); + Map mapCapabilities = new HashMap<>(); mapCapabilities.put(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString(), Boolean.TRUE.toString()); + mapCapabilities.put(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_SNAPSHOT.toString(), Boolean.TRUE.toString()); + mapCapabilities.put(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString(), Boolean.TRUE.toString()); return mapCapabilities; } @@ -117,7 +137,7 @@ private SolidFireUtil.SolidFireAccount createSolidFireAccount(SolidFireUtil.Soli } @Override - public ChapInfo getChapInfo(VolumeInfo volumeInfo) { + public ChapInfo getChapInfo(DataObject dataObject) { return null; } @@ -129,45 +149,52 @@ public ChapInfo getChapInfo(VolumeInfo volumeInfo) { @Override public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore) { - if (dataObject == null || host == null || dataStore == null) { - return false; - } + Preconditions.checkArgument(dataObject != null, "'dataObject' should not be 'null'"); + Preconditions.checkArgument(host != null, "'host' should not be 'null'"); + Preconditions.checkArgument(dataStore != null, "'dataStore' should not be 'null'"); long sfVolumeId = getSolidFireVolumeId(dataObject); long clusterId = host.getClusterId(); long storagePoolId = dataStore.getId(); - ClusterVO cluster = _clusterDao.findById(clusterId); + ClusterVO cluster = clusterDao.findById(clusterId); GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (!lock.lock(s_lockTimeInSeconds)) { - s_logger.debug("Couldn't lock the DB (in grantAccess) on the following string: " + cluster.getUuid()); + if (!lock.lock(LOCK_TIME_IN_SECONDS)) { + String errMsg = "Couldn't lock the DB (in grantAccess) on the following string: " + cluster.getUuid(); + + LOGGER.warn(errMsg); + + throw new CloudRuntimeException(errMsg); } try { - ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); + ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); String vagId = clusterDetail != null ? clusterDetail.getValue() : null; - List hosts = _hostDao.findByClusterId(clusterId); + List hosts = hostDao.findByClusterId(clusterId); if (!SolidFireUtil.hostsSupport_iScsi(hosts)) { - return false; + String errMsg = "Not all hosts in the compute cluster support iSCSI."; + + LOGGER.warn(errMsg); + + throw new CloudRuntimeException(errMsg); } - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); if (vagId != null) { SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); - String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hosts)); long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); - SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds); + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); } else { - SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolumeId, storagePoolId, cluster.getUuid(), hosts, _clusterDetailsDao); + SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolumeId, storagePoolId, cluster.getUuid(), hosts, clusterDetailsDao); } return true; @@ -192,30 +219,31 @@ public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) long clusterId = host.getClusterId(); long storagePoolId = dataStore.getId(); - ClusterVO cluster = _clusterDao.findById(clusterId); + ClusterVO cluster = clusterDao.findById(clusterId); GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); - if (!lock.lock(s_lockTimeInSeconds)) { - s_logger.debug("Couldn't lock the DB (in revokeAccess) on the following string: " + cluster.getUuid()); + if (!lock.lock(LOCK_TIME_IN_SECONDS)) { + String errMsg = "Couldn't lock the DB (in revokeAccess) on the following string: " + cluster.getUuid(); + + LOGGER.debug(errMsg); + + throw new CloudRuntimeException(errMsg); } try { - ClusterDetailsVO clusterDetail = _clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); + ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePoolId)); String vagId = clusterDetail != null ? clusterDetail.getValue() : null; if (vagId != null) { - List hosts = _hostDao.findByClusterId(clusterId); - - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); - String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hosts)); long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); - SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds); + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); } } finally { @@ -230,7 +258,7 @@ private long getSolidFireVolumeId(DataObject dataObject) { } if (dataObject.getType() == DataObjectType.SNAPSHOT) { - SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(dataObject.getId(), SolidFireUtil.VOLUME_ID); + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(dataObject.getId(), SolidFireUtil.VOLUME_ID); if (snapshotDetails == null || snapshotDetails.getValue() == null) { throw new CloudRuntimeException("Unable to locate the volume ID associated with the following snapshot ID: " + dataObject.getId()); @@ -239,11 +267,26 @@ private long getSolidFireVolumeId(DataObject dataObject) { return Long.parseLong(snapshotDetails.getValue()); } + if (dataObject.getType() == DataObjectType.TEMPLATE) { + return getVolumeIdFrom_iScsiPath(((TemplateInfo)dataObject).getInstallPath()); + } + throw new CloudRuntimeException("Invalid DataObjectType (" + dataObject.getType() + ") passed to getSolidFireVolumeId(DataObject)"); } + private long getVolumeIdFrom_iScsiPath(String iScsiPath) { + String[] splits = iScsiPath.split("/"); + String iqn = splits[1]; + + String sequenceToSearchFor = "."; + int lastIndexOf = iqn.lastIndexOf(sequenceToSearchFor); + String volumeIdAsString = iqn.substring(lastIndexOf + sequenceToSearchFor.length()); + + return Long.parseLong(volumeIdAsString); + } + private long getDefaultMinIops(long storagePoolId) { - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS); + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS); String clusterDefaultMinIops = storagePoolDetail.getValue(); @@ -251,7 +294,7 @@ private long getDefaultMinIops(long storagePoolId) { } private long getDefaultMaxIops(long storagePoolId) { - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS); + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS); String clusterDefaultMaxIops = storagePoolDetail.getValue(); @@ -259,7 +302,7 @@ private long getDefaultMaxIops(long storagePoolId) { } private long getDefaultBurstIops(long storagePoolId, long maxIops) { - StoragePoolDetailVO storagePoolDetail = _storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS); + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS); String clusterDefaultBurstIopsPercentOfMaxIops = storagePoolDetail.getValue(); @@ -268,30 +311,56 @@ private long getDefaultBurstIops(long storagePoolId, long maxIops) { return (long)(maxIops * fClusterDefaultBurstIopsPercentOfMaxIops); } - private SolidFireUtil.SolidFireVolume createSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, VolumeInfo volumeInfo, long sfAccountId) { - long storagePoolId = volumeInfo.getDataStore().getId(); + private SolidFireUtil.SolidFireVolume createSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, DataObject dataObject, long sfAccountId) { + long storagePoolId = dataObject.getDataStore().getId(); + Long minIops = null; + Long maxIops = null; + Long volumeSize = dataObject.getSize(); + String volumeName = null; - final Iops iops; + final Map mapAttributes; - Long minIops = volumeInfo.getMinIops(); - Long maxIops = volumeInfo.getMaxIops(); + if (dataObject.getType() == DataObjectType.VOLUME) { + VolumeInfo volumeInfo = (VolumeInfo)dataObject; - if (minIops == null || minIops <= 0 || maxIops == null || maxIops <= 0) { - long defaultMaxIops = getDefaultMaxIops(storagePoolId); + minIops = volumeInfo.getMinIops(); + maxIops = volumeInfo.getMaxIops(); + volumeSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, storagePoolDao.findById(storagePoolId)); + volumeName = volumeInfo.getName(); - iops = new Iops(getDefaultMinIops(storagePoolId), defaultMaxIops, getDefaultBurstIops(storagePoolId, defaultMaxIops)); - } else { - iops = new Iops(volumeInfo.getMinIops(), volumeInfo.getMaxIops(), getDefaultBurstIops(storagePoolId, volumeInfo.getMaxIops())); + mapAttributes = getVolumeAttributes(volumeInfo); + } else if (dataObject.getType() == DataObjectType.TEMPLATE) { + TemplateInfo templateInfo = (TemplateInfo)dataObject; + + minIops = MIN_IOPS_FOR_TEMPLATE_VOLUME; + maxIops = MAX_IOPS_FOR_TEMPLATE_VOLUME; + volumeSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(templateInfo, storagePoolDao.findById(storagePoolId)); + volumeName = templateInfo.getUniqueName(); + + mapAttributes = getTemplateAttributes(templateInfo); + } + else { + throw new CloudRuntimeException("Invalid type passed to createSolidFireVolume: " + dataObject.getType()); } - long volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId)); + final Iops iops = getIops(minIops, maxIops, storagePoolId); - long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true, - NumberFormat.getInstance().format(volumeInfo.getSize()), iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); + long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeName), sfAccountId, + volumeSize, true, mapAttributes, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); return SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId); } + private Iops getIops(Long minIops, Long maxIops, long storagePoolId) { + if (minIops == null || minIops <= 0 || maxIops == null || maxIops <= 0) { + long defaultMaxIops = getDefaultMaxIops(storagePoolId); + + return new Iops(getDefaultMinIops(storagePoolId), defaultMaxIops, getDefaultBurstIops(storagePoolId, defaultMaxIops)); + } + + return new Iops(minIops, maxIops, getDefaultBurstIops(storagePoolId, maxIops)); + } + @Override public long getUsedBytes(StoragePool storagePool) { return getUsedBytes(storagePool, Long.MIN_VALUE); @@ -300,7 +369,7 @@ public long getUsedBytes(StoragePool storagePool) { private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { long usedSpace = 0; - List lstVolumes = _volumeDao.findByPoolId(storagePool.getId(), null); + List lstVolumes = volumeDao.findByPoolId(storagePool.getId(), null); if (lstVolumes != null) { for (VolumeVO volume : lstVolumes) { @@ -308,7 +377,7 @@ private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { continue; } - VolumeDetailVO volumeDetail = _volumeDetailsDao.findDetail(volume.getId(), SolidFireUtil.VOLUME_SIZE); + VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volume.getId(), SolidFireUtil.VOLUME_SIZE); if (volumeDetail != null && volumeDetail.getValue() != null) { long volumeSize = Long.parseLong(volumeDetail.getValue()); @@ -316,18 +385,22 @@ private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { usedSpace += volumeSize; } else { - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), _storagePoolDetailsDao); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); try { long lVolumeId = Long.parseLong(volume.getFolder()); SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, lVolumeId); + long volumeSize = sfVolume.getTotalSize(); + // SolidFireUtil.VOLUME_SIZE was introduced in 4.5. // To be backward compatible with releases prior to 4.5, call updateVolumeDetails here. // That way if SolidFireUtil.VOLUME_SIZE wasn't put in the volume_details table when the // volume was initially created, it can be placed in volume_details here. - updateVolumeDetails(volume.getId(), sfVolume.getTotalSize()); + updateVolumeDetails(volume.getId(), volumeSize); + + usedSpace += volumeSize; } catch (NumberFormatException ex) { // can be ignored (the "folder" column didn't have a valid "long" in it (hasn't been placed there yet)) @@ -336,15 +409,15 @@ private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { } } - List lstSnapshots = _snapshotDao.listAll(); + List lstSnapshots = snapshotDao.listAll(); if (lstSnapshots != null) { for (SnapshotVO snapshot : lstSnapshots) { - SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.STORAGE_POOL_ID); + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.STORAGE_POOL_ID); // if this snapshot belongs to the storagePool that was passed in if (snapshotDetails != null && snapshotDetails.getValue() != null && Long.parseLong(snapshotDetails.getValue()) == storagePool.getId()) { - snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.VOLUME_SIZE); + snapshotDetails = snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.VOLUME_SIZE); if (snapshotDetails != null && snapshotDetails.getValue() != null) { long snapshotSize = Long.parseLong(snapshotDetails.getValue()); @@ -355,6 +428,14 @@ private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { } } + List lstTemplatePoolRefs = tmpltPoolDao.listByPoolId(storagePool.getId()); + + if (lstTemplatePoolRefs != null) { + for (VMTemplateStoragePoolVO templatePoolRef : lstTemplatePoolRefs) { + usedSpace += templatePoolRef.getTemplateSize(); + } + } + return usedSpace; } @@ -362,7 +443,7 @@ private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) { public long getUsedIops(StoragePool storagePool) { long usedIops = 0; - List volumes = _volumeDao.findByPoolId(storagePool.getId(), null); + List volumes = volumeDao.findByPoolId(storagePool.getId(), null); if (volumes != null) { for (VolumeVO volume : volumes) { @@ -374,12 +455,25 @@ public long getUsedIops(StoragePool storagePool) { } @Override - public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { - long volumeSize = volume.getSize(); - Integer hypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve(); + public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) { + long volumeSize = 0; + if (dataObject.getType() == DataObjectType.VOLUME) { + VolumeInfo volume = (VolumeInfo)dataObject; + + volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volume.getSize(), volume.getHypervisorSnapshotReserve()); + } else if (dataObject.getType() == DataObjectType.TEMPLATE) { + TemplateInfo templateInfo = (TemplateInfo)dataObject; + + volumeSize = (long)(templateInfo.getSize() + templateInfo.getSize() * (LOWEST_HYPERVISOR_SNAPSHOT_RESERVE / 100f)); + } + + return volumeSize; + } + + private long getVolumeSizeIncludingHypervisorSnapshotReserve(long volumeSize, Integer hypervisorSnapshotReserve) { if (hypervisorSnapshotReserve != null) { - hypervisorSnapshotReserve = Math.max(hypervisorSnapshotReserve, s_lowestHypervisorSnapshotReserve); + hypervisorSnapshotReserve = Math.max(hypervisorSnapshotReserve, LOWEST_HYPERVISOR_SNAPSHOT_RESERVE); volumeSize += volumeSize * (hypervisorSnapshotReserve / 100f); } @@ -387,6 +481,29 @@ public long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, Stora return volumeSize; } + /** + * This method is only relevant when storagePool is being used with a compute cluster that supports UUID resigning. + */ + @Override + public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) { + List lstTemplatePoolRefs = tmpltPoolDao.listByPoolId(storagePool.getId()); + + if (lstTemplatePoolRefs != null) { + for (VMTemplateStoragePoolVO templatePoolRef : lstTemplatePoolRefs) { + if (templatePoolRef.getTemplateId() == templateInfo.getId()) { + // This indicates that we already have this template stored on this primary storage, so + // we do not require additional space. + return 0; + } + } + } + + // This indicates that we do not have a copy of this template on this primary storage, so + // we need to take it into consideration from a space standpoint (ex. when a new VM is spun + // up and wants to use this particular template for its root disk). + return getDataObjectSizeIncludingHypervisorSnapshotReserve(templateInfo, storagePool); + } + private static class Iops { private final long _minIops; private final long _maxIops; @@ -433,7 +550,7 @@ private void deleteSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnectio long sfVolumeId = Long.parseLong(volumeInfo.getFolder()); - SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId); + deleteSolidFireVolume(sfConnection, volumeInfo.getId(), sfVolumeId); } @Override @@ -441,114 +558,234 @@ public void createAsync(DataStore dataStore, DataObject dataObject, AsyncComplet String iqn = null; String errMsg = null; - if (dataObject.getType() == DataObjectType.VOLUME) { - VolumeInfo volumeInfo = (VolumeInfo)dataObject; + try { + if (dataObject.getType() == DataObjectType.VOLUME) { + iqn = createVolume((VolumeInfo)dataObject, dataStore.getId()); + } else if (dataObject.getType() == DataObjectType.SNAPSHOT) { + createTempVolume((SnapshotInfo)dataObject, dataStore.getId()); + } else if (dataObject.getType() == DataObjectType.TEMPLATE) { + iqn = createTemplateVolume((TemplateInfo)dataObject, dataStore.getId()); + } else { + errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync"; + + LOGGER.error(errMsg); + } + } + catch (Exception ex) { + errMsg = ex.getMessage(); + + LOGGER.error(errMsg); - long storagePoolId = dataStore.getId(); + if (callback == null) { + throw ex; + } + } - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + if (callback != null) { + // path = iqn + // size is pulled from DataObject instance, if errMsg is null + CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg)); - AccountDetailVO accountDetail = SolidFireUtil.getAccountDetail(volumeInfo.getAccountId(), storagePoolId, _accountDetailsDao); + result.setResult(errMsg); - if (accountDetail == null || accountDetail.getValue() == null) { - AccountVO account = _accountDao.findById(volumeInfo.getAccountId()); - String sfAccountName = SolidFireUtil.getSolidFireAccountName(account.getUuid(), account.getAccountId()); - SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName); + callback.complete(result); + } + } - if (sfAccount == null) { - sfAccount = createSolidFireAccount(sfConnection, sfAccountName); - } + private long getCreateSolidFireAccountId(SolidFireUtil.SolidFireConnection sfConnection, long csAccountId, long storagePoolId) { + AccountDetailVO accountDetail = SolidFireUtil.getAccountDetail(csAccountId, storagePoolId, accountDetailsDao); - SolidFireUtil.updateCsDbWithSolidFireAccountInfo(account.getId(), sfAccount, storagePoolId, _accountDetailsDao); + if (accountDetail == null || accountDetail.getValue() == null) { + AccountVO account = accountDao.findById(csAccountId); + String sfAccountName = SolidFireUtil.getSolidFireAccountName(account.getUuid(), account.getAccountId()); + SolidFireUtil.SolidFireAccount sfAccount = SolidFireUtil.getSolidFireAccount(sfConnection, sfAccountName); - accountDetail = SolidFireUtil.getAccountDetail(volumeInfo.getAccountId(), storagePoolId, _accountDetailsDao); + if (sfAccount == null) { + sfAccount = createSolidFireAccount(sfConnection, sfAccountName); } - long sfAccountId = Long.parseLong(accountDetail.getValue()); + SolidFireUtil.updateCsDbWithSolidFireAccountInfo(account.getId(), sfAccount, storagePoolId, accountDetailsDao); - SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(sfConnection, volumeInfo, sfAccountId); + accountDetail = SolidFireUtil.getAccountDetail(csAccountId, storagePoolId, accountDetailsDao); + } - iqn = sfVolume.getIqn(); + return Long.parseLong(accountDetail.getValue()); + } - VolumeVO volume = _volumeDao.findById(volumeInfo.getId()); + private void handleSnapshotDetails(long csSnapshotId, String name, String value) { + snapshotDetailsDao.removeDetail(csSnapshotId, name); - volume.set_iScsiName(iqn); - volume.setFolder(String.valueOf(sfVolume.getId())); - volume.setPoolType(StoragePoolType.IscsiLUN); - volume.setPoolId(storagePoolId); + SnapshotDetailsVO snapshotDetails = new SnapshotDetailsVO(csSnapshotId, name, value, false); - _volumeDao.update(volume.getId(), volume); + snapshotDetailsDao.persist(snapshotDetails); + } - updateVolumeDetails(volume.getId(), sfVolume.getTotalSize()); + private void addTempVolumeId(long csSnapshotId, String tempVolumeId) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID); - StoragePoolVO storagePool = _storagePoolDao.findById(dataStore.getId()); + if (snapshotDetails == null || snapshotDetails.getValue() == null) { + throw new CloudRuntimeException("'addTempVolumeId' should not be invoked unless " + SolidFireUtil.VOLUME_ID + " exists."); + } - long capacityBytes = storagePool.getCapacityBytes(); - // getUsedBytes(StoragePool) will include the bytes of the newly created volume because - // updateVolumeDetails(long, long) has already been called for this volume - long usedBytes = getUsedBytes(storagePool); + String originalVolumeId = snapshotDetails.getValue(); - storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes); + handleSnapshotDetails(csSnapshotId, SolidFireUtil.TEMP_VOLUME_ID, originalVolumeId); + handleSnapshotDetails(csSnapshotId, SolidFireUtil.VOLUME_ID, tempVolumeId); + } - _storagePoolDao.update(storagePoolId, storagePool); - } else { - errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync"; + private void removeTempVolumeId(long csSnapshotId) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.TEMP_VOLUME_ID); + + if (snapshotDetails == null || snapshotDetails.getValue() == null) { + throw new CloudRuntimeException("'removeTempVolumeId' should not be invoked unless " + SolidFireUtil.TEMP_VOLUME_ID + " exists."); } - // path = iqn - // size is pulled from DataObject instance, if errMsg is null - CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg)); + String originalVolumeId = snapshotDetails.getValue(); - result.setResult(errMsg); + handleSnapshotDetails(csSnapshotId, SolidFireUtil.VOLUME_ID, originalVolumeId); - callback.complete(result); + snapshotDetailsDao.remove(snapshotDetails.getId()); } - private void updateVolumeDetails(long volumeId, long sfVolumeSize) { - VolumeDetailVO volumeDetailVo = _volumeDetailsDao.findDetail(volumeId, SolidFireUtil.VOLUME_SIZE); - - if (volumeDetailVo == null || volumeDetailVo.getValue() == null) { - volumeDetailVo = new VolumeDetailVO(volumeId, SolidFireUtil.VOLUME_SIZE, String.valueOf(sfVolumeSize), false); + private long getCsIdForCloning(long volumeId, String cloneOf) { + VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volumeId, cloneOf); - _volumeDetailsDao.persist(volumeDetailVo); + if (volumeDetail != null && volumeDetail.getValue() != null) { + return new Long(volumeDetail.getValue()); } + + return Long.MIN_VALUE; } - @Override - public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback callback) { - String errMsg = null; + private boolean shouldTakeSnapshot(long snapshotId) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotId, "takeSnapshot"); - if (dataObject.getType() == DataObjectType.VOLUME) { - try { - VolumeInfo volumeInfo = (VolumeInfo)dataObject; - long volumeId = volumeInfo.getId(); + if (snapshotDetails != null && snapshotDetails.getValue() != null) { + return new Boolean(snapshotDetails.getValue()); + } - long storagePoolId = dataStore.getId(); + return false; + } - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + private SolidFireUtil.SolidFireVolume createClone(SolidFireUtil.SolidFireConnection sfConnection, long dataObjectId, VolumeInfo volumeInfo, long sfAccountId, + long storagePoolId, DataObjectType dataObjectType) { + String sfNewVolumeName = volumeInfo.getName(); - deleteSolidFireVolume(sfConnection, volumeInfo); + long sfVolumeId = Long.MIN_VALUE; + long sfSnapshotId = Long.MIN_VALUE; - _volumeDetailsDao.removeDetails(volumeId); + if (dataObjectType == DataObjectType.SNAPSHOT) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(dataObjectId, SolidFireUtil.SNAPSHOT_ID); - StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); + if (snapshotDetails != null && snapshotDetails.getValue() != null) { + sfSnapshotId = Long.parseLong(snapshotDetails.getValue()); + } - long usedBytes = getUsedBytes(storagePool, volumeId); + snapshotDetails = snapshotDetailsDao.findDetail(dataObjectId, SolidFireUtil.VOLUME_ID); - storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes); + sfVolumeId = Long.parseLong(snapshotDetails.getValue()); + } else if (dataObjectType == DataObjectType.TEMPLATE) { + // get the cached template on this storage + VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, dataObjectId); - _storagePoolDao.update(storagePoolId, storagePool); + if (templatePoolRef != null) { + sfVolumeId = Long.parseLong(templatePoolRef.getLocalDownloadPath()); } - catch (Exception ex) { - s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume", ex); + } + + if (sfVolumeId <= 0) { + throw new CloudRuntimeException("Unable to find SolidFire volume for the following data-object ID: " + dataObjectId + + " and data-object type: " + dataObjectType); + } + + final long newSfVolumeId = SolidFireUtil.createSolidFireClone(sfConnection, sfVolumeId, sfSnapshotId, sfAccountId, sfNewVolumeName, + getVolumeAttributes(volumeInfo)); + + final Iops iops = getIops(volumeInfo.getMinIops(), volumeInfo.getMaxIops(), storagePoolId); + + SolidFireUtil.modifySolidFireVolume(sfConnection, newSfVolumeId, null, null, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); + + return SolidFireUtil.getSolidFireVolume(sfConnection, newSfVolumeId); + } - errMsg = ex.getMessage(); + private Map getVolumeAttributes(VolumeInfo volumeInfo) { + Map mapAttributes = new HashMap<>(); + + mapAttributes.put(SolidFireUtil.CloudStackVolumeId, String.valueOf(volumeInfo.getId())); + mapAttributes.put(SolidFireUtil.CloudStackVolumeSize, NumberFormat.getInstance().format(volumeInfo.getSize())); + + return mapAttributes; + } + + private Map getSnapshotAttributes(SnapshotInfo snapshotInfo) { + Map mapAttributes = new HashMap<>(); + + mapAttributes.put(SolidFireUtil.CloudStackSnapshotId, String.valueOf(snapshotInfo.getId())); + mapAttributes.put(SolidFireUtil.CloudStackSnapshotSize, NumberFormat.getInstance().format(snapshotInfo.getSize())); + + return mapAttributes; + } + + private Map getTemplateAttributes(TemplateInfo templateInfo) { + Map mapAttributes = new HashMap<>(); + + mapAttributes.put(SolidFireUtil.CloudStackTemplateId, String.valueOf(templateInfo.getId())); + mapAttributes.put(SolidFireUtil.CloudStackTemplateSize, NumberFormat.getInstance().format(templateInfo.getSize())); + + return mapAttributes; + } + + private SolidFireUtil.SolidFireVolume createCloneFromSnapshot(SolidFireUtil.SolidFireConnection sfConnection, long csSnapshotId, long sfAccountId) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID); + + long sfVolumeId = Long.parseLong(snapshotDetails.getValue()); + + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID); + + long sfSnapshotId = Long.parseLong(snapshotDetails.getValue()); + + SolidFireUtil.SolidFireSnapshot sfSnapshot = SolidFireUtil.getSolidFireSnapshot(sfConnection, sfVolumeId, sfSnapshotId); + + long newSfVolumeId = SolidFireUtil.createSolidFireClone(sfConnection, sfVolumeId, sfSnapshotId, sfAccountId, sfSnapshot.getName(), null); + + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.STORAGE_POOL_ID); + + long storagePoolId = Long.parseLong(snapshotDetails.getValue()); + + final Iops iops = getIops(MIN_IOPS_FOR_TEMP_VOLUME, MAX_IOPS_FOR_TEMP_VOLUME, storagePoolId); + + SolidFireUtil.modifySolidFireVolume(sfConnection, newSfVolumeId, null, null, iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); + + return SolidFireUtil.getSolidFireVolume(sfConnection, newSfVolumeId); + } + + private void updateVolumeDetails(long volumeId, long sfVolumeSize) { + volumeDetailsDao.removeDetail(volumeId, SolidFireUtil.VOLUME_SIZE); + + VolumeDetailVO volumeDetailVo = new VolumeDetailVO(volumeId, SolidFireUtil.VOLUME_SIZE, String.valueOf(sfVolumeSize), false); + + volumeDetailsDao.persist(volumeDetailVo); + } + + @Override + public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback callback) { + String errMsg = null; + + try { + if (dataObject.getType() == DataObjectType.VOLUME) { + deleteVolume((VolumeInfo)dataObject, dataStore.getId()); + } else if (dataObject.getType() == DataObjectType.SNAPSHOT) { + deleteSnapshot((SnapshotInfo)dataObject, dataStore.getId()); + } else if (dataObject.getType() == DataObjectType.TEMPLATE) { + deleteTemplate((TemplateInfo)dataObject, dataStore.getId()); + } else { + errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync"; } - } else if (dataObject.getType() == DataObjectType.SNAPSHOT) { - // should return null when no error message - errMsg = deleteSnapshot((SnapshotInfo)dataObject, dataStore.getId()); - } else { - errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to deleteAsync"; + } + catch (Exception ex) { + errMsg = ex.getMessage(); + + LOGGER.error(errMsg); } CommandResult result = new CommandResult(); @@ -574,49 +811,67 @@ public void takeSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback capacityBytes) { throw new CloudRuntimeException("Insufficient amount of space remains in this primary storage to take a snapshot"); } storagePool.setUsedBytes(usedBytes); - String volumeName = volumeInfo.getName() + "-" + snapshotInfo.getUuid(); + SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO(); - long sfNewVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, volumeName, sfVolume.getAccountId(), sfVolumeSize, - sfVolume.isEnable512e(), NumberFormat.getInstance().format(volumeInfo.getSize()), sfVolume.getMinIops(), 50000, 75000); + if (shouldTakeSnapshot(snapshotInfo.getId())) { + // We are supposed to take a SolidFire snapshot to serve as the back-end for our CloudStack volume snapshot. - // Now that we have successfully created a volume, update the space usage in the storage_pool table - // (even though storage_pool.used_bytes is likely no longer in use). - _storagePoolDao.update(storagePoolId, storagePool); + String sfNewSnapshotName = volumeInfo.getName() + "-" + snapshotInfo.getUuid(); - SolidFireUtil.SolidFireVolume sfNewVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfNewVolumeId); + long sfNewSnapshotId = SolidFireUtil.createSolidFireSnapshot(sfConnection, sfVolumeId, sfNewSnapshotName, getSnapshotAttributes(snapshotInfo)); - updateSnapshotDetails(snapshotInfo.getId(), sfNewVolumeId, storagePoolId, sfVolumeSize, sfNewVolume.getIqn()); + updateSnapshotDetails(snapshotInfo.getId(), sfVolumeId, sfNewSnapshotId, storagePoolId, sfVolumeSize); - SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO(); + snapshotObjectTo.setPath("SfSnapshotId=" + sfNewSnapshotId); + } + else { + // We are supposed to create a new SolidFire volume to serve as the back-end for our CloudStack volume snapshot. + + String sfNewVolumeName = volumeInfo.getName() + "-" + snapshotInfo.getUuid(); + + final Iops iops = getIops(MIN_IOPS_FOR_SNAPSHOT_VOLUME, MAX_IOPS_FOR_SNAPSHOT_VOLUME, storagePoolId); + + long sfNewVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, sfNewVolumeName, sfVolume.getAccountId(), sfVolumeSize, + sfVolume.isEnable512e(), getSnapshotAttributes(snapshotInfo), iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops()); - snapshotObjectTo.setPath(String.valueOf(sfNewVolumeId)); + SolidFireUtil.SolidFireVolume sfNewVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfNewVolumeId); + + updateSnapshotDetails(snapshotInfo.getId(), sfNewVolumeId, storagePoolId, sfVolumeSize, sfNewVolume.getIqn()); + + snapshotObjectTo.setPath("SfVolumeId=" + sfNewVolumeId); + } + + // Now that we have successfully created a volume or a snapshot, update the space usage in the cloud.storage_pool table + // (even though cloud.storage_pool.used_bytes is likely no longer in use). + storagePoolDao.update(storagePoolId, storagePool); CreateObjectAnswer createObjectAnswer = new CreateObjectAnswer(snapshotObjectTo); @@ -625,7 +880,7 @@ public void takeSnapshot(SnapshotInfo snapshotInfo, AsyncCompletionCallback 0) { + // We are supposed to create a clone of the underlying volume or snapshot that supports the CloudStack snapshot. + sfVolume = createClone(sfConnection, csSnapshotId, volumeInfo, sfAccountId, storagePoolId, DataObjectType.SNAPSHOT); + } else if (csTemplateId > 0) { + // Clone from template. + sfVolume = createClone(sfConnection, csTemplateId, volumeInfo, sfAccountId, storagePoolId, DataObjectType.TEMPLATE); + + long volumeSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, storagePoolDao.findById(storagePoolId)); + + if (volumeSize > sfVolume.getTotalSize()) { + // Expand the volume to include HSR. + SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolume.getId(), volumeSize, getVolumeAttributes(volumeInfo), + sfVolume.getMinIops(), sfVolume.getMaxIops(), sfVolume.getBurstIops()); + + // Get the SolidFire volume from the SAN again because we just updated its size. + sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolume.getId()); + } + } + else { + sfVolume = createSolidFireVolume(sfConnection, volumeInfo, sfAccountId); + } + + String iqn = sfVolume.getIqn(); + + VolumeVO volume = volumeDao.findById(volumeInfo.getId()); + + volume.set_iScsiName(iqn); + volume.setFolder(String.valueOf(sfVolume.getId())); + volume.setPoolType(StoragePoolType.IscsiLUN); + volume.setPoolId(storagePoolId); + + volumeDao.update(volume.getId(), volume); + + updateVolumeDetails(volume.getId(), sfVolume.getTotalSize()); + + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + + long capacityBytes = storagePool.getCapacityBytes(); + // getUsedBytes(StoragePool) will include the bytes of the newly created volume because + // updateVolumeDetails(long, long) has already been called for this volume + long usedBytes = getUsedBytes(storagePool); + + storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes); + + storagePoolDao.update(storagePoolId, storagePool); + + return iqn; + } + + private void createTempVolume(SnapshotInfo snapshotInfo, long storagePoolId) { + long csSnapshotId = snapshotInfo.getId(); + + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID); + + if (snapshotDetails == null || snapshotDetails.getValue() == null) { + throw new CloudRuntimeException("'createTempVolume(SnapshotInfo, long)' should not be invoked unless " + SolidFireUtil.SNAPSHOT_ID + " exists."); + } + + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); + + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, "tempVolume"); + + if (snapshotDetails != null && snapshotDetails.getValue() != null && snapshotDetails.getValue().equalsIgnoreCase("create")) { + long sfAccountId = getCreateSolidFireAccountId(sfConnection, snapshotInfo.getAccountId(), storagePoolId); + + SolidFireUtil.SolidFireVolume sfVolume = createCloneFromSnapshot(sfConnection, csSnapshotId, sfAccountId); + + addTempVolumeId(csSnapshotId, String.valueOf(sfVolume.getId())); + + handleSnapshotDetails(csSnapshotId, DiskTO.IQN, sfVolume.getIqn()); + } + else if (snapshotDetails != null && snapshotDetails.getValue() != null && snapshotDetails.getValue().equalsIgnoreCase("delete")) { + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID); + + SolidFireUtil.deleteSolidFireVolume(sfConnection, Long.parseLong(snapshotDetails.getValue())); + + removeTempVolumeId(csSnapshotId); + + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, DiskTO.IQN); + + snapshotDetailsDao.remove(snapshotDetails.getId()); + } + else { + throw new CloudRuntimeException("Invalid state in 'createTempVolume(SnapshotInfo, long)'"); + } + } + + private String createTemplateVolume(TemplateInfo templateInfo, long storagePoolId) { + verifySufficientBytesForStoragePool(templateInfo, storagePoolId); + + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); + + long sfAccountId = getCreateSolidFireAccountId(sfConnection, templateInfo.getAccountId(), storagePoolId); + + SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(sfConnection, templateInfo, sfAccountId); + + String iqn = sfVolume.getIqn(); + + VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, templateInfo.getId()); + + templatePoolRef.setInstallPath(iqn); + templatePoolRef.setLocalDownloadPath(Long.toString(sfVolume.getId())); + templatePoolRef.setTemplateSize(sfVolume.getTotalSize()); + + tmpltPoolDao.update(templatePoolRef.getId(), templatePoolRef); + + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + + long capacityBytes = storagePool.getCapacityBytes(); + // getUsedBytes(StoragePool) will include the bytes of the newly created template volume because + // _tmpltPoolDao.update(Long, VMTemplateStoragePoolVO) has already been invoked + long usedBytes = getUsedBytes(storagePool); + + storagePool.setUsedBytes(usedBytes > capacityBytes ? capacityBytes : usedBytes); + + storagePoolDao.update(storagePoolId, storagePool); + + return iqn; + } + + private void deleteVolume(VolumeInfo volumeInfo, long storagePoolId) { + try { + long volumeId = volumeInfo.getId(); + + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); + + deleteSolidFireVolume(sfConnection, volumeInfo); + + volumeDetailsDao.removeDetails(volumeId); + + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + + long usedBytes = getUsedBytes(storagePool, volumeId); + + storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes); + + storagePoolDao.update(storagePoolId, storagePool); + } + catch (Exception ex) { + LOGGER.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume. CloudStack volume ID: " + volumeInfo.getId(), ex); - long snapshotId = snapshotInfo.getId(); + throw ex; + } + } + + private void deleteSnapshot(SnapshotInfo snapshotInfo, long storagePoolId) { + long csSnapshotId = snapshotInfo.getId(); try { - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); + + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID); + + if (snapshotDetails != null && snapshotDetails.getValue() != null) { + // A SolidFire snapshot is being used to support the CloudStack volume snapshot. + + long sfSnapshotId = Long.parseLong(snapshotDetails.getValue()); - SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshotId, SolidFireUtil.VOLUME_ID); + deleteSolidFireSnapshot(sfConnection, csSnapshotId, sfSnapshotId); + } + else { + // A SolidFire volume is being used to support the CloudStack volume snapshot. + + snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID); - long volumeId = Long.parseLong(snapshotDetails.getValue()); + long sfVolumeId = Long.parseLong(snapshotDetails.getValue()); - SolidFireUtil.deleteSolidFireVolume(sfConnection, volumeId); + SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId); + } - _snapshotDetailsDao.removeDetails(snapshotId); + snapshotDetailsDao.removeDetails(csSnapshotId); - StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); // getUsedBytes(StoragePool) will not include the snapshot to delete because it has already been deleted by this point long usedBytes = getUsedBytes(storagePool); storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes); - _storagePoolDao.update(storagePoolId, storagePool); + storagePoolDao.update(storagePoolId, storagePool); } catch (Exception ex) { - s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume. CloudStack snapshot ID: " + snapshotId, ex); + LOGGER.debug(SolidFireUtil.LOG_PREFIX + "Issue in 'deleteSnapshot(SnapshotInfo, long)'. CloudStack snapshot ID: " + csSnapshotId, ex); - errMsg = ex.getMessage(); + throw ex; } + } - return errMsg; + private void deleteTemplate(TemplateInfo template, long storagePoolId) { + try { + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao); + + long sfTemplateVolumeId = getVolumeIdFrom_iScsiPath(template.getInstallPath()); + + SolidFireUtil.deleteSolidFireVolume(sfConnection, sfTemplateVolumeId); + + VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, template.getId()); + + tmpltPoolDao.remove(templatePoolRef.getId()); + + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + + // getUsedBytes(StoragePool) will not include the template to delete because the "template_spool_ref" table has already been updated by this point + long usedBytes = getUsedBytes(storagePool); + + storagePool.setUsedBytes(usedBytes < 0 ? 0 : usedBytes); + + storagePoolDao.update(storagePoolId, storagePool); + } + catch (Exception ex) { + LOGGER.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire template volume. CloudStack template ID: " + template.getId(), ex); + + throw ex; + } } @Override - public void revertSnapshot(SnapshotInfo snapshot, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback callback) { + public void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback callback) { throw new UnsupportedOperationException("Reverting not supported. Create a template or volume based on the snapshot instead."); } @@ -717,26 +1196,49 @@ public void resize(DataObject dataObject, AsyncCompletionCallback hsr) { + hsr = payload.newHypervisorSnapshotReserve; + } + } + else { + hsr = payload.newHypervisorSnapshotReserve; + } + } + + sfNewVolumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(payload.newSize, hsr); + } + + Map mapAttributes = new HashMap<>(); - SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolumeId, sfVolume.getTotalSize(), NumberFormat.getInstance().format(payload.newSize), + mapAttributes.put(SolidFireUtil.CloudStackVolumeId, String.valueOf(volumeInfo.getId())); + mapAttributes.put(SolidFireUtil.CloudStackVolumeSize, NumberFormat.getInstance().format(payload.newSize)); + + SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolumeId, sfNewVolumeSize, mapAttributes, payload.newMinIops, payload.newMaxIops, getDefaultBurstIops(storagePoolId, payload.newMaxIops)); - VolumeVO volume = _volumeDao.findById(volumeInfo.getId()); + VolumeVO volume = volumeDao.findById(volumeInfo.getId()); volume.setMinIops(payload.newMinIops); volume.setMaxIops(payload.newMaxIops); + volume.setHypervisorSnapshotReserve(hsr); - _volumeDao.update(volume.getId(), volume); + volumeDao.update(volume.getId(), volume); // SolidFireUtil.VOLUME_SIZE was introduced in 4.5. - // To be backward compatible with releases prior to 4.5, call updateVolumeDetails here. - // That way if SolidFireUtil.VOLUME_SIZE wasn't put in the volume_details table when the - // volume was initially created, it can be placed in volume_details if the volume is resized. - updateVolumeDetails(volume.getId(), sfVolume.getTotalSize()); + updateVolumeDetails(volume.getId(), sfNewVolumeSize); } else { errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to resize"; } @@ -748,21 +1250,140 @@ public void resize(DataObject dataObject, AsyncCompletionCallback capacityBytes) { + throw new CloudRuntimeException("Insufficient amount of space remains in this primary storage"); + } + } + + private void verifySufficientBytesForStoragePool(DataObject dataObject, long storagePoolId) { + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + + long requestedBytes = getDataObjectSizeIncludingHypervisorSnapshotReserve(dataObject, storagePool); + + verifySufficientBytesForStoragePool(requestedBytes, storagePoolId); + } + + private void verifySufficientBytesForStoragePool(long storagePoolId, long volumeId, long newSize, Integer newHypervisorSnapshotReserve) { + DataStore primaryDataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + VolumeInfo volumeInfo = volumeFactory.getVolume(volumeId, primaryDataStore); + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + long currentSizeWithHsr = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, storagePool); + + newHypervisorSnapshotReserve = newHypervisorSnapshotReserve == null ? LOWEST_HYPERVISOR_SNAPSHOT_RESERVE : + Math.max(newHypervisorSnapshotReserve, LOWEST_HYPERVISOR_SNAPSHOT_RESERVE); + + long newSizeWithHsr = (long)(newSize + newSize * (newHypervisorSnapshotReserve / 100f)); + + if (newSizeWithHsr < currentSizeWithHsr) { + throw new CloudRuntimeException("Storage pool " + storagePoolId + " does not support shrinking a volume."); + } + + long availableBytes = storagePool.getCapacityBytes() - getUsedBytes(storagePool); + + if ((newSizeWithHsr - currentSizeWithHsr) > availableBytes) { + throw new CloudRuntimeException("Storage pool " + storagePoolId + " does not have enough space to expand the volume."); + } + } + + private void verifySufficientIopsForStoragePool(long requestedIops, long storagePoolId) { + StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); + + long usedIops = getUsedIops(storagePool); + long capacityIops = storagePool.getCapacityIops(); + + if (usedIops + requestedIops > capacityIops) { + throw new CloudRuntimeException("Insufficient number of IOPS available in this storage pool"); + } + } + private void verifySufficientIopsForStoragePool(long storagePoolId, long volumeId, long newMinIops) { - StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); - VolumeVO volume = _volumeDao.findById(volumeId); + VolumeVO volume = volumeDao.findById(volumeId); long currentMinIops = volume.getMinIops(); long diffInMinIops = newMinIops - currentMinIops; // if the desire is for more IOPS if (diffInMinIops > 0) { - long usedIops = getUsedIops(storagePool); - long capacityIops = storagePool.getCapacityIops(); + verifySufficientIopsForStoragePool(diffInMinIops, storagePoolId); + } + } + + private void deleteSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, long csVolumeId, long sfVolumeId) { + List lstSnapshots = getNonDestroyedSnapshots(csVolumeId); + + boolean deleteVolume = true; + + for (SnapshotVO snapshot : lstSnapshots) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.SNAPSHOT_ID); + + if (snapshotDetails != null && snapshotDetails.getValue() != null) { + deleteVolume = false; + + break; + } + } - if (usedIops + diffInMinIops > capacityIops) { - throw new CloudRuntimeException("Insufficient number of IOPS available in this storage pool"); + if (deleteVolume) { + SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId); + } + } + + private void deleteSolidFireSnapshot(SolidFireUtil.SolidFireConnection sfConnection, long csSnapshotId, long sfSnapshotId) { + SolidFireUtil.deleteSolidFireSnapshot(sfConnection, sfSnapshotId); + + SnapshotVO snapshot = snapshotDao.findById(csSnapshotId); + VolumeVO volume = volumeDao.findById(snapshot.getVolumeId()); + + if (volume == null) { // if the CloudStack volume has been deleted + List lstSnapshots = getNonDestroyedSnapshots(snapshot.getVolumeId()); + + List lstSnapshots2 = new ArrayList<>(); + + for (SnapshotVO snapshotVo : lstSnapshots) { + // The CloudStack volume snapshot has not yet been set to the DESTROYED state, so check to make + // sure snapshotVo.getId() != csSnapshotId when determining if any volume snapshots remain for the given CloudStack volume. + if (snapshotVo.getId() != csSnapshotId) { + SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotVo.getId(), SolidFireUtil.SNAPSHOT_ID); + + // We are only interested here in volume snapshots that make use of SolidFire snapshots (as opposed to ones + // that make use of SolidFire volumes). + if (snapshotDetails != null && snapshotDetails.getValue() != null) { + lstSnapshots2.add(snapshotVo); + } + } } + + if (lstSnapshots2.isEmpty()) { + volume = volumeDao.findByIdIncludingRemoved(snapshot.getVolumeId()); + + SolidFireUtil.deleteSolidFireVolume(sfConnection, Long.parseLong(volume.getFolder())); + } + } + } + + private List getNonDestroyedSnapshots(long csVolumeId) { + List lstSnapshots = snapshotDao.listByVolumeId(csVolumeId); + + if (lstSnapshots == null) { + lstSnapshots = new ArrayList<>(); } + + List lstSnapshots2 = new ArrayList<>(); + + for (SnapshotVO snapshot : lstSnapshots) { + if (!State.Destroyed.equals(snapshot.getState())) { + lstSnapshots2.add(snapshot); + } + } + + return lstSnapshots2; } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java index 4b38f221df..c47411e39a 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java @@ -33,6 +33,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper; @@ -49,23 +50,27 @@ import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.SnapshotDetailsDao; import com.cloud.storage.dao.SnapshotDetailsVO; +import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.storage.SnapshotVO; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolAutomation; +import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.utils.exception.CloudRuntimeException; public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle { private static final Logger s_logger = Logger.getLogger(SolidFirePrimaryDataStoreLifeCycle.class); @Inject private CapacityManager _capacityMgr; - @Inject private DataCenterDao zoneDao; - @Inject private PrimaryDataStoreDao storagePoolDao; - @Inject private PrimaryDataStoreHelper dataStoreHelper; + @Inject private DataCenterDao _zoneDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private PrimaryDataStoreHelper _dataStoreHelper; @Inject private ResourceManager _resourceMgr; @Inject private SnapshotDao _snapshotDao; @Inject private SnapshotDetailsDao _snapshotDetailsDao; @Inject private StorageManager _storageMgr; - @Inject private StoragePoolAutomation storagePoolAutomation; + @Inject private StoragePoolAutomation _storagePoolAutomation; + @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; + @Inject private VMTemplatePoolDao _tmpltPoolDao; // invoked to add primary storage that is based on the SolidFire plug-in @Override @@ -83,7 +88,7 @@ public DataStore initialize(Map dsInfos) { String storageVip = SolidFireUtil.getStorageVip(url); int storagePort = SolidFireUtil.getStoragePort(url); - DataCenterVO zone = zoneDao.findById(zoneId); + DataCenterVO zone = _zoneDao.findById(zoneId); String uuid = SolidFireUtil.PROVIDER_NAME + "_" + zone.getUuid() + "_" + storageVip; @@ -136,7 +141,7 @@ public DataStore initialize(Map dsInfos) { lClusterDefaultMinIops = Long.parseLong(clusterDefaultMinIops); } } catch (NumberFormatException ex) { - s_logger.warn("Cannot parse the setting of " + SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS + + s_logger.warn("Cannot parse the setting " + SolidFireUtil.CLUSTER_DEFAULT_MIN_IOPS + ", using default value: " + lClusterDefaultMinIops + ". Exception: " + ex); } @@ -148,7 +153,7 @@ public DataStore initialize(Map dsInfos) { lClusterDefaultMaxIops = Long.parseLong(clusterDefaultMaxIops); } } catch (NumberFormatException ex) { - s_logger.warn("Cannot parse the setting of " + SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS + + s_logger.warn("Cannot parse the setting " + SolidFireUtil.CLUSTER_DEFAULT_MAX_IOPS + ", using default value: " + lClusterDefaultMaxIops + ". Exception: " + ex); } @@ -160,7 +165,7 @@ public DataStore initialize(Map dsInfos) { fClusterDefaultBurstIopsPercentOfMaxIops = Float.parseFloat(clusterDefaultBurstIopsPercentOfMaxIops); } } catch (NumberFormatException ex) { - s_logger.warn("Cannot parse the setting of " + SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS + + s_logger.warn("Cannot parse the setting " + SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS + ", using default value: " + fClusterDefaultBurstIopsPercentOfMaxIops + ". Exception: " + ex); } @@ -179,7 +184,7 @@ public DataStore initialize(Map dsInfos) { details.put(SolidFireUtil.CLUSTER_DEFAULT_BURST_IOPS_PERCENT_OF_MAX_IOPS, String.valueOf(fClusterDefaultBurstIopsPercentOfMaxIops)); // this adds a row in the cloud.storage_pool table for this SolidFire cluster - return dataStoreHelper.createPrimaryDataStore(parameters); + return _dataStoreHelper.createPrimaryDataStore(parameters); } // do not implement this method for SolidFire's plug-in @@ -196,7 +201,7 @@ public boolean attachCluster(DataStore store, ClusterScope scope) { @Override public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) { - dataStoreHelper.attachZone(dataStore); + _dataStoreHelper.attachZone(dataStore); List xenServerHosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.XenServer, scope.getScopeId()); List vmWareServerHosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.VMware, scope.getScopeId()); @@ -220,23 +225,25 @@ public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType h @Override public boolean maintain(DataStore dataStore) { - storagePoolAutomation.maintain(dataStore); - dataStoreHelper.maintain(dataStore); + _storagePoolAutomation.maintain(dataStore); + _dataStoreHelper.maintain(dataStore); return true; } @Override public boolean cancelMaintain(DataStore store) { - dataStoreHelper.cancelMaintain(store); - storagePoolAutomation.cancelMaintain(store); + _dataStoreHelper.cancelMaintain(store); + _storagePoolAutomation.cancelMaintain(store); return true; } // invoked to delete primary storage that is based on the SolidFire plug-in @Override - public boolean deleteDataStore(DataStore store) { + public boolean deleteDataStore(DataStore dataStore) { + long storagePoolId = dataStore.getId(); + List lstSnapshots = _snapshotDao.listAll(); if (lstSnapshots != null) { @@ -244,13 +251,39 @@ public boolean deleteDataStore(DataStore store) { SnapshotDetailsVO snapshotDetails = _snapshotDetailsDao.findDetail(snapshot.getId(), SolidFireUtil.STORAGE_POOL_ID); // if this snapshot belongs to the storagePool that was passed in - if (snapshotDetails != null && snapshotDetails.getValue() != null && Long.parseLong(snapshotDetails.getValue()) == store.getId()) { + if (snapshotDetails != null && snapshotDetails.getValue() != null && Long.parseLong(snapshotDetails.getValue()) == storagePoolId) { throw new CloudRuntimeException("This primary storage cannot be deleted because it currently contains one or more snapshots."); } } } - return dataStoreHelper.deletePrimaryDataStore(store); + List lstTemplatePoolRefs = _tmpltPoolDao.listByPoolId(storagePoolId); + + if (lstTemplatePoolRefs != null) { + for (VMTemplateStoragePoolVO templatePoolRef : lstTemplatePoolRefs) { + try { + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); + long sfTemplateVolumeId = Long.parseLong(templatePoolRef.getLocalDownloadPath()); + + SolidFireUtil.deleteSolidFireVolume(sfConnection, sfTemplateVolumeId); + } + catch (Exception ex) { + s_logger.error(ex.getMessage() != null ? ex.getMessage() : "Error deleting SolidFire template volume"); + } + + _tmpltPoolDao.remove(templatePoolRef.getId()); + } + } + + StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); + + storagePool.setUsedBytes(0); + + _storagePoolDao.update(storagePoolId, storagePool); + + _storagePoolDetailsDao.removeDetails(storagePoolId); + + return _dataStoreHelper.deletePrimaryDataStore(dataStore); } /* (non-Javadoc) @@ -263,7 +296,7 @@ public boolean migrateToObjectStore(DataStore store) { @Override public void updateStoragePool(StoragePool storagePool, Map details) { - StoragePoolVO storagePoolVo = storagePoolDao.findById(storagePool.getId()); + StoragePoolVO storagePoolVo = _storagePoolDao.findById(storagePool.getId()); String strCapacityBytes = details.get(PrimaryDataStoreLifeCycle.CAPACITY_BYTES); Long capacityBytes = strCapacityBytes != null ? Long.parseLong(strCapacityBytes) : null; @@ -290,11 +323,11 @@ public void updateStoragePool(StoragePool storagePool, Map detai @Override public void enableStoragePool(DataStore dataStore) { - dataStoreHelper.enable(dataStore); + _dataStoreHelper.enable(dataStore); } @Override public void disableStoragePool(DataStore dataStore) { - dataStoreHelper.disable(dataStore); + _dataStoreHelper.disable(dataStore); } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java index 7cb690014b..6921e4f487 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java @@ -70,6 +70,7 @@ import com.cloud.user.AccountDetailsDao; import com.cloud.user.AccountVO; import com.cloud.user.dao.AccountDao; +import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; public class SolidFireSharedPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCycle { @@ -178,8 +179,7 @@ public DataStore initialize(Map dsInfos) { lMinIops = Long.parseLong(minIops); } } catch (Exception ex) { - s_logger.info("[ignored]" - + "error getting minimals iops: " + ex.getLocalizedMessage()); + s_logger.info("[ignored] error getting Min IOPS: " + ex.getLocalizedMessage()); } try { @@ -189,8 +189,7 @@ public DataStore initialize(Map dsInfos) { lMaxIops = Long.parseLong(maxIops); } } catch (Exception ex) { - s_logger.info("[ignored]" - + "error getting maximal iops: " + ex.getLocalizedMessage()); + s_logger.info("[ignored] error getting Max IOPS: " + ex.getLocalizedMessage()); } try { @@ -200,8 +199,7 @@ public DataStore initialize(Map dsInfos) { lBurstIops = Long.parseLong(burstIops); } } catch (Exception ex) { - s_logger.info("[ignored]" - + "error getting iops bursts: " + ex.getLocalizedMessage()); + s_logger.info("[ignored] error getting Burst IOPS: " + ex.getLocalizedMessage()); } if (lMinIops > lMaxIops) { @@ -255,14 +253,27 @@ public DataStore initialize(Map dsInfos) { parameters.setPath(iqn); } - // this adds a row in the cloud.storage_pool table for this SolidFire volume - DataStore dataStore = _primaryDataStoreHelper.createPrimaryDataStore(parameters); + ClusterVO cluster = _clusterDao.findById(clusterId); + + GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); + + if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) { + String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); + + s_logger.debug(errMsg); + + throw new CloudRuntimeException(errMsg); + } + + DataStore dataStore = null; - // now that we have a DataStore (we need the id from the DataStore instance), we can create a Volume Access Group, if need be, and - // place the newly created volume in the Volume Access Group try { + // this adds a row in the cloud.storage_pool table for this SolidFire volume + dataStore = _primaryDataStoreHelper.createPrimaryDataStore(parameters); + + // now that we have a DataStore (we need the id from the DataStore instance), we can create a Volume Access Group, if need be, and + // place the newly created volume in the Volume Access Group List hosts = _hostDao.findByClusterId(clusterId); - ClusterVO cluster = _clusterDao.findById(clusterId); SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolume.getId(), dataStore.getId(), cluster.getUuid(), hosts, _clusterDetailsDao); @@ -275,6 +286,10 @@ public DataStore initialize(Map dsInfos) { throw new CloudRuntimeException(ex.getMessage()); } + finally { + lock.unlock(); + lock.releaseRef(); + } return dataStore; } @@ -546,7 +561,25 @@ public boolean deleteDataStore(DataStore dataStore) { } if (clusterId != null) { - removeVolumeFromVag(storagePool.getId(), clusterId); + ClusterVO cluster = _clusterDao.findById(clusterId); + + GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); + + if (!lock.lock(SolidFireUtil.s_lockTimeInSeconds)) { + String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); + + s_logger.debug(errMsg); + + throw new CloudRuntimeException(errMsg); + } + + try { + removeVolumeFromVag(storagePool.getId(), clusterId); + } + finally { + lock.unlock(); + lock.releaseRef(); + } } deleteSolidFireVolume(storagePool.getId()); @@ -561,16 +594,13 @@ private void removeVolumeFromVag(long storagePoolId, long clusterId) { String vagId = clusterDetail != null ? clusterDetail.getValue() : null; if (vagId != null) { - List hosts = _hostDao.findByClusterId(clusterId); - SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao); SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); - String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hosts)); long[] volumeIds = SolidFireUtil.getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, false); - SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, volumeIds); + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), sfVag.getInitiators(), volumeIds); } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java index d8e4ec61ec..082e1a3d2b 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireHostListener.java @@ -18,40 +18,69 @@ */ package org.apache.cloudstack.storage.datastore.provider; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import javax.inject.Inject; import org.apache.log4j.Logger; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.ModifyStoragePoolAnswer; import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.alert.AlertManager; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.dao.ClusterDao; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.dao.VMInstanceDao; public class SolidFireHostListener implements HypervisorHostListener { private static final Logger s_logger = Logger.getLogger(SolidFireHostListener.class); - @Inject - private AgentManager _agentMgr; - @Inject - private AlertManager _alertMgr; - @Inject - private DataStoreManager _dataStoreMgr; - @Inject - private HostDao _hostDao; - @Inject - private StoragePoolHostDao storagePoolHostDao; + @Inject private AgentManager _agentMgr; + @Inject private AlertManager _alertMgr; + @Inject private ClusterDao _clusterDao; + @Inject private ClusterDetailsDao _clusterDetailsDao; + @Inject private DataStoreManager _dataStoreMgr; + @Inject private HostDao _hostDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private StoragePoolDetailsDao _storagePoolDetailsDao; + @Inject private StoragePoolHostDao storagePoolHostDao; + @Inject private VMInstanceDao _vmDao; + @Inject private VolumeDao _volumeDao; + + @Override + public boolean hostAdded(long hostId) { + HostVO host = _hostDao.findById(hostId); + + SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), true, SolidFireUtil.PROVIDER_NAME, + _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); + + handleVMware(host, true); + + return true; + } @Override public boolean hostConnect(long hostId, long storagePoolId) { @@ -65,14 +94,174 @@ public boolean hostConnect(long hostId, long storagePoolId) { storagePoolHostDao.persist(storagePoolHost); } - // just want to send the ModifyStoragePoolCommand for KVM - if (host.getHypervisorType() != HypervisorType.KVM) { - return true; + if (host.getHypervisorType().equals(HypervisorType.XenServer)) { + handleXenServer(host.getClusterId(), host.getId(), storagePoolId); + } + else if (host.getHypervisorType().equals(HypervisorType.KVM)) { + handleKVM(hostId, storagePoolId); + } + + return true; + } + + @Override + public boolean hostDisconnected(long hostId, long storagePoolId) { + StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); + + if (storagePoolHost != null) { + storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId); + } + + return true; + } + + @Override + public boolean hostAboutToBeRemoved(long hostId) { + HostVO host = _hostDao.findById(hostId); + + handleVMware(host, false); + + return true; + } + + @Override + public boolean hostRemoved(long hostId, long clusterId) { + SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, clusterId, false, SolidFireUtil.PROVIDER_NAME, + _clusterDao, _clusterDetailsDao, _storagePoolDao, _storagePoolDetailsDao, _hostDao); + + return true; + } + + private void handleXenServer(long clusterId, long hostId, long storagePoolId) { + List storagePaths = getStoragePaths(clusterId, storagePoolId); + + StoragePool storagePool = (StoragePool)_dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + + for (String storagePath : storagePaths) { + ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); + + cmd.setStoragePath(storagePath); + + sendModifyStoragePoolCommand(cmd, storagePool, hostId); + } + } + + private void handleVMware(HostVO host, boolean add) { + if (HypervisorType.VMware.equals(host.getHypervisorType())) { + List storagePools = _storagePoolDao.findPoolsByProvider(SolidFireUtil.PROVIDER_NAME); + + if (storagePools != null && storagePools.size() > 0) { + List> targets = new ArrayList<>(); + + for (StoragePoolVO storagePool : storagePools) { + List> targetsForClusterAndStoragePool = getTargets(host.getClusterId(), storagePool.getId()); + + targets.addAll(targetsForClusterAndStoragePool); + } + + ModifyTargetsCommand cmd = new ModifyTargetsCommand(); + + cmd.setAdd(add); + cmd.setTargets(targets); + + sendModifyTargetsCommand(cmd, host.getId()); + } } + } + private void handleKVM(long hostId, long storagePoolId) { StoragePool storagePool = (StoragePool)_dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); + sendModifyStoragePoolCommand(cmd, storagePool, hostId); + } + + private List getStoragePaths(long clusterId, long storagePoolId) { + List storagePaths = new ArrayList<>(); + + // If you do not pass in null for the second parameter, you only get back applicable ROOT disks. + List volumes = _volumeDao.findByPoolId(storagePoolId, null); + + if (volumes != null) { + for (VolumeVO volume : volumes) { + Long instanceId = volume.getInstanceId(); + + if (instanceId != null) { + VMInstanceVO vmInstance = _vmDao.findById(instanceId); + + Long hostIdForVm = vmInstance.getHostId() != null ? vmInstance.getHostId() : vmInstance.getLastHostId(); + + if (hostIdForVm != null) { + HostVO hostForVm = _hostDao.findById(hostIdForVm); + + if (hostForVm.getClusterId().equals(clusterId)) { + storagePaths.add(volume.get_iScsiName()); + } + } + } + } + } + + return storagePaths; + } + + private List> getTargets(long clusterId, long storagePoolId) { + List> targets = new ArrayList<>(); + + StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId); + + // If you do not pass in null for the second parameter, you only get back applicable ROOT disks. + List volumes = _volumeDao.findByPoolId(storagePoolId, null); + + if (volumes != null) { + for (VolumeVO volume : volumes) { + Long instanceId = volume.getInstanceId(); + + if (instanceId != null) { + VMInstanceVO vmInstance = _vmDao.findById(instanceId); + + Long hostIdForVm = vmInstance.getHostId() != null ? vmInstance.getHostId() : vmInstance.getLastHostId(); + + if (hostIdForVm != null) { + HostVO hostForVm = _hostDao.findById(hostIdForVm); + + if (hostForVm.getClusterId().equals(clusterId)) { + Map details = new HashMap<>(); + + details.put(ModifyTargetsCommand.IQN, volume.get_iScsiName()); + details.put(ModifyTargetsCommand.STORAGE_HOST, storagePool.getHostAddress()); + details.put(ModifyTargetsCommand.STORAGE_PORT, String.valueOf(storagePool.getPort())); + + targets.add(details); + } + } + } + } + } + + return targets; + } + + private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { + Answer answer = _agentMgr.easySend(hostId, cmd); + + if (answer == null) { + throw new CloudRuntimeException("Unable to get an answer to the modify targets command"); + } + + if (!answer.getResult()) { + String msg = "Unable to modify targets on the following host: " + hostId; + + HostVO host = _hostDao.findById(hostId); + + _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), msg, msg); + + throw new CloudRuntimeException(msg); + } + } + + private void sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StoragePool storagePool, long hostId) { Answer answer = _agentMgr.easySend(hostId, cmd); if (answer == null) { @@ -80,7 +269,7 @@ public boolean hostConnect(long hostId, long storagePoolId) { } if (!answer.getResult()) { - String msg = "Unable to attach storage pool " + storagePoolId + " to host " + hostId; + String msg = "Unable to attach storage pool " + storagePool.getId() + " to host " + hostId; _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); @@ -91,18 +280,5 @@ public boolean hostConnect(long hostId, long storagePoolId) { assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer expected ; Pool = " + storagePool.getId() + " Host = " + hostId; s_logger.info("Connection established between storage pool " + storagePool + " and host + " + hostId); - - return true; - } - - @Override - public boolean hostDisconnected(long hostId, long storagePoolId) { - StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); - - if (storagePoolHost != null) { - storagePoolHostDao.deleteStoragePoolHostDetails(hostId, storagePoolId); - } - - return true; } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java index 9881d1d179..f88041a3c4 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/provider/SolidFireSharedHostListener.java @@ -18,18 +18,33 @@ */ package org.apache.cloudstack.storage.datastore.provider; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; +import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.util.SolidFireUtil; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.ModifyStoragePoolAnswer; import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.agent.api.ModifyTargetsCommand; import com.cloud.alert.AlertManager; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; @@ -37,44 +52,53 @@ import com.cloud.utils.exception.CloudRuntimeException; public class SolidFireSharedHostListener implements HypervisorHostListener { - private static final Logger s_logger = Logger.getLogger(DefaultHostListener.class); + private static final Logger LOGGER = Logger.getLogger(SolidFireSharedHostListener.class); @Inject private AgentManager agentMgr; - @Inject private DataStoreManager dataStoreMgr; @Inject private AlertManager alertMgr; + @Inject private ClusterDao clusterDao; + @Inject private ClusterDetailsDao clusterDetailsDao; + @Inject private DataStoreManager dataStoreMgr; + @Inject private HostDao hostDao; + @Inject private PrimaryDataStoreDao storagePoolDao; @Inject private StoragePoolHostDao storagePoolHostDao; - @Inject private PrimaryDataStoreDao primaryStoreDao; + @Inject private StoragePoolDetailsDao storagePoolDetailsDao; @Override - public boolean hostConnect(long hostId, long storagePoolId) { - StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); + public boolean hostAdded(long hostId) { + HostVO host = hostDao.findById(hostId); - if (storagePoolHost == null) { - storagePoolHost = new StoragePoolHostVO(storagePoolId, hostId, ""); + SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), true, SolidFireUtil.SHARED_PROVIDER_NAME, + clusterDao, clusterDetailsDao, storagePoolDao, storagePoolDetailsDao, hostDao); - storagePoolHostDao.persist(storagePoolHost); - } + handleVMware(hostId, true); - StoragePool storagePool = (StoragePool)dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + return true; + } + + @Override + public boolean hostConnect(long hostId, long storagePoolId) { + StoragePool storagePool = (StoragePool) dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool); - Answer answer = agentMgr.easySend(hostId, cmd); - if (answer == null) { - throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command for storage pool: " + storagePool.getId()); - } + ModifyStoragePoolAnswer answer = sendModifyStoragePoolCommand(cmd, storagePool, hostId); - if (!answer.getResult()) { - String msg = "Unable to attach storage pool " + storagePoolId + " to the host " + hostId; + StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId); - alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); + if (storagePoolHost != null) { + storagePoolHost.setLocalPath(answer.getPoolInfo().getLocalPath().replaceAll("//", "/")); + } else { + storagePoolHost = new StoragePoolHostVO(storagePoolId, hostId, answer.getPoolInfo().getLocalPath().replaceAll("//", "/")); - throw new CloudRuntimeException(msg); + storagePoolHostDao.persist(storagePoolHost); } - assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer not returned from ModifyStoragePoolCommand; Storage pool = " + - storagePool.getId() + "; Host=" + hostId; + StoragePoolVO storagePoolVO = storagePoolDao.findById(storagePoolId); + + storagePoolVO.setCapacityBytes(answer.getPoolInfo().getCapacityBytes()); + storagePoolVO.setUsedBytes(answer.getPoolInfo().getCapacityBytes() - answer.getPoolInfo().getAvailableBytes()); - s_logger.info("Connection established between storage pool " + storagePool + " and host + " + hostId); + storagePoolDao.update(storagePoolId, storagePoolVO); return true; } @@ -89,4 +113,107 @@ public boolean hostDisconnected(long hostId, long storagePoolId) { return true; } + + @Override + public boolean hostAboutToBeRemoved(long hostId) { + handleVMware(hostId, false); + + return true; + } + + @Override + public boolean hostRemoved(long hostId, long clusterId) { + SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, clusterId, false, SolidFireUtil.SHARED_PROVIDER_NAME, + clusterDao, clusterDetailsDao, storagePoolDao, storagePoolDetailsDao, hostDao); + + return true; + } + + private void handleVMware(long hostId, boolean add) { + HostVO host = hostDao.findById(hostId); + + if (HypervisorType.VMware.equals(host.getHypervisorType())) { + List storagePools = storagePoolDao.findPoolsByProvider(SolidFireUtil.SHARED_PROVIDER_NAME); + + if (storagePools != null && storagePools.size() > 0) { + List> targets = new ArrayList<>(); + + for (StoragePoolVO storagePool : storagePools) { + if (storagePool.getClusterId().equals(host.getClusterId())) { + long storagePoolId = storagePool.getId(); + + StoragePoolDetailVO storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.IQN); + + String iqn = storagePoolDetail.getValue(); + + storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_VIP); + + String sVip = storagePoolDetail.getValue(); + + storagePoolDetail = storagePoolDetailsDao.findDetail(storagePoolId, SolidFireUtil.STORAGE_PORT); + + String sPort = storagePoolDetail.getValue(); + + Map details = new HashMap<>(); + + details.put(ModifyTargetsCommand.IQN, iqn); + details.put(ModifyTargetsCommand.STORAGE_HOST, sVip); + details.put(ModifyTargetsCommand.STORAGE_PORT, sPort); + + targets.add(details); + } + } + + if (targets.size() > 0) { + ModifyTargetsCommand cmd = new ModifyTargetsCommand(); + + cmd.setAdd(add); + cmd.setTargets(targets); + + sendModifyTargetsCommand(cmd, hostId); + } + } + } + } + + private void sendModifyTargetsCommand(ModifyTargetsCommand cmd, long hostId) { + Answer answer = agentMgr.easySend(hostId, cmd); + + if (answer == null) { + throw new CloudRuntimeException("Unable to get an answer to the modify targets command"); + } + + if (!answer.getResult()) { + String msg = "Unable to modify targets on the following host: " + hostId; + + HostVO host = hostDao.findById(hostId); + + alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), msg, msg); + + throw new CloudRuntimeException(msg); + } + } + + private ModifyStoragePoolAnswer sendModifyStoragePoolCommand(ModifyStoragePoolCommand cmd, StoragePool storagePool, long hostId) { + Answer answer = agentMgr.easySend(hostId, cmd); + + if (answer == null) { + throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command for storage pool: " + storagePool.getId()); + } + + if (!answer.getResult()) { + String msg = "Unable to attach storage pool " + storagePool.getId() + " to the host " + hostId; + + alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg); + + throw new CloudRuntimeException(msg); + } + + assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer not returned from ModifyStoragePoolCommand; Storage pool = " + + storagePool.getId() + "; Host = " + hostId; + + LOGGER.info("Connection established between storage pool " + storagePool + " and host " + hostId); + + return (ModifyStoragePoolAnswer)answer; + } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java index 9c486db429..a9c1227120 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/util/SolidFireUtil.java @@ -28,7 +28,9 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -54,18 +56,24 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.utils.security.SSLUtils; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.dao.ClusterDao; import com.cloud.host.Host; import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; import com.cloud.user.AccountDetailVO; import com.cloud.user.AccountDetailsDao; +import com.cloud.utils.db.GlobalLock; import com.cloud.utils.exception.CloudRuntimeException; public class SolidFireUtil { @@ -73,6 +81,8 @@ public class SolidFireUtil { public static final String PROVIDER_NAME = "SolidFire"; public static final String SHARED_PROVIDER_NAME = "SolidFireShared"; + public static final int s_lockTimeInSeconds = 300; + public static final String LOG_PREFIX = "SolidFire: "; public static final String MANAGEMENT_VIP = "mVip"; @@ -96,6 +106,15 @@ public class SolidFireUtil { public static final String ACCOUNT_ID = "accountId"; public static final String VOLUME_ID = "volumeId"; + public static final String TEMP_VOLUME_ID = "tempVolumeId"; + public static final String SNAPSHOT_ID = "snapshotId"; + + public static final String CloudStackVolumeId = "CloudStackVolumeId"; + public static final String CloudStackVolumeSize = "CloudStackVolumeSize"; + public static final String CloudStackSnapshotId = "CloudStackSnapshotId"; + public static final String CloudStackSnapshotSize = "CloudStackSnapshotSize"; + public static final String CloudStackTemplateId = "CloudStackTemplateId"; + public static final String CloudStackTemplateSize = "CloudStackTemplateSize"; public static final String VOLUME_SIZE = "sfVolumeSize"; @@ -124,6 +143,22 @@ public static class SolidFireConnection { private final String _clusterAdminPassword; public SolidFireConnection(String managementVip, int managementPort, String clusterAdminUsername, String clusterAdminPassword) { + if (managementVip == null) { + throw new CloudRuntimeException("The management VIP cannot be 'null'."); + } + + if (managementPort <= 0) { + throw new CloudRuntimeException("The management port must be a positive integer."); + } + + if (clusterAdminUsername == null) { + throw new CloudRuntimeException("The cluster admin username cannot be 'null'."); + } + + if (clusterAdminPassword == null) { + throw new CloudRuntimeException("The cluster admin password cannot be 'null'."); + } + _managementVip = managementVip; _managementPort = managementPort; _clusterAdminUsername = clusterAdminUsername; @@ -145,6 +180,22 @@ public String getClusterAdminUsername() { public String getClusterAdminPassword() { return _clusterAdminPassword; } + + @Override + public int hashCode() { + return _managementVip.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SolidFireConnection)) { + return false; + } + + SolidFireConnection sfConnection = (SolidFireConnection)obj; + + return _managementVip.equals(sfConnection.getManagementVip()); + } } public static SolidFireConnection getSolidFireConnection(long storagePoolId, StoragePoolDetailsDao storagePoolDetailsDao) { @@ -238,6 +289,58 @@ public static SolidFireAccount getSolidFireAccount(SolidFireConnection sfConnect } } + public static void hostAddedToOrRemovedFromCluster(long hostId, long clusterId, boolean added, String storageProvider, + ClusterDao clusterDao, ClusterDetailsDao clusterDetailsDao, PrimaryDataStoreDao storagePoolDao, StoragePoolDetailsDao storagePoolDetailsDao, HostDao hostDao) { + ClusterVO cluster = clusterDao.findById(clusterId); + + GlobalLock lock = GlobalLock.getInternLock(cluster.getUuid()); + + if (!lock.lock(s_lockTimeInSeconds)) { + String errMsg = "Couldn't lock the DB on the following string: " + cluster.getUuid(); + + s_logger.debug(errMsg); + + throw new CloudRuntimeException(errMsg); + } + + try { + List storagePools = storagePoolDao.findPoolsByProvider(storageProvider); + + if (storagePools != null && storagePools.size() > 0) { + List sfConnections = new ArrayList(); + + for (StoragePoolVO storagePool : storagePools) { + ClusterDetailsVO clusterDetail = clusterDetailsDao.findDetail(clusterId, SolidFireUtil.getVagKey(storagePool.getId())); + + String vagId = clusterDetail != null ? clusterDetail.getValue() : null; + + if (vagId != null) { + SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePool.getId(), storagePoolDetailsDao); + + if (!sfConnections.contains(sfConnection)) { + sfConnections.add(sfConnection); + + SolidFireUtil.SolidFireVag sfVag = SolidFireUtil.getSolidFireVag(sfConnection, Long.parseLong(vagId)); + + List hostsToAddOrRemove = new ArrayList<>(); + HostVO hostToAddOrRemove = hostDao.findByIdIncludingRemoved(hostId); + + hostsToAddOrRemove.add(hostToAddOrRemove); + + String[] hostIqns = SolidFireUtil.getNewHostIqns(sfVag.getInitiators(), SolidFireUtil.getIqnsFromHosts(hostsToAddOrRemove), added); + + SolidFireUtil.modifySolidFireVag(sfConnection, sfVag.getId(), hostIqns, sfVag.getVolumeIds()); + } + } + } + } + } + finally { + lock.unlock(); + lock.releaseRef(); + } + } + public static long placeVolumeInVolumeAccessGroup(SolidFireConnection sfConnection, long sfVolumeId, long storagePoolId, String vagUuid, List hosts, ClusterDetailsDao clusterDetailsDao) { if (hosts == null || hosts.isEmpty()) { @@ -264,8 +367,7 @@ public static long placeVolumeInVolumeAccessGroup(SolidFireConnection sfConnecti long[] volumeIds = getNewVolumeIds(sfVag.getVolumeIds(), sfVolumeId, true); - SolidFireUtil.modifySolidFireVag(sfConnection, lVagId, - sfVag.getInitiators(), volumeIds); + SolidFireUtil.modifySolidFireVag(sfConnection, lVagId, sfVag.getInitiators(), volumeIds); } ClusterDetailsVO clusterDetail = new ClusterDetailsVO(hosts.get(0).getClusterId(), getVagKey(storagePoolId), String.valueOf(lVagId)); @@ -289,20 +391,34 @@ public static boolean hostsSupport_iScsi(List hosts) { return true; } - public static String[] getNewHostIqns(String[] currentIqns, String[] newIqns) { - List lstIqns = new ArrayList(); + public static String[] getNewHostIqns(String[] iqns, String[] iqnsToAddOrRemove, boolean add) { + if (add) { + return getNewHostIqnsAdd(iqns, iqnsToAddOrRemove); + } + + return getNewHostIqnsRemove(iqns, iqnsToAddOrRemove); + } - if (currentIqns != null) { - for (String currentIqn : currentIqns) { - lstIqns.add(currentIqn); + private static String[] getNewHostIqnsAdd(String[] iqns, String[] iqnsToAdd) { + List lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList(); + + if (iqnsToAdd != null) { + for (String iqnToAdd : iqnsToAdd) { + if (!lstIqns.contains(iqnToAdd)) { + lstIqns.add(iqnToAdd); + } } } - if (newIqns != null) { - for (String newIqn : newIqns) { - if (!lstIqns.contains(newIqn)) { - lstIqns.add(newIqn); - } + return lstIqns.toArray(new String[0]); + } + + private static String[] getNewHostIqnsRemove(String[] iqns, String[] iqnsToRemove) { + List lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList(); + + if (iqnsToRemove != null) { + for (String iqnToRemove : iqnsToRemove) { + lstIqns.remove(iqnToRemove); } } @@ -457,13 +573,44 @@ public static String getSolidFireVolumeName(String strCloudStackVolumeName) { } public static long createSolidFireVolume(SolidFireConnection sfConnection, String strSfVolumeName, long lSfAccountId, long lTotalSize, - boolean bEnable512e, String strCloudStackVolumeSize, long minIops, long maxIops, long burstIops) + boolean bEnable512e, Map mapAttributes, long minIops, long maxIops, long burstIops) { - final Gson gson = new GsonBuilder().create(); + JsonObject volumeToCreate = new JsonObject(); + + volumeToCreate.addProperty("method", "CreateVolume"); + + JsonObject params = new JsonObject(); + + volumeToCreate.add("params", params); + + params.addProperty("name", strSfVolumeName); + params.addProperty("accountID", lSfAccountId); + params.addProperty("totalSize", lTotalSize); + params.addProperty("enable512e", bEnable512e); + + JsonObject qos = new JsonObject(); + + params.add("qos", qos); + + qos.addProperty("minIOPS", minIops); + qos.addProperty("maxIOPS", maxIops); + qos.addProperty("burstIOPS", burstIops); - Object volumeToCreate = strCloudStackVolumeSize != null && strCloudStackVolumeSize.trim().length() > 0 ? - new VolumeToCreateWithCloudStackVolumeSize(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, minIops, maxIops, burstIops) : - new VolumeToCreate(strSfVolumeName, lSfAccountId, lTotalSize, bEnable512e, minIops, maxIops, burstIops); + if (mapAttributes != null && mapAttributes.size() > 0) { + JsonObject attributes = new JsonObject(); + + params.add("attributes", attributes); + + Iterator> itr = mapAttributes.entrySet().iterator(); + + while (itr.hasNext()) { + Map.Entry pair = itr.next(); + + attributes.addProperty(pair.getKey(), pair.getValue()); + } + } + + final Gson gson = new GsonBuilder().create(); String strVolumeToCreateJson = gson.toJson(volumeToCreate); @@ -476,14 +623,46 @@ public static long createSolidFireVolume(SolidFireConnection sfConnection, Strin return volumeCreateResult.result.volumeID; } - public static void modifySolidFireVolume(SolidFireConnection sfConnection, long volumeId, long totalSize, String strCloudStackVolumeSize, + public static void modifySolidFireVolume(SolidFireConnection sfConnection, long volumeId, Long totalSize, Map mapAttributes, long minIops, long maxIops, long burstIops) { - final Gson gson = new GsonBuilder().create(); + JsonObject volumeToModify = new JsonObject(); - Object volumeToModify = strCloudStackVolumeSize != null && strCloudStackVolumeSize.trim().length() > 0 ? - new VolumeToModifyWithCloudStackVolumeSize(volumeId, totalSize, strCloudStackVolumeSize, minIops, maxIops, burstIops) : - new VolumeToModify(volumeId, totalSize, minIops, maxIops, burstIops); + volumeToModify.addProperty("method", "ModifyVolume"); + + JsonObject params = new JsonObject(); + + volumeToModify.add("params", params); + + params.addProperty("volumeID", volumeId); + + if (totalSize != null) { + params.addProperty("totalSize", totalSize); + } + + JsonObject qos = new JsonObject(); + + params.add("qos", qos); + + qos.addProperty("minIOPS", minIops); + qos.addProperty("maxIOPS", maxIops); + qos.addProperty("burstIOPS", burstIops); + + if (mapAttributes != null && mapAttributes.size() > 0) { + JsonObject attributes = new JsonObject(); + + params.add("attributes", attributes); + + Iterator> itr = mapAttributes.entrySet().iterator(); + + while (itr.hasNext()) { + Map.Entry pair = itr.next(); + + attributes.addProperty(pair.getKey(), pair.getValue()); + } + } + + final Gson gson = new GsonBuilder().create(); String strVolumeToModifyJson = gson.toJson(volumeToModify); @@ -582,7 +761,7 @@ public static void deleteSolidFireVolume(SolidFireConnection sfConnection, long executeJsonRpc(sfConnection, strVolumeToDeleteJson); } - public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId) + public static void purgeSolidFireVolume(SolidFireConnection sfConnection, long lVolumeId) { final Gson gson = new GsonBuilder().create(); @@ -695,10 +874,51 @@ public boolean equals(Object obj) { } } - public static long createSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, String snapshotName) { - final Gson gson = new GsonBuilder().create(); + public static class SolidFireSnapshot { + private final long _id; + private final String _name; + + public SolidFireSnapshot(long id, String name) { + _id = id; + _name = name; + } + + public long getId() { + return _id; + } + + public String getName() { + return _name; + } + } + + public static long createSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, String snapshotName, Map mapAttributes) { + JsonObject snapshotToCreate = new JsonObject(); + + snapshotToCreate.addProperty("method", "CreateSnapshot"); + + JsonObject params = new JsonObject(); + + snapshotToCreate.add("params", params); - SnapshotToCreate snapshotToCreate = new SnapshotToCreate(lVolumeId, snapshotName); + params.addProperty("volumeID", lVolumeId); + params.addProperty("name", snapshotName); + + if (mapAttributes != null && mapAttributes.size() > 0) { + JsonObject attributes = new JsonObject(); + + params.add("attributes", attributes); + + Iterator> itr = mapAttributes.entrySet().iterator(); + + while (itr.hasNext()) { + Map.Entry pair = itr.next(); + + attributes.addProperty(pair.getKey(), pair.getValue()); + } + } + + final Gson gson = new GsonBuilder().create(); String strSnapshotToCreateJson = gson.toJson(snapshotToCreate); @@ -711,6 +931,38 @@ public static long createSolidFireSnapshot(SolidFireConnection sfConnection, lon return snapshotCreateResult.result.snapshotID; } + public static SolidFireSnapshot getSolidFireSnapshot(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId) { + final Gson gson = new GsonBuilder().create(); + + SnapshotsToGet snapshotsToGet = new SnapshotsToGet(lVolumeId); + + String strSnapshotsToGetJson = gson.toJson(snapshotsToGet); + + String strSnapshotsGetResultJson = executeJsonRpc(sfConnection, strSnapshotsToGetJson); + + SnapshotsGetResult snapshotsGetResult = gson.fromJson(strSnapshotsGetResultJson, SnapshotsGetResult.class); + + verifyResult(snapshotsGetResult.result, strSnapshotsGetResultJson, gson); + + String snapshotName = null; + + if (snapshotsGetResult.result.snapshots != null) { + for (SnapshotsGetResult.Result.Snapshot snapshot : snapshotsGetResult.result.snapshots) { + if (snapshot.snapshotID == lSnapshotId) { + snapshotName = snapshot.name; + + break; + } + } + } + + if (snapshotName == null) { + throw new CloudRuntimeException("Could not find SolidFire snapshot ID: " + lSnapshotId + " for the following SolidFire volume ID: " + lVolumeId); + } + + return new SolidFireSnapshot(lSnapshotId, snapshotName); + } + public static void deleteSolidFireSnapshot(SolidFireConnection sfConnection, long lSnapshotId) { final Gson gson = new GsonBuilder().create(); @@ -736,10 +988,40 @@ public static void rollBackVolumeToSnapshot(SolidFireConnection sfConnection, lo verifyResult(rollbackInitiatedResult.result, strRollbackInitiatedResultJson, gson); } - public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId, String cloneName) { - final Gson gson = new GsonBuilder().create(); + public static long createSolidFireClone(SolidFireConnection sfConnection, long lVolumeId, long lSnapshotId, long sfAccountId, + String cloneName, Map mapAttributes) { + JsonObject cloneToCreate = new JsonObject(); + + cloneToCreate.addProperty("method", "CloneVolume"); + + JsonObject params = new JsonObject(); + + cloneToCreate.add("params", params); + + params.addProperty("volumeID", lVolumeId); + + if (lSnapshotId > 0) { + params.addProperty("snapshotID", lSnapshotId); + } + + params.addProperty("newAccountID", sfAccountId); + params.addProperty("name", cloneName); + + if (mapAttributes != null && mapAttributes.size() > 0) { + JsonObject attributes = new JsonObject(); + + params.add("attributes", attributes); - CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, lSnapshotId, cloneName); + Iterator> itr = mapAttributes.entrySet().iterator(); + + while (itr.hasNext()) { + Map.Entry pair = itr.next(); + + attributes.addProperty(pair.getKey(), pair.getValue()); + } + } + + final Gson gson = new GsonBuilder().create(); String strCloneToCreateJson = gson.toJson(cloneToCreate); @@ -749,7 +1031,33 @@ public static long createSolidFireClone(SolidFireConnection sfConnection, long l verifyResult(cloneCreateResult.result, strCloneCreateResultJson, gson); - return cloneCreateResult.result.cloneID; + // Clone is an async operation. Poll until we get data. + + AsyncJobToPoll asyncJobToPoll = new AsyncJobToPoll(cloneCreateResult.result.asyncHandle); + + String strAsyncJobToPollJson = gson.toJson(asyncJobToPoll); + + do { + String strAsyncJobResultJson = executeJsonRpc(sfConnection, strAsyncJobToPollJson); + + AsyncJobResult asyncJobResult = gson.fromJson(strAsyncJobResultJson, AsyncJobResult.class); + + verifyResult(asyncJobResult.result, strAsyncJobResultJson, gson); + + if (asyncJobResult.result.status.equals("complete")) { + break; + } + + try { + Thread.sleep(500); // sleep for 1/2 of a second + } + catch (Exception ex) { + // ignore + } + } + while (true); + + return cloneCreateResult.result.volumeID; } public static long createSolidFireAccount(SolidFireConnection sfConnection, String strAccountName) @@ -1029,189 +1337,6 @@ public boolean equals(Object obj) { } } - @SuppressWarnings("unused") - private static final class VolumeToCreateWithCloudStackVolumeSize { - private final String method = "CreateVolume"; - private final VolumeToCreateParams params; - - private VolumeToCreateWithCloudStackVolumeSize(final String strVolumeName, final long lAccountId, final long lTotalSize, - final boolean bEnable512e, final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e, strCloudStackVolumeSize, lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToCreateParams { - private final String name; - private final long accountID; - private final long totalSize; - private final boolean enable512e; - private final VolumeToCreateParamsAttributes attributes; - private final VolumeToCreateParamsQoS qos; - - private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e, - final String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - name = strVolumeName; - accountID = lAccountId; - totalSize = lTotalSize; - enable512e = bEnable512e; - - attributes = new VolumeToCreateParamsAttributes(strCloudStackVolumeSize); - qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToCreateParamsAttributes { - private final String CloudStackVolumeSize; - - private VolumeToCreateParamsAttributes(final String strCloudStackVolumeSize) { - CloudStackVolumeSize = strCloudStackVolumeSize; - } - } - - private static final class VolumeToCreateParamsQoS { - private final long minIOPS; - private final long maxIOPS; - private final long burstIOPS; - - private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - minIOPS = lMinIOPS; - maxIOPS = lMaxIOPS; - burstIOPS = lBurstIOPS; - } - } - } - } - - @SuppressWarnings("unused") - private static final class VolumeToCreate { - private final String method = "CreateVolume"; - private final VolumeToCreateParams params; - - private VolumeToCreate(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e, - final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - params = new VolumeToCreateParams(strVolumeName, lAccountId, lTotalSize, bEnable512e, lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToCreateParams { - private final String name; - private final long accountID; - private final long totalSize; - private final boolean enable512e; - private final VolumeToCreateParamsQoS qos; - - private VolumeToCreateParams(final String strVolumeName, final long lAccountId, final long lTotalSize, final boolean bEnable512e, - final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - name = strVolumeName; - accountID = lAccountId; - totalSize = lTotalSize; - enable512e = bEnable512e; - - qos = new VolumeToCreateParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToCreateParamsQoS { - private final long minIOPS; - private final long maxIOPS; - private final long burstIOPS; - - private VolumeToCreateParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - minIOPS = lMinIOPS; - maxIOPS = lMaxIOPS; - burstIOPS = lBurstIOPS; - } - } - } - } - - @SuppressWarnings("unused") - private static final class VolumeToModifyWithCloudStackVolumeSize - { - private final String method = "ModifyVolume"; - private final VolumeToModifyParams params; - - private VolumeToModifyWithCloudStackVolumeSize(final long lVolumeId, final long lTotalSize, final String strCloudStackVolumeSize, - final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) - { - params = new VolumeToModifyParams(lVolumeId, lTotalSize, strCloudStackVolumeSize, lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToModifyParams - { - private final long volumeID; - private final long totalSize; - private final VolumeToModifyParamsAttributes attributes; - private final VolumeToModifyParamsQoS qos; - - private VolumeToModifyParams(final long lVolumeId, final long lTotalSize, String strCloudStackVolumeSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) - { - volumeID = lVolumeId; - - totalSize = lTotalSize; - - attributes = new VolumeToModifyParamsAttributes(strCloudStackVolumeSize); - qos = new VolumeToModifyParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS); - } - } - - private static final class VolumeToModifyParamsAttributes { - private final String CloudStackVolumeSize; - - private VolumeToModifyParamsAttributes(final String strCloudStackVolumeSize) { - CloudStackVolumeSize = strCloudStackVolumeSize; - } - } - - private static final class VolumeToModifyParamsQoS { - private final long minIOPS; - private final long maxIOPS; - private final long burstIOPS; - - private VolumeToModifyParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - minIOPS = lMinIOPS; - maxIOPS = lMaxIOPS; - burstIOPS = lBurstIOPS; - } - } - } - - @SuppressWarnings("unused") - private static final class VolumeToModify - { - private final String method = "ModifyVolume"; - private final VolumeToModifyParams params; - - private VolumeToModify(final long lVolumeId, final long lTotalSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) - { - params = new VolumeToModifyParams(lVolumeId, lTotalSize, lMinIOPS, lMaxIOPS, lBurstIOPS); - } - - private static final class VolumeToModifyParams - { - private final long volumeID; - private final long totalSize; - private final VolumeToModifyParamsQoS qos; - - private VolumeToModifyParams(final long lVolumeId, final long lTotalSize, final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) - { - volumeID = lVolumeId; - - totalSize = lTotalSize; - - qos = new VolumeToModifyParamsQoS(lMinIOPS, lMaxIOPS, lBurstIOPS); - } - } - - private static final class VolumeToModifyParamsQoS { - private final long minIOPS; - private final long maxIOPS; - private final long burstIOPS; - - private VolumeToModifyParamsQoS(final long lMinIOPS, final long lMaxIOPS, final long lBurstIOPS) { - minIOPS = lMinIOPS; - maxIOPS = lMaxIOPS; - burstIOPS = lBurstIOPS; - } - } - } - @SuppressWarnings("unused") private static final class VolumeToGet { @@ -1302,21 +1427,20 @@ private VolumeToPurgeParams(final long lVolumeId) { } @SuppressWarnings("unused") - private static final class SnapshotToCreate { - private final String method = "CreateSnapshot"; - private final SnapshotToCreateParams params; + private static final class SnapshotsToGet + { + private final String method = "ListSnapshots"; + private final SnapshotsToGetParams params; - private SnapshotToCreate(final long lVolumeId, final String snapshotName) { - params = new SnapshotToCreateParams(lVolumeId, snapshotName); + private SnapshotsToGet(final long lVolumeId) { + params = new SnapshotsToGetParams(lVolumeId); } - private static final class SnapshotToCreateParams { + private static final class SnapshotsToGetParams { private final long volumeID; - private final String name; - private SnapshotToCreateParams(final long lVolumeId, final String snapshotName) { + private SnapshotsToGetParams(final long lVolumeId) { volumeID = lVolumeId; - name = snapshotName; } } } @@ -1360,28 +1484,6 @@ private RollbackToInitiateParams(final long lVolumeId, final long lSnapshotId) { } } - @SuppressWarnings("unused") - private static final class CloneToCreate { - private final String method = "CloneVolume"; - private final CloneToCreateParams params; - - private CloneToCreate(final long lVolumeId, final long lSnapshotId, final String cloneName) { - params = new CloneToCreateParams(lVolumeId, lSnapshotId, cloneName); - } - - private static final class CloneToCreateParams { - private final long volumeID; - private final long snapshotID; - private final String name; - - private CloneToCreateParams(final long lVolumeId, final long lSnapshotId, final String cloneName) { - volumeID = lVolumeId; - snapshotID = lSnapshotId; - name = cloneName; - } - } - } - @SuppressWarnings("unused") private static final class AccountToAdd { @@ -1575,6 +1677,28 @@ private VagToDeleteParams(final long lVagId) { } } + @SuppressWarnings("unused") + private static final class AsyncJobToPoll + { + private final String method = "GetAsyncResult"; + private final AsyncJobToPollParams params; + + private AsyncJobToPoll(final long asyncHandle) + { + params = new AsyncJobToPollParams(asyncHandle); + } + + private static final class AsyncJobToPollParams + { + private final long asyncHandle; + + private AsyncJobToPollParams(final long asyncHandle) + { + this.asyncHandle = asyncHandle; + } + } + } + private static final class VolumeCreateResult { private Result result; @@ -1616,6 +1740,19 @@ private static final class Result { } } + private static final class SnapshotsGetResult { + private Result result; + + private static final class Result { + private Snapshot[] snapshots; + + private static final class Snapshot { + private long snapshotID; + private String name; + } + } + } + @SuppressWarnings("unused") private static final class RollbackInitiatedResult { private Result result; @@ -1629,7 +1766,8 @@ private static final class CloneCreateResult { private Result result; private static final class Result { - private long cloneID; + private long volumeID; + private long asyncHandle; } } @@ -1681,6 +1819,15 @@ private static final class Vag } } + private static final class AsyncJobResult { + private AsyncResult result; + + private static final class AsyncResult + { + private String status; + } + } + private static final class JsonError { private Error error; diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml index 95e7824acc..7b3b8f76e1 100644 --- a/plugins/user-authenticators/ldap/pom.xml +++ b/plugins/user-authenticators/ldap/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml @@ -96,13 +96,15 @@ org.spockframework spock-core - 0.7-groovy-2.0 + 1.0-groovy-2.4 + test cglib cglib-nodep - + test + diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java index 1968f85b04..d845857925 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java @@ -16,12 +16,12 @@ // under the License. package org.apache.cloudstack.api.command; -import java.io.UnsupportedEncodingException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Map; - -import javax.inject.Inject; +import com.cloud.domain.DomainVO; +import com.cloud.user.Account; +import com.cloud.user.AccountService; +import com.cloud.user.User; +import com.cloud.user.UserAccount; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -31,6 +31,7 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.RoleResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.ldap.LdapManager; import org.apache.cloudstack.ldap.LdapUser; @@ -38,11 +39,11 @@ import org.apache.log4j.Logger; import org.bouncycastle.util.encoders.Base64; -import com.cloud.domain.DomainVO; -import com.cloud.user.Account; -import com.cloud.user.AccountService; -import com.cloud.user.User; -import com.cloud.user.UserAccount; +import javax.inject.Inject; +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Map; @APICommand(name = "ldapCreateAccount", description = "Creates an account from an LDAP user", responseObject = AccountResponse.class, since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class LdapCreateAccountCmd extends BaseCmd { @@ -55,9 +56,12 @@ public class LdapCreateAccountCmd extends BaseCmd { @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "Creates the user under the specified account. If no account is specified, the username will be used as the account name.") private String accountName; - @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, required = true, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") + @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") private Short accountType; + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.") + private Long roleId; + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Creates the user under the specified domain.") private Long domainId; @@ -92,7 +96,7 @@ public LdapCreateAccountCmd(final LdapManager ldapManager, final AccountService UserAccount createCloudstackUserAccount(final LdapUser user, String accountName, Long domainId) { Account account = _accountService.getActiveAccountByName(accountName, domainId); if (account == null) { - return _accountService.createUserAccount(username, generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, accountType, + return _accountService.createUserAccount(username, generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, getAccountType(), getRoleId(), domainId, networkDomain, details, accountUUID, userUUID, User.Source.LDAP); } else { User newUser = _accountService.createUser(username, generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, domainId, @@ -101,6 +105,14 @@ UserAccount createCloudstackUserAccount(final LdapUser user, String accountName, } } + public Short getAccountType() { + return RoleType.getAccountTypeByRole(roleService.findRole(roleId), accountType); + } + + public Long getRoleId() { + return RoleType.getRoleByAccountType(roleId, accountType); + } + private String getAccountName() { String name = accountName; if (accountName == null) { @@ -119,6 +131,9 @@ private Long getDomainId() { @Override public void execute() throws ServerApiException { + if (getAccountType() == null && getRoleId() == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Both account type and role ID are not provided"); + } final CallContext callContext = getCurrentContext(); String finalAccountName = getAccountName(); Long finalDomainId = getDomainId(); diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java index 63549f1111..9fdd700638 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapImportUsersCmd.java @@ -29,6 +29,7 @@ import com.cloud.user.Account; import com.cloud.user.User; import com.cloud.user.UserAccount; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -38,6 +39,7 @@ import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.LdapUserResponse; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.RoleResponse; import org.apache.cloudstack.ldap.LdapManager; import org.apache.cloudstack.ldap.LdapUser; import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException; @@ -70,10 +72,12 @@ public class LdapImportUsersCmd extends BaseListCmd { @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, - required = true, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin") private Short accountType; + @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.") + private Long roleId; + @Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, description = "details for account used to store specific parameters") private Map details; @@ -112,7 +116,7 @@ private void createCloudstackUserAccount(LdapUser user, String accountName, Doma Account account = _accountService.getActiveAccountByName(accountName, domain.getId()); if (account == null) { s_logger.debug("No account exists with name: " + accountName + " creating the account and an user with name: " + user.getUsername() + " in the account"); - _accountService.createUserAccount(user.getUsername(), generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, accountType, + _accountService.createUserAccount(user.getUsername(), generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, getAccountType(), getRoleId(), domain.getId(), domain.getNetworkDomain(), details, UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP); } else { // check if the user exists. if yes, call update @@ -131,7 +135,9 @@ private void createCloudstackUserAccount(LdapUser user, String accountName, Doma @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { - + if (getAccountType() == null && getRoleId() == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Both account type and role ID are not provided"); + } List users; try { if (StringUtils.isNotBlank(groupName)) { @@ -161,6 +167,14 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE setResponseObject(response); } + public Short getAccountType() { + return RoleType.getAccountTypeByRole(roleService.findRole(roleId), accountType); + } + + public Long getRoleId() { + return RoleType.getRoleByAccountType(roleId, accountType); + } + private String getAccountName(LdapUser user) { String finalAccountName = accountName; if(finalAccountName == null ) { diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java index ae3e706513..477e80f255 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LinkDomainToLdapCmd.java @@ -23,6 +23,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.user.User; import com.cloud.user.UserAccount; +import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -82,7 +83,7 @@ public void execute() throws ServerApiException { if (account == null) { try { UserAccount userAccount = _accountService.createUserAccount(admin, "", ldapUser.getFirstname(), ldapUser.getLastname(), ldapUser.getEmail(), null, - admin, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, domainId, null, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP); + admin, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, RoleType.DomainAdmin.getId(), domainId, null, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP); response.setAdminId(String.valueOf(userAccount.getAccountId())); s_logger.info("created an account with name " + admin + " in the given domain " + domainId); } catch (Exception e) { diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java index 5683b50a47..add39c5b13 100644 --- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java +++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java @@ -21,6 +21,7 @@ import javax.inject.Inject; +import org.apache.cloudstack.acl.RoleType; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -119,7 +120,8 @@ private void enableUserInCloudStack(UserAccount user) { private void createCloudStackUserAccount(LdapUser user, long domainId, short accountType) { String username = user.getUsername(); - _accountManager.createUserAccount(username, "", user.getFirstname(), user.getLastname(), user.getEmail(), null, username, accountType, domainId, null, null, + _accountManager.createUserAccount(username, "", user.getFirstname(), user.getLastname(), user.getEmail(), null, username, + accountType, RoleType.getByAccountType(accountType).getId(), domainId, null, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP); } diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy index 514caeb17d..434151ae23 100644 --- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy +++ b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/LdapImportUsersCmdSpec.groovy @@ -246,7 +246,7 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { 1 * accountService.getActiveAccountByName('ACCOUNT', 0) >> Mock(AccountVO) 1 * accountService.getActiveUserAccount('rmurphy',0) >> Mock(UserAccountVO) 0 * accountService.createUser('rmurphy', _ , 'Ryan', 'Murphy', 'rmurphy@test.com', null, 'ACCOUNT', 0, _) >> Mock(UserVO) - 0 * accountService.createUserAccount('rmurphy', _, 'Ryan', 'Murphy', 'rmurphy@test.com', null, 'ACCOUNT', 2, 0, 'DOMAIN', null, _, _) + 0 * accountService.createUserAccount('rmurphy', _, 'Ryan', 'Murphy', 'rmurphy@test.com', null, 'ACCOUNT', 2, null, 0, 'DOMAIN', null, _, _) 1 * accountService.updateUser(_,'Ryan', 'Murphy', 'rmurphy@test.com', null, null, null, null, null); def ldapImportUsersCmd = new LdapImportUsersCmd(ldapManager, domainService, accountService) diff --git a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/NoSuchLdapUserExceptionSpec.groovy b/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/NoSuchLdapUserExceptionSpec.groovy deleted file mode 100644 index dbdf646721..0000000000 --- a/plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/NoSuchLdapUserExceptionSpec.groovy +++ /dev/null @@ -1,30 +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 groovy.org.apache.cloudstack.ldap - -import org.apache.cloudstack.ldap.NoSuchLdapUserException; - -class NoSuchLdapUserExceptionSpec extends spock.lang.Specification { - def "Test that the username is correctly set within the No such LDAP user exception object"() { - given: "You have created an No such LDAP user exception object with the username set" - def exception = new NoSuchLdapUserException(username) - expect: "The username is equal to the given data source" - exception.getUsername() == username - where: "The username is set to " - username << ["", null, "rmurphy"] - } -} diff --git a/plugins/user-authenticators/md5/pom.xml b/plugins/user-authenticators/md5/pom.xml index 29199a7de5..f436f90e32 100644 --- a/plugins/user-authenticators/md5/pom.xml +++ b/plugins/user-authenticators/md5/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/user-authenticators/pbkdf2/pom.xml b/plugins/user-authenticators/pbkdf2/pom.xml index 1f62293476..b26636bd7e 100644 --- a/plugins/user-authenticators/pbkdf2/pom.xml +++ b/plugins/user-authenticators/pbkdf2/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/user-authenticators/plain-text/pom.xml b/plugins/user-authenticators/plain-text/pom.xml index c64f6fce9d..3598cc168d 100644 --- a/plugins/user-authenticators/plain-text/pom.xml +++ b/plugins/user-authenticators/plain-text/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/plugins/user-authenticators/saml2/pom.xml b/plugins/user-authenticators/saml2/pom.xml index f7b6140c63..5e24df35c5 100644 --- a/plugins/user-authenticators/saml2/pom.xml +++ b/plugins/user-authenticators/saml2/pom.xml @@ -23,15 +23,10 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml - - org.springframework.security.extensions - spring-security-saml2-core - 1.0.0.RELEASE - org.opensaml opensaml @@ -52,5 +47,11 @@ cloud-framework-config ${project.version} + + xerces + xercesImpl + 2.11.0 + test + diff --git a/plugins/user-authenticators/sha256salted/pom.xml b/plugins/user-authenticators/sha256salted/pom.xml index 3713ab2ba5..fe5fa6f5ed 100644 --- a/plugins/user-authenticators/sha256salted/pom.xml +++ b/plugins/user-authenticators/sha256salted/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-plugins - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/pom.xml b/pom.xml index 5c81b3fd1b..5ecce93581 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT pom Apache CloudStack Apache CloudStack is an IaaS (“Infrastructure as a Service”) cloud orchestration platform. @@ -44,10 +44,6 @@ https://issues.apache.org/jira/browse/CLOUDSTACK - - 3.0.4 - - 1.7 UTF-8 @@ -55,7 +51,7 @@ 1.2.17 1.2.17 - 3.1 + 3.2.1 1.4 1.6 1.10 @@ -65,25 +61,25 @@ 0.5 3.0 - 4.11 + 4.12 1.3 1.46 - 0.1.51 - 2.1.0 + 0.1.53 + 2.1.1 1.9.2 - 1.0.0-build217 - 2.6.9 + 1.0.0-build220 + 2.6.11 1.7.2 18.0 - 18.0 + 19.0 6.2.0-3.1 - 4.5 - 4.4 + 4.5.2 + 4.4.4 3.1 5.1.34 - 1.4.7 + 1.4.9 3.1.3 - 1.4.7 + 1.5.0-b01 1.4 1.5.6 1.5.1 @@ -91,32 +87,42 @@ 2.0.4 2.5 1.2 + 1.2.1 1.0-20081010.060147 6.0 - 3.2.12.RELEASE - 1.9.5 - 1.5.3 - 1.10.34 - 2.6.3 + 3.2.16.RELEASE + 1.10.19 + 1.6.4 + 1.10.64 + 2.7.1 2.6 3.4 2.4 - 1.4.0 - 0.9.9 - 0.15 + 1.3.1 + 3.2.2 + 1.5.0 + 0.9.10 + 0.16 build/replace.properties 0.5.1 0.2.0 target 1.0.15 4.0.0 - 2.11 - 2.7 - 3.0.1 - 2.10.1 - 2.6.1 + 2.17 + 2.11 + 3.0.3 + 2.10.3 + 2.6.4 1.4.01 2.8.1 + 1.8 + 2.3.4_1 + 9.2.15.v20160210 + 3.1.4 + 2.4.6 + 9.2.15.v20160210 + 10.1 @@ -208,6 +214,41 @@ + + org.eclipse.jetty + apache-jsp + ${cs.apache-jsp.version} + + + org.codehaus.groovy + groovy-all + ${cs.groovy.version} + + + org.bouncycastle + bcprov-jdk15on + ${cs.bcprov.version} + + + org.apache.xmlgraphics + batik-css + ${cs.batik.version} + + + org.apache.xmlgraphics + batik-ext + ${cs.batik.version} + + + org.apache.xmlgraphics + batik-util + ${cs.batik.version} + + + commons-collections + commons-collections + ${cs.commons-collections.version} + mysql mysql-connector-java @@ -245,26 +286,26 @@ ehcache-core ${cs.ehcache.version} - - commons-pool - commons-pool - ${cs.pool.version} - commons-codec commons-codec ${cs.codec.version} + + commons-fileupload + commons-fileupload + ${cs.commons-fileupload.version} + + + commons-pool + commons-pool + ${cs.pool.version} + commons-validator commons-validator ${cs.commons-validator.version} - - org.bouncycastle - bcprov-jdk16 - ${cs.bcprov.version} - com.jcraft jsch @@ -325,7 +366,7 @@ org.owasp.esapi esapi - 2.1.0 + 2.1.0.1 org.eclipse.persistence @@ -390,17 +431,17 @@ org.apache.servicemix.bundles org.apache.servicemix.bundles.snmp4j - 2.3.1_1 + ${cs.servicemix.version} org.aspectj aspectjtools - 1.8.4 + 1.8.9 org.aspectj aspectjweaver - 1.8.4 + 1.8.9 org.apache.axis @@ -425,12 +466,12 @@ org.slf4j slf4j-api - 1.7.7 + 1.7.21 org.slf4j slf4j-log4j12 - 1.7.7 + 1.7.21 @@ -756,6 +797,8 @@ CONTRIBUTING.md tools/docker/Dockerfile tools/docker/supervisord.conf + .java-version + .python-version .idea/ **/*.log **/*.patch @@ -842,6 +885,7 @@ ui/lib/qunit/qunit.js ui/lib/reset.css ui/lib/require.js + utils/testsmallfileinactive systemvm/conf/agent.properties systemvm/conf/environment.properties systemvm/js/jquery.js @@ -881,6 +925,7 @@ **/.checkstyle scripts/installer/windows/acs_license.rtf **/*.md + test/integration/component/test_host_ha.sh diff --git a/python/lib/cloudutils/db.py b/python/lib/cloudutils/db.py index 8fe3195599..f2ce6f9b50 100644 --- a/python/lib/cloudutils/db.py +++ b/python/lib/cloudutils/db.py @@ -5,21 +5,21 @@ # 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. -import MySQLdb import os from utilities import bash from cloudException import CloudRuntimeException -import sys -class Database: +import mysql.connector + +class Database(object): """Database connection""" def __init__(self, username, password=None, host='localhost', port='3306', db="cloud"): self.host = host @@ -28,15 +28,16 @@ def __init__(self, username, password=None, host='localhost', port='3306', db="c self.port = port self.db = db + def connect(self): + return mysql.connector.connect(host=self.host, + user=self.username, + password=self.password, + database=self.db) + def execute(self, statement): txn = None try: - if self.password is not None: - txn = MySQLdb.Connect(host=self.host, user=self.username, - passwd=self.password, db=self.db) - else: - txn = MySQLdb.Connect(host=self.host, user=self.username, - db=self.db) + txn = self.connect() cursor = txn.cursor() cursor.execute(statement) cursor.close() @@ -47,35 +48,33 @@ def execute(self, statement): except: pass except: + raise CloudRuntimeException("Failed to execute: %s " % statement) + finally: if txn is not None: try: txn.close() except: pass - raise CloudRuntimeException("Failed to execute:%s"%statement) - + def testConnection(self): try: - if self.password is not None: - db = MySQLdb.Connect(host=self.host, user=self.username, - passwd=self.password, db=self.db) - else: - db = MySQLdb.Connect(host=self.host, user=self.username, - db=self.db) + conn = self.connect() + conn.ping() + conn.close() return True except: raise CloudRuntimeException("Failed to Connect to DB") - + def executeFromFile(self, file): if not os.path.exists(file): return False - + cmdLine = "mysql --host=" + self.host + " --port=" + str(self.port) + " --user=" + self.username if self.password is not None: cmdLine += " --password=" + self.password - + cmdLine += " < " + file - + try: bash(cmdLine) except: diff --git a/python/lib/cloudutils/serviceConfigServer.py b/python/lib/cloudutils/serviceConfigServer.py index 7812fff4f7..dce85a028e 100644 --- a/python/lib/cloudutils/serviceConfigServer.py +++ b/python/lib/cloudutils/serviceConfigServer.py @@ -120,7 +120,6 @@ def checkHostName(): bash("chown cloud.cloud /var/run/cloudstack-management.pid") #distro like sl 6.1 needs this folder, or tomcat6 failed to start checkHostName() - bash("mkdir /var/log/cloudstack-management/") bash("chown cloud:cloud -R /var/lib/cloudstack/") bash("chmod +x -R /usr/share/cloudstack-management/webapps/client/WEB-INF/classes/scripts/") #set max process per account is unlimited diff --git a/quickcloud/pom.xml b/quickcloud/pom.xml index a1ec781c94..841a9c5185 100644 --- a/quickcloud/pom.xml +++ b/quickcloud/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloud-maven-standard - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../maven-standard/pom.xml diff --git a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup b/requirements.txt old mode 100755 new mode 100644 similarity index 67% rename from systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup rename to requirements.txt index 9d254d3fbb..f5c7666231 --- a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup +++ b/requirements.txt @@ -1,5 +1,3 @@ -#!/bin/sh -# /etc/cron.daily/cloud-cleanup: cleanup old cloudstack logs # 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 @@ -17,11 +15,7 @@ # specific language governing permissions and limitations # under the License. -cd / -output=$(find /var/log/cloud -mtime +7 -size +1M -exec rm -v '{}' \; ) -logger -t cloud "cloud-cleanup cronjob: cleaning up logfiles in /var/log/cloud older than 7 days and more than 1M in size" +# Install the latest version of cloudmonkey +cloudmonkey -[ "$output" != "" ] && logger -t cloud $output -[ -z "$output" ] && logger -t cloud "No files removed" - -exit 0 +# Marvin dependencies are installed via its bundle diff --git a/scripts/installer/windows/client.wxs b/scripts/installer/windows/client.wxs index 3c9121de69..f5aec48bde 100644 --- a/scripts/installer/windows/client.wxs +++ b/scripts/installer/windows/client.wxs @@ -595,9 +595,6 @@ - - - @@ -1058,7 +1055,7 @@ - + diff --git a/scripts/util/migrate-dynamicroles.py b/scripts/util/migrate-dynamicroles.py new file mode 100755 index 0000000000..d2356fb345 --- /dev/null +++ b/scripts/util/migrate-dynamicroles.py @@ -0,0 +1,136 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# 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. + +import os +import sys +import uuid + +from contextlib import closing +from optparse import OptionParser + +try: + import mysql.connector +except ImportError: + print("mysql.connector cannot be imported, please install mysql-connector-python") + sys.exit(1) + +dryrun = False + + +def runSql(conn, query): + if dryrun: + print("Running SQL query: " + query) + return + with closing(conn.cursor()) as cursor: + cursor.execute(query) + + +def migrateApiRolePermissions(apis, conn): + # All allow for root admin role Admin(id:1) + runSql(conn, "INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 1, '*', 'ALLOW', 0);") + # Migrate rules based on commands.properties rule for ResourceAdmin(id:2), DomainAdmin(id:3), User(id:4) + octetKey = {2:2, 3:4, 4:8} + for role in [2, 3, 4]: + sortOrder = 0 + for api in sorted(apis.keys()): + # Ignore auth commands + if api in ['login', 'logout', 'samlSso', 'samlSlo', 'listIdps', 'listAndSwitchSamlAccount', 'getSPMetadata']: + continue + if (octetKey[role] & int(apis[api])) > 0: + runSql(conn, "INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), %d, '%s', 'ALLOW', %d);" % (role, api, sortOrder)) + sortOrder += 1 + + +def main(): + parser = OptionParser() + parser.add_option("-b", "--db", action="store", type="string", dest="db", default="cloud", + help="The name of the database, default: cloud") + parser.add_option("-u", "--user", action="store", type="string", dest="user", default="cloud", + help="User name a MySQL user with privileges on cloud database") + parser.add_option("-p", "--password", action="store", type="string", dest="password", default="cloud", + help="Password of a MySQL user with privileges on cloud database") + parser.add_option("-H", "--host", action="store", type="string", dest="host", default="127.0.0.1", + help="Host or IP of the MySQL server") + parser.add_option("-P", "--port", action="store", type="int", dest="port", default=3306, + help="Host or IP of the MySQL server") + parser.add_option("-f", "--properties-file", action="store", type="string", dest="commandsfile", default="/etc/cloudstack/management/commands.properties", + help="The commands.properties file") + parser.add_option("-d", "--dryrun", action="store_true", dest="dryrun", default=False, + help="Dry run and debug operations this tool will perform") + (options, args) = parser.parse_args() + + print("Apache CloudStack Role Permission Migration Tool") + print("(c) Apache CloudStack Authors and the ASF, under the Apache License, Version 2.0\n") + + global dryrun + if options.dryrun: + dryrun = True + + conn = mysql.connector.connect( + host=options.host, + user=options.user, + passwd=options.password, + port=int(options.port), + db=options.db) + + if not os.path.isfile(options.commandsfile): + print("Provided commands.properties cannot be accessed or does not exist, please check check permissions") + sys.exit(1) + + while True: + choice = raw_input("Running this migration tool will remove any " + + "default-role permissions from cloud.role_permissions. " + + "Do you want to continue? [y/N]").lower() + if choice == 'y': + break + else: + print("Aborting!") + sys.exit(1) + + # Generate API to permission octet map + apiMap = {} + with open(options.commandsfile) as f: + for line in f.readlines(): + if not line or line == '' or line == '\n' or line.startswith('#'): + continue + name, value = line.split('=') + apiMap[name.strip()] = value.strip() + + # Rename and deprecate old commands.properties file + if not dryrun: + os.rename(options.commandsfile, options.commandsfile + '.deprecated') + print("The commands.properties file has been deprecated and moved at: " + options.commandsfile + '.deprecated') + + # Truncate any rules in cloud.role_permissions table + runSql(conn, "DELETE FROM `cloud`.`role_permissions` WHERE `role_id` in (1,2,3,4);") + + # Migrate rules from commands.properties to cloud.role_permissions + migrateApiRolePermissions(apiMap, conn) + print("Static role permissions from commands.properties have been migrated into the db") + + # Enable dynamic role based API checker + runSql(conn, "UPDATE `cloud`.`configuration` SET value='true' where name='dynamic.apichecker.enabled'") + conn.commit() + conn.close() + + print("Dynamic role based API checker has been enabled!") + + +if __name__ == '__main__': + main() diff --git a/scripts/vm/hypervisor/kvm/patchviasocket.pl b/scripts/vm/hypervisor/kvm/patchviasocket.pl deleted file mode 100755 index 7bcd245bc3..0000000000 --- a/scripts/vm/hypervisor/kvm/patchviasocket.pl +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/perl -w -# 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. - -############################################################# -# This script connects to the system vm socket and writes the -# authorized_keys and cmdline data to it. The system VM then -# reads it from /dev/vport0p1 in cloud_early_config -############################################################# - -use strict; -use Getopt::Std; -use IO::Socket; -$|=1; - -my $opts = {}; -getopt('pn',$opts); -my $name = $opts->{n}; -my $cmdline = $opts->{p}; -my $sockfile = "/var/lib/libvirt/qemu/$name.agent"; -my $pubkeyfile = "/root/.ssh/id_rsa.pub.cloud"; - -if (! -S $sockfile) { - print "ERROR: $sockfile socket not found\n"; - exit 1; -} - -if (! -f $pubkeyfile) { - print "ERROR: ssh public key not found on host at $pubkeyfile\n"; - exit 1; -} - -open(FILE,$pubkeyfile) or die "ERROR: unable to open $pubkeyfile - $^E"; -my $key = ; -close FILE; - -$cmdline =~ s/%/ /g; -my $msg = "pubkey:" . $key . "\ncmdline:" . $cmdline; - -my $socket = IO::Socket::UNIX->new(Peer=>$sockfile,Type=>SOCK_STREAM) - or die "ERROR: unable to connect to $sockfile - $^E\n"; -print $socket "$msg\n"; -close $socket; - diff --git a/scripts/vm/hypervisor/kvm/patchviasocket.py b/scripts/vm/hypervisor/kvm/patchviasocket.py new file mode 100755 index 0000000000..c971d5dcc5 --- /dev/null +++ b/scripts/vm/hypervisor/kvm/patchviasocket.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# 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. + +# +# This script connects to the system vm socket and writes the +# authorized_keys and cmdline data to it. The system VM then +# reads it from /dev/vport0p1 in cloud_early_config +# + +import argparse +import os +import socket + +SOCK_FILE = "/var/lib/libvirt/qemu/{name}.agent" +PUB_KEY_FILE = "/root/.ssh/id_rsa.pub.cloud" +MESSAGE = "pubkey:{key}\ncmdline:{cmdline}\n" + + +def send_to_socket(sock_file, key_file, cmdline): + if not os.path.exists(key_file): + print("ERROR: ssh public key not found on host at {0}".format(key_file)) + return 1 + + try: + with open(key_file, "r") as f: + pub_key = f.read() + except IOError as e: + print("ERROR: unable to open {0} - {1}".format(key_file, e.strerror)) + return 1 + + # Keep old substitution from perl code: + cmdline = cmdline.replace("%", " ") + + msg = MESSAGE.format(key=pub_key, cmdline=cmdline) + + if not os.path.exists(sock_file): + print("ERROR: {0} socket not found".format(sock_file)) + return 1 + + try: + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + s.connect(sock_file) + s.sendall(msg) + s.close() + except IOError as e: + print("ERROR: unable to connect to {0} - {1}".format(sock_file, e.strerror)) + return 1 + + return 0 # Success + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Send configuration to system VM socket") + parser.add_argument("-n", "--name", required=True, help="Name of VM") + parser.add_argument("-p", "--cmdline", required=True, help="Command line") + + arguments = parser.parse_args() + + socket_file = SOCK_FILE.format(name=arguments.name) + + exit(send_to_socket(socket_file, PUB_KEY_FILE, arguments.cmdline)) diff --git a/scripts/vm/hypervisor/kvm/test_patchviasocket.py b/scripts/vm/hypervisor/kvm/test_patchviasocket.py new file mode 100755 index 0000000000..6b411d3224 --- /dev/null +++ b/scripts/vm/hypervisor/kvm/test_patchviasocket.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python +# 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. + +import patchviasocket + +import getpass +import os +import socket +import tempfile +import time +import threading +import unittest + +KEY_DATA = "I luv\nCloudStack\n" +CMD_DATA = "/run/this-for-me --please=TRUE! very%quickly" +NON_EXISTING_FILE = "must-not-exist" + + +def write_key_file(): + _, tmpfile = tempfile.mkstemp(".sck") + with open(tmpfile, "w") as f: + f.write(KEY_DATA) + return tmpfile + + +class SocketThread(threading.Thread): + def __init__(self): + super(SocketThread, self).__init__() + self._data = "" + self._folder = tempfile.mkdtemp(".sck") + self._file = os.path.join(self._folder, "socket") + self._ready = False + + def data(self): + return self._data + + def file(self): + return self._file + + def wait_until_ready(self): + while not self._ready: + time.sleep(0.050) + + def run(self): + TIMEOUT = 0.314 # Very short time for tests that don't write to socket. + MAX_SIZE = 10 * 1024 + + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + s.bind(self._file) + s.listen(1) + s.settimeout(TIMEOUT) + try: + self._ready = True + client, address = s.accept() + self._data = client.recv(MAX_SIZE) + client.close() + except socket.timeout: + pass + finally: + s.close() + os.remove(self._file) + os.rmdir(self._folder) + + +class TestPatchViaSocket(unittest.TestCase): + def setUp(self): + self._key_file = write_key_file() + + self._unreadable = write_key_file() + os.chmod(self._unreadable, 0) + + self.assertFalse(os.path.exists(NON_EXISTING_FILE)) + self.assertNotEqual("root", getpass.getuser(), "must be non-root user (to test access denied errors)") + + def tearDown(self): + os.remove(self._key_file) + os.remove(self._unreadable) + + def test_write_to_socket(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(0, patchviasocket.send_to_socket(reader.file(), self._key_file, CMD_DATA)) + reader.join() + data = reader.data() + self.assertIn(KEY_DATA, data) + self.assertIn(CMD_DATA.replace("%", " "), data) + self.assertNotIn("LUV", data) + self.assertNotIn("very%quickly", data) # Testing substitution + + def test_host_key_error(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(1, patchviasocket.send_to_socket(reader.file(), NON_EXISTING_FILE, CMD_DATA)) + reader.join() # timeout + + def test_host_key_access_denied(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(1, patchviasocket.send_to_socket(reader.file(), self._unreadable, CMD_DATA)) + reader.join() # timeout + + def test_nonexistant_socket_error(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(1, patchviasocket.send_to_socket(NON_EXISTING_FILE, self._key_file, CMD_DATA)) + reader.join() # timeout + + def test_invalid_socket_error(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(1, patchviasocket.send_to_socket(self._key_file, self._key_file, CMD_DATA)) + reader.join() # timeout + + def test_access_denied_socket_error(self): + reader = SocketThread() + reader.start() + reader.wait_until_ready() + self.assertEquals(1, patchviasocket.send_to_socket(self._unreadable, self._key_file, CMD_DATA)) + reader.join() # timeout + + +if __name__ == '__main__': + unittest.main() diff --git a/scripts/vm/network/security_group.py b/scripts/vm/network/security_group.py index 915a8afb06..e459a29740 100755 --- a/scripts/vm/network/security_group.py +++ b/scripts/vm/network/security_group.py @@ -26,8 +26,11 @@ from optparse import OptionParser, OptionGroup, OptParseError, BadOptionError, OptionError, OptionConflictError, OptionValueError import re import libvirt +import fcntl +import time logpath = "/var/run/cloud/" # FIXME: Logs should reside in /var/log/cloud +lock_file = "/var/lock/cloudstack_security_group.lock" iptables = Command("iptables") bash = Command("/bin/bash") ebtables = Command("ebtables") @@ -36,6 +39,21 @@ hyper = cfo.getEntry("hypervisor.type") if hyper == "lxc": driver = "lxc:///" + +lock_handle = None + +def obtain_file_lock(path): + global lock_handle + + try: + lock_handle = open(path, 'w') + fcntl.flock(lock_handle, fcntl.LOCK_EX | fcntl.LOCK_NB) + return True + except IOError: + pass + + return False + def execute(cmd): logging.debug(cmd) return bash("-c", cmd).stdout @@ -303,7 +321,7 @@ def default_network_rules_systemvm(vm_name, localbrname): for bridge in bridges: if bridge != localbrname: if not addFWFramework(bridge): - return False + return False brfw = getBrfw(bridge) vifs = getVifsForBridge(vm_name, bridge) for vif in vifs: @@ -1029,6 +1047,14 @@ def addFWFramework(brname): sys.exit(1) cmd = args[0] logging.debug("Executing command: " + str(cmd)) + + for i in range(0, 30): + if obtain_file_lock(lock_file) is False: + logging.warn("Lock on %s is being held by other process. Waiting for release." % lock_file) + time.sleep(0.5) + else: + break + if cmd == "can_bridge_firewall": can_bridge_firewall(args[1]) elif cmd == "default_network_rules": diff --git a/server/conf/cloudstack-catalina.logrotate b/server/conf/cloudstack-catalina.logrotate new file mode 100644 index 0000000000..498f690dd0 --- /dev/null +++ b/server/conf/cloudstack-catalina.logrotate @@ -0,0 +1,26 @@ +# 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. + + +/var/log/cloudstack/management/catalina.out { + copytruncate + daily + rotate 14 + compress + missingok + create 0644 cloud cloud +} \ No newline at end of file diff --git a/server/pom.xml b/server/pom.xml index 0656541f08..32695094e6 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT @@ -72,6 +72,12 @@ jstl jstl + ${cs.jstl.version} + + + javax.servlet.jsp.jstl + javax.servlet.jsp.jstl-api + ${cs.jstl-api.version} commons-codec diff --git a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml index e39d918c9d..b25c1c3d3a 100644 --- a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml +++ b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml @@ -37,6 +37,8 @@ value="#{pluggableAPIAuthenticatorsRegistry.registered}" /> + + @@ -140,6 +142,10 @@ + + + + diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java index 9b9802a095..e18d231e17 100644 --- a/server/src/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/com/cloud/alert/AlertManagerImpl.java @@ -758,7 +758,8 @@ public void sendAlert(AlertType alertType, long dataCenterId, Long podId, Long c (alertType != AlertManager.AlertType.ALERT_TYPE_STORAGE_MISC) && (alertType != AlertManager.AlertType.ALERT_TYPE_MANAGMENT_NODE) && (alertType != AlertManager.AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED) && - (alertType != AlertManager.AlertType.ALERT_TYPE_UPLOAD_FAILED)) { + (alertType != AlertManager.AlertType.ALERT_TYPE_UPLOAD_FAILED) && + (alertType != AlertManager.AlertType.ALERT_TYPE_OOBM_AUTH_ERROR)) { alert = _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId, clusterId); } diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 1c55c674e6..d6b529fa2f 100644 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -27,6 +27,8 @@ import javax.annotation.PostConstruct; import javax.inject.Inject; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RoleService; import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.affinity.dao.AffinityGroupDao; @@ -423,6 +425,7 @@ public class ApiDBUtils { static AffinityGroupJoinDao s_affinityGroupJoinDao; static GlobalLoadBalancingRulesService s_gslbService; static NetworkACLDao s_networkACLDao; + static RoleService s_roleService; static AccountService s_accountService; static ResourceMetaDataService s_resourceDetailsService; static HostGpuGroupsDao s_hostGpuGroupsDao; @@ -646,6 +649,8 @@ public class ApiDBUtils { @Inject private NetworkACLDao networkACLDao; @Inject + private RoleService roleService; + @Inject private AccountService accountService; @Inject private ConfigurationManager configMgr; @@ -768,6 +773,7 @@ void init() { // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned s_statsCollector = StatsCollector.getInstance(); s_networkACLDao = networkACLDao; + s_roleService = roleService; s_accountService = accountService; s_resourceDetailsService = resourceDetailsService; s_hostGpuGroupsDao = hostGpuGroupsDao; @@ -1695,6 +1701,15 @@ public static UserResponse newUserResponse(UserAccountJoinVO usr) { public static UserResponse newUserResponse(UserAccountJoinVO usr, Long domainId) { UserResponse response = s_userAccountJoinDao.newUserResponse(usr); + // Populate user account role information + if (usr.getAccountRoleId() != null) { + Role role = s_roleService.findRole( usr.getAccountRoleId()); + if (role != null) { + response.setRoleId(role.getUuid()); + response.setRoleType(role.getRoleType()); + response.setRoleName(role.getName()); + } + } if (domainId != null && usr.getDomainId() != domainId) response.setIsCallerChildDomain(true); else @@ -1820,7 +1835,17 @@ public static DomainResponse newDomainResponse(ResponseView view, DomainJoinVO v } public static AccountResponse newAccountResponse(ResponseView view, AccountJoinVO ve) { - return s_accountJoinDao.newAccountResponse(view, ve); + AccountResponse response = s_accountJoinDao.newAccountResponse(view, ve); + // Populate account role information + if (ve.getRoleId() != null) { + Role role = s_roleService.findRole(ve.getRoleId()); + if (role != null) { + response.setRoleId(role.getUuid()); + response.setRoleType(role.getRoleType()); + response.setRoleName(role.getName()); + } + } + return response; } public static AccountJoinVO newAccountView(Account e) { diff --git a/server/src/com/cloud/api/ApiResponseGsonHelper.java b/server/src/com/cloud/api/ApiResponseGsonHelper.java index 1708fa764d..19db96ae36 100644 --- a/server/src/com/cloud/api/ApiResponseGsonHelper.java +++ b/server/src/com/cloud/api/ApiResponseGsonHelper.java @@ -68,7 +68,7 @@ public boolean shouldSkipField(FieldAttributes f) { boolean permittedParameter = false; Account caller = CallContext.current().getCallingAccount(); for (RoleType allowedRole : allowedRoles) { - if (allowedRole.getValue() == caller.getType()) { + if (allowedRole.getAccountType() == caller.getType()) { permittedParameter = true; break; } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 1c256440d4..66b8faab88 100644 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -191,6 +191,7 @@ import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.ResourceCount; import com.cloud.configuration.ResourceLimit; +import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.HostPodVO; @@ -342,6 +343,8 @@ public class ApiResponseHelper implements ResponseGenerator { private SnapshotDataStoreDao _snapshotStoreDao; @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject + private ClusterDetailsDao _clusterDetailsDao; @Override public UserResponse createUserResponse(User user) { @@ -1053,6 +1056,7 @@ public ClusterResponse createClusterResponse(Cluster cluster, Boolean showCapaci String memoryOvercommitRatio = ApiDBUtils.findClusterDetails(cluster.getId(), "memoryOvercommitRatio"); clusterResponse.setCpuOvercommitRatio(cpuOvercommitRatio); clusterResponse.setMemoryOvercommitRatio(memoryOvercommitRatio); + clusterResponse.setResourceDetails(_clusterDetailsDao.findDetails(cluster.getId())); if (showCapacities != null && showCapacities) { List capacities = ApiDBUtils.getCapacityByClusterPodZone(null, null, cluster.getId()); @@ -1388,7 +1392,7 @@ public TemplateResponse createTemplateUpdateResponse(ResponseView view, VirtualM @Override public List createTemplateResponses(ResponseView view, VirtualMachineTemplate result, Long zoneId, boolean readyOnly) { List tvo = null; - if (zoneId == null || zoneId == -1) { + if (zoneId == null || zoneId == -1 || result.isCrossZones()) { tvo = ApiDBUtils.newTemplateView(result); } else { tvo = ApiDBUtils.newTemplateView(result, zoneId, readyOnly); diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index 689ae9c675..0651d1671c 100644 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -16,45 +16,45 @@ // under the License. package com.cloud.api; -import com.cloud.api.dispatch.DispatchChainFactory; -import com.cloud.api.dispatch.DispatchTask; -import com.cloud.api.response.ApiResponseSerializer; -import com.cloud.configuration.Config; -import com.cloud.domain.Domain; -import com.cloud.domain.DomainVO; -import com.cloud.domain.dao.DomainDao; -import com.cloud.event.ActionEventUtils; -import com.cloud.event.EventCategory; -import com.cloud.event.EventTypes; -import com.cloud.exception.AccountLimitException; -import com.cloud.exception.CloudAuthenticationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.RequestLimitException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.DomainManager; -import com.cloud.user.User; -import com.cloud.user.UserAccount; -import com.cloud.user.UserVO; -import com.cloud.utils.ConstantTimeComparator; -import com.cloud.utils.HttpUtils; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.Pair; -import com.cloud.utils.StringUtils; -import com.cloud.utils.component.ComponentContext; -import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.component.PluggableService; -import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.db.EntityManager; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.TransactionLegacy; -import com.cloud.utils.db.UUIDManager; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.exception.ExceptionProxyObject; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.lang.reflect.Type; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.security.SecureRandom; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + import org.apache.cloudstack.acl.APIChecker; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -138,83 +138,88 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.stereotype.Component; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.inject.Inject; -import javax.naming.ConfigurationException; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URLEncoder; -import java.security.SecureRandom; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TimeZone; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import com.cloud.api.dispatch.DispatchChainFactory; +import com.cloud.api.dispatch.DispatchTask; +import com.cloud.api.response.ApiResponseSerializer; +import com.cloud.configuration.Config; +import com.cloud.domain.Domain; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.event.ActionEventUtils; +import com.cloud.event.EventCategory; +import com.cloud.event.EventTypes; +import com.cloud.exception.AccountLimitException; +import com.cloud.exception.CloudAuthenticationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.RequestLimitException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.DomainManager; +import com.cloud.user.User; +import com.cloud.user.UserAccount; +import com.cloud.user.UserVO; +import com.cloud.utils.ConstantTimeComparator; +import com.cloud.utils.HttpUtils; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.component.PluggableService; +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.TransactionLegacy; +import com.cloud.utils.db.UUIDManager; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.exception.ExceptionProxyObject; +import com.google.gson.reflect.TypeToken; @Component public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiServerService { private static final Logger s_logger = Logger.getLogger(ApiServer.class.getName()); private static final Logger s_accessLogger = Logger.getLogger("apiserver." + ApiServer.class.getName()); - public static boolean encodeApiResponse = false; - public static boolean s_enableSecureCookie = false; - public static String s_jsonContentType = HttpUtils.JSON_CONTENT_TYPE; + private static boolean encodeApiResponse = false; + private boolean enableSecureCookie = false; + private String jsonContentType = HttpUtils.JSON_CONTENT_TYPE; /** * Non-printable ASCII characters - numbers 0 to 31 and 127 decimal */ - public static final String CONTROL_CHARACTERS = "[\000-\011\013-\014\016-\037\177]"; + private static final String CONTROL_CHARACTERS = "[\000-\011\013-\014\016-\037\177]"; @Inject - protected ApiDispatcher _dispatcher; + private ApiDispatcher dispatcher; @Inject - protected DispatchChainFactory dispatchChainFactory; + private DispatchChainFactory dispatchChainFactory; @Inject - private AccountManager _accountMgr; + private AccountManager accountMgr; @Inject - private DomainManager _domainMgr; + private DomainManager domainMgr; @Inject - private DomainDao _domainDao; + private DomainDao domainDao; @Inject - private UUIDManager _uuidMgr; + private UUIDManager uuidMgr; @Inject - private AsyncJobManager _asyncMgr; + private AsyncJobManager asyncMgr; @Inject - private ConfigurationDao _configDao; + private ConfigurationDao configDao; @Inject - private EntityManager _entityMgr; + private EntityManager entityMgr; @Inject - APIAuthenticationManager _authManager; + private APIAuthenticationManager authManager; + + private List pluggableServices; - List _pluggableServices; - List _apiAccessCheckers; + private List apiAccessCheckers; @Inject - protected ApiAsyncJobDispatcher _asyncDispatcher; + private ApiAsyncJobDispatcher asyncDispatcher; private static int s_workerCount = 0; private static final DateFormat DateFormatToUse = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); @@ -223,19 +228,16 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer private static ExecutorService s_executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue(), new NamedThreadFactory( "ApiServer")); @Inject - MessageBus _messageBus; - - public ApiServer() { - } + private MessageBus messageBus; @Override public boolean configure(final String name, final Map params) throws ConfigurationException { - _messageBus.subscribe(AsyncJob.Topics.JOB_EVENT_PUBLISH, MessageDispatcher.getDispatcher(this)); + messageBus.subscribe(AsyncJob.Topics.JOB_EVENT_PUBLISH, MessageDispatcher.getDispatcher(this)); return true; } @MessageHandler(topic = AsyncJob.Topics.JOB_EVENT_PUBLISH) - private void handleAsyncJobPublishEvent(String subject, String senderAddress, Object args) { + public void handleAsyncJobPublishEvent(String subject, String senderAddress, Object args) { assert (args != null); @SuppressWarnings("unchecked") @@ -257,17 +259,18 @@ private void handleAsyncJobPublishEvent(String subject, String senderAddress, Ob return; } - User userJobOwner = _accountMgr.getUserIncludingRemoved(job.getUserId()); - Account jobOwner = _accountMgr.getAccount(userJobOwner.getAccountId()); + User userJobOwner = accountMgr.getUserIncludingRemoved(job.getUserId()); + Account jobOwner = accountMgr.getAccount(userJobOwner.getAccountId()); // Get the event type from the cmdInfo json string String info = job.getCmdInfo(); String cmdEventType = "unknown"; if (info != null) { - String marker = "\"cmdEventType\""; - int begin = info.indexOf(marker); - if (begin >= 0) { - cmdEventType = info.substring(begin + marker.length() + 2, info.indexOf(",", begin) - 1); + Type type = new TypeToken>(){}.getType(); + Map cmdInfo = ApiGsonHelper.getBuilder().create().fromJson(info, type); + String eventTypeObj = cmdInfo.get("cmdEventType"); + if (eventTypeObj != null) { + cmdEventType = eventTypeObj; if (s_logger.isDebugEnabled()) s_logger.debug("Retrieved cmdEventType from job info: " + cmdEventType); @@ -296,9 +299,9 @@ private void handleAsyncJobPublishEvent(String subject, String senderAddress, Ob eventDescription.put("cmdInfo", job.getCmdInfo()); eventDescription.put("status", "" + job.getStatus() ); // If the event.accountinfo boolean value is set, get the human readable value for the username / domainname - Map configs = _configDao.getConfiguration("management-server", new HashMap()); + Map configs = configDao.getConfiguration("management-server", new HashMap()); if (Boolean.valueOf(configs.get("event.accountinfo"))) { - DomainVO domain = _domainDao.findById(jobOwner.getDomainId()); + DomainVO domain = domainDao.findById(jobOwner.getDomainId()); eventDescription.put("username", userJobOwner.getUsername()); eventDescription.put("accountname", jobOwner.getAccountName()); eventDescription.put("domainname", domain.getName()); @@ -316,9 +319,9 @@ private void handleAsyncJobPublishEvent(String subject, String senderAddress, Ob @Override public boolean start() { Integer apiPort = null; // api port, null by default - final SearchCriteria sc = _configDao.createSearchCriteria(); + final SearchCriteria sc = configDao.createSearchCriteria(); sc.addAnd("name", SearchCriteria.Op.EQ, Config.IntegrationAPIPort.key()); - final List values = _configDao.search(sc, null); + final List values = configDao.search(sc, null); if ((values != null) && (values.size() > 0)) { final ConfigurationVO apiPortConfig = values.get(0); if (apiPortConfig.getValue() != null) { @@ -326,19 +329,19 @@ public boolean start() { } } - final Map configs = _configDao.getConfiguration(); + final Map configs = configDao.getConfiguration(); final String strSnapshotLimit = configs.get(Config.ConcurrentSnapshotsThresholdPerHost.key()); if (strSnapshotLimit != null) { final Long snapshotLimit = NumbersUtil.parseLong(strSnapshotLimit, 1L); if (snapshotLimit.longValue() <= 0) { s_logger.debug("Global config parameter " + Config.ConcurrentSnapshotsThresholdPerHost.toString() + " is less or equal 0; defaulting to unlimited"); } else { - _dispatcher.setCreateSnapshotQueueSizeLimit(snapshotLimit); + dispatcher.setCreateSnapshotQueueSizeLimit(snapshotLimit); } } final Set> cmdClasses = new HashSet>(); - for (final PluggableService pluggableService : _pluggableServices) { + for (final PluggableService pluggableService : pluggableServices) { cmdClasses.addAll(pluggableService.getCommands()); if (s_logger.isDebugEnabled()) { s_logger.debug("Discovered plugin " + pluggableService.getClass().getSimpleName()); @@ -361,14 +364,14 @@ public boolean start() { } - setEncodeApiResponse(Boolean.valueOf(_configDao.getValue(Config.EncodeApiResponse.key()))); - final String jsonType = _configDao.getValue(Config.JSONDefaultContentType.key()); + setEncodeApiResponse(Boolean.valueOf(configDao.getValue(Config.EncodeApiResponse.key()))); + final String jsonType = configDao.getValue(Config.JSONDefaultContentType.key()); if (jsonType != null) { - s_jsonContentType = jsonType; + jsonContentType = jsonType; } - final Boolean enableSecureSessionCookie = Boolean.valueOf(_configDao.getValue(Config.EnableSecureSessionCookie.key())); + final Boolean enableSecureSessionCookie = Boolean.valueOf(configDao.getValue(Config.EnableSecureSessionCookie.key())); if (enableSecureSessionCookie != null) { - s_enableSecureCookie = enableSecureSessionCookie; + enableSecureCookie = enableSecureSessionCookie; } if (apiPort != null) { @@ -429,7 +432,7 @@ public void handle(final HttpRequest request, final HttpResponse response, final try { // always trust commands from API port, user context will always be UID_SYSTEM/ACCOUNT_ID_SYSTEM - CallContext.register(_accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); + CallContext.register(accountMgr.getSystemUser(), accountMgr.getSystemAccount()); sb.insert(0, "(userId=" + User.UID_SYSTEM + " accountId=" + Account.ACCOUNT_ID_SYSTEM + " sessionId=" + null + ") "); final String responseText = handleRequest(parameterMap, responseType, sb); sb.append(" 200 " + ((responseText == null) ? 0 : responseText.length())); @@ -494,7 +497,7 @@ public String handleRequest(final Map params, final String responseType, final S throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent"); } else { // Don't allow Login/Logout APIs to go past this point - if (_authManager.getAPIAuthenticator(command[0]) != null) { + if (authManager.getAPIAuthenticator(command[0]) != null) { return null; } final Map paramMap = new HashMap(); @@ -562,7 +565,7 @@ public String handleRequest(final Map params, final String responseType, final S } catch (final InsufficientCapacityException ex) { s_logger.info(ex.getMessage()); String errorMsg = ex.getMessage(); - if (!_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { + if (!accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } @@ -573,7 +576,7 @@ public String handleRequest(final Map params, final String responseType, final S } catch (final ResourceUnavailableException ex) { s_logger.info(ex.getMessage()); String errorMsg = ex.getMessage(); - if (!_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { + if (!accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } @@ -584,7 +587,7 @@ public String handleRequest(final Map params, final String responseType, final S } catch (final Exception ex) { s_logger.error("unhandled exception executing api command: " + ((command == null) ? "null" : command), ex); String errorMsg = ex.getMessage(); - if (!_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { + if (!accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { // hide internal details to non-admin user for security reason errorMsg = BaseCmd.USER_ERROR_MESSAGE; } @@ -597,7 +600,7 @@ public String handleRequest(final Map params, final String responseType, final S private String getBaseAsyncResponse(final long jobId, final BaseAsyncCmd cmd) { final AsyncJobResponse response = new AsyncJobResponse(); - final AsyncJob job = _entityMgr.findById(AsyncJob.class, jobId); + final AsyncJob job = entityMgr.findById(AsyncJob.class, jobId); response.setJobId(job.getUuid()); response.setResponseName(cmd.getCommandName()); return ApiResponseSerializer.toSerializedString(response, cmd.getResponseType()); @@ -605,7 +608,7 @@ private String getBaseAsyncResponse(final long jobId, final BaseAsyncCmd cmd) { private String getBaseAsyncCreateResponse(final long jobId, final BaseAsyncCreateCmd cmd, final String objectUuid) { final CreateCmdResponse response = new CreateCmdResponse(); - final AsyncJob job = _entityMgr.findById(AsyncJob.class, jobId); + final AsyncJob job = entityMgr.findById(AsyncJob.class, jobId); response.setJobId(job.getUuid()); response.setId(objectUuid); response.setResponseName(cmd.getCommandName()); @@ -626,7 +629,7 @@ private String queueCommand(final BaseCmd cmdObj, final Map para String objectUuid = null; if (cmdObj instanceof BaseAsyncCreateCmd) { final BaseAsyncCreateCmd createCmd = (BaseAsyncCreateCmd)cmdObj; - _dispatcher.dispatchCreateCmd(createCmd, params); + dispatcher.dispatchCreateCmd(createCmd, params); objectId = createCmd.getEntityId(); objectUuid = createCmd.getEntityUuid(); params.put("id", objectId.toString()); @@ -671,31 +674,38 @@ private String queueCommand(final BaseCmd cmdObj, final Map para // users can provide the job id they want to use, so log as it is a uuid and is unique String injectedJobId = asyncCmd.getInjectedJobId(); - _uuidMgr.checkUuidSimple(injectedJobId, AsyncJob.class); + uuidMgr.checkUuidSimple(injectedJobId, AsyncJob.class); AsyncJobVO job = new AsyncJobVO("", callerUserId, caller.getId(), cmdObj.getClass().getName(), ApiGsonHelper.getBuilder().create().toJson(params), instanceId, asyncCmd.getInstanceType() != null ? asyncCmd.getInstanceType().toString() : null, - injectedJobId); - job.setDispatcher(_asyncDispatcher.getName()); + injectedJobId); + job.setDispatcher(asyncDispatcher.getName()); - final long jobId = _asyncMgr.submitAsyncJob(job); + final long jobId = asyncMgr.submitAsyncJob(job); if (jobId == 0L) { final String errorMsg = "Unable to schedule async job for command " + job.getCmd(); s_logger.warn(errorMsg); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg); } - + final String response; if (objectId != null) { final String objUuid = (objectUuid == null) ? objectId.toString() : objectUuid; - return getBaseAsyncCreateResponse(jobId, (BaseAsyncCreateCmd)asyncCmd, objUuid); + response = getBaseAsyncCreateResponse(jobId, (BaseAsyncCreateCmd)asyncCmd, objUuid); } else { SerializationContext.current().setUuidTranslation(true); - return getBaseAsyncResponse(jobId, asyncCmd); + response = getBaseAsyncResponse(jobId, asyncCmd); } + // Always log response for async for now, I don't think any sensitive data will be in here. + // It might be nice to send this through scrubbing similar to how + // ApiResponseSerializer.toSerializedStringWithSecureLogs works. For now, this gets jobid's + // in the api logs. + log.append(response); + return response; + } else { - _dispatcher.dispatch(cmdObj, params, false); + dispatcher.dispatch(cmdObj, params, false); // if the command is of the listXXXCommand, we will need to also return the // the job id and status if possible @@ -723,10 +733,10 @@ private void buildAsyncListResponse(final BaseListCmd command, final Account acc List jobs = null; // list all jobs for ROOT admin - if (_accountMgr.isRootAdmin(account.getId())) { - jobs = _asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType().toString(), null); + if (accountMgr.isRootAdmin(account.getId())) { + jobs = asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType().toString(), null); } else { - jobs = _asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType().toString(), account.getId()); + jobs = asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType().toString(), account.getId()); } if (jobs.size() == 0) { @@ -790,15 +800,15 @@ public boolean verifyRequest(final Map requestParameters, fina s_logger.debug(ex.getMessage()); throw new ServerApiException(ApiErrorCode.API_LIMIT_EXCEED, ex.getMessage()); } catch (final PermissionDeniedException ex) { - s_logger.debug("The given command:" + commandName + " does not exist or it is not available for user with id:" + userId); - throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "The given command does not exist or it is not available for user"); + s_logger.debug("The user with id:" + userId + " is not allowed to request the API command or the API command does not exist: " + commandName); + throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "The user is not allowed to request the API command or the API command does not exist"); } return true; } else { // check against every available command to see if the command exists or not if (!s_apiNameCmdClassMap.containsKey(commandName) && !commandName.equals("login") && !commandName.equals("logout")) { - s_logger.debug("The given command:" + commandName + " does not exist or it is not available for user with id:" + userId); - throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "The given command does not exist or it is not available for user"); + s_logger.debug("The user with id:" + userId + " is not allowed to request the API command or the API command does not exist: " + commandName); + throw new ServerApiException(ApiErrorCode.UNSUPPORTED_ACTION_ERROR, "The user is not allowed to request the API command or the API command does not exist"); } } @@ -871,7 +881,7 @@ public boolean verifyRequest(final Map requestParameters, fina txn.close(); User user = null; // verify there is a user with this api key - final Pair userAcctPair = _accountMgr.findUserByApiKey(apiKey); + final Pair userAcctPair = accountMgr.findUserByApiKey(apiKey); if (userAcctPair == null) { s_logger.debug("apiKey does not map to a valid user -- ignoring request, apiKey: " + apiKey); return false; @@ -931,7 +941,7 @@ public boolean verifyRequest(final Map requestParameters, fina @Override public Long fetchDomainId(final String domainUUID) { - final Domain domain = _domainMgr.getDomain(domainUUID); + final Domain domain = domainMgr.getDomain(domainUUID); if (domain != null) return domain.getId(); else @@ -993,14 +1003,14 @@ public ResponseObject loginUser(final HttpSession session, final String username final Map requestParameters) throws CloudAuthenticationException { // We will always use domainId first. If that does not exist, we will use domain name. If THAT doesn't exist // we will default to ROOT - final Domain userDomain = _domainMgr.findDomainByIdOrPath(domainId, domainPath); + final Domain userDomain = domainMgr.findDomainByIdOrPath(domainId, domainPath); if (userDomain == null || userDomain.getId() < 1L) { throw new CloudAuthenticationException("Unable to find the domain from the path " + domainPath); } else { domainId = userDomain.getId(); } - final UserAccount userAcct = _accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters); + final UserAccount userAcct = accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters); if (userAcct != null) { final String timezone = userAcct.getTimezone(); float offsetInHrs = 0f; @@ -1015,11 +1025,11 @@ public ResponseObject loginUser(final HttpSession session, final String username s_logger.info("Timezone offset from UTC is: " + offsetInHrs); } - final Account account = _accountMgr.getAccount(userAcct.getAccountId()); + final Account account = accountMgr.getAccount(userAcct.getAccountId()); // set the userId and account object for everyone session.setAttribute("userid", userAcct.getId()); - final UserVO user = (UserVO)_accountMgr.getActiveUser(userAcct.getId()); + final UserVO user = (UserVO)accountMgr.getActiveUser(userAcct.getId()); if (user.getUuid() != null) { session.setAttribute("user_UUID", user.getUuid()); } @@ -1031,7 +1041,7 @@ public ResponseObject loginUser(final HttpSession session, final String username session.setAttribute("account", account.getAccountName()); session.setAttribute("domainid", account.getDomainId()); - final DomainVO domain = (DomainVO)_domainMgr.getDomain(account.getDomainId()); + final DomainVO domain = (DomainVO)domainMgr.getDomain(account.getDomainId()); if (domain.getUuid() != null) { session.setAttribute("domain_UUID", domain.getUuid()); } @@ -1060,16 +1070,16 @@ public ResponseObject loginUser(final HttpSession session, final String username @Override public void logoutUser(final long userId) { - _accountMgr.logoutUser(userId); + accountMgr.logoutUser(userId); return; } @Override public boolean verifyUser(final Long userId) { - final User user = _accountMgr.getUserIncludingRemoved(userId); + final User user = accountMgr.getUserIncludingRemoved(userId); Account account = null; if (user != null) { - account = _accountMgr.getAccount(user.getAccountId()); + account = accountMgr.getAccount(user.getAccountId()); } if ((user == null) || (user.getRemoved() != null) || !user.getState().equals(Account.State.enabled) || (account == null) || @@ -1085,7 +1095,7 @@ private void checkCommandAvailable(final User user, final String commandName) th throw new PermissionDeniedException("User is null for role based API access check for command" + commandName); } - for (final APIChecker apiChecker : _apiAccessCheckers) { + for (final APIChecker apiChecker : apiAccessCheckers) { apiChecker.checkAccess(user, commandName); } } @@ -1101,7 +1111,7 @@ else if (cmdList.size() == 1) // determine the cmd class based on calling context ResponseView view = ResponseView.Restricted; if (CallContext.current() != null - && _accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { + && accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())) { view = ResponseView.Full; } for (Class cmdClass : cmdList) { @@ -1169,10 +1179,10 @@ public ListenerThread(final ApiServer requestHandler, final int port) { _params = new BasicHttpParams(); _params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 30000) - .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) - .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false) - .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) - .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); + .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) + .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false) + .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) + .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); // Set up the HTTP protocol processor final BasicHttpProcessor httpproc = new BasicHttpProcessor(); @@ -1334,37 +1344,31 @@ public String getSerializedApiError(final ServerApiException ex, final Map getPluggableServices() { - return _pluggableServices; - } - @Inject public void setPluggableServices(final List pluggableServices) { - _pluggableServices = pluggableServices; - } - - public List getApiAccessCheckers() { - return _apiAccessCheckers; + this.pluggableServices = pluggableServices; } @Inject public void setApiAccessCheckers(final List apiAccessCheckers) { - _apiAccessCheckers = apiAccessCheckers; + this.apiAccessCheckers = apiAccessCheckers; } public static boolean isEncodeApiResponse() { - return encodeApiResponse; + return ApiServer.encodeApiResponse; } private static void setEncodeApiResponse(final boolean encodeApiResponse) { ApiServer.encodeApiResponse = encodeApiResponse; } - public static boolean isSecureSessionCookieEnabled() { - return s_enableSecureCookie; + @Override + public boolean isSecureSessionCookieEnabled() { + return enableSecureCookie; } - public static String getJSONContentType() { - return s_jsonContentType; + @Override + public String getJSONContentType() { + return jsonContentType; } } diff --git a/server/src/com/cloud/api/ApiServlet.java b/server/src/com/cloud/api/ApiServlet.java index 51827daf1d..6c83698461 100644 --- a/server/src/com/cloud/api/ApiServlet.java +++ b/server/src/com/cloud/api/ApiServlet.java @@ -16,13 +16,23 @@ // under the License. package com.cloud.api; -import com.cloud.user.Account; -import com.cloud.user.AccountService; -import com.cloud.user.User; -import com.cloud.utils.HttpUtils; -import com.cloud.utils.StringUtils; -import com.cloud.utils.db.EntityManager; -import com.cloud.utils.net.NetUtils; +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.URLDecoder; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiServerService; @@ -36,22 +46,14 @@ import org.springframework.stereotype.Component; import org.springframework.web.context.support.SpringBeanAutowiringSupport; -import javax.inject.Inject; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.net.URLDecoder; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import com.cloud.user.Account; +import com.cloud.user.AccountService; +import com.cloud.user.User; + +import com.cloud.utils.HttpUtils; +import com.cloud.utils.StringUtils; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.net.NetUtils; @Component("apiServlet") @SuppressWarnings("serial") @@ -63,15 +65,15 @@ public class ApiServlet extends HttpServlet { "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR", "Remote_Addr")); @Inject - ApiServerService _apiServer; + ApiServerService apiServer; @Inject - AccountService _accountMgr; + AccountService accountMgr; @Inject - EntityManager _entityMgr; + EntityManager entityMgr; @Inject - ManagedContext _managedContext; + ManagedContext managedContext; @Inject - APIAuthenticationManager _authManager; + APIAuthenticationManager authManager; public ApiServlet() { } @@ -121,7 +123,7 @@ private String decodeUtf8(final String value) { } private void processRequest(final HttpServletRequest req, final HttpServletResponse resp) { - _managedContext.runWithContext(new Runnable() { + managedContext.runWithContext(new Runnable() { @Override public void run() { processRequestInContext(req, resp); @@ -156,7 +158,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp try { if (HttpUtils.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) { - resp.setContentType(ApiServer.getJSONContentType()); + resp.setContentType(apiServer.getJSONContentType()); } else if (HttpUtils.RESPONSE_TYPE_XML.equalsIgnoreCase(responseType)){ resp.setContentType(HttpUtils.XML_CONTENT_TYPE); } @@ -171,7 +173,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp if (commandObj != null) { final String command = (String) commandObj[0]; - APIAuthenticator apiAuthenticator = _authManager.getAPIAuthenticator(command); + APIAuthenticator apiAuthenticator = authManager.getAPIAuthenticator(command); if (apiAuthenticator != null) { auditTrailSb.append("command="); auditTrailSb.append(command); @@ -187,7 +189,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp } } session = req.getSession(true); - if (ApiServer.isSecureSessionCookieEnabled()) { + if (apiServer.isSecureSessionCookieEnabled()) { resp.setHeader("SET-COOKIE", String.format("JSESSIONID=%s;Secure;HttpOnly;Path=/client", session.getId())); if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) { @@ -218,7 +220,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp } auditTrailSb.insert(0, "(userId=" + userId + " accountId=" + accountId + " sessionId=" + session.getId() + ")"); if (userId != null) { - _apiServer.logoutUser(userId); + apiServer.logoutUser(userId); } try { session.invalidate(); @@ -229,7 +231,7 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp sessionKeyCookie.setMaxAge(0); resp.addCookie(sessionKeyCookie); } - HttpUtils.writeHttpResponse(resp, responseString, httpResponseCode, responseType, ApiServer.getJSONContentType()); + HttpUtils.writeHttpResponse(resp, responseString, httpResponseCode, responseType, apiServer.getJSONContentType()); return; } } @@ -253,22 +255,22 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp } auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); final String serializedResponse = - _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); - HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.getJSONContentType()); + apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); + HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, apiServer.getJSONContentType()); return; } // Do a sanity check here to make sure the user hasn't already been deleted - if ((userId != null) && (account != null) && (accountObj != null) && _apiServer.verifyUser(userId)) { + if ((userId != null) && (account != null) && (accountObj != null) && apiServer.verifyUser(userId)) { final String[] command = (String[])params.get(ApiConstants.COMMAND); if (command == null) { s_logger.info("missing command, ignoring request..."); auditTrailSb.append(" " + HttpServletResponse.SC_BAD_REQUEST + " " + "no command specified"); - final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_BAD_REQUEST, "no command specified", params, responseType); - HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST, responseType, ApiServer.getJSONContentType()); + final String serializedResponse = apiServer.getSerializedApiError(HttpServletResponse.SC_BAD_REQUEST, "no command specified", params, responseType); + HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST, responseType, apiServer.getJSONContentType()); return; } - final User user = _entityMgr.findById(User.class, userId); + final User user = entityMgr.findById(User.class, userId); CallContext.register(user, (Account)accountObj); } else { // Invalidate the session to ensure we won't allow a request across management server @@ -280,22 +282,22 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); final String serializedResponse = - _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); - HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.getJSONContentType()); + apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); + HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, apiServer.getJSONContentType()); return; } } else { - CallContext.register(_accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); + CallContext.register(accountMgr.getSystemUser(), accountMgr.getSystemAccount()); } - if (_apiServer.verifyRequest(params, userId)) { + if (apiServer.verifyRequest(params, userId)) { auditTrailSb.insert(0, "(userId=" + CallContext.current().getCallingUserId() + " accountId=" + CallContext.current().getCallingAccount().getId() + - " sessionId=" + (session != null ? session.getId() : null) + ")"); + " sessionId=" + (session != null ? session.getId() : null) + ")"); // Add the HTTP method (GET/POST/PUT/DELETE) as well into the params map. params.put("httpmethod", new String[] {req.getMethod()}); - final String response = _apiServer.handleRequest(params, responseType, auditTrailSb); - HttpUtils.writeHttpResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK, responseType, ApiServer.getJSONContentType()); + final String response = apiServer.handleRequest(params, responseType, auditTrailSb); + HttpUtils.writeHttpResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK, responseType, apiServer.getJSONContentType()); } else { if (session != null) { try { @@ -306,15 +308,15 @@ void processRequestInContext(final HttpServletRequest req, final HttpServletResp auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials and/or request signature"); final String serializedResponse = - _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials and/or request signature", params, - responseType); - HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.getJSONContentType()); + apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials and/or request signature", params, + responseType); + HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, apiServer.getJSONContentType()); } } catch (final ServerApiException se) { - final String serializedResponseText = _apiServer.getSerializedApiError(se, params, responseType); + final String serializedResponseText = apiServer.getSerializedApiError(se, params, responseType); resp.setHeader("X-Description", se.getDescription()); - HttpUtils.writeHttpResponse(resp, serializedResponseText, se.getErrorCode().getHttpCode(), responseType, ApiServer.getJSONContentType()); + HttpUtils.writeHttpResponse(resp, serializedResponseText, se.getErrorCode().getHttpCode(), responseType, apiServer.getJSONContentType()); auditTrailSb.append(" " + se.getErrorCode() + " " + se.getDescription()); } catch (final Exception ex) { s_logger.error("unknown exception writing api response", ex); diff --git a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java index 099c0c91e6..feefaabc55 100644 --- a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java +++ b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java @@ -34,6 +34,7 @@ import javax.inject.Inject; +import com.google.common.base.Strings; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.ControlledEntity; @@ -49,6 +50,7 @@ import org.apache.cloudstack.api.InternalIdentity; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.ApiArgValidator; import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd; import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd; import org.apache.cloudstack.api.command.admin.usage.GetUsageRecordsCmd; @@ -92,6 +94,55 @@ public void handle(final DispatchTask task) { processParameters(task.getCmd(), task.getParams()); } + private void validateNonEmptyString(final Object param, final String argName) { + if (param == null || Strings.isNullOrEmpty(param.toString())) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Empty or null value provided for API arg: %s", argName)); + } + } + + private void validateNaturalNumber(final Object param, final String argName) { + Long value = null; + if (param != null && param instanceof Long) { + value = (Long) param; + } else if (param != null) { + value = Long.valueOf(param.toString()); + } + if (value == null || value < 1L) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Invalid value provided for API arg: %s", argName)); + } + } + + private void validateField(final Object paramObj, final Parameter annotation) throws ServerApiException { + if (annotation == null) { + return; + } + final String argName = annotation.name(); + for (final ApiArgValidator validator : annotation.validations()) { + if (validator == null) { + continue; + } + switch (validator) { + case NotNullOrEmpty: + switch (annotation.type()) { + case UUID: + case STRING: + validateNonEmptyString(paramObj, argName); + break; + } + break; + case PositiveNumber: + switch (annotation.type()) { + case SHORT: + case INTEGER: + case LONG: + validateNaturalNumber(paramObj, argName); + break; + } + break; + } + } + } + @SuppressWarnings({"unchecked", "rawtypes"}) public void processParameters(final BaseCmd cmd, final Map params) { final Map entitiesToAccess = new HashMap(); @@ -112,6 +163,7 @@ public void processParameters(final BaseCmd cmd, final Map params) { // marshall the parameter into the correct type and set the field value try { + validateField(paramObj, parameterAnnotation); setFieldValue(field, cmd, paramObj, parameterAnnotation); } catch (final IllegalArgumentException argEx) { if (s_logger.isDebugEnabled()) { @@ -420,6 +472,7 @@ private Long translateUuidToInternalId(final String uuid, final Parameter annota for (final Class entity : entities) { CallContext.current().putContextParameter(entity, internalId); } + validateNaturalNumber(internalId, annotation.name()); return internalId; } } @@ -452,6 +505,7 @@ private Long translateUuidToInternalId(final String uuid, final Parameter annota throw new InvalidParameterValueException("Invalid parameter " + annotation.name() + " value=" + uuid + " due to incorrect long value format, or entity does not exist or due to incorrect parameter annotation for the field in api cmd class."); } + validateNaturalNumber(internalId, annotation.name()); return internalId; } } diff --git a/server/src/com/cloud/api/doc/ApiXmlDocWriter.java b/server/src/com/cloud/api/doc/ApiXmlDocWriter.java index 166af4bafd..9246edd4ad 100644 --- a/server/src/com/cloud/api/doc/ApiXmlDocWriter.java +++ b/server/src/com/cloud/api/doc/ApiXmlDocWriter.java @@ -41,7 +41,6 @@ import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; @@ -67,16 +66,10 @@ public class ApiXmlDocWriter { public static final Logger s_logger = Logger.getLogger(ApiXmlDocWriter.class.getName()); - private static final short DOMAIN_ADMIN_COMMAND = 4; - private static final short USER_COMMAND = 8; + private static String s_dirName = ""; private static Map> s_apiNameCmdClassMap = new HashMap>(); private static LinkedHashMap s_allApiCommands = new LinkedHashMap(); - private static LinkedHashMap s_domainAdminApiCommands = new LinkedHashMap(); - private static LinkedHashMap s_regularUserApiCommands = new LinkedHashMap(); private static TreeMap s_allApiCommandsSorted = new TreeMap(); - private static TreeMap s_domainAdminApiCommandsSorted = new TreeMap(); - private static TreeMap s_regularUserApiCommandsSorted = new TreeMap(); - private static String s_dirName = ""; private static final List AsyncResponses = setAsyncResponses(); private static List setAsyncResponses() { @@ -123,71 +116,22 @@ public static void main(String[] args) { s_apiNameCmdClassMap.put(apiName, cmdClass); } } - - LinkedProperties preProcessedCommands = new LinkedProperties(); - String[] fileNames = null; - + System.out.printf("Scanned and found %d APIs\n", s_apiNameCmdClassMap.size()); List argsList = Arrays.asList(args); Iterator iter = argsList.iterator(); while (iter.hasNext()) { String arg = iter.next(); - // populate the file names - if (arg.equals("-f")) { - fileNames = iter.next().split(","); - } if (arg.equals("-d")) { s_dirName = iter.next(); } } - if ((fileNames == null) || (fileNames.length == 0)) { - System.out.println("Please specify input file(s) separated by coma using -f option"); - System.exit(2); - } - - for (String fileName : fileNames) { - try(FileInputStream in = new FileInputStream(fileName);) { - preProcessedCommands.load(in); - } catch (FileNotFoundException ex) { - System.out.println("Can't find file " + fileName); - System.exit(2); - } catch (IOException ex1) { - System.out.println("Error reading from file " + ex1); - System.exit(2); - } - } - - Iterator propertiesIterator = preProcessedCommands.keys.iterator(); - // Get command classes and response object classes - while (propertiesIterator.hasNext()) { - String key = (String)propertiesIterator.next(); - String preProcessedCommand = preProcessedCommands.getProperty(key); - int splitIndex = preProcessedCommand.lastIndexOf(";"); - String commandRoleMask = preProcessedCommand.substring(splitIndex + 1); - Class cmdClass = s_apiNameCmdClassMap.get(key); - if (cmdClass == null) { - System.out.println("Check, is this api part of another build profile? Null value for key: " + key + " preProcessedCommand=" + preProcessedCommand); - continue; - } - String commandName = cmdClass.getName(); - s_allApiCommands.put(key, commandName); - - short cmdPermissions = 1; - if (commandRoleMask != null) { - cmdPermissions = Short.parseShort(commandRoleMask); - } - - if ((cmdPermissions & DOMAIN_ADMIN_COMMAND) != 0) { - s_domainAdminApiCommands.put(key, commandName); - } - if ((cmdPermissions & USER_COMMAND) != 0) { - s_regularUserApiCommands.put(key, commandName); - } + for (Map.Entry> entry: s_apiNameCmdClassMap.entrySet()) { + Class cls = entry.getValue(); + s_allApiCommands.put(entry.getKey(), cls.getName()); } s_allApiCommandsSorted.putAll(s_allApiCommands); - s_domainAdminApiCommandsSorted.putAll(s_domainAdminApiCommands); - s_regularUserApiCommandsSorted.putAll(s_regularUserApiCommands); try { // Create object writer @@ -195,83 +139,38 @@ public static void main(String[] args) { xs.alias("command", Command.class); xs.alias("arg", Argument.class); String xmlDocDir = s_dirName + "/xmldoc"; - String rootAdminDirName = xmlDocDir + "/root_admin"; - String domainAdminDirName = xmlDocDir + "/domain_admin"; - String regularUserDirName = xmlDocDir + "/regular_user"; + String rootAdminDirName = xmlDocDir + "/apis"; (new File(rootAdminDirName)).mkdirs(); - (new File(domainAdminDirName)).mkdirs(); - (new File(regularUserDirName)).mkdirs(); ObjectOutputStream out = xs.createObjectOutputStream(new FileWriter(s_dirName + "/commands.xml"), "commands"); - ObjectOutputStream rootAdmin = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + "rootAdminSummary.xml"), "commands"); - ObjectOutputStream rootAdminSorted = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + "rootAdminSummarySorted.xml"), "commands"); - ObjectOutputStream domainAdmin = xs.createObjectOutputStream(new FileWriter(domainAdminDirName + "/" + "domainAdminSummary.xml"), "commands"); - ObjectOutputStream outDomainAdminSorted = xs.createObjectOutputStream(new FileWriter(domainAdminDirName + "/" + "domainAdminSummarySorted.xml"), "commands"); - ObjectOutputStream regularUser = xs.createObjectOutputStream(new FileWriter(regularUserDirName + "/regularUserSummary.xml"), "commands"); - ObjectOutputStream regularUserSorted = xs.createObjectOutputStream(new FileWriter(regularUserDirName + "/regularUserSummarySorted.xml"), "commands"); - - // Write commands in the order they are represented in commands.properties.in file + ObjectOutputStream rootAdmin = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + "apiSummary.xml"), "commands"); + ObjectOutputStream rootAdminSorted = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + "apiSummarySorted.xml"), "commands"); + Iterator it = s_allApiCommands.keySet().iterator(); while (it.hasNext()) { String key = (String)it.next(); - // Write admin commands writeCommand(out, key); writeCommand(rootAdmin, key); - // Write single commands to separate xml files ObjectOutputStream singleRootAdminCommandOs = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + key + ".xml"), "command"); writeCommand(singleRootAdminCommandOs, key); singleRootAdminCommandOs.close(); - - if (s_domainAdminApiCommands.containsKey(key)) { - writeCommand(domainAdmin, key); - ObjectOutputStream singleDomainAdminCommandOs = xs.createObjectOutputStream(new FileWriter(domainAdminDirName + "/" + key + ".xml"), "command"); - writeCommand(singleDomainAdminCommandOs, key); - singleDomainAdminCommandOs.close(); - } - - if (s_regularUserApiCommands.containsKey(key)) { - writeCommand(regularUser, key); - ObjectOutputStream singleRegularUserCommandOs = xs.createObjectOutputStream(new FileWriter(regularUserDirName + "/" + key + ".xml"), "command"); - writeCommand(singleRegularUserCommandOs, key); - singleRegularUserCommandOs.close(); - } } // Write sorted commands it = s_allApiCommandsSorted.keySet().iterator(); while (it.hasNext()) { String key = (String)it.next(); - writeCommand(rootAdminSorted, key); - - if (s_domainAdminApiCommands.containsKey(key)) { - writeCommand(outDomainAdminSorted, key); - } - - if (s_regularUserApiCommands.containsKey(key)) { - writeCommand(regularUserSorted, key); - } } out.close(); rootAdmin.close(); rootAdminSorted.close(); - domainAdmin.close(); - outDomainAdminSorted.close(); - regularUser.close(); - regularUserSorted.close(); // write alerttypes to xml writeAlertTypes(xmlDocDir); - - // gzip directory with xml doc - // zipDir(dirName + "xmldoc.zip", xmlDocDir); - - // Delete directory - // deleteDir(new File(xmlDocDir)); - } catch (Exception ex) { ex.printStackTrace(); System.exit(2); @@ -537,5 +436,4 @@ public Object put(Object key, Object value) { return super.put(key, value); } } - } diff --git a/server/src/com/cloud/api/query/MutualExclusiveIdsManagerBase.java b/server/src/com/cloud/api/query/MutualExclusiveIdsManagerBase.java new file mode 100755 index 0000000000..c7b32225b5 --- /dev/null +++ b/server/src/com/cloud/api/query/MutualExclusiveIdsManagerBase.java @@ -0,0 +1,62 @@ +// +// 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.api.query; + +import java.util.ArrayList; +import java.util.List; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.SearchCriteria; + +public class MutualExclusiveIdsManagerBase extends ManagerBase { + + /*** + * Include ids list in query criteria if ids is not null + * @param sc search criteria, class type SearchCriteria + * @param ids ids list, class type List + */ + protected void setIdsListToSearchCriteria(SearchCriteria sc, List ids){ + if (ids != null && !ids.isEmpty()) { + sc.setParameters("idIN", ids.toArray()); + } + } + + /*** + * Mutually exclusive parameters id and ids for API calls.
+ * Retrieve a list of ids or a list containing id depending on which of them is not null, or null if both are null + * @param id entity id, class type T + * @param ids entities ids, class type List + * @return if id is not null return a list containing id else return ids, if both parameters are null -> return null + * @throws InvalidParameterValueException - if id and ids are both not null + */ + protected List getIdsListFromCmd(T id, List ids){ + List idsList = null; + if (id != null) { + if (ids != null && !ids.isEmpty()) { + throw new InvalidParameterValueException("Specify either id or ids but not both parameters"); + } + idsList = new ArrayList(); + idsList.add(id); + } else { + idsList = ids; + } + return idsList; + } +} diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 0e3f3f2a89..95f260d53c 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -205,7 +205,6 @@ import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; import com.cloud.utils.Ternary; -import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; @@ -222,7 +221,7 @@ import com.cloud.vm.dao.VMInstanceDao; @Component -public class QueryManagerImpl extends ManagerBase implements QueryService, Configurable { +public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements QueryService, Configurable { public static final Logger s_logger = Logger.getLogger(QueryManagerImpl.class); @@ -1578,6 +1577,8 @@ public Pair, Integer> searchForServersInternal(ListHostsCmd cmd Object cluster = cmd.getClusterId(); Object id = cmd.getId(); Object keyword = cmd.getKeyword(); + Object outOfBandManagementEnabled = cmd.isOutOfBandManagementEnabled(); + Object powerState = cmd.getHostOutOfBandManagementPowerState(); Object resourceState = cmd.getResourceState(); Object haHosts = cmd.getHaHost(); Long startIndex = cmd.getStartIndex(); @@ -1596,6 +1597,8 @@ public Pair, Integer> searchForServersInternal(ListHostsCmd cmd sb.and("dataCenterId", sb.entity().getZoneId(), SearchCriteria.Op.EQ); sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ); sb.and("clusterId", sb.entity().getClusterId(), SearchCriteria.Op.EQ); + sb.and("oobmEnabled", sb.entity().isOutOfBandManagementEnabled(), SearchCriteria.Op.EQ); + sb.and("powerState", sb.entity().getOutOfBandManagementPowerState(), SearchCriteria.Op.EQ); sb.and("resourceState", sb.entity().getResourceState(), SearchCriteria.Op.EQ); sb.and("hypervisor_type", sb.entity().getHypervisorType(), SearchCriteria.Op.EQ); @@ -1645,6 +1648,14 @@ public Pair, Integer> searchForServersInternal(ListHostsCmd cmd sc.setParameters("clusterId", cluster); } + if (outOfBandManagementEnabled != null) { + sc.setParameters("oobmEnabled", outOfBandManagementEnabled); + } + + if (powerState != null) { + sc.setParameters("powerState", powerState); + } + if (resourceState != null) { sc.setParameters("resourceState", resourceState); } @@ -1731,6 +1742,8 @@ private Pair, Integer> searchForVolumesInternal(ListVolumesCm Long zoneId = cmd.getZoneId(); Long podId = cmd.getPodId(); + List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); + Ternary domainIdRecursiveListProject = new Ternary( cmd.getDomainId(), cmd.isRecursive(), null); _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, @@ -1754,6 +1767,7 @@ private Pair, Integer> searchForVolumesInternal(ListVolumesCm sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); sb.and("volumeType", sb.entity().getVolumeType(), SearchCriteria.Op.LIKE); sb.and("instanceId", sb.entity().getVmId(), SearchCriteria.Op.EQ); sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); @@ -1790,6 +1804,8 @@ private Pair, Integer> searchForVolumesInternal(ListVolumesCm sc.setParameters("display", display); } + setIdsListToSearchCriteria(sc, ids); + sc.setParameters("systemUse", 1); if (tags != null && !tags.isEmpty()) { @@ -3077,14 +3093,15 @@ private Pair, Integer> searchForTemplatesInternal(ListTempl return searchForTemplatesInternal(id, cmd.getTemplateName(), cmd.getKeyword(), templateFilter, false, null, cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), hypervisorType, showDomr, - cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedTmpl); + cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedTmpl, + cmd.getIds()); } private Pair, Integer> searchForTemplatesInternal(Long templateId, String name, String keyword, TemplateFilter templateFilter, boolean isIso, Boolean bootable, Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean showDomr, boolean onlyReady, List permittedAccounts, Account caller, ListProjectResourcesCriteria listProjectResourcesCriteria, - Map tags, boolean showRemovedTmpl) { + Map tags, boolean showRemovedTmpl, List ids) { // check if zone is configured, if not, just return empty list List hypers = null; @@ -3104,6 +3121,9 @@ private Pair, Integer> searchForTemplatesInternal(Long temp SearchBuilder sb = _templateJoinDao.createSearchBuilder(); sb.select(null, Func.DISTINCT, sb.entity().getTempZonePair()); // select distinct (templateId, zoneId) pair + if (ids != null && !ids.isEmpty()){ + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); + } SearchCriteria sc = sb.create(); // verify templateId parameter and specially handle it @@ -3149,6 +3169,8 @@ private Pair, Integer> searchForTemplatesInternal(Long temp // hypers = _resourceMgr.listAvailHypervisorInZone(null, null); // } + setIdsListToSearchCriteria(sc, ids); + // add criteria for project or not if (listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources) { sc.addAnd("accountType", SearchCriteria.Op.NEQ, Account.ACCOUNT_TYPE_PROJECT); @@ -3386,7 +3408,8 @@ private Pair, Integer> searchForIsosInternal(ListIsosCmd cm return searchForTemplatesInternal(cmd.getId(), cmd.getIsoName(), cmd.getKeyword(), isoFilter, true, cmd.isBootable(), cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), hypervisorType, true, - cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO); + cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO, + null); } @Override diff --git a/server/src/com/cloud/api/query/dao/DomainJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/DomainJoinDaoImpl.java index be3f5b4126..6aecb8159d 100644 --- a/server/src/com/cloud/api/query/dao/DomainJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/DomainJoinDaoImpl.java @@ -110,7 +110,7 @@ public void setResourceLimits(DomainJoinVO domain, boolean fullView, ResourceLim long volumeLimit = ApiDBUtils.findCorrectResourceLimitForDomain(domain.getVolumeLimit(), fullView, ResourceType.volume, domain.getId()); String volumeLimitDisplay = (fullView || volumeLimit == -1) ? "Unlimited" : String.valueOf(volumeLimit); - long volumeTotal = (domain.getVolumeTotal() == 0) ? 0 : domain.getVolumeTotal(); + long volumeTotal = (domain.getVolumeTotal() == null) ? 0 : domain.getVolumeTotal(); String volumeAvail = (fullView || volumeLimit == -1) ? "Unlimited" : String.valueOf(volumeLimit - volumeTotal); response.setVolumeLimit(volumeLimitDisplay); response.setVolumeTotal(volumeTotal); diff --git a/server/src/com/cloud/api/query/dao/GenericDaoBaseWithTagInformation.java b/server/src/com/cloud/api/query/dao/GenericDaoBaseWithTagInformation.java new file mode 100755 index 0000000000..e6760d8a21 --- /dev/null +++ b/server/src/com/cloud/api/query/dao/GenericDaoBaseWithTagInformation.java @@ -0,0 +1,51 @@ +// 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.api.query.dao; + +import org.apache.cloudstack.api.BaseResponseWithTagInformation; + +import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.vo.BaseViewWithTagInformationVO; +import com.cloud.api.query.vo.ResourceTagJoinVO; +import com.cloud.utils.db.GenericDaoBase; + +public abstract class GenericDaoBaseWithTagInformation extends GenericDaoBase { + + /** + * Update tag information on baseResponse + * @param baseView base view containing tag information + * @param baseResponse response to update + */ + protected void addTagInformation(T baseView, Z baseResponse) { + ResourceTagJoinVO vtag = new ResourceTagJoinVO(); + vtag.setId(baseView.getTagId()); + vtag.setUuid(baseView.getTagUuid()); + vtag.setKey(baseView.getTagKey()); + vtag.setValue(baseView.getTagValue()); + vtag.setDomainId(baseView.getTagDomainId()); + vtag.setAccountId(baseView.getTagAccountId()); + vtag.setResourceId(baseView.getTagResourceId()); + vtag.setResourceUuid(baseView.getTagResourceUuid()); + vtag.setResourceType(baseView.getTagResourceType()); + vtag.setCustomer(baseView.getTagCustomer()); + vtag.setAccountName(baseView.getTagAccountName()); + vtag.setDomainName(baseView.getTagDomainName()); + vtag.setDomainUuid(baseView.getTagDomainUuid()); + baseResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); + } + +} diff --git a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java index 970c2b21f1..6c15a8be4d 100644 --- a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java @@ -22,7 +22,6 @@ import java.util.EnumSet; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import javax.inject.Inject; @@ -36,6 +35,7 @@ import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.VgpuResponse; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao; import com.cloud.api.ApiDBUtils; import com.cloud.api.query.vo.HostJoinVO; @@ -43,8 +43,7 @@ import com.cloud.gpu.VGPUTypesVO; import com.cloud.host.Host; import com.cloud.host.HostStats; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor; import com.cloud.storage.StorageStats; import com.cloud.utils.db.GenericDaoBase; @@ -58,7 +57,9 @@ public class HostJoinDaoImpl extends GenericDaoBase implements @Inject private ConfigurationDao _configDao; @Inject - private HostDao hostDao; + private HostDetailsDao hostDetailsDao; + @Inject + private OutOfBandManagementDao outOfBandManagementDao; private final SearchBuilder hostSearch; @@ -189,11 +190,7 @@ public HostResponse newHostResponse(HostJoinVO host, EnumSet detail if (details.contains(HostDetails.all) && host.getHypervisorType() == Hypervisor.HypervisorType.KVM) { //only kvm has the requirement to return host details try { - HostVO h = hostDao.findById(host.getId()); - hostDao.loadDetails(h); - Map hostVoDetails; - hostVoDetails = h.getDetails(); - hostResponse.setDetails(hostVoDetails); + hostResponse.setDetails(hostDetailsDao.findDetails(host.getId())); } catch (Exception e) { s_logger.debug("failed to get host details", e); } @@ -225,6 +222,7 @@ public HostResponse newHostResponse(HostJoinVO host, EnumSet detail } } + hostResponse.setOutOfBandManagementResponse(outOfBandManagementDao.findByHost(host.getId())); hostResponse.setResourceState(host.getResourceState().toString()); // set async job diff --git a/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java index 5444eca6ba..38120af38c 100644 --- a/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/TemplateJoinDaoImpl.java @@ -46,13 +46,12 @@ import com.cloud.user.AccountService; import com.cloud.utils.Pair; import com.cloud.utils.db.Filter; -import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @Component -public class TemplateJoinDaoImpl extends GenericDaoBase implements TemplateJoinDao { +public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation implements TemplateJoinDao { public static final Logger s_logger = Logger.getLogger(TemplateJoinDaoImpl.class); @@ -188,10 +187,7 @@ public TemplateResponse newTemplateResponse(ResponseView view, TemplateJoinVO te // update tag information long tag_id = template.getTagId(); if (tag_id > 0) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - templateResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(template, templateResponse); } templateResponse.setObjectName("template"); @@ -257,10 +253,7 @@ public TemplateResponse setTemplateResponse(ResponseView view, TemplateResponse // update tag information long tag_id = template.getTagId(); if (tag_id > 0) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - templateResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(template, templateResponse); } return templateResponse; diff --git a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index 7983065f31..106cd25a5b 100644 --- a/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -27,9 +27,6 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.ApiConstants.VMDetails; import org.apache.cloudstack.api.ResponseObject.ResponseView; @@ -38,19 +35,18 @@ import org.apache.cloudstack.api.response.SecurityGroupResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; import com.cloud.api.ApiDBUtils; -import com.cloud.api.query.vo.ResourceTagJoinVO; import com.cloud.api.query.vo.UserVmJoinVO; import com.cloud.gpu.GPU; -import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.service.ServiceOfferingDetailsVO; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.User; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; -import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.vm.UserVmDetailVO; @@ -61,7 +57,7 @@ import com.cloud.vm.dao.UserVmDetailsDao; @Component -public class UserVmJoinDaoImpl extends GenericDaoBase implements UserVmJoinDao { +public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation implements UserVmJoinDao { public static final Logger s_logger = Logger.getLogger(UserVmJoinDaoImpl.class); @Inject @@ -202,20 +198,16 @@ public UserVmResponse newUserVmResponse(ResponseView view, String objectName, Us VmStats vmStats = ApiDBUtils.getVmStatistics(userVm.getId()); if (vmStats != null) { userVmResponse.setCpuUsed(new DecimalFormat("#.##").format(vmStats.getCPUUtilization()) + "%"); - userVmResponse.setNetworkKbsRead((long)vmStats.getNetworkReadKBs()); - userVmResponse.setNetworkKbsWrite((long)vmStats.getNetworkWriteKBs()); + userVmResponse.setDiskKbsRead((long)vmStats.getDiskReadKBs()); + userVmResponse.setDiskKbsWrite((long)vmStats.getDiskWriteKBs()); + userVmResponse.setDiskIORead((long)vmStats.getDiskReadIOs()); + userVmResponse.setDiskIOWrite((long)vmStats.getDiskWriteIOs()); + userVmResponse.setMemoryKBs((long)vmStats.getMemoryKBs()); + userVmResponse.setMemoryIntFreeKBs((long)vmStats.getIntFreeMemoryKBs()); + userVmResponse.setMemoryTargetKBs((long)vmStats.getTargetMemoryKBs()); - if ((userVm.getHypervisorType() != null) && (userVm.getHypervisorType().equals(HypervisorType.KVM) || userVm.getHypervisorType().equals(HypervisorType.XenServer))) { // support KVM and XenServer only util 2013.06.25 - userVmResponse.setDiskKbsRead((long)vmStats.getDiskReadKBs()); - - userVmResponse.setDiskKbsWrite((long)vmStats.getDiskWriteKBs()); - - userVmResponse.setDiskIORead((long)vmStats.getDiskReadIOs()); - - userVmResponse.setDiskIOWrite((long)vmStats.getDiskWriteIOs()); - } } } @@ -283,10 +275,7 @@ public UserVmResponse newUserVmResponse(ResponseView view, String objectName, Us // update tag information long tag_id = userVm.getTagId(); if (tag_id > 0 && !userVmResponse.containTag(tag_id)) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - userVmResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(userVm, userVmResponse); } if (details.contains(VMDetails.all) || details.contains(VMDetails.affgrp)) { @@ -383,10 +372,7 @@ public UserVmResponse setUserVmResponse(ResponseView view, UserVmResponse userVm long tag_id = uvo.getTagId(); if (tag_id > 0 && !userVmData.containTag(tag_id)) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - userVmData.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(uvo, userVmData); } Long affinityGroupId = uvo.getAffinityGroupId(); diff --git a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java index 6d8a8ab552..73e0c6d6cd 100644 --- a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java +++ b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java @@ -29,7 +29,6 @@ import com.cloud.api.ApiDBUtils; import com.cloud.api.ApiResponseHelper; -import com.cloud.api.query.vo.ResourceTagJoinVO; import com.cloud.api.query.vo.VolumeJoinVO; import com.cloud.offering.ServiceOffering; import com.cloud.storage.Storage; @@ -37,12 +36,11 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.Volume; import com.cloud.user.AccountManager; -import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @Component -public class VolumeJoinDaoImpl extends GenericDaoBase implements VolumeJoinDao { +public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation implements VolumeJoinDao { public static final Logger s_logger = Logger.getLogger(VolumeJoinDaoImpl.class); @Inject @@ -81,14 +79,18 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) volResponse.setZoneId(volume.getDataCenterUuid()); volResponse.setZoneName(volume.getDataCenterName()); - volResponse.setVolumeType(volume.getVolumeType().toString()); + if (volume.getVolumeType() != null) { + volResponse.setVolumeType(volume.getVolumeType().toString()); + } volResponse.setDeviceId(volume.getDeviceId()); long instanceId = volume.getVmId(); if (instanceId > 0 && volume.getState() != Volume.State.Destroy) { volResponse.setVirtualMachineId(volume.getVmUuid()); volResponse.setVirtualMachineName(volume.getVmName()); - volResponse.setVirtualMachineState(volume.getVmState().toString()); + if (volume.getVmState() != null) { + volResponse.setVirtualMachineState(volume.getVmState().toString()); + } if (volume.getVmDisplayName() != null) { volResponse.setVirtualMachineDisplayName(volume.getVmDisplayName()); } else { @@ -96,7 +98,9 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) } } - volResponse.setProvisioningType(volume.getProvisioningType().toString()); + if (volume.getProvisioningType() != null) { + volResponse.setProvisioningType(volume.getProvisioningType().toString()); + } // Show the virtual size of the volume volResponse.setSize(volume.getSize()); @@ -105,7 +109,9 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) volResponse.setMaxIops(volume.getMaxIops()); volResponse.setCreated(volume.getCreated()); - volResponse.setState(volume.getState().toString()); + if (volume.getState() != null) { + volResponse.setState(volume.getState().toString()); + } if (volume.getState() == Volume.State.UploadOp) { // com.cloud.storage.VolumeHostVO volumeHostRef = // ApiDBUtils.findVolumeHostRef(volume.getId(), @@ -213,10 +219,7 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) // update tag information long tag_id = volume.getTagId(); if (tag_id > 0) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - volResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(volume, volResponse); } volResponse.setExtractable(isExtractable); @@ -245,10 +248,7 @@ public VolumeResponse newVolumeResponse(ResponseView view, VolumeJoinVO volume) public VolumeResponse setVolumeResponse(ResponseView view, VolumeResponse volData, VolumeJoinVO vol) { long tag_id = vol.getTagId(); if (tag_id > 0) { - ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id); - if (vtag != null) { - volData.addTag(ApiDBUtils.newResourceTagResponse(vtag, false)); - } + addTagInformation(vol, volData); } return volData; } diff --git a/server/src/com/cloud/api/query/vo/AccountJoinVO.java b/server/src/com/cloud/api/query/vo/AccountJoinVO.java index 8d642edd7c..f251abc472 100644 --- a/server/src/com/cloud/api/query/vo/AccountJoinVO.java +++ b/server/src/com/cloud/api/query/vo/AccountJoinVO.java @@ -48,6 +48,9 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident @Column(name = "type") private short type; + @Column(name = "role_id") + private Long roleId; + @Column(name = "state") @Enumerated(value = EnumType.STRING) private State state; @@ -202,6 +205,10 @@ public short getType() { return type; } + public Long getRoleId() { + return roleId; + } + public State getState() { return state; } diff --git a/server/src/com/cloud/api/query/vo/BaseViewWithTagInformationVO.java b/server/src/com/cloud/api/query/vo/BaseViewWithTagInformationVO.java new file mode 100755 index 0000000000..ec2947ae1f --- /dev/null +++ b/server/src/com/cloud/api/query/vo/BaseViewWithTagInformationVO.java @@ -0,0 +1,183 @@ +// 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.api.query.vo; + +import java.io.Serializable; +import javax.persistence.Column; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; + +import com.cloud.server.ResourceTag.ResourceObjectType; + +@MappedSuperclass +public abstract class BaseViewWithTagInformationVO extends BaseViewVO implements Serializable { + + @Id + @Column(name = "id") + private long id; + + @Column(name = "tag_id") + private long tagId; + + @Column(name = "tag_uuid") + private String tagUuid; + + @Column(name = "tag_key") + private String tagKey; + + @Column(name = "tag_value") + private String tagValue; + + @Column(name = "tag_domain_id") + private long tagDomainId; + + @Column(name = "tag_account_id") + private long tagAccountId; + + @Column(name = "tag_resource_id") + private long tagResourceId; + + @Column(name = "tag_resource_uuid") + private String tagResourceUuid; + + @Column(name = "tag_resource_type") + @Enumerated(value = EnumType.STRING) + private ResourceObjectType tagResourceType; + + @Column(name = "tag_customer") + private String tagCustomer; + + @Column(name = "tag_account_name") + private String tagAccountName; + + @Column(name = "tag_domain_uuid") + private String tagDomainUuid; + + @Column(name = "tag_domain_name") + private String tagDomainName; + + public long getTagId() { + return tagId; + } + + public void setTagId(long tagId) { + this.tagId = tagId; + } + + public String getTagUuid() { + return tagUuid; + } + + public void setTagUuid(String tagUuid) { + this.tagUuid = tagUuid; + } + + public String getTagKey() { + return tagKey; + } + + public void setTagKey(String tagKey) { + this.tagKey = tagKey; + } + + public String getTagValue() { + return tagValue; + } + + public void setTagValue(String tagValue) { + this.tagValue = tagValue; + } + + public long getTagDomainId() { + return tagDomainId; + } + + public void setTagDomainId(long tagDomainId) { + this.tagDomainId = tagDomainId; + } + + public long getTagAccountId() { + return tagAccountId; + } + + public void setTagAccountId(long tagAccountId) { + this.tagAccountId = tagAccountId; + } + + public long getTagResourceId() { + return tagResourceId; + } + + public void setTagResourceId(long tagResourceId) { + this.tagResourceId = tagResourceId; + } + + public String getTagResourceUuid() { + return tagResourceUuid; + } + + public void setTagResourceUuid(String tagResourceUuid) { + this.tagResourceUuid = tagResourceUuid; + } + + public ResourceObjectType getTagResourceType() { + return tagResourceType; + } + + public void setTagResourceType(ResourceObjectType tagResourceType) { + this.tagResourceType = tagResourceType; + } + + public String getTagCustomer() { + return tagCustomer; + } + + public void setTagCustomer(String tagCustomer) { + this.tagCustomer = tagCustomer; + } + + public String getTagAccountName() { + return tagAccountName; + } + + public void setTagAccountName(String tagAccountName) { + this.tagAccountName = tagAccountName; + } + + public String getTagDomainUuid() { + return tagDomainUuid; + } + + public void setTagDomainUuid(String tagDomainUuid) { + this.tagDomainUuid = tagDomainUuid; + } + + public String getTagDomainName() { + return tagDomainName; + } + + public void setTagDomainName(String tagDomainName) { + this.tagDomainName = tagDomainName; + } + + public long getId() { + return id; + } + +} diff --git a/server/src/com/cloud/api/query/vo/HostJoinVO.java b/server/src/com/cloud/api/query/vo/HostJoinVO.java index 48ac531ce8..dcd058fce1 100644 --- a/server/src/com/cloud/api/query/vo/HostJoinVO.java +++ b/server/src/com/cloud/api/query/vo/HostJoinVO.java @@ -36,6 +36,7 @@ import com.cloud.org.Cluster; import com.cloud.resource.ResourceState; import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; /** * Host DB view. @@ -91,6 +92,13 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity @Column(name = GenericDao.REMOVED_COLUMN) private Date removed; + @Column(name = "oobm_enabled") + private boolean outOfBandManagementEnabled = false; + + @Column(name = "oobm_power_state") + @Enumerated(value = EnumType.STRING) + private OutOfBandManagement.PowerState outOfBandManagementPowerState; + @Column(name = "resource_state") @Enumerated(value = EnumType.STRING) private ResourceState resourceState; @@ -244,6 +252,14 @@ public Date getRemoved() { return removed; } + public boolean isOutOfBandManagementEnabled() { + return outOfBandManagementEnabled; + } + + public OutOfBandManagement.PowerState getOutOfBandManagementPowerState() { + return outOfBandManagementPowerState; + } + public ResourceState getResourceState() { return resourceState; } diff --git a/server/src/com/cloud/api/query/vo/ImageStoreJoinVO.java b/server/src/com/cloud/api/query/vo/ImageStoreJoinVO.java index 99f61c3661..6d9f03842f 100644 --- a/server/src/com/cloud/api/query/vo/ImageStoreJoinVO.java +++ b/server/src/com/cloud/api/query/vo/ImageStoreJoinVO.java @@ -50,7 +50,7 @@ public class ImageStoreJoinVO extends BaseViewVO implements InternalIdentity, Id @Column(name = "name") private String name; - @Column(name = "url") + @Column(name = "url", length = 2048) private String url; @Column(name = "protocol") diff --git a/server/src/com/cloud/api/query/vo/ResourceTagJoinVO.java b/server/src/com/cloud/api/query/vo/ResourceTagJoinVO.java index 2c1ff47509..6758552ed3 100644 --- a/server/src/com/cloud/api/query/vo/ResourceTagJoinVO.java +++ b/server/src/com/cloud/api/query/vo/ResourceTagJoinVO.java @@ -184,4 +184,56 @@ public String getCustomer() { public Class getEntityType() { return ResourceTag.class; } + + public void setId(long id) { + this.id = id; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public void setKey(String key) { + this.key = key; + } + + public void setValue(String value) { + this.value = value; + } + + public void setResourceId(long resourceId) { + this.resourceId = resourceId; + } + + public void setResourceUuid(String resourceUuid) { + this.resourceUuid = resourceUuid; + } + + public void setResourceType(ResourceObjectType resourceType) { + this.resourceType = resourceType; + } + + public void setAccountId(long accountId) { + this.accountId = accountId; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public void setDomainId(long domainId) { + this.domainId = domainId; + } + + public void setDomainUuid(String domainUuid) { + this.domainUuid = domainUuid; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + public void setCustomer(String customer) { + this.customer = customer; + } } diff --git a/server/src/com/cloud/api/query/vo/TemplateJoinVO.java b/server/src/com/cloud/api/query/vo/TemplateJoinVO.java index 834a9cedd0..43a9c3b09c 100644 --- a/server/src/com/cloud/api/query/vo/TemplateJoinVO.java +++ b/server/src/com/cloud/api/query/vo/TemplateJoinVO.java @@ -22,7 +22,6 @@ import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; -import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; @@ -30,7 +29,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.server.ResourceTag.ResourceObjectType; import com.cloud.storage.ScopeType; import com.cloud.storage.Storage; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; @@ -40,11 +38,7 @@ @Entity @Table(name = "template_view") -public class TemplateJoinVO extends BaseViewVO implements ControlledViewEntity { - - @Id - @Column(name = "id") - private long id; +public class TemplateJoinVO extends BaseViewWithTagInformationVO implements ControlledViewEntity { @Column(name = "uuid") private String uuid; @@ -218,37 +212,6 @@ public class TemplateJoinVO extends BaseViewVO implements ControlledViewEntity { @Column(name = "detail_value") private String detailValue; - @Column(name = "tag_id") - private long tagId; - - @Column(name = "tag_uuid") - private String tagUuid; - - @Column(name = "tag_key") - private String tagKey; - - @Column(name = "tag_value") - private String tagValue; - - @Column(name = "tag_domain_id") - private long tagDomainId; - - @Column(name = "tag_account_id") - private long tagAccountId; - - @Column(name = "tag_resource_id") - private long tagResourceId; - - @Column(name = "tag_resource_uuid") - private String tagResourceUuid; - - @Column(name = "tag_resource_type") - @Enumerated(value = EnumType.STRING) - private ResourceObjectType tagResourceType; - - @Column(name = "tag_customer") - private String tagCustomer; - @Column(name = "state") @Enumerated(EnumType.STRING) ObjectInDataStoreStateMachine.State state; @@ -259,11 +222,6 @@ public class TemplateJoinVO extends BaseViewVO implements ControlledViewEntity { public TemplateJoinVO() { } - @Override - public long getId() { - return id; - } - @Override public String getUuid() { return uuid; @@ -343,46 +301,6 @@ public Storage.TemplateType getTemplateType() { return templateType; } - public long getTagId() { - return tagId; - } - - public String getTagUuid() { - return tagUuid; - } - - public String getTagKey() { - return tagKey; - } - - public String getTagValue() { - return tagValue; - } - - public long getTagDomainId() { - return tagDomainId; - } - - public long getTagAccountId() { - return tagAccountId; - } - - public long getTagResourceId() { - return tagResourceId; - } - - public String getTagResourceUuid() { - return tagResourceUuid; - } - - public ResourceObjectType getTagResourceType() { - return tagResourceType; - } - - public String getTagCustomer() { - return tagCustomer; - } - public long getDataCenterId() { return dataCenterId; } @@ -547,4 +465,9 @@ public State getTemplateState() { public Class getEntityType() { return VirtualMachineTemplate.class; } + + public void setAccountId(long accountId) { + this.accountId = accountId; + } + } diff --git a/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java b/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java index 0e66ca022c..e6b1ace096 100644 --- a/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserAccountJoinVO.java @@ -96,6 +96,9 @@ public class UserAccountJoinVO extends BaseViewVO implements InternalIdentity, I @Column(name = "account_type") private short accountType; + @Column(name = "account_role_id") + private Long accountRoleId; + @Column(name = "domain_id") private long domainId; @@ -149,6 +152,10 @@ public short getAccountType() { return accountType; } + public Long getAccountRoleId() { + return accountRoleId; + } + public long getDomainId() { return domainId; } diff --git a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java index 54a48fb06a..7ff557c8fc 100644 --- a/server/src/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/com/cloud/api/query/vo/UserVmJoinVO.java @@ -20,6 +20,7 @@ import java.util.Date; import java.util.Map; +import javax.persistence.AttributeOverride; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; @@ -31,7 +32,6 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Network.GuestType; import com.cloud.network.Networks.TrafficType; -import com.cloud.server.ResourceTag.ResourceObjectType; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Volume; import com.cloud.utils.db.GenericDao; @@ -40,7 +40,8 @@ @Entity @Table(name = "user_vm_view") -public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { +@AttributeOverride( name="id", column = @Column(name = "id", updatable = false, nullable = false) ) +public class UserVmJoinVO extends BaseViewWithTagInformationVO implements ControlledViewEntity { @Id @Column(name = "id", updatable = false, nullable = false) @@ -346,37 +347,6 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { @Column(name = "job_status") private int jobStatus; - @Column(name = "tag_id") - private long tagId; - - @Column(name = "tag_uuid") - private String tagUuid; - - @Column(name = "tag_key") - private String tagKey; - - @Column(name = "tag_value") - private String tagValue; - - @Column(name = "tag_domain_id") - private long tagDomainId; - - @Column(name = "tag_account_id") - private long tagAccountId; - - @Column(name = "tag_resource_id") - private long tagResourceId; - - @Column(name = "tag_resource_uuid") - private String tagResourceUuid; - - @Column(name = "tag_resource_type") - @Enumerated(value = EnumType.STRING) - private ResourceObjectType tagResourceType; - - @Column(name = "tag_customer") - private String tagCustomer; - @Column(name = "affinity_group_id") private long affinityGroupId; @@ -404,11 +374,6 @@ public class UserVmJoinVO extends BaseViewVO implements ControlledViewEntity { public UserVmJoinVO() { } - @Override - public long getId() { - return id; - } - @Override public String getUuid() { return uuid; @@ -776,46 +741,6 @@ public String getKeypairName() { return keypairName; } - public long getTagId() { - return tagId; - } - - public String getTagUuid() { - return tagUuid; - } - - public String getTagKey() { - return tagKey; - } - - public String getTagValue() { - return tagValue; - } - - public long getTagDomainId() { - return tagDomainId; - } - - public long getTagAccountId() { - return tagAccountId; - } - - public long getTagResourceId() { - return tagResourceId; - } - - public String getTagResourceUuid() { - return tagResourceUuid; - } - - public ResourceObjectType getTagResourceType() { - return tagResourceType; - } - - public String getTagCustomer() { - return tagCustomer; - } - public boolean isLimitCpuUse() { return limitCpuUse; } @@ -865,7 +790,7 @@ public int getJobStatus() { @Override public String toString() { if (toString == null) { - toString = new StringBuilder("VM[").append(id).append("|").append(name).append("]").toString(); + toString = new StringBuilder("VM[").append(getId()).append("|").append(name).append("]").toString(); } return toString; } @@ -907,4 +832,5 @@ public Boolean isDynamicallyScalable() { public Class getEntityType() { return VirtualMachine.class; } + } diff --git a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java index d9c482ce0a..77785b1de5 100644 --- a/server/src/com/cloud/api/query/vo/VolumeJoinVO.java +++ b/server/src/com/cloud/api/query/vo/VolumeJoinVO.java @@ -22,13 +22,11 @@ import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; -import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.server.ResourceTag.ResourceObjectType; import com.cloud.storage.Storage; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.Volume; @@ -37,11 +35,7 @@ @Entity @Table(name = "volume_view") -public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { - - @Id - @Column(name = "id") - private long id; +public class VolumeJoinVO extends BaseViewWithTagInformationVO implements ControlledViewEntity { @Column(name = "uuid") private String uuid; @@ -252,37 +246,6 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { @Column(name = "job_status") private int jobStatus; - @Column(name = "tag_id") - private long tagId; - - @Column(name = "tag_uuid") - private String tagUuid; - - @Column(name = "tag_key") - private String tagKey; - - @Column(name = "tag_value") - private String tagValue; - - @Column(name = "tag_domain_id") - private long tagDomainId; - - @Column(name = "tag_account_id") - private long tagAccountId; - - @Column(name = "tag_resource_id") - private long tagResourceId; - - @Column(name = "tag_resource_uuid") - private String tagResourceUuid; - - @Column(name = "tag_resource_type") - @Enumerated(value = EnumType.STRING) - private ResourceObjectType tagResourceType; - - @Column(name = "tag_customer") - private String tagCustomer; - @Column(name = "display_volume", updatable = true, nullable = false) protected boolean displayVolume; @@ -295,11 +258,6 @@ public class VolumeJoinVO extends BaseViewVO implements ControlledViewEntity { public VolumeJoinVO() { } - @Override - public long getId() { - return id; - } - @Override public String getUuid() { return uuid; @@ -563,46 +521,6 @@ public int getJobStatus() { return jobStatus; } - public long getTagId() { - return tagId; - } - - public String getTagUuid() { - return tagUuid; - } - - public String getTagKey() { - return tagKey; - } - - public String getTagValue() { - return tagValue; - } - - public long getTagDomainId() { - return tagDomainId; - } - - public long getTagAccountId() { - return tagAccountId; - } - - public long getTagResourceId() { - return tagResourceId; - } - - public String getTagResourceUuid() { - return tagResourceUuid; - } - - public ResourceObjectType getTagResourceType() { - return tagResourceType; - } - - public String getTagCustomer() { - return tagCustomer; - } - public long getDataCenterId() { return dataCenterId; } @@ -636,4 +554,5 @@ public String getChainInfo() { public Class getEntityType() { return Volume.class; } + } diff --git a/server/src/com/cloud/api/response/ApiResponseSerializer.java b/server/src/com/cloud/api/response/ApiResponseSerializer.java index 59426e6574..2b9717de1e 100644 --- a/server/src/com/cloud/api/response/ApiResponseSerializer.java +++ b/server/src/com/cloud/api/response/ApiResponseSerializer.java @@ -251,7 +251,7 @@ private static void serializeResponseObjFieldsXML(StringBuilder sb, StringBuilde boolean permittedParameter = false; Account caller = CallContext.current().getCallingAccount(); for (RoleType allowedRole : allowedRoles) { - if (allowedRole.getValue() == caller.getType()) { + if (allowedRole.getAccountType() == caller.getType()) { permittedParameter = true; break; } diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index 55ed9171c9..d0ae3e9969 100644 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -549,28 +549,35 @@ public long getAllocatedPoolCapacity(StoragePoolVO pool, VMTemplateVO templateFo return getUsedBytes(pool); } else { - // Get size for all the non-destroyed volumes + // Get size for all the non-destroyed volumes. Pair sizes = _volumeDao.getNonDestroyedCountAndTotalByPool(pool.getId()); totalAllocatedSize = sizes.second() + sizes.first() * _extraBytesPerVolume; } - // Get size for VM Snapshots - totalAllocatedSize = totalAllocatedSize + _volumeDao.getVMSnapshotSizeByPool(pool.getId()); + // Get size for VM Snapshots. + totalAllocatedSize += _volumeDao.getVMSnapshotSizeByPool(pool.getId()); - // Iterate through all templates on this storage pool - boolean tmpinstalled = false; - List templatePoolVOs; - templatePoolVOs = _templatePoolDao.listByPoolId(pool.getId()); + boolean tmpInstalled = false; + // Iterate through all templates on this storage pool. + List templatePoolVOs = _templatePoolDao.listByPoolId(pool.getId()); for (VMTemplateStoragePoolVO templatePoolVO : templatePoolVOs) { - if ((templateForVmCreation != null) && !tmpinstalled && (templatePoolVO.getTemplateId() == templateForVmCreation.getId())) { - tmpinstalled = true; + if ((templateForVmCreation != null) && !tmpInstalled && (templatePoolVO.getTemplateId() == templateForVmCreation.getId())) { + tmpInstalled = true; } + long templateSize = templatePoolVO.getTemplateSize(); + totalAllocatedSize += templateSize + _extraBytesPerVolume; } + if ((templateForVmCreation != null) && !tmpInstalled) { + long templateForVmCreationSize = templateForVmCreation.getSize() != null ? templateForVmCreation.getSize() : 0; + + totalAllocatedSize += templateForVmCreationSize + _extraBytesPerVolume; + } + return totalAllocatedSize; } @@ -981,6 +988,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { // TODO Auto-generated method stub @@ -993,6 +1004,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { // TODO Auto-generated method stub @@ -1082,6 +1101,6 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { return new ConfigKey[] {CpuOverprovisioningFactor, MemOverprovisioningFactor, StorageCapacityDisableThreshold, StorageOverprovisioningFactor, - StorageAllocatedCapacityDisableThreshold}; + StorageAllocatedCapacityDisableThreshold, StorageOperationsExcludeCluster}; } } diff --git a/server/src/com/cloud/capacity/ComputeCapacityListener.java b/server/src/com/cloud/capacity/ComputeCapacityListener.java index d8a3e6a893..453960de5c 100644 --- a/server/src/com/cloud/capacity/ComputeCapacityListener.java +++ b/server/src/com/cloud/capacity/ComputeCapacityListener.java @@ -55,6 +55,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host server, StartupCommand startup, boolean forRebalance) throws ConnectionException { if (!(startup instanceof StartupRoutingCommand)) { @@ -68,6 +72,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; diff --git a/server/src/com/cloud/capacity/StorageCapacityListener.java b/server/src/com/cloud/capacity/StorageCapacityListener.java index f83cbd3a53..e2d5a5d0aa 100644 --- a/server/src/com/cloud/capacity/StorageCapacityListener.java +++ b/server/src/com/cloud/capacity/StorageCapacityListener.java @@ -58,6 +58,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host server, StartupCommand startup, boolean forRebalance) throws ConnectionException { @@ -81,6 +85,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; diff --git a/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java index b473f7e7f3..70afd8ab1d 100644 --- a/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java +++ b/server/src/com/cloud/consoleproxy/AgentBasedStandaloneConsoleProxyManager.java @@ -18,7 +18,6 @@ import java.util.List; - import org.apache.log4j.Logger; import com.cloud.host.Host; @@ -26,6 +25,10 @@ import com.cloud.info.ConsoleProxyInfo; import com.cloud.vm.UserVmVO; +/** + * This class is intended to replace the use of console proxy VMs managed by the Apache CloudStack (ACS) + * to non ACS console proxy services. The documentation that describe its use and requirements can be found in QuickCloud. + */ public class AgentBasedStandaloneConsoleProxyManager extends AgentBasedConsoleProxyManager { private static final Logger s_logger = Logger.getLogger(AgentBasedStandaloneConsoleProxyManager.class); @@ -58,26 +61,30 @@ public ConsoleProxyInfo assignProxy(long dataCenterId, long userVmId) { } } if (allocatedHost == null) { - if (s_logger.isDebugEnabled()) + if (s_logger.isDebugEnabled()) { s_logger.debug("Failed to find a console proxy at host: " + host.getName() + " and in the pod: " + host.getPodId() + " to user vm " + userVmId); + } return null; } - if (s_logger.isDebugEnabled()) - s_logger.debug("Assign standalone console proxy running at " + allocatedHost.getName() + " to user vm " + userVmId + " with public IP " + - allocatedHost.getPublicIpAddress()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Assign standalone console proxy running at " + allocatedHost.getName() + " to user vm " + userVmId + " with public IP " + + allocatedHost.getPublicIpAddress()); + } // only private IP, public IP, host id have meaningful values, rest of all are place-holder values String publicIp = allocatedHost.getPublicIpAddress(); if (publicIp == null) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Host " + allocatedHost.getName() + "/" + allocatedHost.getPrivateIpAddress() + - " does not have public interface, we will return its private IP for cosole proxy."); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Host " + allocatedHost.getName() + "/" + allocatedHost.getPrivateIpAddress() + + " does not have public interface, we will return its private IP for cosole proxy."); + } publicIp = allocatedHost.getPrivateIpAddress(); } int urlPort = _consoleProxyUrlPort; - if (allocatedHost.getProxyPort() != null && allocatedHost.getProxyPort().intValue() > 0) + if (allocatedHost.getProxyPort() != null && allocatedHost.getProxyPort().intValue() > 0) { urlPort = allocatedHost.getProxyPort().intValue(); + } return new ConsoleProxyInfo(_sslEnabled, publicIp, _consoleProxyPort, urlPort, _consoleProxyUrlDomain); } else { diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java b/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java index 2c1bbd6732..77c9d5a17a 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java @@ -63,6 +63,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) { _proxyMgr.onAgentConnect(host, cmd); @@ -78,6 +82,14 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return true; diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index f3766c339c..1817ade287 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -41,6 +41,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -666,35 +667,88 @@ public ConsoleProxyVO startNew(long dataCenterId) throws ConcurrentOperationExce return null; } - protected Map createProxyInstance(long dataCenterId, VMTemplateVO template) throws ConcurrentOperationException { - - long id = _consoleProxyDao.getNextInSequence(Long.class, "id"); - String name = VirtualMachineName.getConsoleProxyName(id, _instance); - DataCenterVO dc = _dcDao.findById(dataCenterId); - Account systemAcct = _accountMgr.getSystemAccount(); + /** + * Get the default network for the console proxy VM, based on the zone it is in. Delegates to + * either {@link #getDefaultNetworkForZone(DataCenter)} or {@link #getDefaultNetworkForAdvancedSGZone(DataCenter)}, + * depending on the zone network type and whether or not security groups are enabled in the zone. + * @param dc - The zone (DataCenter) of the console proxy VM. + * @return The default network for use with the console proxy VM. + */ + protected NetworkVO getDefaultNetworkForCreation(DataCenter dc) { + if (dc.getNetworkType() == NetworkType.Advanced) { + return getDefaultNetworkForAdvancedZone(dc); + } else { + return getDefaultNetworkForBasicZone(dc); + } + } - DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); + /** + * Get default network for a console proxy VM starting up in an advanced zone. If the zone + * is security group-enabled, the first network found that supports SG services is returned. + * If the zone is not SG-enabled, the Public network is returned. + * @param dc - The zone. + * @return The selected default network. + * @throws CloudRuntimeException - If the zone is not a valid choice or a network couldn't be found. + */ + protected NetworkVO getDefaultNetworkForAdvancedZone(DataCenter dc) { + if (dc.getNetworkType() != NetworkType.Advanced) { + throw new CloudRuntimeException("Zone " + dc + " is not advanced."); + } - NetworkVO defaultNetwork = null; - if (dc.getNetworkType() == NetworkType.Advanced && dc.isSecurityGroupEnabled()) { - List networks = _networkDao.listByZoneSecurityGroup(dataCenterId); - if (networks == null || networks.size() == 0) { + if (dc.isSecurityGroupEnabled()) { + List networks = _networkDao.listByZoneSecurityGroup(dc.getId()); + if (CollectionUtils.isEmpty(networks)) { throw new CloudRuntimeException("Can not found security enabled network in SG Zone " + dc); } - defaultNetwork = networks.get(0); - } else { + + return networks.get(0); + } + else { TrafficType defaultTrafficType = TrafficType.Public; - if (dc.getNetworkType() == NetworkType.Basic || dc.isSecurityGroupEnabled()) { - defaultTrafficType = TrafficType.Guest; - } - List defaultNetworks = _networkDao.listByZoneAndTrafficType(dataCenterId, defaultTrafficType); + List defaultNetworks = _networkDao.listByZoneAndTrafficType(dc.getId(), defaultTrafficType); // api should never allow this situation to happen if (defaultNetworks.size() != 1) { throw new CloudRuntimeException("Found " + defaultNetworks.size() + " networks of type " + defaultTrafficType + " when expect to find 1"); } - defaultNetwork = defaultNetworks.get(0); + + return defaultNetworks.get(0); } + } + + /** + * Get default network for console proxy VM for starting up in a basic zone. Basic zones select + * the Guest network whether or not the zone is SG-enabled. + * @param dc - The zone. + * @return The default network according to the zone's network selection rules. + * @throws CloudRuntimeException - If the zone is not a valid choice or a network couldn't be found. + */ + protected NetworkVO getDefaultNetworkForBasicZone(DataCenter dc) { + if (dc.getNetworkType() != NetworkType.Basic) { + throw new CloudRuntimeException("Zone " + dc + "is not basic."); + } + + TrafficType defaultTrafficType = TrafficType.Guest; + List defaultNetworks = _networkDao.listByZoneAndTrafficType(dc.getId(), defaultTrafficType); + + // api should never allow this situation to happen + if (defaultNetworks.size() != 1) { + throw new CloudRuntimeException("Found " + defaultNetworks.size() + " networks of type " + defaultTrafficType + " when expect to find 1"); + } + + return defaultNetworks.get(0); + } + + protected Map createProxyInstance(long dataCenterId, VMTemplateVO template) throws ConcurrentOperationException { + + long id = _consoleProxyDao.getNextInSequence(Long.class, "id"); + String name = VirtualMachineName.getConsoleProxyName(id, _instance); + DataCenterVO dc = _dcDao.findById(dataCenterId); + Account systemAcct = _accountMgr.getSystemAccount(); + + DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); + + NetworkVO defaultNetwork = getDefaultNetworkForCreation(dc); List offerings = _networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemControlNetwork, NetworkOffering.SystemManagementNetwork); @@ -1127,7 +1181,7 @@ public boolean rebootProxy(long proxyVmId) { } if (proxy.getState() == State.Running && proxy.getHostId() != null) { - final RebootCommand cmd = new RebootCommand(proxy.getInstanceName()); + final RebootCommand cmd = new RebootCommand(proxy.getInstanceName(), _itMgr.getExecuteInSequence(proxy.getHypervisorType())); final Answer answer = _agentMgr.easySend(proxy.getHostId(), cmd); if (answer != null && answer.getResult()) { diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index f5d2af92be..ef0ad19079 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -899,6 +899,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { if (!(cmd instanceof StartupRoutingCommand)) { @@ -920,6 +924,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { // TODO Auto-generated method stub @@ -1222,7 +1234,8 @@ public int compare(Volume v1, Volume v2) { requestVolumes = new ArrayList(); requestVolumes.add(vol); - if (!_storageMgr.storagePoolHasEnoughSpace(requestVolumes, potentialSPool)) + if (!_storageMgr.storagePoolHasEnoughIops(requestVolumes, potentialSPool) || + !_storageMgr.storagePoolHasEnoughSpace(requestVolumes, potentialSPool, potentialHost.getClusterId())) continue; volumeAllocationMap.put(potentialSPool, requestVolumes); } diff --git a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java index ac7dbd17b8..53d79f7107 100644 --- a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java +++ b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java @@ -62,6 +62,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.server.ManagementServer; +import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StorageManager; import com.cloud.storage.dao.GuestOSCategoryDao; @@ -264,6 +265,13 @@ public void scheduleRestartForVmsOnHost(final HostVO host, boolean investigate) "Host [" + hostDesc + "] is down." + ((sb != null) ? sb.toString() : "")); for (VMInstanceVO vm : reorderedVMList) { + ServiceOfferingVO vmOffering = _serviceOfferingDao.findById(vm.getServiceOfferingId()); + if (vmOffering.getUseLocalStorage()) { + if (s_logger.isDebugEnabled()){ + s_logger.debug("Skipping HA on vm " + vm + ", because it uses local storage. Its fate is tied to the host."); + } + continue; + } if (s_logger.isDebugEnabled()) { s_logger.debug("Notifying HA Mgr of to restart vm " + vm.getId() + "-" + vm.getInstanceName()); } diff --git a/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java b/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java index 4bdb2bc1d4..2aa9b04b2a 100644 --- a/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java +++ b/server/src/com/cloud/hypervisor/CloudZonesStartupProcessor.java @@ -44,9 +44,11 @@ import com.cloud.dc.dao.DataCenterDetailsDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.exception.ConnectionException; +import com.cloud.host.DetailVO; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; +import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.exception.CloudRuntimeException; @@ -69,6 +71,8 @@ public class CloudZonesStartupProcessor extends AdapterBase implements StartupCo @Inject HostDao _hostDao = null; @Inject + private HostDetailsDao hostDetailsDao; + @Inject HostPodDao _podDao = null; @Inject DataCenterDetailsDao _zoneDetailsDao = null; @@ -319,6 +323,25 @@ protected void updateComputeHost(final HostVO host, final StartupCommand startup host.setHypervisorType(hyType); host.setHypervisorVersion(scc.getHypervisorVersion()); + updateHostDetails(host, scc); + } + + private void updateHostDetails(HostVO host, StartupRoutingCommand startupRoutingCmd) { + final String name = "supportsResign"; + final String value = String.valueOf(startupRoutingCmd.getSupportsClonedVolumes()); + + DetailVO hostDetail = hostDetailsDao.findDetail(host.getId(), name); + + if (hostDetail != null) { + hostDetail.setValue(value); + + hostDetailsDao.update(hostDetail.getId(), hostDetail); + } + else { + hostDetail = new DetailVO(host.getId(), name, value); + + hostDetailsDao.persist(hostDetail); + } } private boolean checkCIDR(Host.Type type, HostPodVO pod, String serverPrivateIP, String serverPrivateNetmask) { diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java index fb14dc4408..e48c1f587a 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java @@ -33,11 +33,9 @@ import com.cloud.network.dao.NetworkVO; import com.cloud.offering.ServiceOffering; import com.cloud.resource.ResourceManager; -import com.cloud.server.ConfigurationServer; import com.cloud.service.ServiceOfferingDetailsVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.service.dao.ServiceOfferingDetailsDao; -import com.cloud.storage.dao.VMTemplateDetailsDao; import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; import com.cloud.vm.NicProfile; @@ -55,29 +53,21 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis public static final Logger s_logger = Logger.getLogger(HypervisorGuruBase.class); @Inject - VMTemplateDetailsDao _templateDetailsDao; + private NicDao _nicDao; @Inject - NicDao _nicDao; + private NetworkDao _networkDao; @Inject - NetworkDao _networkDao; + private VMInstanceDao _virtualMachineDao; @Inject - VMInstanceDao _virtualMachineDao; + private UserVmDetailsDao _userVmDetailsDao; @Inject - UserVmDetailsDao _userVmDetailsDao; + private NicSecondaryIpDao _nicSecIpDao; @Inject - NicSecondaryIpDao _nicSecIpDao; + private ResourceManager _resourceMgr; @Inject - ConfigurationServer _configServer; + private ServiceOfferingDetailsDao _serviceOfferingDetailsDao; @Inject - ResourceManager _resourceMgr; - @Inject - ServiceOfferingDetailsDao _serviceOfferingDetailsDao; - @Inject - ServiceOfferingDao _serviceOfferingDao; - - protected HypervisorGuruBase() { - super(); - } + private ServiceOfferingDao _serviceOfferingDao; @Override public NicTO toNicTO(NicProfile profile) { diff --git a/server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java b/server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java index 48be8f2851..13a1a64cd2 100644 --- a/server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java +++ b/server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java @@ -85,6 +85,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) { } @@ -95,6 +99,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { // TODO Auto-generated method stub diff --git a/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java b/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java index 59b398f5b5..200b279bf9 100644 --- a/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java +++ b/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java @@ -340,6 +340,15 @@ public ExternalDeviceNetworkUsageTask() { @Override protected void runInContext() { + + // Check if there are any external devices + // Skip external device usage collection if none exist + + if(_hostDao.listByType(Host.Type.ExternalFirewall).isEmpty() && _hostDao.listByType(Host.Type.ExternalLoadBalancer).isEmpty()){ + s_logger.debug("External devices are not used. Skipping external device usage collection"); + return; + } + GlobalLock scanLock = GlobalLock.getInternLock("ExternalDeviceNetworkUsageManagerImpl"); try { if (scanLock.lock(20)) { @@ -356,7 +365,7 @@ protected void runInContext() { } } - private void runExternalDeviceNetworkUsageTask() { + protected void runExternalDeviceNetworkUsageTask() { s_logger.debug("External devices stats collector is running..."); for (DataCenterVO zone : _dcDao.listAll()) { diff --git a/server/src/com/cloud/network/IpAddressManagerImpl.java b/server/src/com/cloud/network/IpAddressManagerImpl.java index d4da5fae24..e65adb60f7 100644 --- a/server/src/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/com/cloud/network/IpAddressManagerImpl.java @@ -401,7 +401,7 @@ public boolean configure(String name, Map params) { AssignIpAddressFromPodVlanSearch.join("vlan", podVlanSearch, podVlanSearch.entity().getId(), AssignIpAddressFromPodVlanSearch.entity().getVlanId(), JoinType.INNER); AssignIpAddressFromPodVlanSearch.done(); - Network.State.getStateMachine().registerListener(new NetworkStateListener(_usageEventDao, _networksDao, _configDao)); + Network.State.getStateMachine().registerListener(new NetworkStateListener(_configDao)); s_logger.info("Network Manager is configured."); diff --git a/server/src/com/cloud/network/NetworkUsageManagerImpl.java b/server/src/com/cloud/network/NetworkUsageManagerImpl.java index a0356ca90b..b7adecda0d 100644 --- a/server/src/com/cloud/network/NetworkUsageManagerImpl.java +++ b/server/src/com/cloud/network/NetworkUsageManagerImpl.java @@ -483,6 +483,10 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) { if (cmd instanceof StartupTrafficMonitorCommand) { @@ -498,6 +502,14 @@ public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) return; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return true; diff --git a/server/src/com/cloud/network/SshKeysDistriMonitor.java b/server/src/com/cloud/network/SshKeysDistriMonitor.java index 1eeb3a3213..e263c548cd 100644 --- a/server/src/com/cloud/network/SshKeysDistriMonitor.java +++ b/server/src/com/cloud/network/SshKeysDistriMonitor.java @@ -40,12 +40,10 @@ public class SshKeysDistriMonitor implements Listener { private static final Logger s_logger = Logger.getLogger(SshKeysDistriMonitor.class); AgentManager _agentMgr; - private final HostDao _hostDao; private ConfigurationDao _configDao; public SshKeysDistriMonitor(AgentManager mgr, HostDao host, ConfigurationDao config) { - this._agentMgr = mgr; - _hostDao = host; + _agentMgr = mgr; _configDao = config; } @@ -67,6 +65,18 @@ public synchronized boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { if (cmd instanceof StartupRoutingCommand) { diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index f7947d5c54..3332393f65 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -251,159 +251,98 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V Configurable, StateListener { private static final Logger s_logger = Logger.getLogger(VirtualNetworkApplianceManagerImpl.class); - @Inject - EntityManager _entityMgr; - @Inject - DataCenterDao _dcDao = null; - @Inject - VlanDao _vlanDao = null; - @Inject - FirewallRulesDao _rulesDao = null; - @Inject - LoadBalancerDao _loadBalancerDao = null; - @Inject - LoadBalancerVMMapDao _loadBalancerVMMapDao = null; - @Inject - IPAddressDao _ipAddressDao = null; - @Inject - VMTemplateDao _templateDao = null; - @Inject - DomainRouterDao _routerDao = null; - @Inject - UserDao _userDao = null; - @Inject - UserStatisticsDao _userStatsDao = null; - @Inject - HostDao _hostDao = null; - @Inject - ConfigurationDao _configDao; - @Inject - HostPodDao _podDao = null; - @Inject - UserStatsLogDao _userStatsLogDao = null; - @Inject - AgentManager _agentMgr; - @Inject - AlertManager _alertMgr; - @Inject - AccountManager _accountMgr; - @Inject - ConfigurationManager _configMgr; - @Inject - ConfigurationServer _configServer; - @Inject - ServiceOfferingDao _serviceOfferingDao = null; - @Inject - UserVmDao _userVmDao; - @Inject - VMInstanceDao _vmDao; - @Inject - NetworkOfferingDao _networkOfferingDao = null; - @Inject - GuestOSDao _guestOSDao = null; - @Inject - NetworkOrchestrationService _networkMgr; - @Inject - NetworkModel _networkModel; - @Inject - VirtualMachineManager _itMgr; - @Inject - VpnUserDao _vpnUsersDao; - @Inject - RulesManager _rulesMgr; - @Inject - NetworkDao _networkDao; - @Inject - LoadBalancingRulesManager _lbMgr; - @Inject - PortForwardingRulesDao _pfRulesDao; - @Inject - RemoteAccessVpnDao _vpnDao; - @Inject - NicDao _nicDao; - @Inject - NicIpAliasDao _nicIpAliasDao; - @Inject - VolumeDao _volumeDao = null; - @Inject - UserVmDetailsDao _vmDetailsDao; - @Inject - ClusterDao _clusterDao; - @Inject - ResourceManager _resourceMgr; - @Inject - PhysicalNetworkServiceProviderDao _physicalProviderDao; - @Inject - VirtualRouterProviderDao _vrProviderDao; - @Inject - ManagementServerHostDao _msHostDao; - @Inject - Site2SiteCustomerGatewayDao _s2sCustomerGatewayDao; - @Inject - Site2SiteVpnGatewayDao _s2sVpnGatewayDao; - @Inject - Site2SiteVpnConnectionDao _s2sVpnConnectionDao; - @Inject - Site2SiteVpnManager _s2sVpnMgr; - @Inject - UserIpv6AddressDao _ipv6Dao; - @Inject - NetworkService _networkSvc; - @Inject - IpAddressManager _ipAddrMgr; - @Inject - ConfigDepot _configDepot; - @Inject - MonitoringServiceDao _monitorServiceDao; - @Inject - AsyncJobManager _asyncMgr; - @Inject - protected VpcDao _vpcDao; - @Inject - protected ApiAsyncJobDispatcher _asyncDispatcher; - @Inject - OpRouterMonitorServiceDao _opRouterMonitorServiceDao; - - @Inject - protected NetworkTopologyContext _networkTopologyContext; + @Inject private EntityManager _entityMgr; + @Inject private DataCenterDao _dcDao; + @Inject protected VlanDao _vlanDao; + @Inject private FirewallRulesDao _rulesDao; + @Inject private LoadBalancerDao _loadBalancerDao; + @Inject private LoadBalancerVMMapDao _loadBalancerVMMapDao; + @Inject protected IPAddressDao _ipAddressDao; + @Inject private VMTemplateDao _templateDao; + @Inject protected DomainRouterDao _routerDao; + @Inject private UserDao _userDao; + @Inject protected UserStatisticsDao _userStatsDao; + @Inject private HostDao _hostDao; + @Inject private ConfigurationDao _configDao; + @Inject private HostPodDao _podDao; + @Inject private UserStatsLogDao _userStatsLogDao; + @Inject protected AgentManager _agentMgr; + @Inject private AlertManager _alertMgr; + @Inject private AccountManager _accountMgr; + @Inject private ConfigurationManager _configMgr; + @Inject private ConfigurationServer _configServer; + @Inject private ServiceOfferingDao _serviceOfferingDao; + @Inject private UserVmDao _userVmDao; + @Inject private VMInstanceDao _vmDao; + @Inject private NetworkOfferingDao _networkOfferingDao; + @Inject private GuestOSDao _guestOSDao; + @Inject private NetworkOrchestrationService _networkMgr; + @Inject protected NetworkModel _networkModel; + @Inject protected VirtualMachineManager _itMgr; + @Inject private VpnUserDao _vpnUsersDao; + @Inject private RulesManager _rulesMgr; + @Inject protected NetworkDao _networkDao; + @Inject private LoadBalancingRulesManager _lbMgr; + @Inject private PortForwardingRulesDao _pfRulesDao; + @Inject protected RemoteAccessVpnDao _vpnDao; + @Inject protected NicDao _nicDao; + @Inject private NicIpAliasDao _nicIpAliasDao; + @Inject private VolumeDao _volumeDao; + @Inject private UserVmDetailsDao _vmDetailsDao; + @Inject private ClusterDao _clusterDao; + @Inject private ResourceManager _resourceMgr; + @Inject private PhysicalNetworkServiceProviderDao _physicalProviderDao; + @Inject protected VirtualRouterProviderDao _vrProviderDao; + @Inject private ManagementServerHostDao _msHostDao; + @Inject private Site2SiteCustomerGatewayDao _s2sCustomerGatewayDao; + @Inject private Site2SiteVpnGatewayDao _s2sVpnGatewayDao; + @Inject private Site2SiteVpnConnectionDao _s2sVpnConnectionDao; + @Inject private Site2SiteVpnManager _s2sVpnMgr; + @Inject private UserIpv6AddressDao _ipv6Dao; + @Inject private NetworkService _networkSvc; + @Inject private IpAddressManager _ipAddrMgr; + @Inject private ConfigDepot _configDepot; + @Inject private MonitoringServiceDao _monitorServiceDao; + @Inject private AsyncJobManager _asyncMgr; + @Inject protected VpcDao _vpcDao; + @Inject protected ApiAsyncJobDispatcher _asyncDispatcher; + @Inject private OpRouterMonitorServiceDao _opRouterMonitorServiceDao; + + @Inject protected NetworkTopologyContext _networkTopologyContext; @Autowired @Qualifier("networkHelper") protected NetworkHelper _nwHelper; - @Inject - protected RouterControlHelper _routerControlHelper; + @Inject protected RouterControlHelper _routerControlHelper; - @Inject - protected CommandSetupHelper _commandSetupHelper; - @Inject - protected RouterDeploymentDefinitionBuilder _routerDeploymentManagerBuilder; + @Inject protected CommandSetupHelper _commandSetupHelper; + @Inject protected RouterDeploymentDefinitionBuilder _routerDeploymentManagerBuilder; - int _routerRamSize; - int _routerCpuMHz; - int _retry = 2; - String _mgmtCidr; + private int _routerRamSize; + private int _routerCpuMHz; + private String _mgmtCidr; - int _routerStatsInterval = 300; - int _routerCheckInterval = 30; - int _rvrStatusUpdatePoolSize = 10; + private int _routerStatsInterval = 300; + private int _routerCheckInterval = 30; + private int _rvrStatusUpdatePoolSize = 10; private String _dnsBasicZoneUpdates = "all"; - private final Set _guestOSNeedGatewayOnNonDefaultNetwork = new HashSet(); + private final Set _guestOSNeedGatewayOnNonDefaultNetwork = new HashSet<>(); private boolean _disableRpFilter = false; - int _routerExtraPublicNics = 2; + private int _routerExtraPublicNics = 2; private int _usageAggregationRange = 1440; private String _usageTimeZone = "GMT"; private final long mgmtSrvrId = MacAddress.getMacAddress().toLong(); private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 5; // 5 seconds private boolean _dailyOrHourly = false; - ScheduledExecutorService _executor; - ScheduledExecutorService _checkExecutor; - ScheduledExecutorService _networkStatsUpdateExecutor; - ExecutorService _rvrStatusUpdateExecutor; + private ScheduledExecutorService _executor; + private ScheduledExecutorService _checkExecutor; + private ScheduledExecutorService _networkStatsUpdateExecutor; + private ExecutorService _rvrStatusUpdateExecutor; - BlockingQueue _vrUpdateQueue = null; + private BlockingQueue _vrUpdateQueue; @Override public VirtualRouter destroyRouter(final long routerId, final Account caller, final Long callerUserId) throws ResourceUnavailableException, ConcurrentOperationException { @@ -586,10 +525,7 @@ public boolean configure(final String name, final Map params) th } } - String value = configs.get("start.retry"); - _retry = NumbersUtil.parseInt(value, 2); - - value = configs.get("router.stats.interval"); + String value = configs.get("router.stats.interval"); _routerStatsInterval = NumbersUtil.parseInt(value, 300); value = configs.get("router.check.interval"); @@ -1591,9 +1527,6 @@ protected StringBuilder createGuestBootLoadArgs(final NicProfile guestNic, final protected StringBuilder createRedundantRouterArgs(final NicProfile nic, final DomainRouterVO router) { final StringBuilder buf = new StringBuilder(); - final long networkId = nic.getNetworkId(); - final NetworkVO network = _networkDao.findById(networkId); - final boolean isRedundant = router.getIsRedundantRouter(); if (isRedundant) { buf.append(" redundant_router=1"); @@ -2364,6 +2297,10 @@ public boolean processCommands(final long agentId, final long seq, final Command return false; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(final Host host, final StartupCommand cmd, final boolean forRebalance) throws ConnectionException { final List routers = _routerDao.listIsolatedByHostId(host.getId()); @@ -2398,6 +2335,14 @@ public boolean processDisconnect(final long agentId, final Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(final long agentId, final long seq) { return false; diff --git a/server/src/com/cloud/network/security/SecurityGroupListener.java b/server/src/com/cloud/network/security/SecurityGroupListener.java index af963b1ad4..32186cc046 100644 --- a/server/src/com/cloud/network/security/SecurityGroupListener.java +++ b/server/src/com/cloud/network/security/SecurityGroupListener.java @@ -81,7 +81,7 @@ public boolean isRecurring() { @Override public boolean processAnswers(long agentId, long seq, Answer[] answers) { List affectedVms = new ArrayList(); - int commandNum = 0; + for (Answer ans : answers) { if (ans instanceof SecurityGroupRuleAnswer) { SecurityGroupRuleAnswer ruleAnswer = (SecurityGroupRuleAnswer)ans; @@ -106,7 +106,7 @@ public boolean processAnswers(long agentId, long seq, Answer[] answers) { } } } - commandNum++; + if (_workTracker != null) _workTracker.processAnswers(agentId, seq, answers); } @@ -151,6 +151,10 @@ public boolean processCommands(long agentId, long seq, Command[] commands) { return processed; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) { if (s_logger.isInfoEnabled()) @@ -188,6 +192,14 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { if (_workTracker != null) { diff --git a/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java b/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java index 64204fe9a7..64bbb75faa 100644 --- a/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java +++ b/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java @@ -182,8 +182,6 @@ public void sendRulesetUpdates(SecurityGroupWork work) { List nicSecIps = null; if (nic != null) { if (nic.getSecondaryIp()) { - //get secondary ips of the vm - long networkId = nic.getNetworkId(); nicSecIps = _nicSecIpDao.getSecondaryIpAddressesForNic(nic.getId()); } } @@ -193,7 +191,7 @@ public void sendRulesetUpdates(SecurityGroupWork work) { cmd.setMsId(_serverId); if (s_logger.isDebugEnabled()) { s_logger.debug("SecurityGroupManager v2: sending ruleset update for vm " + vm.getInstanceName() + ":ingress num rules=" + - cmd.getIngressRuleSet().length + ":egress num rules=" + cmd.getEgressRuleSet().length + " num cidrs=" + cmd.getTotalNumCidrs() + " sig=" + + cmd.getIngressRuleSet().size() + ":egress num rules=" + cmd.getEgressRuleSet().size() + " num cidrs=" + cmd.getTotalNumCidrs() + " sig=" + cmd.getSignature()); } Commands cmds = new Commands(cmd); diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 18fbfe2022..706f4c4abf 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -46,6 +46,7 @@ import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.cloud.configuration.Config; @@ -402,8 +403,6 @@ public VpcOffering createVpcOffering(final String name, final String displayText svcProviderMap.put(Service.NetworkACL, defaultProviders); } - svcProviderMap.put(Service.Gateway, defaultProviders); - if (serviceProviders != null) { for (final Entry> serviceEntry : serviceProviders.entrySet()) { final Network.Service service = Network.Service.getService(serviceEntry.getKey()); @@ -425,6 +424,12 @@ public VpcOffering createVpcOffering(final String name, final String displayText } } + // add gateway provider (if sourceNat provider is enabled) + final Set sourceNatServiceProviders = svcProviderMap.get(Service.SourceNat); + if (CollectionUtils.isNotEmpty(sourceNatServiceProviders)) { + svcProviderMap.put(Service.Gateway, sourceNatServiceProviders); + } + validateConnectivtyServiceCapabilities(svcProviderMap.get(Service.Connectivity), serviceCapabilitystList); final boolean supportsDistributedRouter = isVpcOfferingSupportsDistributedRouter(serviceCapabilitystList); diff --git a/server/src/com/cloud/projects/ProjectManagerImpl.java b/server/src/com/cloud/projects/ProjectManagerImpl.java index ee6650698c..a8dd225c54 100644 --- a/server/src/com/cloud/projects/ProjectManagerImpl.java +++ b/server/src/com/cloud/projects/ProjectManagerImpl.java @@ -211,7 +211,7 @@ public Project doInTransaction(TransactionStatus status) { StringBuilder acctNm = new StringBuilder("PrjAcct-"); acctNm.append(name).append("-").append(ownerFinal.getDomainId()); - Account projectAccount = _accountMgr.createAccount(acctNm.toString(), Account.ACCOUNT_TYPE_PROJECT, domainId, null, null, UUID.randomUUID().toString()); + Account projectAccount = _accountMgr.createAccount(acctNm.toString(), Account.ACCOUNT_TYPE_PROJECT, null, domainId, null, null, UUID.randomUUID().toString()); Project project = _projectDao.persist(new ProjectVO(name, displayText, ownerFinal.getDomainId(), projectAccount.getId())); diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 359bccf034..2bb1596ed1 100644 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -76,6 +76,7 @@ import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterIpAddressVO; import com.cloud.dc.DataCenterVO; @@ -771,6 +772,9 @@ private List discoverHostsFull(final Long dcId, final Long podId, Long c _hostTagsDao.persist(host.getId(), hostTags); } hosts.add(host); + + _agentMgr.notifyMonitorsOfNewlyAddedHost(host.getId()); + return hosts; } } @@ -843,10 +847,13 @@ protected boolean doDeleteHost(final long hostId, final boolean isForced, final return true; } + Long clusterId = host.getClusterId(); + + _agentMgr.notifyMonitorsOfHostAboutToBeRemoved(host.getId()); + Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(final TransactionStatus status) { - _dcDao.releasePrivateIpAddress(host.getPrivateIpAddress(), host.getDataCenterId(), null); _agentMgr.disconnectWithoutInvestigation(hostId, Status.Event.Remove); @@ -920,6 +927,10 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } }); + if (clusterId != null) { + _agentMgr.notifyMonitorsOfRemovedHost(host.getId(), clusterId); + } + return true; } @@ -1168,7 +1179,8 @@ public boolean resourceStateTransitTo(final Host host, final ResourceState.Event // TO DO - Make it more granular and have better conversion into capacity type if(host.getType() == Type.Routing){ final CapacityState capacityState = nextState == ResourceState.Enabled ? CapacityState.Enabled : CapacityState.Disabled; - _capacityDao.updateCapacityState(null, null, null, host.getId(), capacityState.toString()); + final short[] capacityTypes = {Capacity.CAPACITY_TYPE_CPU, Capacity.CAPACITY_TYPE_MEMORY}; + _capacityDao.updateCapacityState(null, null, null, host.getId(), capacityState.toString(), capacityTypes); } return _hostDao.updateResourceState(currentState, event, nextState, host); } @@ -1349,6 +1361,11 @@ public Cluster getCluster(final Long clusterId) { return _clusterDao.findById(clusterId); } + @Override + public DataCenter getZone(Long zoneId) { + return _dcDao.findById(zoneId); + } + @Override public boolean configure(final String name, final Map params) throws ConfigurationException { _defaultSystemVMHypervisor = HypervisorType.getType(_configDao.getValue(Config.SystemVMDefaultHypervisor.toString())); @@ -1570,17 +1587,35 @@ private boolean checkCIDR(final HostPodVO pod, final String serverPrivateIP, fin return true; } + private HostVO getNewHost(StartupCommand[] startupCommands) { + StartupCommand startupCommand = startupCommands[0]; + + HostVO host = findHostByGuid(startupCommand.getGuid()); + + if (host != null) { + return host; + } + + host = findHostByGuid(startupCommand.getGuidWithoutResource()); + + if (host != null) { + return host; + } + + return null; + } + protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource resource, final Map details, List hostTags, final ResourceStateAdapter.Event stateEvent) { - final StartupCommand startup = cmds[0]; - HostVO host = findHostByGuid(startup.getGuid()); - boolean isNew = false; - if (host == null) { - host = findHostByGuid(startup.getGuidWithoutResource()); - } + boolean newHost = false; + StartupCommand startup = cmds[0]; + + HostVO host = getNewHost(cmds); + if (host == null) { host = new HostVO(startup.getGuid()); - isNew = true; + + newHost = true; } String dataCenter = startup.getDataCenter(); @@ -1695,12 +1730,18 @@ protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource throw new CloudRuntimeException("No resource state adapter response"); } - if (isNew) { + if (newHost) { host = _hostDao.persist(host); } else { _hostDao.update(host.getId(), host); } + if (startup instanceof StartupRoutingCommand) { + final StartupRoutingCommand ssCmd = (StartupRoutingCommand)startup; + + updateSupportsClonedVolumes(host, ssCmd.getSupportsClonedVolumes()); + } + try { resourceStateTransitTo(host, ResourceState.Event.InternalCreated, _nodeId); /* Agent goes to Connecting status */ @@ -1718,6 +1759,64 @@ protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource return host; } + private void updateSupportsClonedVolumes(HostVO host, boolean supportsClonedVolumes) { + final String name = "supportsResign"; + + DetailVO hostDetail = _hostDetailsDao.findDetail(host.getId(), name); + + if (hostDetail != null) { + if (supportsClonedVolumes) { + hostDetail.setValue(Boolean.TRUE.toString()); + + _hostDetailsDao.update(hostDetail.getId(), hostDetail); + } + else { + _hostDetailsDao.remove(hostDetail.getId()); + } + } + else { + if (supportsClonedVolumes) { + hostDetail = new DetailVO(host.getId(), name, Boolean.TRUE.toString()); + + _hostDetailsDao.persist(hostDetail); + } + } + + boolean clusterSupportsResigning = true; + + List hostVOs = _hostDao.findByClusterId(host.getClusterId()); + + for (HostVO hostVO : hostVOs) { + DetailVO hostDetailVO = _hostDetailsDao.findDetail(hostVO.getId(), name); + + if (hostDetailVO == null || Boolean.parseBoolean(hostDetailVO.getValue()) == false) { + clusterSupportsResigning = false; + + break; + } + } + + ClusterDetailsVO clusterDetailsVO = _clusterDetailsDao.findDetail(host.getClusterId(), name); + + if (clusterDetailsVO != null) { + if (clusterSupportsResigning) { + clusterDetailsVO.setValue(Boolean.TRUE.toString()); + + _clusterDetailsDao.update(clusterDetailsVO.getId(), clusterDetailsVO); + } + else { + _clusterDetailsDao.remove(clusterDetailsVO.getId()); + } + } + else { + if (clusterSupportsResigning) { + clusterDetailsVO = new ClusterDetailsVO(host.getClusterId(), name, Boolean.TRUE.toString()); + + _clusterDetailsDao.persist(clusterDetailsVO); + } + } + } + private boolean isFirstHostInCluster(final HostVO host) { boolean isFirstHost = true; if (host.getClusterId() != null) { @@ -1794,9 +1893,13 @@ private Host createHostAndAgent(final ServerResource resource, final Map vms = _haMgr.findTakenMigrationWork(); for (final VMInstanceVO vm : vms) { - if (vm != null && vm.getHostId() != null && vm.getHostId() == hostId) { - s_logger.info("Unable to cancel migration because the vm is being migrated: " + vm); - return false; + if (vm.getHostId() != null && vm.getHostId() == hostId) { + s_logger.warn("Unable to cancel migration because the vm is being migrated: " + vm + ", hostId = " + hostId); + vms_migrating = true; } } @@ -2125,7 +2237,7 @@ private boolean doCancelMaintenance(final long hostId) { _agentMgr.pullAgentOutMaintenance(hostId); // for kvm, need to log into kvm host, restart cloudstack-agent - if (host.getHypervisorType() == HypervisorType.KVM || host.getHypervisorType() == HypervisorType.LXC) { + if ((host.getHypervisorType() == HypervisorType.KVM && !vms_migrating) || host.getHypervisorType() == HypervisorType.LXC) { final boolean sshToAgent = Boolean.parseBoolean(_configDao.getValue(Config.KvmSshToAgentEnabled.key())); if (!sshToAgent) { diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 16e4ff0590..13f98a2f48 100644 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -449,7 +449,7 @@ public void saveUser() { public void doInTransactionWithoutResult(TransactionStatus status) { TransactionLegacy txn = TransactionLegacy.currentTxn(); // insert system account - String insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id, account.default) VALUES (1, UUID(), 'system', '1', '1', 1)"; + String insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, role_id, domain_id, account.default) VALUES (1, UUID(), 'system', '1', '1', '1', 1)"; try { PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql); @@ -476,8 +476,8 @@ public void doInTransactionWithoutResult(TransactionStatus status) { String lastname = "cloud"; // create an account for the admin user first - insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id, account.default) VALUES (" + id + ", UUID(), '" + username - + "', '1', '1', 1)"; + insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, role_id, domain_id, account.default) VALUES (" + id + ", UUID(), '" + username + + "', '1', '1', '1', 1)"; try { PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql); stmt.executeUpdate(); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index e4ae8e1669..60b44d74c2 100644 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -133,6 +133,15 @@ import org.apache.cloudstack.api.command.admin.offering.DeleteServiceOfferingCmd; import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd; import org.apache.cloudstack.api.command.admin.offering.UpdateServiceOfferingCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.DisableOutOfBandManagementForClusterCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.DisableOutOfBandManagementForHostCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.DisableOutOfBandManagementForZoneCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.EnableOutOfBandManagementForClusterCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.EnableOutOfBandManagementForHostCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.EnableOutOfBandManagementForZoneCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.ConfigureOutOfBandManagementCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.IssueOutOfBandManagementPowerActionCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.ChangeOutOfBandManagementPasswordCmd; import org.apache.cloudstack.api.command.admin.pod.CreatePodCmd; import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd; @@ -3021,6 +3030,17 @@ public List> getCommands() { cmdList.add(UpdateLBHealthCheckPolicyCmd.class); cmdList.add(GetUploadParamsForTemplateCmd.class); cmdList.add(GetUploadParamsForVolumeCmd.class); + // Out-of-band management APIs for admins + cmdList.add(EnableOutOfBandManagementForHostCmd.class); + cmdList.add(DisableOutOfBandManagementForHostCmd.class); + cmdList.add(EnableOutOfBandManagementForClusterCmd.class); + cmdList.add(DisableOutOfBandManagementForClusterCmd.class); + cmdList.add(EnableOutOfBandManagementForZoneCmd.class); + cmdList.add(DisableOutOfBandManagementForZoneCmd.class); + cmdList.add(ConfigureOutOfBandManagementCmd.class); + cmdList.add(IssueOutOfBandManagementPowerActionCmd.class); + cmdList.add(ChangeOutOfBandManagementPasswordCmd.class); + return cmdList; } diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index ca86cfd080..e4687e4daf 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -20,6 +20,7 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -33,10 +34,14 @@ import javax.inject.Inject; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementService; +import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementVO; +import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao; +import org.apache.cloudstack.utils.identity.ManagementServerNode; import org.apache.cloudstack.utils.usage.UsageUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; @@ -90,6 +95,7 @@ import com.cloud.resource.ResourceState; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.StorageManager; import com.cloud.storage.StorageStats; import com.cloud.storage.VolumeStats; @@ -151,6 +157,8 @@ public String toString() { @Inject private HostDao _hostDao; @Inject + private OutOfBandManagementDao outOfBandManagementDao; + @Inject private UserVmDao _userVmDao; @Inject private VolumeDao _volsDao; @@ -167,6 +175,8 @@ public String toString() { @Inject private ResourceManager _resourceMgr; @Inject + private OutOfBandManagementService outOfBandManagementService; + @Inject private ConfigurationDao _configDao; @Inject private EndPointSelector _epSelector; @@ -198,6 +208,8 @@ public String toString() { private ServiceOfferingDao _serviceOfferingDao; @Inject private HostGpuGroupsDao _hostGpuGroupsDao; + @Inject + private ImageStoreDetailsUtil imageStoreDetailsUtil; private ConcurrentHashMap _hostStats = new ConcurrentHashMap(); private final ConcurrentHashMap _VmStats = new ConcurrentHashMap(); @@ -206,6 +218,7 @@ public String toString() { private ConcurrentHashMap _storagePoolStats = new ConcurrentHashMap(); long hostStatsInterval = -1L; + long hostOutOfBandManagementStatsInterval = -1L; long hostAndVmStatsInterval = -1L; long storageStatsInterval = -1L; long volumeStatsInterval = -1L; @@ -249,8 +262,9 @@ public boolean start() { } private void init(Map configs) { - _executor = Executors.newScheduledThreadPool(4, new NamedThreadFactory("StatsCollector")); + _executor = Executors.newScheduledThreadPool(6, new NamedThreadFactory("StatsCollector")); + hostOutOfBandManagementStatsInterval = OutOfBandManagementService.SyncThreadInterval.value(); hostStatsInterval = NumbersUtil.parseLong(configs.get("host.stats.interval"), 60000L); hostAndVmStatsInterval = NumbersUtil.parseLong(configs.get("vm.stats.interval"), 60000L); storageStatsInterval = NumbersUtil.parseLong(configs.get("storage.stats.interval"), 60000L); @@ -292,6 +306,10 @@ private void init(Map configs) { _executor.scheduleWithFixedDelay(new HostCollector(), 15000L, hostStatsInterval, TimeUnit.MILLISECONDS); } + if (hostOutOfBandManagementStatsInterval > 0) { + _executor.scheduleWithFixedDelay(new HostOutOfBandManagementStatsCollector(), 15000L, hostOutOfBandManagementStatsInterval, TimeUnit.MILLISECONDS); + } + if (hostAndVmStatsInterval > 0) { _executor.scheduleWithFixedDelay(new VmStatsCollector(), 15000L, hostAndVmStatsInterval, TimeUnit.MILLISECONDS); } @@ -410,6 +428,36 @@ protected void runInContext() { } } + class HostOutOfBandManagementStatsCollector extends ManagedContextRunnable { + @Override + protected void runInContext() { + try { + s_logger.debug("HostOutOfBandManagementStatsCollector is running..."); + List outOfBandManagementHosts = outOfBandManagementDao.findAllByManagementServer(ManagementServerNode.getManagementServerId()); + if (outOfBandManagementHosts == null) { + return; + } + for (OutOfBandManagement outOfBandManagementHost : outOfBandManagementHosts) { + Host host = _hostDao.findById(outOfBandManagementHost.getHostId()); + if (host == null) { + continue; + } + if (outOfBandManagementService.isOutOfBandManagementEnabled(host)) { + outOfBandManagementService.submitBackgroundPowerSyncTask(host); + } else if (outOfBandManagementHost.getPowerState() != OutOfBandManagement.PowerState.Disabled) { + if (outOfBandManagementService.transitionPowerStateToDisabled(Collections.singletonList(host))) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Out-of-band management was disabled in zone/cluster/host, disabled power state for host id:" + host.getId()); + } + } + } + } + } catch (Throwable t) { + s_logger.error("Error trying to retrieve host out-of-band management stats", t); + } + } + } + class VmStatsCollector extends ManagedContextRunnable { @Override protected void runInContext() { @@ -462,6 +510,9 @@ protected void runInContext() { statsInMemory.setDiskReadIOs(statsInMemory.getDiskReadIOs() + statsForCurrentIteration.getDiskReadIOs()); statsInMemory.setDiskWriteIOs(statsInMemory.getDiskWriteIOs() + statsForCurrentIteration.getDiskWriteIOs()); statsInMemory.setDiskReadKBs(statsInMemory.getDiskReadKBs() + statsForCurrentIteration.getDiskReadKBs()); + statsInMemory.setMemoryKBs(statsForCurrentIteration.getMemoryKBs()); + statsInMemory.setIntFreeMemoryKBs(statsForCurrentIteration.getIntFreeMemoryKBs()); + statsInMemory.setTargetMemoryKBs(statsForCurrentIteration.getTargetMemoryKBs()); _VmStats.put(vmId, statsInMemory); } @@ -482,6 +533,10 @@ protected void runInContext() { metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.read_kbs", statsForCurrentIteration.getDiskReadKBs()); metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.write_iops", statsForCurrentIteration.getDiskWriteIOs()); metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".disk.read_iops", statsForCurrentIteration.getDiskReadIOs()); + metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.total_kbs", statsForCurrentIteration.getMemoryKBs()); + metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.internalfree_kbs", statsForCurrentIteration.getIntFreeMemoryKBs()); + metrics.put(externalStatsPrefix + "cloudstack.stats.instances." + vmName + ".memory.target_kbs", statsForCurrentIteration.getTargetMemoryKBs()); + } } @@ -715,7 +770,8 @@ protected void runInContext() { continue; } - GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO()); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(store.getId()); + GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), nfsVersion); EndPoint ssAhost = _epSelector.select(store); if (ssAhost == null) { s_logger.debug("There is no secondary storage VM for secondary storage host " + store.getName()); @@ -762,6 +818,7 @@ protected void runInContext() { s_logger.error("Error trying to retrieve storage stats", t); } } + } class AutoScaleMonitor extends ManagedContextRunnable { diff --git a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java new file mode 100755 index 0000000000..7107650779 --- /dev/null +++ b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java @@ -0,0 +1,67 @@ +// 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.Map; + +import javax.inject.Inject; + +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; + +public class ImageStoreDetailsUtil { + + @Inject + protected ImageStoreDao imageStoreDao; + @Inject + protected ImageStoreDetailsDao imageStoreDetailsDao; + + /** + * Obtain NFS protocol version (if provided) for a store id.
+ * It can be set by adding an entry in {@code image_store_details} table, providing {@code name=nfs.version} and {@code value=X} (e.g. 3) + * @param storeId image store id + * @return {@code null} if {@code nfs.version} is not found for storeId
+ * {@code X} if {@code nfs.version} is found found for storeId + */ + public Integer getNfsVersion(long storeId) throws NumberFormatException { + String nfsVersion = null; + if (imageStoreDetailsDao.getDetails(storeId) != null){ + Map storeDetails = imageStoreDetailsDao.getDetails(storeId); + if (storeDetails != null && storeDetails.containsKey("nfs.version")){ + nfsVersion = storeDetails.get("nfs.version"); + } + } + return (nfsVersion != null ? Integer.valueOf(nfsVersion) : null); + } + + /** + * Obtain NFS protocol version (if provided) for a store uuid.
+ * It can be set by adding an entry in {@code image_store_details} table, providing {@code name=nfs.version} and {@code value=X} (e.g. 3) + * @param storeId image store id + * @return {@code null} if {@code nfs.version} is not found for storeUuid
+ * {@code X} if {@code nfs.version} is found found for storeUuid + */ + public Integer getNfsVersionByUuid(String storeUuid){ + ImageStoreVO imageStore = imageStoreDao.findByUuid(storeUuid); + if (imageStore != null){ + return getNfsVersion(imageStore.getId()); + } + return null; + } + +} diff --git a/server/src/com/cloud/storage/ImageStoreUploadMonitorImpl.java b/server/src/com/cloud/storage/ImageStoreUploadMonitorImpl.java index 1478910413..2d9f544bff 100755 --- a/server/src/com/cloud/storage/ImageStoreUploadMonitorImpl.java +++ b/server/src/com/cloud/storage/ImageStoreUploadMonitorImpl.java @@ -115,7 +115,7 @@ public class ImageStoreUploadMonitorImpl extends ManagerBase implements ImageSto public boolean configure(String name, Map params) throws ConfigurationException { _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Upload-Monitor")); _monitoringInterval = UploadMonitoringInterval.value(); - _uploadOperationTimeout = UploadOperationTimeout.value() * 60 * 1000; + _uploadOperationTimeout = UploadOperationTimeout.value() * 60 * 1000L; _nodeId = ManagementServerNode.getManagementServerId(); return true; } @@ -152,6 +152,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean isRecurring() { return false; @@ -167,6 +175,10 @@ public boolean processTimeout(long agentId, long seq) { return false; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { } diff --git a/server/src/com/cloud/storage/LocalStoragePoolListener.java b/server/src/com/cloud/storage/LocalStoragePoolListener.java index a66515ebdc..941e505fa7 100644 --- a/server/src/com/cloud/storage/LocalStoragePoolListener.java +++ b/server/src/com/cloud/storage/LocalStoragePoolListener.java @@ -18,8 +18,6 @@ import javax.inject.Inject; -import org.apache.log4j.Logger; - import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import com.cloud.agent.Listener; @@ -39,17 +37,11 @@ import com.cloud.utils.db.DB; public class LocalStoragePoolListener implements Listener { - private final static Logger s_logger = Logger.getLogger(LocalStoragePoolListener.class); - @Inject - PrimaryDataStoreDao _storagePoolDao; - @Inject - StoragePoolHostDao _storagePoolHostDao; - @Inject - CapacityDao _capacityDao; - @Inject - StorageManager _storageMgr; - @Inject - DataCenterDao _dcDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; + @Inject private StoragePoolHostDao _storagePoolHostDao; + @Inject private CapacityDao _capacityDao; + @Inject private StorageManager _storageMgr; + @Inject private DataCenterDao _dcDao; @Override public int getTimeout() { @@ -71,6 +63,10 @@ public boolean processCommands(long agentId, long seq, Command[] commands) { return false; } + @Override + public void processHostAdded(long hostId) { + } + @Override @DB public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { @@ -102,6 +98,14 @@ public boolean processDisconnect(long agentId, Status state) { return false; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return false; diff --git a/server/src/com/cloud/storage/ResizeVolumePayload.java b/server/src/com/cloud/storage/ResizeVolumePayload.java index 7a927b2179..9e4c3ec528 100644 --- a/server/src/com/cloud/storage/ResizeVolumePayload.java +++ b/server/src/com/cloud/storage/ResizeVolumePayload.java @@ -21,16 +21,21 @@ public class ResizeVolumePayload { public final Long newSize; public final Long newMinIops; public final Long newMaxIops; + public final Integer newHypervisorSnapshotReserve; public final boolean shrinkOk; public final String instanceName; public final long[] hosts; + public final boolean isManaged; - public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, boolean shrinkOk, String instanceName, long[] hosts) { + public ResizeVolumePayload(Long newSize, Long newMinIops, Long newMaxIops, Integer newHypervisorSnapshotReserve, boolean shrinkOk, + String instanceName, long[] hosts, boolean isManaged) { this.newSize = newSize; this.newMinIops = newMinIops; this.newMaxIops = newMaxIops; + this.newHypervisorSnapshotReserve = newHypervisorSnapshotReserve; this.shrinkOk = shrinkOk; this.instanceName = instanceName; this.hosts = hosts; + this.isManaged = isManaged; } } diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 97a4db6f90..c0dda25bf0 100644 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -70,6 +70,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService.TemplateApiResult; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; @@ -466,7 +467,7 @@ public boolean configure(String name, Map params) throws Configu _storagePoolAcquisitionWaitSeconds = NumbersUtil.parseInt(configs.get("pool.acquisition.wait.seconds"), 1800); s_logger.info("pool.acquisition.wait.seconds is configured as " + _storagePoolAcquisitionWaitSeconds + " seconds"); - _agentMgr.registerForHostEvents(new StoragePoolMonitor(this, _storagePoolDao), true, false, true); + _agentMgr.registerForHostEvents(new StoragePoolMonitor(this, _storagePoolDao, _dataStoreProviderMgr), true, false, true); String value = _configDao.getValue(Config.StorageTemplateCleanupEnabled.key()); _templateCleanupEnabled = (value == null ? true : Boolean.parseBoolean(value)); @@ -1676,9 +1677,9 @@ public boolean storagePoolHasEnoughIops(List requestedVolumes, StoragePo return false; } - // Only IOPS guaranteed primary storage like SolidFire is using/setting IOPS. + // Only IOPS-guaranteed primary storage like SolidFire is using/setting IOPS. // This check returns true for storage that does not specify IOPS. - if (pool.getCapacityIops() == null ) { + if (pool.getCapacityIops() == null) { s_logger.info("Storage pool " + pool.getName() + " (" + pool.getId() + ") does not supply IOPS capacity, assuming enough capacity"); return true; @@ -1704,6 +1705,11 @@ public boolean storagePoolHasEnoughIops(List requestedVolumes, StoragePo @Override public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) { + return storagePoolHasEnoughSpace(volumes, pool, null); + } + + @Override + public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool, Long clusterId) { if (volumes == null || volumes.isEmpty()) { return false; } @@ -1712,10 +1718,11 @@ public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) return false; } - // allocated space includes template of specified volume + // allocated space includes templates StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); - long allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null); + long allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null); long totalAskingSize = 0; + for (Volume volume : volumes) { // refreshing the volume from the DB to get latest hv_ss_reserve (hypervisor snapshot reserve) field // I could have just assigned this to "volume", but decided to make a new variable for it so that it @@ -1726,18 +1733,37 @@ public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) // update the volume's hv_ss_reserve (hypervisor snapshot reserve) from a disk offering (used for managed storage) volService.updateHypervisorSnapshotReserveForVolume(getDiskOfferingVO(volumeVO), volumeVO.getId(), getHypervisorType(volumeVO)); - // hv_ss_reserve field might have been updated; refresh from DB to make use of it in getVolumeSizeIncludingHypervisorSnapshotReserve + // hv_ss_reserve field might have been updated; refresh from DB to make use of it in getDataObjectSizeIncludingHypervisorSnapshotReserve volumeVO = _volumeDao.findById(volume.getId()); } - if (volumeVO.getTemplateId() != null) { - VMTemplateVO tmpl = _templateDao.findByIdIncludingRemoved(volumeVO.getTemplateId()); - if (tmpl != null && tmpl.getFormat() != ImageFormat.ISO) { - allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, tmpl); + // this if statement should resolve to true at most once per execution of the for loop its contained within (for a root disk that is + // to leverage a template) + if (volume.getTemplateId() != null) { + VMTemplateVO tmpl = _templateDao.findByIdIncludingRemoved(volume.getTemplateId()); + + if (tmpl != null && !ImageFormat.ISO.equals(tmpl.getFormat())) { + allocatedSizeWithTemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, tmpl); } } + if (volumeVO.getState() != Volume.State.Ready) { - totalAskingSize = totalAskingSize + getVolumeSizeIncludingHypervisorSnapshotReserve(volumeVO, pool); + totalAskingSize += getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeVO, pool); + + if (ScopeType.ZONE.equals(poolVO.getScope()) && volumeVO.getTemplateId() != null) { + VMTemplateVO tmpl = _templateDao.findByIdIncludingRemoved(volumeVO.getTemplateId()); + + if (tmpl != null && !ImageFormat.ISO.equals(tmpl.getFormat())) { + // Storage plug-ins for zone-wide primary storage can be designed in such a way as to store a template on the + // primary storage once and make use of it in different clusters (via cloning). + // This next call leads to CloudStack asking how many more bytes it will need for the template (if the template is + // already stored on the primary storage, then the answer is 0). + + if (clusterId != null && _clusterDao.getSupportsResigning(clusterId)) { + totalAskingSize += getBytesRequiredForTemplate(tmpl, pool); + } + } + } } } @@ -1757,11 +1783,11 @@ public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) double storageAllocatedThreshold = CapacityManager.StorageAllocatedCapacityDisableThreshold.valueIn(pool.getDataCenterId()); if (s_logger.isDebugEnabled()) { s_logger.debug("Checking pool: " + pool.getId() + " for volume allocation " + volumes.toString() + ", maxSize : " + totalOverProvCapacity + - ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " + + ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " + storageAllocatedThreshold); } - double usedPercentage = (allocatedSizeWithtemplate + totalAskingSize) / (double)(totalOverProvCapacity); + double usedPercentage = (allocatedSizeWithTemplate + totalAskingSize) / (double)(totalOverProvCapacity); if (usedPercentage > storageAllocatedThreshold) { if (s_logger.isDebugEnabled()) { s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + @@ -1771,10 +1797,10 @@ public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) return false; } - if (totalOverProvCapacity < (allocatedSizeWithtemplate + totalAskingSize)) { + if (totalOverProvCapacity < (allocatedSizeWithTemplate + totalAskingSize)) { if (s_logger.isDebugEnabled()) { s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + - ", not enough storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + + ", not enough storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithTemplate + ", askingSize : " + totalAskingSize); } return false; @@ -1800,19 +1826,36 @@ private HypervisorType getHypervisorType(Volume volume) { return null; } - private long getVolumeSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { + private long getDataObjectSizeIncludingHypervisorSnapshotReserve(Volume volume, StoragePool pool) { DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName()); DataStoreDriver storeDriver = storeProvider.getDataStoreDriver(); if (storeDriver instanceof PrimaryDataStoreDriver) { PrimaryDataStoreDriver primaryStoreDriver = (PrimaryDataStoreDriver)storeDriver; - return primaryStoreDriver.getVolumeSizeIncludingHypervisorSnapshotReserve(volume, pool); + VolumeInfo volumeInfo = volFactory.getVolume(volume.getId()); + + return primaryStoreDriver.getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, pool); } return volume.getSize(); } + private long getBytesRequiredForTemplate(VMTemplateVO tmpl, StoragePool pool) { + DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(pool.getStorageProviderName()); + DataStoreDriver storeDriver = storeProvider.getDataStoreDriver(); + + if (storeDriver instanceof PrimaryDataStoreDriver) { + PrimaryDataStoreDriver primaryStoreDriver = (PrimaryDataStoreDriver)storeDriver; + + TemplateInfo templateInfo = tmplFactory.getReadyTemplateOnImageStore(tmpl.getId(), pool.getDataCenterId()); + + return primaryStoreDriver.getBytesRequiredForTemplate(templateInfo, pool); + } + + return tmpl.getSize(); + } + @Override public void createCapacityEntry(long poolId) { StoragePoolVO storage = _storagePoolDao.findById(poolId); diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index 92435030ca..77ecc2a040 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -841,6 +841,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep Long newSize = null; Long newMinIops = null; Long newMaxIops = null; + Integer newHypervisorSnapshotReserve = null; boolean shrinkOk = cmd.getShrinkOk(); VolumeVO volume = _volsDao.findById(cmd.getEntityId()); @@ -883,6 +884,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep // if we are to use the existing disk offering if (newDiskOffering == null) { newSize = cmd.getSize(); + newHypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve(); // if the caller is looking to change the size of the volume if (newSize != null) { @@ -941,10 +943,6 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep throw new InvalidParameterValueException("There are no tags on the current disk offering. The new disk offering needs to have no tags, as well."); } - if (!areIntegersEqual(diskOffering.getHypervisorSnapshotReserve(), newDiskOffering.getHypervisorSnapshotReserve())) { - throw new InvalidParameterValueException("The hypervisor snapshot reverse on the new and old disk offerings must be equal."); - } - if (newDiskOffering.getDomainId() != null) { // not a public offering; check access _configMgr.checkDiskOfferingAccess(CallContext.current().getCallingAccount(), newDiskOffering); @@ -977,6 +975,9 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep newMinIops = newDiskOffering.getMinIops(); newMaxIops = newDiskOffering.getMaxIops(); } + + // if the hypervisor snapshot reserve value is null, it must remain null (currently only KVM uses null and null is all KVM uses for a value here) + newHypervisorSnapshotReserve = volume.getHypervisorSnapshotReserve() != null ? newDiskOffering.getHypervisorSnapshotReserve() : null; } long currentSize = volume.getSize(); @@ -1015,6 +1016,7 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep volume.setSize(newSize); volume.setMinIops(newMinIops); volume.setMaxIops(newMaxIops); + volume.setHypervisorSnapshotReserve(newHypervisorSnapshotReserve); if (newDiskOffering != null) { volume.setDiskOfferingId(cmd.getNewDiskOfferingId()); @@ -1040,13 +1042,13 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep try { return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, - newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); + newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); } finally { _workJobDao.expunge(placeHolder.getId()); } } else { Outcome outcome = resizeVolumeThroughJobQueue(userVm.getId(), volume.getId(), currentSize, newSize, newMinIops, newMaxIops, - newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); + newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); try { outcome.get(); @@ -1081,19 +1083,7 @@ else if (jobResult instanceof Long) { } return orchestrateResizeVolume(volume.getId(), currentSize, newSize, newMinIops, newMaxIops, - newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); - } - - private static boolean areIntegersEqual(Integer i1, Integer i2) { - if (i1 == null) { - i1 = 0; - } - - if (i2 == null) { - i2 = 0; - } - - return i1.equals(i2); + newHypervisorSnapshotReserve, newDiskOffering != null ? cmd.getNewDiskOfferingId() : null, shrinkOk); } private void validateIops(Long minIops, Long maxIops) { @@ -1108,9 +1098,12 @@ private void validateIops(Long minIops, Long maxIops) { } } - private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long newSize, Long newMinIops, Long newMaxIops, Long newDiskOfferingId, boolean shrinkOk) { + private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long newSize, Long newMinIops, Long newMaxIops, + Integer newHypervisorSnapshotReserve, Long newDiskOfferingId, boolean shrinkOk) { VolumeVO volume = _volsDao.findById(volumeId); UserVmVO userVm = _userVmDao.findById(volume.getInstanceId()); + StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); + boolean isManaged = storagePool.isManaged(); /* * get a list of hosts to send the commands to, try the system the * associated vm is running on first, then the last known place it ran. @@ -1129,8 +1122,6 @@ private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long n final String errorMsg = "The VM must be stopped or the disk detached in order to resize with the XenServer Hypervisor."; - StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId()); - if (storagePool.isManaged() && storagePool.getHypervisor() == HypervisorType.Any && hosts != null && hosts.length > 0) { HostVO host = _hostDao.findById(hosts[0]); @@ -1145,13 +1136,20 @@ private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long n } } - ResizeVolumePayload payload = new ResizeVolumePayload(newSize, newMinIops, newMaxIops, shrinkOk, instanceName, hosts); + ResizeVolumePayload payload = new ResizeVolumePayload(newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, + shrinkOk, instanceName, hosts, isManaged); try { VolumeInfo vol = volFactory.getVolume(volume.getId()); vol.addPayload(payload); - StoragePoolVO storagePool = _storagePoolDao.findById(vol.getPoolId()); + // this call to resize has a different impact depending on whether the + // underlying primary storage is managed or not + // if managed, this is the chance for the plug-in to change IOPS value, if applicable + // if not managed, this is the chance for the plug-in to talk to the hypervisor layer + // to change the size of the disk + AsyncCallFuture future = volService.resize(vol); + VolumeApiResult result = future.get(); // managed storage is designed in such a way that the storage plug-in does not // talk to the hypervisor layer; as such, if the storage is managed and the @@ -1167,14 +1165,6 @@ private VolumeVO orchestrateResizeVolume(long volumeId, long currentSize, long n _volsDao.update(volume.getId(), volume); } - // this call to resize has a different impact depending on whether the - // underlying primary storage is managed or not - // if managed, this is the chance for the plug-in to change IOPS value, if applicable - // if not managed, this is the chance for the plug-in to talk to the hypervisor layer - // to change the size of the disk - AsyncCallFuture future = volService.resize(vol); - VolumeApiResult result = future.get(); - if (result.isFailed()) { s_logger.warn("Failed to resize the volume " + volume); String details = ""; @@ -2761,9 +2751,9 @@ public Outcome detachVolumeFromVmThroughJobQueue(final Long vmId, final return new VmJobVolumeOutcome(workJob, volumeId); } - public Outcome resizeVolumeThroughJobQueue(final Long vmId, final long volumeId, - final long currentSize, final long newSize, final Long newMinIops, final Long newMaxIops, final Long newServiceOfferingId, final boolean shrinkOk) { - + public Outcome resizeVolumeThroughJobQueue(final Long vmId, final long volumeId, final long currentSize, final long newSize, + final Long newMinIops, final Long newMaxIops, final Integer newHypervisorSnapshotReserve, + final Long newServiceOfferingId, final boolean shrinkOk) { final CallContext context = CallContext.current(); final User callingUser = context.getCallingUser(); final Account callingAccount = context.getCallingAccount(); @@ -2784,7 +2774,7 @@ public Outcome resizeVolumeThroughJobQueue(final Long vmId, final long v // save work context info (there are some duplications) VmWorkResizeVolume workInfo = new VmWorkResizeVolume(callingUser.getId(), callingAccount.getId(), vm.getId(), - VolumeApiServiceImpl.VM_WORK_JOB_HANDLER, volumeId, currentSize, newSize, newMinIops, newMaxIops, newServiceOfferingId, shrinkOk); + VolumeApiServiceImpl.VM_WORK_JOB_HANDLER, volumeId, currentSize, newSize, newMinIops, newMaxIops, newHypervisorSnapshotReserve, newServiceOfferingId, shrinkOk); workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); @@ -2918,7 +2908,7 @@ private Pair orchestrateDetachVolumeFromVM(VmWorkDetachV @ReflectionUse private Pair orchestrateResizeVolume(VmWorkResizeVolume work) throws Exception { Volume vol = orchestrateResizeVolume(work.getVolumeId(), work.getCurrentSize(), work.getNewSize(), work.getNewMinIops(), work.getNewMaxIops(), - work.getNewServiceOfferingId(), work.isShrinkOk()); + work.getNewHypervisorSnapshotReserve(), work.getNewServiceOfferingId(), work.isShrinkOk()); return new Pair(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(new Long(vol.getId()))); } diff --git a/server/src/com/cloud/storage/download/DownloadListener.java b/server/src/com/cloud/storage/download/DownloadListener.java index 814ce3c44b..51f9d42980 100644 --- a/server/src/com/cloud/storage/download/DownloadListener.java +++ b/server/src/com/cloud/storage/download/DownloadListener.java @@ -270,9 +270,7 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman } @Override - public boolean processDisconnect(long agentId, com.cloud.host.Status state) { - setDisconnected(); - return true; + public void processHostAdded(long hostId) { } @Override @@ -310,6 +308,20 @@ else if (cmd instanceof StartupSecondaryStorageCommand) { } } + @Override + public boolean processDisconnect(long agentId, com.cloud.host.Status state) { + setDisconnected(); + return true; + } + + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + public void setCommand(DownloadCommand cmd) { this._cmd = cmd; } diff --git a/server/src/com/cloud/storage/listener/StoragePoolMonitor.java b/server/src/com/cloud/storage/listener/StoragePoolMonitor.java index ad65bd63b6..dcbe4744ad 100644 --- a/server/src/com/cloud/storage/listener/StoragePoolMonitor.java +++ b/server/src/com/cloud/storage/listener/StoragePoolMonitor.java @@ -22,6 +22,10 @@ import org.apache.log4j.Logger; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreProvider; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; @@ -46,13 +50,14 @@ public class StoragePoolMonitor implements Listener { private static final Logger s_logger = Logger.getLogger(StoragePoolMonitor.class); private final StorageManagerImpl _storageManager; private final PrimaryDataStoreDao _poolDao; + private DataStoreProviderManager _dataStoreProviderMgr; @Inject OCFS2Manager _ocfs2Mgr; - public StoragePoolMonitor(StorageManagerImpl mgr, PrimaryDataStoreDao poolDao) { - this._storageManager = mgr; - this._poolDao = poolDao; - + public StoragePoolMonitor(StorageManagerImpl mgr, PrimaryDataStoreDao poolDao, DataStoreProviderManager dataStoreProviderMgr) { + _storageManager = mgr; + _poolDao = poolDao; + _dataStoreProviderMgr = dataStoreProviderMgr; } @Override @@ -66,8 +71,25 @@ public synchronized boolean processAnswers(long agentId, long seq, Answer[] resp } @Override - public synchronized boolean processDisconnect(long agentId, Status state) { - return true; + public void processHostAdded(long hostId) { + List providers = _dataStoreProviderMgr.getProviders(); + + if (providers != null) { + for (DataStoreProvider provider : providers) { + if (provider instanceof PrimaryDataStoreProvider) { + try { + HypervisorHostListener hypervisorHostListener = provider.getHostListener(); + + if (hypervisorHostListener != null) { + hypervisorHostListener.hostAdded(hostId); + } + } + catch (Exception ex) { + s_logger.error("hostAdded(long) failed for storage provider " + provider.getName(), ex); + } + } + } + } } @Override @@ -111,6 +133,55 @@ public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) } } + @Override + public synchronized boolean processDisconnect(long agentId, Status state) { + return true; + } + + @Override + public void processHostAboutToBeRemoved(long hostId) { + List providers = _dataStoreProviderMgr.getProviders(); + + if (providers != null) { + for (DataStoreProvider provider : providers) { + if (provider instanceof PrimaryDataStoreProvider) { + try { + HypervisorHostListener hypervisorHostListener = provider.getHostListener(); + + if (hypervisorHostListener != null) { + hypervisorHostListener.hostAboutToBeRemoved(hostId); + } + } + catch (Exception ex) { + s_logger.error("hostAboutToBeRemoved(long) failed for storage provider " + provider.getName(), ex); + } + } + } + } + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + List providers = _dataStoreProviderMgr.getProviders(); + + if (providers != null) { + for (DataStoreProvider provider : providers) { + if (provider instanceof PrimaryDataStoreProvider) { + try { + HypervisorHostListener hypervisorHostListener = provider.getHostListener(); + + if (hypervisorHostListener != null) { + hypervisorHostListener.hostRemoved(hostId, clusterId); + } + } + catch (Exception ex) { + s_logger.error("hostRemoved(long, long) failed for storage provider " + provider.getName(), ex); + } + } + } + } + } + @Override public boolean processCommands(long agentId, long seq, Command[] req) { return false; diff --git a/server/src/com/cloud/storage/listener/StorageSyncListener.java b/server/src/com/cloud/storage/listener/StorageSyncListener.java index fe15d30b95..eeef434367 100644 --- a/server/src/com/cloud/storage/listener/StorageSyncListener.java +++ b/server/src/com/cloud/storage/listener/StorageSyncListener.java @@ -50,6 +50,10 @@ public boolean processAnswers(long agentId, long seq, Answer[] answers) { return true; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) { } @@ -60,6 +64,14 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processCommands(long agentId, long seq, Command[] request) { return false; diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java b/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java index 43613e7f9c..b78a548729 100644 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java @@ -65,6 +65,10 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman return null; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) { if ((cmd instanceof StartupStorageCommand)) { @@ -91,6 +95,14 @@ public boolean processDisconnect(long agentId, Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return true; diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 65f5140418..16762c5013 100644 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -35,6 +35,7 @@ import org.apache.cloudstack.api.command.user.snapshot.UpdateSnapshotPolicyCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreCapabilities; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; @@ -58,6 +59,7 @@ import com.cloud.agent.api.DeleteSnapshotsDirCommand; import com.cloud.alert.AlertManager; import com.cloud.api.commands.ListRecurringSnapshotScheduleCmd; +import com.cloud.api.query.MutualExclusiveIdsManagerBase; import com.cloud.configuration.Config; import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.ClusterVO; @@ -112,7 +114,6 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; -import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; @@ -129,7 +130,7 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component -public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, SnapshotApiService { +public class SnapshotManagerImpl extends MutualExclusiveIdsManagerBase implements SnapshotManager, SnapshotApiService { private static final Logger s_logger = Logger.getLogger(SnapshotManagerImpl.class); @Inject VMTemplateDao _templateDao; @@ -512,6 +513,8 @@ public Pair, Integer> listSnapshots(ListSnapshotsCmd cm } } + List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); + Ternary domainIdRecursiveListProject = new Ternary(cmd.getDomainId(), cmd.isRecursive(), null); _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); Long domainId = domainIdRecursiveListProject.first(); @@ -526,6 +529,7 @@ public Pair, Integer> listSnapshots(ListSnapshotsCmd cm sb.and("volumeId", sb.entity().getVolumeId(), SearchCriteria.Op.EQ); sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); sb.and("snapshotTypeEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.IN); sb.and("snapshotTypeNEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.NEQ); sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); @@ -565,6 +569,8 @@ public Pair, Integer> listSnapshots(ListSnapshotsCmd cm sc.setParameters("dataCenterId", zoneId); } + setIdsListToSearchCriteria(sc, ids); + if (name != null) { sc.setParameters("name", "%" + name + "%"); } @@ -1008,9 +1014,14 @@ public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationExc try { postCreateSnapshot(volume.getId(), snapshotId, payload.getSnapshotPolicyId()); - SnapshotDataStoreVO snapshotStoreRef = _snapshotStoreDao.findBySnapshot(snapshotId, DataStoreRole.Image); + + DataStoreRole dataStoreRole = getDataStoreRole(snapshot, _snapshotStoreDao, dataStoreMgr); + + SnapshotDataStoreVO snapshotStoreRef = _snapshotStoreDao.findBySnapshot(snapshotId, dataStoreRole); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, snapshotStoreRef.getPhysicalSize(), volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid()); + // Correct the resource count of snapshot in case of delta snapshots. _resourceLimitMgr.decrementResourceCount(snapshotOwner.getId(), ResourceType.secondary_storage, new Long(volume.getSize() - snapshotStoreRef.getPhysicalSize())); } catch (Exception e) { @@ -1025,6 +1036,30 @@ public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationExc return snapshot; } + private static DataStoreRole getDataStoreRole(Snapshot snapshot, SnapshotDataStoreDao snapshotStoreDao, DataStoreManager dataStoreMgr) { + SnapshotDataStoreVO snapshotStore = snapshotStoreDao.findBySnapshot(snapshot.getId(), DataStoreRole.Primary); + + if (snapshotStore == null) { + return DataStoreRole.Image; + } + + long storagePoolId = snapshotStore.getDataStoreId(); + DataStore dataStore = dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + + Map mapCapabilities = dataStore.getDriver().getCapabilities(); + + if (mapCapabilities != null) { + String value = mapCapabilities.get(DataStoreCapabilities.STORAGE_SYSTEM_SNAPSHOT.toString()); + Boolean supportsStorageSystemSnapshots = new Boolean(value); + + if (supportsStorageSystemSnapshots) { + return DataStoreRole.Primary; + } + } + + return DataStoreRole.Image; + } + @Override public boolean configure(String name, Map params) throws ConfigurationException { diff --git a/server/src/com/cloud/storage/upload/UploadListener.java b/server/src/com/cloud/storage/upload/UploadListener.java index f6ad815d00..838676ef0f 100644 --- a/server/src/com/cloud/storage/upload/UploadListener.java +++ b/server/src/com/cloud/storage/upload/UploadListener.java @@ -113,8 +113,6 @@ protected void runInContext() { private DataStore sserver; - private boolean uploadActive = true; - private UploadDao uploadDao; private final UploadMonitorImpl uploadMonitor; @@ -250,6 +248,10 @@ public boolean processCommands(long agentId, long seq, Command[] commands) { return false; } + @Override + public void processHostAdded(long hostId) { + } + @Override public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) { if (!(cmd instanceof StartupStorageCommand)) { @@ -270,7 +272,6 @@ public AgentControlAnswer processControlCommand(long agentId, AgentControlComman } public void setUploadInactive(Status reason) { - uploadActive = false; uploadMonitor.handleUploadEvent(accountId, typeName, type, uploadId, reason, eventId); } @@ -294,6 +295,14 @@ public boolean processDisconnect(long agentId, com.cloud.host.Status state) { return true; } + @Override + public void processHostAboutToBeRemoved(long hostId) { + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + } + @Override public boolean processTimeout(long agentId, long seq) { return true; diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index e6141425df..c03db35672 100644 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -38,8 +38,10 @@ import com.google.gson.GsonBuilder; import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd; -import org.apache.cloudstack.api.response.GetUploadParamsResponse; +import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; @@ -62,12 +64,14 @@ import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd; import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd; +import org.apache.cloudstack.api.response.GetUploadParamsResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; @@ -79,7 +83,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; -import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -262,7 +265,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, private UserVmJoinDao _userVmJoinDao; @Inject private SnapshotDataStoreDao _snapshotStoreDao; - + @Inject + private ImageStoreDao _imgStoreDao; @Inject MessageBus _messageBus; @@ -276,6 +280,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Inject private EndPointSelector selector; + private TemplateAdapter getAdapter(HypervisorType type) { TemplateAdapter adapter = null; if (type == HypervisorType.BareMetal) { @@ -689,7 +694,9 @@ public boolean resetTemplateDownloadStateOnPool(long templateStoragePoolRefId) { } try { + templateStoragePoolRef.setTemplateSize(0); templateStoragePoolRef.setDownloadState(VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED); + _tmpltPoolDao.update(templateStoragePoolRefId, templateStoragePoolRef); } finally { _tmpltPoolDao.releaseFromLockTable(templateStoragePoolRefId); @@ -873,41 +880,55 @@ public List getUnusedTemplatesInPool(StoragePoolVO pool @Override @DB public void evictTemplateFromStoragePool(VMTemplateStoragePoolVO templatePoolVO) { - //Need to hold the lock, otherwise, another thread may create a volume from the template at the same time. - //Assumption here is that, we will hold the same lock during create volume from template + // Need to hold the lock; otherwise, another thread may create a volume from the template at the same time. + // Assumption here is that we will hold the same lock during create volume from template. VMTemplateStoragePoolVO templatePoolRef = _tmpltPoolDao.acquireInLockTable(templatePoolVO.getId()); + if (templatePoolRef == null) { - s_logger.debug("can't aquire the lock for template pool ref:" + templatePoolVO.getId()); + s_logger.debug("Can't aquire the lock for template pool ref: " + templatePoolVO.getId()); + return; } - try { - StoragePool pool = (StoragePool)_dataStoreMgr.getPrimaryDataStore(templatePoolVO.getPoolId()); - VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId()); + PrimaryDataStore pool = (PrimaryDataStore)_dataStoreMgr.getPrimaryDataStore(templatePoolVO.getPoolId()); + TemplateInfo template = _tmplFactory.getTemplate(templatePoolRef.getTemplateId(), pool); + try { if (s_logger.isDebugEnabled()) { s_logger.debug("Evicting " + templatePoolVO); } - DestroyCommand cmd = new DestroyCommand(pool, templatePoolVO); - try { + if (pool.isManaged()) { + // For managed store, just delete the template volume. + AsyncCallFuture future = _tmpltSvr.deleteTemplateOnPrimary(template, pool); + TemplateApiResult result = future.get(); + + if (result.isFailed()) { + s_logger.debug("Failed to delete template " + template.getId() + " from storage pool " + pool.getId()); + } else { + // Remove the templatePoolVO. + if (_tmpltPoolDao.remove(templatePoolVO.getId())) { + s_logger.debug("Successfully evicted template " + template.getName() + " from storage pool " + pool.getName()); + } + } + } else { + DestroyCommand cmd = new DestroyCommand(pool, templatePoolVO); Answer answer = _storageMgr.sendToPool(pool, cmd); if (answer != null && answer.getResult()) { - // Remove the templatePoolVO + // Remove the templatePoolVO. if (_tmpltPoolDao.remove(templatePoolVO.getId())) { - s_logger.debug("Successfully evicted template: " + template.getName() + " from storage pool: " + pool.getName()); + s_logger.debug("Successfully evicted template " + template.getName() + " from storage pool " + pool.getName()); } } else { - s_logger.info("Will retry evicte template: " + template.getName() + " from storage pool: " + pool.getName()); + s_logger.info("Will retry evict template " + template.getName() + " from storage pool " + pool.getName()); } - } catch (StorageUnavailableException e) { - s_logger.info("Storage is unavailable currently. Will retry evicte template: " + template.getName() + " from storage pool: " + pool.getName()); } + } catch (StorageUnavailableException | InterruptedException | ExecutionException e) { + s_logger.info("Storage is unavailable currently. Will retry evicte template " + template.getName() + " from storage pool " + pool.getName()); } finally { _tmpltPoolDao.releaseFromLockTable(templatePoolRef.getId()); } - } @Override @@ -926,7 +947,7 @@ public boolean configure(String name, Map params) throws Configu String disableExtraction = _configDao.getValue(Config.DisableExtraction.toString()); _disableExtraction = (disableExtraction == null) ? false : Boolean.parseBoolean(disableExtraction); - _preloadExecutor = Executors.newFixedThreadPool(8, new NamedThreadFactory("Template-Preloader")); + _preloadExecutor = Executors.newFixedThreadPool(TemplatePreloaderPoolSize.value(), new NamedThreadFactory("Template-Preloader")); return true; } @@ -1482,14 +1503,17 @@ public VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd command) t future = _tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store); } else if (volumeId != null) { VolumeInfo volInfo = _volFactory.getVolume(volumeId); + future = _tmpltSvr.createTemplateFromVolumeAsync(volInfo, tmplInfo, store); } else { throw new CloudRuntimeException("Creating private Template need to specify snapshotId or volumeId"); } CommandResult result = null; + try { result = future.get(); + if (result.isFailed()) { privateTemplate = null; s_logger.debug("Failed to create template" + result.getResult()); @@ -1699,6 +1723,14 @@ public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account t s_logger.debug("This template is getting created from other template, setting source template Id to: " + sourceTemplateId); } } + + + // for region wide storage, set cross zones flag + List stores = _imgStoreDao.findRegionImageStores(); + if (!CollectionUtils.isEmpty(stores)) { + privateTemplate.setCrossZones(true); + } + privateTemplate.setSourceTemplateId(sourceTemplateId); VMTemplateVO template = _tmpltDao.persist(privateTemplate); @@ -1975,7 +2007,7 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {AllowPublicUserTemplates}; + return new ConfigKey[] {AllowPublicUserTemplates, TemplatePreloaderPoolSize}; } public List getTemplateAdapters() { diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java index 7b9e0936bb..9789a22329 100644 --- a/server/src/com/cloud/user/AccountManager.java +++ b/server/src/com/cloud/user/AccountManager.java @@ -50,7 +50,7 @@ public interface AccountManager extends AccountService { Long checkAccessAndSpecifyAuthority(Account caller, Long zoneId); - Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details, String uuid); + Account createAccount(String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String uuid); /** * Logs out a user diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index d3eb40c7db..7e80681caa 100644 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -994,9 +994,9 @@ private boolean doDisableAccount(long accountId) throws ConcurrentOperationExcep @ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User") }) public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, final String timezone, - String accountName, final short accountType, Long domainId, final String networkDomain, final Map details, String accountUUID, final String userUUID) { + String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map details, String accountUUID, final String userUUID) { - return createUserAccount(userName, password, firstName, lastName, email, timezone, accountName, accountType, domainId, networkDomain, details, accountUUID, userUUID, + return createUserAccount(userName, password, firstName, lastName, email, timezone, accountName, accountType, roleId, domainId, networkDomain, details, accountUUID, userUUID, User.Source.UNKNOWN); } @@ -1011,7 +1011,7 @@ public UserAccount createUserAccount(final String userName, final String passwor @ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User") }) public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, - final String timezone, String accountName, final short accountType, Long domainId, final String networkDomain, final Map details, + final String timezone, String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map details, String accountUUID, final String userUUID, final User.Source source) { if (accountName == null) { @@ -1065,7 +1065,7 @@ public Pair doInTransaction(TransactionStatus status) { if (accountUUID == null) { accountUUID = UUID.randomUUID().toString(); } - AccountVO account = createAccount(accountNameFinal, accountType, domainIdFinal, networkDomain, details, accountUUID); + AccountVO account = createAccount(accountNameFinal, accountType, roleId, domainIdFinal, networkDomain, details, accountUUID); long accountId = account.getId(); // create the first user for the account @@ -1869,27 +1869,10 @@ public Account getAccount(long accountId) { @Override public RoleType getRoleType(Account account) { - RoleType roleType = RoleType.Unknown; - if (account == null) - return roleType; - short accountType = account.getType(); - - // Account type to role type translation - switch (accountType) { - case Account.ACCOUNT_TYPE_ADMIN: - roleType = RoleType.Admin; - break; - case Account.ACCOUNT_TYPE_DOMAIN_ADMIN: - roleType = RoleType.DomainAdmin; - break; - case Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN: - roleType = RoleType.ResourceAdmin; - break; - case Account.ACCOUNT_TYPE_NORMAL: - roleType = RoleType.User; - break; + if (account == null) { + return RoleType.Unknown; } - return roleType; + return RoleType.getByAccountType(account.getType()); } @Override @@ -1916,7 +1899,7 @@ public void markUserRegistered(long userId) { @Override @DB - public AccountVO createAccount(final String accountName, final short accountType, final Long domainId, final String networkDomain, final Map details, + public AccountVO createAccount(final String accountName, final short accountType, final Long roleId, final Long domainId, final String networkDomain, final Map details, final String uuid) { // Validate domain Domain domain = _domainMgr.getDomain(domainId); @@ -1929,7 +1912,7 @@ public AccountVO createAccount(final String accountName, final short accountType } if ((domainId != Domain.ROOT_DOMAIN) && (accountType == Account.ACCOUNT_TYPE_ADMIN)) { - throw new InvalidParameterValueException("Invalid account type " + accountType + " given for an account in domain " + domainId + "; unable to create user."); + throw new InvalidParameterValueException("Invalid account type " + accountType + " given for an account in domain " + domainId + "; unable to create user of admin role type in non-ROOT domain."); } // Validate account/user/domain settings @@ -1961,7 +1944,7 @@ public AccountVO createAccount(final String accountName, final short accountType return Transaction.execute(new TransactionCallback() { @Override public AccountVO doInTransaction(TransactionStatus status) { - AccountVO account = _accountDao.persist(new AccountVO(accountName, domainId, networkDomain, accountType, uuid)); + AccountVO account = _accountDao.persist(new AccountVO(accountName, domainId, networkDomain, accountType, roleId, uuid)); if (account == null) { throw new CloudRuntimeException("Failed to create account name " + accountName + " in domain id=" + domainId); diff --git a/server/src/com/cloud/user/DomainManagerImpl.java b/server/src/com/cloud/user/DomainManagerImpl.java index 71f9b6726e..13dcd90f42 100644 --- a/server/src/com/cloud/user/DomainManagerImpl.java +++ b/server/src/com/cloud/user/DomainManagerImpl.java @@ -328,6 +328,7 @@ public boolean deleteDomain(DomainVO domain, Boolean cleanup) { cleanupDomainOfferings(domain.getId()); CallContext.current().putContextParameter(Domain.class, domain.getUuid()); + _messageBus.publish(_name, MESSAGE_REMOVE_DOMAIN_EVENT, PublishScope.LOCAL, domain); return true; } catch (Exception ex) { s_logger.error("Exception deleting domain with id " + domain.getId(), ex); diff --git a/server/src/com/cloud/vm/UserVmManager.java b/server/src/com/cloud/vm/UserVmManager.java index fe0e98c8cd..411fd9b669 100644 --- a/server/src/com/cloud/vm/UserVmManager.java +++ b/server/src/com/cloud/vm/UserVmManager.java @@ -103,7 +103,7 @@ boolean upgradeVirtualMachine(Long id, Long serviceOfferingId, Map securityGroupIdList) throws ResourceUnavailableException, InsufficientCapacityException; //the validateCustomParameters, save and remove CustomOfferingDetils functions can be removed from the interface once we can //find a common place for all the scaling and upgrading code of both user and systemvms. diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index cc007d9021..9eddf6dabd 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -55,6 +55,7 @@ import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; +import org.apache.cloudstack.api.command.user.vm.SecurityGroupAction; import org.apache.cloudstack.api.command.user.vm.StartVMCmd; import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; @@ -194,6 +195,7 @@ import com.cloud.network.security.dao.SecurityGroupVMMapDao; import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offering.DiskOffering; import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offering.ServiceOffering; @@ -2289,6 +2291,7 @@ public UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableEx String hostName = cmd.getHostName(); Map details = cmd.getDetails(); Account caller = CallContext.current().getCallingAccount(); + List securityGroupIdList = getSecurityGroupIdList(cmd); // Input validation and permission checks UserVmVO vmInstance = _vmDao.findById(id); @@ -2339,7 +2342,7 @@ public UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableEx } return updateVirtualMachine(id, displayName, group, ha, isDisplayVm, osTypeId, userData, isDynamicallyScalable, - cmd.getHttpMethod(), cmd.getCustomId(), hostName, cmd.getInstanceName()); + cmd.getHttpMethod(), cmd.getCustomId(), hostName, cmd.getInstanceName(), securityGroupIdList); } private void saveUsageEvent(UserVmVO vm) { @@ -2389,10 +2392,11 @@ private void generateNetworkUsageForVm(VirtualMachine vm, boolean isDisplay, Str @Override public UserVm updateVirtualMachine(long id, String displayName, String group, Boolean ha, Boolean isDisplayVmEnabled, Long osTypeId, String userData, - Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName) throws ResourceUnavailableException, InsufficientCapacityException { + Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List securityGroupIdList) + throws ResourceUnavailableException, InsufficientCapacityException { UserVmVO vm = _vmDao.findById(id); if (vm == null) { - throw new CloudRuntimeException("Unable to find virual machine with id " + id); + throw new CloudRuntimeException("Unable to find virtual machine with id " + id); } if(instanceName != null){ @@ -2451,6 +2455,44 @@ public UserVm updateVirtualMachine(long id, String displayName, String group, Bo isDynamicallyScalable = vm.isDynamicallyScalable(); } + boolean isVMware = (vm.getHypervisorType() == HypervisorType.VMware); + + if (securityGroupIdList != null && isVMware) { + throw new InvalidParameterValueException("Security group feature is not supported for vmWare hypervisor"); + } else { + // Get default guest network in Basic zone + Network defaultNetwork = null; + try { + DataCenterVO zone = _dcDao.findById(vm.getDataCenterId()); + + if (zone.getNetworkType() == NetworkType.Basic) { + // Get default guest network in Basic zone + defaultNetwork = _networkModel.getExclusiveGuestNetwork(zone.getId()); + } else if (zone.isSecurityGroupEnabled()) { + NicVO defaultNic = _nicDao.findDefaultNicForVM(vm.getId()); + if (defaultNic != null) { + defaultNetwork = _networkDao.findById(defaultNic.getNetworkId()); + } + } + } catch (InvalidParameterValueException e) { + if(s_logger.isDebugEnabled()) { + s_logger.debug(e.getMessage(),e); + } + defaultNetwork = _networkModel.getDefaultNetworkForVm(id); + } + + if (securityGroupIdList != null && _networkModel.isSecurityGroupSupportedInNetwork(defaultNetwork) && _networkModel.canAddDefaultSecurityGroup()) { + if (vm.getState() == State.Stopped) { + // Remove instance from security groups + _securityGroupMgr.removeInstanceFromGroups(id); + // Add instance in provided groups + _securityGroupMgr.addInstanceToGroups(id, securityGroupIdList); + } else { + throw new InvalidParameterValueException("Virtual machine must be stopped prior to update security groups "); + } + } + } + if (hostName != null) { // Check is hostName is RFC compliant checkNameForRFCCompliance(hostName); @@ -2492,24 +2534,34 @@ private boolean updateUserDataInternal(UserVm vm) throws ResourceUnavailableExce return false; } + boolean userDataApplied = false; for (Nic nic : nics) { - Network network = _networkDao.findById(nic.getNetworkId()); - NicProfile nicProfile = new NicProfile(nic, network, null, null, null, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag( - template.getHypervisorType(), network)); + userDataApplied |= applyUserData(template.getHypervisorType(), vm, nic); + } + return userDataApplied; + } - VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vm); + protected boolean applyUserData(HypervisorType hyperVisorType, UserVm vm, Nic nic) throws ResourceUnavailableException, InsufficientCapacityException { + Network network = _networkDao.findById(nic.getNetworkId()); + NicProfile nicProfile = new NicProfile(nic, network, null, null, null, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag( + hyperVisorType, network)); + VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vm); - UserDataServiceProvider element = _networkModel.getUserDataUpdateProvider(network); - if (element == null) { - throw new CloudRuntimeException("Can't find network element for " + Service.UserData.getName() + " provider needed for UserData update"); - } - boolean result = element.saveUserData(network, nicProfile, vmProfile); - if (!result) { - s_logger.error("Failed to update userdata for vm " + vm + " and nic " + nic); - } + if (_networkModel.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Service.UserData)) { + UserDataServiceProvider element = _networkModel.getUserDataUpdateProvider(network); + if (element == null) { + throw new CloudRuntimeException("Can't find network element for " + Service.UserData.getName() + " provider needed for UserData update"); + } + boolean result = element.saveUserData(network, nicProfile, vmProfile); + if (!result) { + s_logger.error("Failed to update userdata for vm " + vm + " and nic " + nic); + } else { + return true; + } + } else { + s_logger.debug("Not applying userdata for nic id=" + nic.getId() + " in vm id=" + vmProfile.getId() + " because it is not supported in network id=" + network.getId()); } - - return true; + return false; } @Override @@ -4270,8 +4322,172 @@ public HypervisorType getHypervisorTypeOfUserVM(long vmId) { @Override public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { - // TODO Auto-generated method stub - return null; + //Verify that all objects exist before passing them to the service + Account owner = _accountService.getActiveAccountById(cmd.getEntityOwnerId()); + + verifyDetails(cmd.getDetails()); + + Long zoneId = cmd.getZoneId(); + + DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId); + if (zone == null) { + throw new InvalidParameterValueException("Unable to find zone by id=" + zoneId); + } + + Long serviceOfferingId = cmd.getServiceOfferingId(); + + ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId); + if (serviceOffering == null) { + throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId); + } + + Long templateId = cmd.getTemplateId(); + + if(!serviceOffering.isDynamic()) { + for(String detail: cmd.getDetails().keySet()) { + if(detail.equalsIgnoreCase("cpuNumber") || detail.equalsIgnoreCase("cpuSpeed") || detail.equalsIgnoreCase("memory")) { + throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering"); + } + } + } + + VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId); + // Make sure a valid template ID was specified + if (template == null) { + throw new InvalidParameterValueException("Unable to use template " + templateId); + } + + Long diskOfferingId = cmd.getDiskOfferingId(); + DiskOffering diskOffering = null; + if (diskOfferingId != null) { + diskOffering = _entityMgr.findById(DiskOffering.class, diskOfferingId); + if (diskOffering == null) { + throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId); + } + } + + if (!zone.isLocalStorageEnabled()) { + if (serviceOffering.getUseLocalStorage()) { + throw new InvalidParameterValueException("Zone is not configured to use local storage but service offering " + serviceOffering.getName() + " uses it"); + } + if (diskOffering != null && diskOffering.getUseLocalStorage()) { + throw new InvalidParameterValueException("Zone is not configured to use local storage but disk offering " + diskOffering.getName() + " uses it"); + } + } + + String ipAddress = cmd.getIpAddress(); + String ip6Address = cmd.getIp6Address(); + String name = cmd.getName(); + String displayName = cmd.getDisplayName(); + UserVm vm = null; + IpAddresses addrs = new IpAddresses(ipAddress, ip6Address); + Long size = cmd.getSize(); + String group = cmd.getGroup(); + String userData = cmd.getUserData(); + String sshKeyPairName = cmd.getSSHKeyPairName(); + Boolean displayVm = cmd.getDisplayVm(); + String keyboard = cmd.getKeyboard(); + if (zone.getNetworkType() == NetworkType.Basic) { + if (cmd.getNetworkIds() != null) { + throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); + } else { + vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId, + size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData , sshKeyPairName , cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(), + cmd.getDetails(), cmd.getCustomId()); + } + } else { + if (zone.isSecurityGroupEnabled()) { + vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, cmd.getNetworkIds(), getSecurityGroupIdList(cmd), owner, name, + displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, + cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId()); + + } else { + if (cmd.getSecurityGroupIdList() != null && !cmd.getSecurityGroupIdList().isEmpty()) { + throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); + } + vm = createAdvancedVirtualMachine(zone, serviceOffering, template, cmd.getNetworkIds(), owner, name, displayName, diskOfferingId, size, group, + cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(), + cmd.getCustomId()); + } + } + return vm; + } + + private List getSecurityGroupIdList(SecurityGroupAction cmd) { + if (cmd.getSecurityGroupNameList() != null && cmd.getSecurityGroupIdList() != null) { + throw new InvalidParameterValueException("securitygroupids parameter is mutually exclusive with securitygroupnames parameter"); + } + + //transform group names to ids here + if (cmd.getSecurityGroupNameList() != null) { + List securityGroupIds = new ArrayList(); + for (String groupName : cmd.getSecurityGroupNameList()) { + SecurityGroup sg = _securityGroupMgr.getSecurityGroup(groupName, cmd.getEntityOwnerId()); + if (sg == null) { + throw new InvalidParameterValueException("Unable to find group by name " + groupName); + } else { + securityGroupIds.add(sg.getId()); + } + } + return securityGroupIds; + } else { + return cmd.getSecurityGroupIdList(); + } + } + + // this is an opportunity to verify that parameters that came in via the Details Map are OK + // for example, minIops and maxIops should either both be specified or neither be specified and, + // if specified, minIops should be <= maxIops + private void verifyDetails(Map details) { + if (details != null) { + String minIops = (String)details.get("minIops"); + String maxIops = (String)details.get("maxIops"); + + verifyMinAndMaxIops(minIops, maxIops); + + minIops = (String)details.get("minIopsDo"); + maxIops = (String)details.get("maxIopsDo"); + + verifyMinAndMaxIops(minIops, maxIops); + } + } + + private void verifyMinAndMaxIops(String minIops, String maxIops) { + if ((minIops != null && maxIops == null) || (minIops == null && maxIops != null)) { + throw new InvalidParameterValueException("Either 'Min IOPS' and 'Max IOPS' must both be specified or neither be specified."); + } + + long lMinIops; + + try { + if (minIops != null) { + lMinIops = Long.parseLong(minIops); + } + else { + lMinIops = 0; + } + } + catch (NumberFormatException ex) { + throw new InvalidParameterValueException("'Min IOPS' must be a whole number."); + } + + long lMaxIops; + + try { + if (maxIops != null) { + lMaxIops = Long.parseLong(maxIops); + } + else { + lMaxIops = 0; + } + } + catch (NumberFormatException ex) { + throw new InvalidParameterValueException("'Max IOPS' must be a whole number."); + } + + if (lMinIops > lMaxIops) { + throw new InvalidParameterValueException("'Min IOPS' must be less than or equal to 'Max IOPS'."); + } } @Override diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java index c113e3c920..d8f459627b 100644 --- a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -46,6 +46,7 @@ import org.apache.cloudstack.jobs.JobInfo; import org.apache.cloudstack.utils.identity.ManagementServerNode; +import com.cloud.api.query.MutualExclusiveIdsManagerBase; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; @@ -77,7 +78,6 @@ import com.cloud.utils.Predicate; import com.cloud.utils.ReflectionUse; import com.cloud.utils.Ternary; -import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.Filter; import com.cloud.utils.db.SearchBuilder; @@ -99,7 +99,7 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component -public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotManager, VMSnapshotService, VmWorkJobHandler { +public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase implements VMSnapshotManager, VMSnapshotService, VmWorkJobHandler { private static final Logger s_logger = Logger.getLogger(VMSnapshotManagerImpl.class); public static final String VM_WORK_JOB_HANDLER = VMSnapshotManagerImpl.class.getSimpleName(); @@ -176,6 +176,8 @@ public List listVMSnapshots(ListVMSnapshotCmd cmd) { String name = cmd.getVmSnapshotName(); String accountName = cmd.getAccountName(); + List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); + Ternary domainIdRecursiveListProject = new Ternary( cmd.getDomainId(), cmd.isRecursive(), null); _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, listAll, @@ -193,6 +195,7 @@ public List listVMSnapshots(ListVMSnapshotCmd cmd) { sb.and("status", sb.entity().getState(), SearchCriteria.Op.IN); sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); + sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); sb.and("display_name", sb.entity().getDisplayName(), SearchCriteria.Op.EQ); sb.and("account_id", sb.entity().getAccountId(), SearchCriteria.Op.EQ); sb.done(); @@ -209,6 +212,8 @@ public List listVMSnapshots(ListVMSnapshotCmd cmd) { sc.setParameters("vm_id", vmId); } + setIdsListToSearchCriteria(sc, ids); + if (domainId != null) { sc.setParameters("domain_id", domainId); } diff --git a/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java b/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java new file mode 100644 index 0000000000..7363b13b35 --- /dev/null +++ b/server/src/org/apache/cloudstack/acl/RoleManagerImpl.java @@ -0,0 +1,264 @@ +// 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.acl; + +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.user.Account; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.ListUtils; +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.component.PluggableService; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionStatus; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.dao.RoleDao; +import org.apache.cloudstack.acl.dao.RolePermissionsDao; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.admin.acl.CreateRoleCmd; +import org.apache.cloudstack.api.command.admin.acl.CreateRolePermissionCmd; +import org.apache.cloudstack.api.command.admin.acl.DeleteRoleCmd; +import org.apache.cloudstack.api.command.admin.acl.DeleteRolePermissionCmd; +import org.apache.cloudstack.api.command.admin.acl.ListRolePermissionsCmd; +import org.apache.cloudstack.api.command.admin.acl.ListRolesCmd; +import org.apache.cloudstack.api.command.admin.acl.UpdateRoleCmd; +import org.apache.cloudstack.api.command.admin.acl.UpdateRolePermissionCmd; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; + +import javax.ejb.Local; +import javax.inject.Inject; +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Local(value = {RoleService.class}) +public class RoleManagerImpl extends ManagerBase implements RoleService, Configurable, PluggableService { + @Inject + private AccountDao accountDao; + @Inject + private RoleDao roleDao; + @Inject + private RolePermissionsDao rolePermissionsDao; + + private void checkCallerAccess() { + if (!isEnabled()) { + throw new PermissionDeniedException("Dynamic api checker is not enabled, aborting role operation"); + } + Account caller = CallContext.current().getCallingAccount(); + if (caller == null || caller.getRoleId() == null) { + throw new PermissionDeniedException("Restricted API called by an invalid user account"); + } + Role callerRole = findRole(caller.getRoleId()); + if (callerRole == null || callerRole.getRoleType() != RoleType.Admin) { + throw new PermissionDeniedException("Restricted API called by an user account of non-Admin role type"); + } + } + + @Override + public boolean isEnabled() { + File apiCmdFile = PropertiesUtil.findConfigFile(PropertiesUtil.getDefaultApiCommandsFileName()); + return RoleService.EnableDynamicApiChecker.value() && (apiCmdFile == null || !apiCmdFile.exists()); + } + + @Override + public Role findRole(final Long id) { + if (id == null || id < 1L) { + return null; + } + return roleDao.findById(id); + } + + @Override + public RolePermission findRolePermission(final Long id) { + if (id == null) { + return null; + } + return rolePermissionsDao.findById(id); + } + + @Override + public RolePermission findRolePermissionByUuid(final String uuid) { + if (Strings.isNullOrEmpty(uuid)) { + return null; + } + return rolePermissionsDao.findByUuid(uuid); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_CREATE, eventDescription = "creating Role") + public Role createRole(final String name, final RoleType roleType, final String description) { + checkCallerAccess(); + if (roleType == null || roleType == RoleType.Unknown) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role type provided"); + } + return Transaction.execute(new TransactionCallback() { + @Override + public RoleVO doInTransaction(TransactionStatus status) { + return roleDao.persist(new RoleVO(name, roleType, description)); + } + }); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_UPDATE, eventDescription = "updating Role") + public boolean updateRole(final Role role, final String name, final RoleType roleType, final String description) { + checkCallerAccess(); + if (role == null) { + return false; + } + if (roleType != null && roleType == RoleType.Unknown) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unknown is not a valid role type"); + } + RoleVO roleVO = (RoleVO) role; + if (!Strings.isNullOrEmpty(name)) { + roleVO.setName(name); + } + if (roleType != null) { + if (role.getId() <= RoleType.User.getId()) { + throw new PermissionDeniedException("The role type of default roles cannot be changed"); + } + List accounts = accountDao.findAccountsByRole(role.getId()); + if (accounts == null || accounts.isEmpty()) { + roleVO.setRoleType(roleType); + } else { + throw new PermissionDeniedException("Found accounts that have role in use, won't allow to change role type"); + } + } + if (!Strings.isNullOrEmpty(description)) { + roleVO.setDescription(description); + } + return roleDao.update(role.getId(), roleVO); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_DELETE, eventDescription = "deleting Role") + public boolean deleteRole(final Role role) { + checkCallerAccess(); + if (role == null) { + return false; + } + if (role.getId() <= RoleType.User.getId()) { + throw new PermissionDeniedException("Default roles cannot be deleted"); + } + List accounts = accountDao.findAccountsByRole(role.getId()); + if (accounts == null || accounts.size() == 0) { + return Transaction.execute(new TransactionCallback() { + @Override + public Boolean doInTransaction(TransactionStatus status) { + List rolePermissions = rolePermissionsDao.findAllByRoleIdSorted(role.getId()); + if (rolePermissions != null && !rolePermissions.isEmpty()) { + for (RolePermission rolePermission : rolePermissions) { + rolePermissionsDao.remove(rolePermission.getId()); + } + } + return roleDao.remove(role.getId()); + } + }); + } + throw new PermissionDeniedException("Found accounts that have role in use, won't allow to delete role"); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_PERMISSION_CREATE, eventDescription = "creating Role Permission") + public RolePermission createRolePermission(final Role role, final Rule rule, final RolePermission.Permission permission, final String description) { + checkCallerAccess(); + return Transaction.execute(new TransactionCallback() { + @Override + public RolePermissionVO doInTransaction(TransactionStatus status) { + return rolePermissionsDao.persist(new RolePermissionVO(role.getId(), rule.toString(), permission, description)); + } + }); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_PERMISSION_UPDATE, eventDescription = "updating Role Permission order") + public boolean updateRolePermission(final Role role, final List newOrder) { + checkCallerAccess(); + return role != null && newOrder != null && rolePermissionsDao.update(role, newOrder); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_ROLE_PERMISSION_DELETE, eventDescription = "deleting Role Permission") + public boolean deleteRolePermission(final RolePermission rolePermission) { + checkCallerAccess(); + return rolePermission != null && rolePermissionsDao.remove(rolePermission.getId()); + } + + @Override + public List findRolesByName(final String name) { + List roles = null; + if (!Strings.isNullOrEmpty(name)) { + roles = roleDao.findAllByName(name); + } + return ListUtils.toListOfInterface(roles); + } + + @Override + public List findRolesByType(final RoleType roleType) { + List roles = null; + if (roleType != null) { + roles = roleDao.findAllByRoleType(roleType); + } + return ListUtils.toListOfInterface(roles); + } + + @Override + public List listRoles() { + List roles = roleDao.listAll(); + return ListUtils.toListOfInterface(roles); + } + + @Override + public List findAllPermissionsBy(final Long roleId) { + List permissions = rolePermissionsDao.findAllByRoleIdSorted(roleId); + if (permissions != null) { + return new ArrayList<>(permissions); + } + return Collections.emptyList(); + } + + @Override + public String getConfigComponentName() { + return RoleService.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[]{RoleService.EnableDynamicApiChecker}; + } + + @Override + public List> getCommands() { + final List> cmdList = new ArrayList<>(); + cmdList.add(CreateRoleCmd.class); + cmdList.add(ListRolesCmd.class); + cmdList.add(UpdateRoleCmd.class); + cmdList.add(DeleteRoleCmd.class); + cmdList.add(CreateRolePermissionCmd.class); + cmdList.add(ListRolePermissionsCmd.class); + cmdList.add(UpdateRolePermissionCmd.class); + cmdList.add(DeleteRolePermissionCmd.class); + return cmdList; + } + } diff --git a/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java b/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java index 2b8873729d..0869b2289c 100644 --- a/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java +++ b/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java @@ -278,7 +278,11 @@ public String[] applyVpnUsers(final Network network, final List outOfBandManagementDrivers = new ArrayList<>(); + private final Map outOfBandManagementDriversMap = new HashMap(); + + private static final String OOBM_ENABLED_DETAIL = "outOfBandManagementEnabled"; + private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_HOST = 120; + + private static Cache hostAlertCache; + private static ExecutorService backgroundSyncBlockingExecutor; + + private String getOutOfBandManagementHostLock(long id) { + return "oobm.host." + id; + } + + private void initializeDriversMap() { + if (outOfBandManagementDriversMap.isEmpty() && outOfBandManagementDrivers != null && outOfBandManagementDrivers.size() > 0) { + for (final OutOfBandManagementDriver driver : outOfBandManagementDrivers) { + outOfBandManagementDriversMap.put(driver.getName().toLowerCase(), driver); + } + LOG.debug("Discovered out-of-band management drivers configured in the OutOfBandManagementService"); + } + } + + private OutOfBandManagementDriver getDriver(final OutOfBandManagement outOfBandManagementConfig) { + if (!Strings.isNullOrEmpty(outOfBandManagementConfig.getDriver())) { + final OutOfBandManagementDriver driver = outOfBandManagementDriversMap.get(outOfBandManagementConfig.getDriver()); + if (driver != null) { + return driver; + } + } + throw new CloudRuntimeException("Configured out-of-band management driver is not available. Aborting any out-of-band management action."); + } + + protected OutOfBandManagement updateConfig(final OutOfBandManagement outOfBandManagementConfig, final ImmutableMap options) { + if (outOfBandManagementConfig == null) { + throw new CloudRuntimeException("Out-of-band management is not configured for the host. Aborting."); + } + if (options == null) { + return outOfBandManagementConfig; + } + for (OutOfBandManagement.Option option: options.keySet()) { + final String value = options.get(option); + if (Strings.isNullOrEmpty(value)) { + continue; + } + switch (option) { + case DRIVER: + outOfBandManagementConfig.setDriver(value); + break; + case ADDRESS: + outOfBandManagementConfig.setAddress(value); + break; + case PORT: + outOfBandManagementConfig.setPort(Integer.parseInt(value)); + break; + case USERNAME: + outOfBandManagementConfig.setUsername(value); + break; + case PASSWORD: + outOfBandManagementConfig.setPassword(value); + break; + } + } + return outOfBandManagementConfig; + } + + protected ImmutableMap getOptions(final OutOfBandManagement outOfBandManagementConfig) { + final ImmutableMap.Builder optionsBuilder = ImmutableMap.builder(); + if (outOfBandManagementConfig == null) { + throw new CloudRuntimeException("Out-of-band management is not configured for the host. Aborting."); + } + for (OutOfBandManagement.Option option: OutOfBandManagement.Option.values()) { + String value = null; + switch (option) { + case DRIVER: + value = outOfBandManagementConfig.getDriver(); + break; + case ADDRESS: + value = outOfBandManagementConfig.getAddress(); + break; + case PORT: + if (outOfBandManagementConfig.getPort() != null) { + value = String.valueOf(outOfBandManagementConfig.getPort()); + } + break; + case USERNAME: + value = outOfBandManagementConfig.getUsername(); + break; + case PASSWORD: + value = outOfBandManagementConfig.getPassword(); + break; + } + if (value != null) { + optionsBuilder.put(option, value); + } + } + return optionsBuilder.build(); + } + + private void sendAuthError(final Host host, final String message) { + try { + hostAlertCache.asMap().putIfAbsent(host.getId(), 0L); + Long sentCount = hostAlertCache.asMap().get(host.getId()); + 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()); + LOG.error(subject + ": " + message); + alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_OOBM_AUTH_ERROR, host.getDataCenterId(), host.getPodId(), subject, message); + } + } + } catch (Exception ignored) { + } + } + + private boolean transitionPowerState(OutOfBandManagement.PowerState.Event event, OutOfBandManagement outOfBandManagementHost) { + if (outOfBandManagementHost == null) { + return false; + } + OutOfBandManagement.PowerState currentPowerState = outOfBandManagementHost.getPowerState(); + try { + OutOfBandManagement.PowerState newPowerState = OutOfBandManagement.PowerState.getStateMachine().getNextState(currentPowerState, event); + boolean result = outOfBandManagementDao.updateState(currentPowerState, event, newPowerState, outOfBandManagementHost, null); + 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()); + LOG.debug(message); + ActionEventUtils.onActionEvent(CallContext.current().getCallingUserId(), CallContext.current().getCallingAccountId(), Domain.ROOT_DOMAIN, + EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_POWERSTATE_TRANSITION, message); + } + 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)); + } + return false; + } + + private boolean isOutOfBandManagementEnabledForZone(Long zoneId) { + if (zoneId == null) { + return true; + } + final DataCenterDetailVO zoneDetails = dataCenterDetailsDao.findDetail(zoneId, OOBM_ENABLED_DETAIL); + if (zoneDetails != null && !Strings.isNullOrEmpty(zoneDetails.getValue()) && !Boolean.valueOf(zoneDetails.getValue())) { + return false; + } + return true; + } + + private boolean isOutOfBandManagementEnabledForCluster(Long clusterId) { + if (clusterId == null) { + return true; + } + final ClusterDetailsVO clusterDetails = clusterDetailsDao.findDetail(clusterId, OOBM_ENABLED_DETAIL); + if (clusterDetails != null && !Strings.isNullOrEmpty(clusterDetails.getValue()) && !Boolean.valueOf(clusterDetails.getValue())) { + return false; + } + return true; + } + + private boolean isOutOfBandManagementEnabledForHost(Long hostId) { + if (hostId == null) { + return false; + } + final OutOfBandManagement outOfBandManagementConfig = outOfBandManagementDao.findByHost(hostId); + if (outOfBandManagementConfig == null || !outOfBandManagementConfig.isEnabled()) { + return false; + } + return true; + } + + private void checkOutOfBandManagementEnabledByZoneClusterHost(final Host host) { + if (!isOutOfBandManagementEnabledForZone(host.getDataCenterId())) { + throw new CloudRuntimeException("Out-of-band management is disabled for the host's zone. Aborting Operation."); + } + if (!isOutOfBandManagementEnabledForCluster(host.getClusterId())) { + throw new CloudRuntimeException("Out-of-band management is disabled for the host's cluster. Aborting Operation."); + } + if (!isOutOfBandManagementEnabledForHost(host.getId())) { + throw new CloudRuntimeException("Out-of-band management is disabled or not configured for the host. Aborting Operation."); + } + } + + public boolean isOutOfBandManagementEnabled(final Host host) { + return isOutOfBandManagementEnabledForZone(host.getDataCenterId()) + && isOutOfBandManagementEnabledForCluster(host.getClusterId()) + && isOutOfBandManagementEnabledForHost(host.getId()); + } + + public boolean transitionPowerStateToDisabled(List hosts) { + boolean result = true; + for (Host host : hosts) { + result = result && transitionPowerState(OutOfBandManagement.PowerState.Event.Disabled, + outOfBandManagementDao.findByHost(host.getId())); + } + return result; + } + + public void submitBackgroundPowerSyncTask(final Host host) { + if (host != null) { + backgroundSyncBlockingExecutor.submit(new OutOfBandManagementBackgroundTask(this, host, OutOfBandManagement.PowerOperation.STATUS)); + } + } + + private OutOfBandManagementResponse buildEnableDisableResponse(final boolean enabled) { + final OutOfBandManagementResponse response = new OutOfBandManagementResponse(); + response.setEnabled(enabled); + response.setSuccess(true); + return response; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE, eventDescription = "enabling out-of-band management on a zone") + public OutOfBandManagementResponse enableOutOfBandManagement(final DataCenter zone) { + dataCenterDetailsDao.persist(zone.getId(), OOBM_ENABLED_DETAIL, String.valueOf(true)); + return buildEnableDisableResponse(true); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE, eventDescription = "disabling out-of-band management on a zone") + public OutOfBandManagementResponse disableOutOfBandManagement(final DataCenter zone) { + dataCenterDetailsDao.persist(zone.getId(), OOBM_ENABLED_DETAIL, String.valueOf(false)); + transitionPowerStateToDisabled(hostDao.findByDataCenterId(zone.getId())); + + return buildEnableDisableResponse(false); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE, eventDescription = "enabling out-of-band management on a cluster") + public OutOfBandManagementResponse enableOutOfBandManagement(final Cluster cluster) { + clusterDetailsDao.persist(cluster.getId(), OOBM_ENABLED_DETAIL, String.valueOf(true)); + return buildEnableDisableResponse(true); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE, eventDescription = "disabling out-of-band management on a cluster") + public OutOfBandManagementResponse disableOutOfBandManagement(final Cluster cluster) { + clusterDetailsDao.persist(cluster.getId(), OOBM_ENABLED_DETAIL, String.valueOf(false)); + transitionPowerStateToDisabled(hostDao.findByClusterId(cluster.getId())); + return buildEnableDisableResponse(false); + } + + private OutOfBandManagement getConfigForHost(final Host host) { + final OutOfBandManagement outOfBandManagementConfig = outOfBandManagementDao.findByHost(host.getId()); + if (outOfBandManagementConfig == null) { + throw new CloudRuntimeException("Out-of-band management is not configured for the host. Please configure the host before enabling/disabling it."); + } + return outOfBandManagementConfig; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ENABLE, eventDescription = "enabling out-of-band management on a host") + public OutOfBandManagementResponse enableOutOfBandManagement(final Host host) { + final OutOfBandManagement outOfBandManagementConfig = getConfigForHost(host); + hostAlertCache.invalidate(host.getId()); + outOfBandManagementConfig.setEnabled(true); + boolean updateResult = outOfBandManagementDao.update(outOfBandManagementConfig.getId(), (OutOfBandManagementVO) outOfBandManagementConfig); + if (updateResult) { + transitionPowerStateToDisabled(Collections.singletonList(host)); + } + return buildEnableDisableResponse(true); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_DISABLE, eventDescription = "disabling out-of-band management on a host") + public OutOfBandManagementResponse disableOutOfBandManagement(final Host host) { + final OutOfBandManagement outOfBandManagementConfig = getConfigForHost(host); + hostAlertCache.invalidate(host.getId()); + outOfBandManagementConfig.setEnabled(false); + boolean updateResult = outOfBandManagementDao.update(outOfBandManagementConfig.getId(), (OutOfBandManagementVO) outOfBandManagementConfig); + if (updateResult) { + transitionPowerStateToDisabled(Collections.singletonList(host)); + } + return buildEnableDisableResponse(false); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_CONFIGURE, eventDescription = "updating out-of-band management configuration") + public OutOfBandManagementResponse configureOutOfBandManagement(final Host host, final ImmutableMap options) { + OutOfBandManagement outOfBandManagementConfig = outOfBandManagementDao.findByHost(host.getId()); + if (outOfBandManagementConfig == null) { + outOfBandManagementConfig = outOfBandManagementDao.persist(new OutOfBandManagementVO(host.getId())); + } + outOfBandManagementConfig = updateConfig(outOfBandManagementConfig, options); + if (Strings.isNullOrEmpty(outOfBandManagementConfig.getDriver()) || !outOfBandManagementDriversMap.containsKey(outOfBandManagementConfig.getDriver().toLowerCase())) { + throw new CloudRuntimeException("Out-of-band management driver is not available. Please provide a valid driver name."); + } + + boolean updatedConfig = outOfBandManagementDao.update(outOfBandManagementConfig.getId(), (OutOfBandManagementVO) outOfBandManagementConfig); + CallContext.current().setEventDetails("host id:" + host.getId() + " configuration:" + outOfBandManagementConfig.getAddress() + ":" + outOfBandManagementConfig.getPort()); + + if (!updatedConfig) { + throw new CloudRuntimeException("Failed to update out-of-band management config for the host in the database."); + } + + String result = "Out-of-band management successfully configured for the host"; + LOG.debug(result); + + final OutOfBandManagementResponse response = new OutOfBandManagementResponse(outOfBandManagementDao.findByHost(host.getId())); + response.setResultDescription(result); + response.setSuccess(true); + return response; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_ACTION, eventDescription = "issuing host out-of-band management action", async = true) + public OutOfBandManagementResponse executeOutOfBandManagementPowerOperation(final Host host, final OutOfBandManagement.PowerOperation powerOperation, final Long timeout) { + checkOutOfBandManagementEnabledByZoneClusterHost(host); + final OutOfBandManagement outOfBandManagementConfig = getConfigForHost(host); + final ImmutableMap options = getOptions(outOfBandManagementConfig); + final OutOfBandManagementDriver driver = getDriver(outOfBandManagementConfig); + + Long actionTimeOut = timeout; + if (actionTimeOut == null) { + actionTimeOut = ActionTimeout.valueIn(host.getClusterId()); + } + + final OutOfBandManagementDriverPowerCommand cmd = new OutOfBandManagementDriverPowerCommand(options, actionTimeOut, powerOperation); + 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())); + } + + if (powerOperation.equals(OutOfBandManagement.PowerOperation.STATUS)) { + transitionPowerState(driverResponse.toEvent(), outOfBandManagementConfig); + } + + 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()); + 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()); + sendAuthError(host, errorMessage); + } + if (!powerOperation.equals(OutOfBandManagement.PowerOperation.STATUS)) { + LOG.debug(errorMessage); + } + throw new CloudRuntimeException(errorMessage); + } + + final OutOfBandManagementResponse response = new OutOfBandManagementResponse(outOfBandManagementDao.findByHost(host.getId())); + response.setSuccess(driverResponse.isSuccess()); + response.setResultDescription(driverResponse.getResult()); + response.setId(host.getUuid()); + response.setOutOfBandManagementAction(powerOperation.toString()); + return response; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_HOST_OUTOFBAND_MANAGEMENT_CHANGE_PASSWORD, eventDescription = "updating out-of-band management password") + public OutOfBandManagementResponse changeOutOfBandManagementPassword(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())); + } + GlobalLock outOfBandManagementHostLock = GlobalLock.getInternLock(getOutOfBandManagementHostLock(host.getId())); + try { + if (outOfBandManagementHostLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_HOST)) { + try { + 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())); + } + final OutOfBandManagementDriver driver = getDriver(outOfBandManagementConfig); + + final OutOfBandManagementDriverChangePasswordCommand cmd = new OutOfBandManagementDriverChangePasswordCommand(options, ActionTimeout.valueIn(host.getClusterId()), newPassword); + final OutOfBandManagementDriverResponse driverResponse; + try { + driverResponse = driver.execute(cmd); + } 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())); + } + + 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())); + } + + final boolean updatedConfigResult = Transaction.execute(new TransactionCallback() { + @Override + public Boolean doInTransaction(TransactionStatus status) { + OutOfBandManagement updatedOutOfBandManagementConfig = outOfBandManagementDao.findByHost(host.getId()); + updatedOutOfBandManagementConfig.setPassword(newPassword); + return outOfBandManagementDao.update(updatedOutOfBandManagementConfig.getId(), (OutOfBandManagementVO) updatedOutOfBandManagementConfig); + } + }); + + if (!updatedConfigResult) { + LOG.error(String.format("Succeeded to change out-of-band management password but failed to updated in database the new password:%s for the host id:%d", newPassword, host.getId())); + } + + final OutOfBandManagementResponse response = new OutOfBandManagementResponse(); + response.setSuccess(updatedConfigResult && driverResponse.isSuccess()); + response.setResultDescription(driverResponse.getResult()); + response.setId(host.getUuid()); + return response; + } finally { + outOfBandManagementHostLock.unlock(); + } + } else { + LOG.error("Unable to acquire synchronization lock to change out-of-band management password for host id: " + host.getId()); + throw new CloudRuntimeException(String.format("Unable to acquire lock to change out-of-band management password for host (%s), please try after some time.", host.getUuid())); + } + } finally { + outOfBandManagementHostLock.releaseRef(); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public long getId() { + return serviceId; + } + + @Override + public boolean configure(final String name, final Map params) throws ConfigurationException { + this.name = name; + this.serviceId = ManagementServerNode.getManagementServerId(); + + final int poolSize = SyncThreadPoolSize.value(); + + hostAlertCache = CacheBuilder.newBuilder() + .concurrencyLevel(4) + .weakKeys() + .maximumSize(100 * poolSize) + .expireAfterWrite(1, TimeUnit.DAYS) + .build(); + + backgroundSyncBlockingExecutor = new ThreadPoolExecutor(poolSize, poolSize, + 0L, TimeUnit.MILLISECONDS, + new ArrayBlockingQueue(10 * poolSize, true), new ThreadPoolExecutor.CallerRunsPolicy()); + + LOG.info("Starting out-of-band management background sync executor with thread pool-size=" + poolSize + " and background sync thread interval=" + SyncThreadInterval.value() + "s"); + return true; + } + + @Override + public boolean start() { + initializeDriversMap(); + return true; + } + + @Override + public boolean stop() { + backgroundSyncBlockingExecutor.shutdown(); + outOfBandManagementDao.expireOutOfBandManagementOwnershipByServer(getId()); + return true; + } + + @Override + public String getConfigComponentName() { + return OutOfBandManagementServiceImpl.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[] {ActionTimeout, SyncThreadInterval, SyncThreadPoolSize}; + } + + public List getOutOfBandManagementDrivers() { + return outOfBandManagementDrivers; + } + + public void setOutOfBandManagementDrivers(List outOfBandManagementDrivers) { + this.outOfBandManagementDrivers = outOfBandManagementDrivers; + } +} diff --git a/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java b/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java index 2d04a7e633..19f80b94a4 100644 --- a/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java +++ b/server/src/org/cloud/network/router/deployment/RouterDeploymentDefinition.java @@ -193,28 +193,45 @@ protected void generateDeploymentPlan() { } public List deployVirtualRouter() throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { - findOrDeployVirtualRouter(); - return nwHelper.startRouters(this); } + private boolean isRouterDeployed() throws ResourceUnavailableException { + boolean isDeployed = true; + checkPreconditions(); + final List destinations = findDestinations(); + for (final DeployDestination destination : destinations) { + dest = destination; + generateDeploymentPlan(); + planDeploymentRouters(); + if (getNumberOfRoutersToDeploy() > 0 && prepareDeployment()) { + isDeployed = false; + break; + } + } + return isDeployed; + } + @DB protected void findOrDeployVirtualRouter() throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { - try { - lock(); - checkPreconditions(); - - // dest has pod=null, for Basic Zone findOrDeployVRs for all Pods - final List destinations = findDestinations(); - - for (final DeployDestination destination : destinations) { - dest = destination; - generateDeploymentPlan(); - executeDeployment(); + if (!isRouterDeployed()) { + try { + lock(); + // reset router list that got populated during isRouterDeployed() + routers.clear(); + checkPreconditions(); + + // dest has pod=null, for Basic Zone findOrDeployVRs for all Pods + final List destinations = findDestinations(); + for (final DeployDestination destination : destinations) { + dest = destination; + generateDeploymentPlan(); + executeDeployment(); + } + } finally { + unlock(); } - } finally { - unlock(); } } @@ -378,7 +395,7 @@ protected void findVirtualProvider() { final PhysicalNetworkServiceProvider provider = physicalProviderDao.findByServiceProvider(physicalNetworkId, type.toString()); if (provider == null) { - throw new CloudRuntimeException(String.format("Cannot find service provider %s in physical network %s", type.toString(), physicalNetworkId)); + throw new CloudRuntimeException(String.format("Cannot find service provider %s in physical network %s", type.toString(), physicalNetworkId)); } vrProvider = vrProviderDao.findByNspIdAndType(provider.getId(), type); diff --git a/server/test/com/cloud/api/ApiServletTest.java b/server/test/com/cloud/api/ApiServletTest.java index a0a600409c..e7cdf41a38 100644 --- a/server/test/com/cloud/api/ApiServletTest.java +++ b/server/test/com/cloud/api/ApiServletTest.java @@ -89,7 +89,7 @@ public class ApiServletTest { @SuppressWarnings("unchecked") @Before public void setup() throws SecurityException, NoSuchFieldException, - IllegalArgumentException, IllegalAccessException, IOException, UnknownHostException { + IllegalArgumentException, IllegalAccessException, IOException, UnknownHostException { servlet = new ApiServlet(); responseWriter = new StringWriter(); Mockito.when(response.getWriter()).thenReturn( @@ -98,8 +98,7 @@ public void setup() throws SecurityException, NoSuchFieldException, Mockito.when(accountService.getSystemUser()).thenReturn(user); Mockito.when(accountService.getSystemAccount()).thenReturn(account); - Field accountMgrField = ApiServlet.class - .getDeclaredField("_accountMgr"); + Field accountMgrField = ApiServlet.class.getDeclaredField("accountMgr"); accountMgrField.setAccessible(true); accountMgrField.set(servlet, accountService); @@ -107,11 +106,11 @@ public void setup() throws SecurityException, NoSuchFieldException, Mockito.when(authenticator.authenticate(Mockito.anyString(), Mockito.anyMap(), Mockito.isA(HttpSession.class), Mockito.same(InetAddress.getByName("127.0.0.1")), Mockito.anyString(), Mockito.isA(StringBuilder.class), Mockito.isA(HttpServletRequest.class), Mockito.isA(HttpServletResponse.class))).thenReturn("{\"loginresponse\":{}"); - Field authManagerField = ApiServlet.class.getDeclaredField("_authManager"); + Field authManagerField = ApiServlet.class.getDeclaredField("authManager"); authManagerField.setAccessible(true); authManagerField.set(servlet, authManager); - Field apiServerField = ApiServlet.class.getDeclaredField("_apiServer"); + Field apiServerField = ApiServlet.class.getDeclaredField("apiServer"); apiServerField.setAccessible(true); apiServerField.set(servlet, apiServer); } @@ -176,7 +175,7 @@ public void processRequestInContextUnauthorizedGET() { Mockito.when(request.getMethod()).thenReturn("GET"); Mockito.when( apiServer.verifyRequest(Mockito.anyMap(), Mockito.anyLong())) - .thenReturn(false); + .thenReturn(false); servlet.processRequestInContext(request, response); Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED); Mockito.verify(apiServer, Mockito.never()).handleRequest( @@ -190,7 +189,7 @@ public void processRequestInContextAuthorizedGet() { Mockito.when(request.getMethod()).thenReturn("GET"); Mockito.when( apiServer.verifyRequest(Mockito.anyMap(), Mockito.anyLong())) - .thenReturn(true); + .thenReturn(true); servlet.processRequestInContext(request, response); Mockito.verify(response).setStatus(HttpServletResponse.SC_OK); Mockito.verify(apiServer, Mockito.times(1)).handleRequest( diff --git a/server/test/com/cloud/api/query/MutualExclusiveIdsManagerBaseTest.java b/server/test/com/cloud/api/query/MutualExclusiveIdsManagerBaseTest.java new file mode 100755 index 0000000000..a4d92614b3 --- /dev/null +++ b/server/test/com/cloud/api/query/MutualExclusiveIdsManagerBaseTest.java @@ -0,0 +1,102 @@ +// +// 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.api.query; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.never; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.db.SearchCriteria; + +@RunWith(MockitoJUnitRunner.class) +public class MutualExclusiveIdsManagerBaseTest { + + @Mock + SearchCriteria sc; + + private static Long id1 = 1L; + private static Long id2 = 2L; + + private List idsList; + private List idsEmptyList; + private List expectedListId; + private List expectedListIds; + + private MutualExclusiveIdsManagerBase mgr = new MutualExclusiveIdsManagerBase(); + + @Before + public void setup() { + idsList = Arrays.asList(id1, id2); + idsEmptyList = Arrays.asList(); + expectedListId = Arrays.asList(id1); + expectedListIds = Arrays.asList(id1, id2); + } + + @Test + public void testSetIdsListToSearchCriteria(){ + mgr.setIdsListToSearchCriteria(sc, idsList); + Mockito.verify(sc).setParameters(Mockito.same("idIN"), Mockito.same(id1), Mockito.same(id2)); + } + + @Test + public void testSetIdsListToSearchCriteriaEmptyList(){ + mgr.setIdsListToSearchCriteria(sc, idsEmptyList); + Mockito.verify(sc, never()).setParameters(Mockito.anyString(), Mockito.any()); + } + + @Test + public void testGetIdsListId(){ + List result = mgr.getIdsListFromCmd(id1, idsEmptyList); + assertEquals(expectedListId, result); + } + + @Test + public void testGetIdsListProvideList(){ + List result = mgr.getIdsListFromCmd(null, idsList); + assertEquals(expectedListIds, result); + } + + @Test(expected=InvalidParameterValueException.class) + public void testGetIdsListBothNotNull(){ + mgr.getIdsListFromCmd(id1, idsList); + } + + @Test + public void testGetIdsListBothNull(){ + List result = mgr.getIdsListFromCmd(null, null); + assertNull(result); + } + + @Test + public void testGetIdsEmptyListIdNull(){ + List result = mgr.getIdsListFromCmd(null, idsEmptyList); + assertEquals(idsEmptyList, result); + } +} diff --git a/server/test/com/cloud/api/query/dao/GenericDaoBaseWithTagInformationBaseTest.java b/server/test/com/cloud/api/query/dao/GenericDaoBaseWithTagInformationBaseTest.java new file mode 100755 index 0000000000..c7c65f8d93 --- /dev/null +++ b/server/test/com/cloud/api/query/dao/GenericDaoBaseWithTagInformationBaseTest.java @@ -0,0 +1,90 @@ +// 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.api.query.dao; + +import static org.junit.Assert.assertEquals; + +import org.apache.cloudstack.api.BaseResponseWithTagInformation; +import org.apache.cloudstack.api.response.ResourceTagResponse; +import org.powermock.api.mockito.PowerMockito; + +import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.vo.BaseViewWithTagInformationVO; +import com.cloud.server.ResourceTag.ResourceObjectType; + +public abstract class GenericDaoBaseWithTagInformationBaseTest { + + private final static long TAG_ID = 1l; + private final static String TAG_KEY = "type"; + private final static String TAG_VALUE = "supported"; + private final static String TAG_UUID = "aaaa-aaaa-aaaa-aaaa"; + private final static ResourceObjectType TAG_RESOURCE_TYPE = ResourceObjectType.Template; + private final static String TAG_RESOURCE_TYPE_STR = "Template"; + private final static String TAG_RESOURCE_UUID = "aaaa-aaaa-aaaa-aaaa"; + private final static long TAG_DOMAIN_ID = 123l; + private final static String TAG_DOMAIN_ID_STR = "123"; + private final static String TAG_DOMAIN_NAME = "aaaa-aaaa-aaaa-aaaa"; + private final static String TAG_CUSTOMER = "aaaa-aaaa-aaaa-aaaa"; + private final static String TAG_ACCOUNT_NAME = "admin"; + + private final static String RESPONSE_OBJECT_NAME = "tag"; + + public void prepareSetup(){ + PowerMockito.spy(ApiDBUtils.class); + PowerMockito.stub(PowerMockito.method(ApiDBUtils.class, "newResourceTagResponse")).toReturn(getResourceTagResponse()); + } + + private ResourceTagResponse getResourceTagResponse(){ + ResourceTagResponse tagResponse = new ResourceTagResponse(); + tagResponse.setKey(TAG_KEY); + tagResponse.setValue(TAG_VALUE); + tagResponse.setObjectName(RESPONSE_OBJECT_NAME); + tagResponse.setResourceType(TAG_RESOURCE_TYPE_STR); + tagResponse.setResourceId(TAG_RESOURCE_UUID); + tagResponse.setDomainId(TAG_DOMAIN_ID_STR); + tagResponse.setDomainName(TAG_DOMAIN_NAME); + tagResponse.setCustomer(TAG_CUSTOMER); + tagResponse.setAccountName(TAG_ACCOUNT_NAME); + return tagResponse; + } + + private void prepareBaseView(long tagId, T baseView){ + baseView.setTagId(tagId); + baseView.setTagKey(TAG_KEY); + baseView.setTagValue(TAG_VALUE); + baseView.setTagUuid(TAG_UUID); + baseView.setTagResourceType(TAG_RESOURCE_TYPE); + baseView.setTagAccountName(TAG_ACCOUNT_NAME); + baseView.setTagDomainId(TAG_DOMAIN_ID); + baseView.setTagDomainName(TAG_DOMAIN_NAME); + baseView.setTagCustomer(TAG_CUSTOMER); + baseView.setTagAccountName(TAG_ACCOUNT_NAME); + } + + public void testUpdateTagInformation(GenericDaoBaseWithTagInformation dao, T baseView, Z baseResponse){ + prepareBaseView(TAG_ID, baseView); + dao.addTagInformation(baseView, baseResponse); + ResourceTagResponse[] responseArray = new ResourceTagResponse[baseResponse.getTags().size()]; + baseResponse.getTags().toArray(responseArray); + assertEquals(1, responseArray.length); + assertEquals(TAG_KEY, responseArray[0].getKey()); + assertEquals(TAG_VALUE, responseArray[0].getValue()); + assertEquals(RESPONSE_OBJECT_NAME, responseArray[0].getObjectName()); + } + +} diff --git a/server/test/com/cloud/api/query/dao/TemplateJoinDaoImplTest.java b/server/test/com/cloud/api/query/dao/TemplateJoinDaoImplTest.java new file mode 100755 index 0000000000..d194e32c0f --- /dev/null +++ b/server/test/com/cloud/api/query/dao/TemplateJoinDaoImplTest.java @@ -0,0 +1,50 @@ +// 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.api.query.dao; + +import org.apache.cloudstack.api.response.TemplateResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.vo.TemplateJoinVO; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(ApiDBUtils.class) +public class TemplateJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseTest { + + @InjectMocks + private TemplateJoinDaoImpl _templateJoinDaoImpl; + + private TemplateJoinVO template = new TemplateJoinVO(); + private TemplateResponse templateResponse = new TemplateResponse(); + + @Before + public void setup() { + prepareSetup(); + } + + @Test + public void testUpdateTemplateTagInfo(){ + testUpdateTagInformation(_templateJoinDaoImpl, template, templateResponse); + } + +} \ No newline at end of file diff --git a/server/test/com/cloud/api/query/dao/UserVmJoinDaoImplTest.java b/server/test/com/cloud/api/query/dao/UserVmJoinDaoImplTest.java new file mode 100755 index 0000000000..669143ebf4 --- /dev/null +++ b/server/test/com/cloud/api/query/dao/UserVmJoinDaoImplTest.java @@ -0,0 +1,50 @@ +// 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.api.query.dao; + +import org.apache.cloudstack.api.response.UserVmResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.vo.UserVmJoinVO; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(ApiDBUtils.class) +public class UserVmJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseTest { + + @InjectMocks + private UserVmJoinDaoImpl _userVmJoinDaoImpl; + + private UserVmJoinVO userVm = new UserVmJoinVO(); + private UserVmResponse userVmResponse = new UserVmResponse(); + + @Before + public void setup() { + prepareSetup(); + } + + @Test + public void testUpdateUserVmTagInfo(){ + testUpdateTagInformation(_userVmJoinDaoImpl, userVm, userVmResponse); + } + +} \ No newline at end of file diff --git a/server/test/com/cloud/api/query/dao/VolumeJoinDaoImplTest.java b/server/test/com/cloud/api/query/dao/VolumeJoinDaoImplTest.java new file mode 100755 index 0000000000..b0b0ad2273 --- /dev/null +++ b/server/test/com/cloud/api/query/dao/VolumeJoinDaoImplTest.java @@ -0,0 +1,50 @@ +// 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.api.query.dao; + +import org.apache.cloudstack.api.response.VolumeResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.vo.VolumeJoinVO; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(ApiDBUtils.class) +public class VolumeJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseTest { + + @InjectMocks + private VolumeJoinDaoImpl _volumeJoinDaoImpl; + + private VolumeJoinVO volume = new VolumeJoinVO(); + private VolumeResponse volumeResponse = new VolumeResponse(); + + @Before + public void setup() { + prepareSetup(); + } + + @Test + public void testUpdateVolumeTagInfo(){ + testUpdateTagInformation(_volumeJoinDaoImpl, volume, volumeResponse); + } + +} diff --git a/server/test/com/cloud/consoleproxy/ConsoleProxyManagerTest.java b/server/test/com/cloud/consoleproxy/ConsoleProxyManagerTest.java index fd12d23a52..76a3f42766 100644 --- a/server/test/com/cloud/consoleproxy/ConsoleProxyManagerTest.java +++ b/server/test/com/cloud/consoleproxy/ConsoleProxyManagerTest.java @@ -17,7 +17,17 @@ package com.cloud.consoleproxy; +import static org.mockito.AdditionalMatchers.not; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Collections; + import org.apache.log4j.Logger; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -25,7 +35,15 @@ import org.mockito.MockitoAnnotations; import org.springframework.test.util.ReflectionTestUtils; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.ConsoleProxyVO; public class ConsoleProxyManagerTest { @@ -37,13 +55,22 @@ public class ConsoleProxyManagerTest { @Mock ConsoleProxyVO proxyVO; @Mock + DataCenterDao _dcDao; + @Mock + NetworkDao _networkDao; + @Mock ConsoleProxyManagerImpl cpvmManager; @Before public void setup() throws Exception { MockitoAnnotations.initMocks(this); ReflectionTestUtils.setField(cpvmManager, "_allocProxyLock", globalLock); + ReflectionTestUtils.setField(cpvmManager, "_dcDao", _dcDao); + ReflectionTestUtils.setField(cpvmManager, "_networkDao", _networkDao); Mockito.doCallRealMethod().when(cpvmManager).expandPool(Mockito.anyLong(), Mockito.anyObject()); + Mockito.doCallRealMethod().when(cpvmManager).getDefaultNetworkForCreation(Mockito.any(DataCenter.class)); + Mockito.doCallRealMethod().when(cpvmManager).getDefaultNetworkForAdvancedZone(Mockito.any(DataCenter.class)); + Mockito.doCallRealMethod().when(cpvmManager).getDefaultNetworkForBasicZone(Mockito.any(DataCenter.class)); } @Test @@ -87,4 +114,136 @@ public void testExisingCPVMStartFailure() throws Exception { cpvmManager.expandPool(new Long(1), new Object()); } + + @Test + public void getDefaultNetworkForAdvancedNonSG() { + DataCenterVO dc = mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(false); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Public))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Public)))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = cpvmManager.getDefaultNetworkForAdvancedZone(dc); + + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForAdvancedSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), any(TrafficType.class))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(network)); + + NetworkVO returnedNetwork = cpvmManager.getDefaultNetworkForAdvancedZone(dc); + + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForBasicNonSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(false); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = cpvmManager.getDefaultNetworkForBasicZone(dc); + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForBasicSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = cpvmManager.getDefaultNetworkForBasicZone(dc); + + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + //also test invalid input + @Test(expected=CloudRuntimeException.class) + public void getDefaultNetworkForBasicSGWrongZoneType() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + cpvmManager.getDefaultNetworkForBasicZone(dc); + } + + @Test(expected=CloudRuntimeException.class) + public void getDefaultNetworkForAdvancedWrongZoneType() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), any(TrafficType.class))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(network)); + + cpvmManager.getDefaultNetworkForAdvancedZone(dc); + } } diff --git a/server/test/com/cloud/ha/HighAvailabilityManagerImplTest.java b/server/test/com/cloud/ha/HighAvailabilityManagerImplTest.java index f60044e453..898dff2b79 100644 --- a/server/test/com/cloud/ha/HighAvailabilityManagerImplTest.java +++ b/server/test/com/cloud/ha/HighAvailabilityManagerImplTest.java @@ -59,6 +59,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.server.ManagementServer; +import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StorageManager; import com.cloud.storage.dao.GuestOSCategoryDao; @@ -195,6 +196,7 @@ public void scheduleRestartForVmsOnHostNonEmptyVMList() { Mockito.when(_dcDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(DataCenterVO.class)); Mockito.when(_haDao.findPreviousHA(Mockito.anyLong())).thenReturn(Arrays.asList(Mockito.mock(HaWorkVO.class))); Mockito.when(_haDao.persist((HaWorkVO)Mockito.anyObject())).thenReturn(Mockito.mock(HaWorkVO.class)); + Mockito.when(_serviceOfferingDao.findById(vm1.getServiceOfferingId())).thenReturn(Mockito.mock(ServiceOfferingVO.class)); highAvailabilityManager.scheduleRestartForVmsOnHost(hostVO, true); } diff --git a/server/test/com/cloud/network/ExternalLoadBalancerDeviceManagerImplTest.java b/server/test/com/cloud/network/ExternalLoadBalancerDeviceManagerImplTest.java index 046bdb6475..dbc31ba6ef 100644 --- a/server/test/com/cloud/network/ExternalLoadBalancerDeviceManagerImplTest.java +++ b/server/test/com/cloud/network/ExternalLoadBalancerDeviceManagerImplTest.java @@ -20,11 +20,13 @@ import java.lang.reflect.Field; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import javax.inject.Inject; +import com.cloud.host.Host; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.junit.Assert; @@ -207,4 +209,15 @@ private void setupLBHealthChecksMocks() throws URISyntaxException { HostVO hostVo = Mockito.mock(HostVO.class); Mockito.when(_hostDao.findById(Mockito.anyLong())).thenReturn(hostVo); } + + + @Test + public void testUsageTask() { + ExternalDeviceUsageManagerImpl.ExternalDeviceNetworkUsageTask usageTask = Mockito + .mock(ExternalDeviceUsageManagerImpl.ExternalDeviceNetworkUsageTask.class); + Mockito.when(_hostDao.listByType(Host.Type.ExternalFirewall)).thenReturn(new ArrayList()); + Mockito.when(_hostDao.listByType(Host.Type.ExternalLoadBalancer)).thenReturn(new ArrayList()); + usageTask.runInContext(); + Mockito.verify(usageTask, Mockito.times(0)).runExternalDeviceNetworkUsageTask(); + } } diff --git a/server/test/com/cloud/resource/MockResourceManagerImpl.java b/server/test/com/cloud/resource/MockResourceManagerImpl.java index 86de140b97..6e6d66fe18 100644 --- a/server/test/com/cloud/resource/MockResourceManagerImpl.java +++ b/server/test/com/cloud/resource/MockResourceManagerImpl.java @@ -37,6 +37,7 @@ import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.VgpuTypesInfo; import com.cloud.agent.api.to.GPUDeviceTO; +import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.PodCluster; @@ -172,6 +173,12 @@ public Cluster getCluster(final Long clusterId) { return null; } + @Override + public DataCenter getZone(Long zoneId) { + // TODO Auto-generated method stub + return null; + } + /* (non-Javadoc) * @see com.cloud.resource.ResourceService#getSupportedHypervisorTypes(long, boolean, java.lang.Long) */ diff --git a/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java new file mode 100755 index 0000000000..4b3ce40bbd --- /dev/null +++ b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java @@ -0,0 +1,95 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.storage; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; +import org.junit.Before; +import org.junit.Test; + +public class ImageStoreDetailsUtilTest { + + private final static long STORE_ID = 1l; + private final static String STORE_UUID = "aaaa-aaaa-aaaa-aaaa"; + private final static Integer NFS_VERSION = 3; + + ImageStoreDetailsUtil imageStoreDetailsUtil = new ImageStoreDetailsUtil(); + + ImageStoreDao imgStoreDao = mock(ImageStoreDao.class); + ImageStoreDetailsDao imgStoreDetailsDao = mock(ImageStoreDetailsDao.class); + + @Before + public void setup() throws Exception { + Map imgStoreDetails = new HashMap(); + imgStoreDetails.put("nfs.version", String.valueOf(NFS_VERSION)); + when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); + + ImageStoreVO imgStoreVO = mock(ImageStoreVO.class); + when(imgStoreVO.getId()).thenReturn(Long.valueOf(STORE_ID)); + when(imgStoreDao.findByUuid(STORE_UUID)).thenReturn(imgStoreVO); + + imageStoreDetailsUtil.imageStoreDao = imgStoreDao; + imageStoreDetailsUtil.imageStoreDetailsDao = imgStoreDetailsDao; + } + + @Test + public void testGetNfsVersion(){ + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + assertEquals(NFS_VERSION, nfsVersion); + } + + @Test + public void testGetNfsVersionNotFound(){ + Map imgStoreDetails = new HashMap(); + imgStoreDetails.put("other.prop", "propValue"); + when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); + + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + assertNull(nfsVersion); + } + + @Test + public void testGetNfsVersionNoDetails(){ + Map imgStoreDetails = new HashMap(); + when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); + + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + assertNull(nfsVersion); + } + + @Test + public void testGetNfsVersionByUuid(){ + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(STORE_UUID); + assertEquals(NFS_VERSION, nfsVersion); + } + + @Test + public void testGetNfsVersionByUuidNoImgStore(){ + when(imgStoreDao.findByUuid(STORE_UUID)).thenReturn(null); + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(STORE_UUID); + assertNull(nfsVersion); + } +} \ No newline at end of file diff --git a/server/test/com/cloud/template/TemplateManagerImplTest.java b/server/test/com/cloud/template/TemplateManagerImplTest.java index ed4ec520a9..6e1693832a 100644 --- a/server/test/com/cloud/template/TemplateManagerImplTest.java +++ b/server/test/com/cloud/template/TemplateManagerImplTest.java @@ -21,13 +21,19 @@ import com.cloud.agent.AgentManager; import com.cloud.api.query.dao.UserVmJoinDao; +import com.cloud.configuration.Resource; import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.dao.DomainDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor; import com.cloud.projects.ProjectManager; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; @@ -54,6 +60,7 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; @@ -66,6 +73,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; @@ -77,6 +86,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -102,11 +113,13 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.eq; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class) @@ -133,6 +146,21 @@ public class TemplateManagerImplTest { @Inject PrimaryDataStoreDao primaryDataStoreDao; + @Inject + ResourceLimitService resourceLimitMgr; + + @Inject + ImageStoreDao imgStoreDao; + + @Inject + GuestOSDao guestOSDao; + + @Inject + VMTemplateDao tmpltDao; + + @Inject + SnapshotDao snapshotDao; + public class CustomThreadPoolExecutor extends ThreadPoolExecutor { AtomicInteger ai = new AtomicInteger(0); public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, @@ -357,6 +385,58 @@ public void testTemplateScheduledForDownloadInMultiplePool() { assertTrue("Test template is scheduled for seeding to on pool", ((CustomThreadPoolExecutor) preloadExecutor).getCount() == 2); } + @Test + public void testCreatePrivateTemplateRecordForRegionStore() throws ResourceAllocationException { + + CreateTemplateCmd mockCreateCmd = mock(CreateTemplateCmd.class); + when(mockCreateCmd.getTemplateName()).thenReturn("test"); + when(mockCreateCmd.getTemplateTag()).thenReturn(null); + when(mockCreateCmd.getBits()).thenReturn(64); + when(mockCreateCmd.getRequiresHvm()).thenReturn(true); + when(mockCreateCmd.isPasswordEnabled()).thenReturn(false); + when(mockCreateCmd.isPublic()).thenReturn(false); + when(mockCreateCmd.isFeatured()).thenReturn(false); + when(mockCreateCmd.isDynamicallyScalable()).thenReturn(false); + when(mockCreateCmd.getVolumeId()).thenReturn(null); + when(mockCreateCmd.getSnapshotId()).thenReturn(1L); + when(mockCreateCmd.getOsTypeId()).thenReturn(1L); + when(mockCreateCmd.getEventDescription()).thenReturn("test"); + when(mockCreateCmd.getDetails()).thenReturn(null); + + Account mockTemplateOwner = mock(Account.class); + + SnapshotVO mockSnapshot = mock(SnapshotVO.class); + when(snapshotDao.findById(anyLong())).thenReturn(mockSnapshot); + + when(mockSnapshot.getVolumeId()).thenReturn(1L); + when(mockSnapshot.getState()).thenReturn(Snapshot.State.BackedUp); + when(mockSnapshot.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.XenServer); + + doNothing().when(resourceLimitMgr).checkResourceLimit(any(Account.class), eq(Resource.ResourceType.template)); + doNothing().when(resourceLimitMgr).checkResourceLimit(any(Account.class), eq(Resource.ResourceType.secondary_storage), anyLong()); + + GuestOSVO mockGuestOS = mock(GuestOSVO.class); + when(guestOSDao.findById(anyLong())).thenReturn(mockGuestOS); + + when(tmpltDao.getNextInSequence(eq(Long.class), eq("id"))).thenReturn(1L); + + List mockRegionStores = new ArrayList<>(); + ImageStoreVO mockRegionStore = mock(ImageStoreVO.class); + mockRegionStores.add(mockRegionStore); + when(imgStoreDao.findRegionImageStores()).thenReturn(mockRegionStores); + + when(tmpltDao.persist(any(VMTemplateVO.class))).thenAnswer(new Answer() { + @Override + public VMTemplateVO answer(InvocationOnMock invocationOnMock) throws Throwable { + Object[] args = invocationOnMock.getArguments(); + return (VMTemplateVO)args[0]; + } + }); + + VMTemplateVO template = templateManager.createPrivateTemplateRecord(mockCreateCmd, mockTemplateOwner); + assertTrue("Template in a region store should have cross zones set", template.isCrossZones()); + } + @Configuration @ComponentScan(basePackageClasses = {TemplateManagerImpl.class}, includeFilters = {@ComponentScan.Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)}, @@ -523,6 +603,11 @@ public SnapshotDataStoreDao snapshotStoreDao() { return Mockito.mock(SnapshotDataStoreDao.class); } + @Bean + public ImageStoreDao imageStoreDao() { + return Mockito.mock(ImageStoreDao.class); + } + @Bean public MessageBus messageBus() { return Mockito.mock(MessageBus.class); diff --git a/server/test/com/cloud/user/MockAccountManagerImpl.java b/server/test/com/cloud/user/MockAccountManagerImpl.java index 3971fd6b4f..fd85167225 100644 --- a/server/test/com/cloud/user/MockAccountManagerImpl.java +++ b/server/test/com/cloud/user/MockAccountManagerImpl.java @@ -328,13 +328,13 @@ public UserAccount getUserByApiKey(String apiKey) { @Override public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, - short accountType, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID) { + short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID) { // TODO Auto-generated method stub return null; } @Override - public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, + public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID, User.Source source) { // TODO Auto-generated method stub return null; @@ -366,7 +366,7 @@ public boolean deleteAccount(AccountVO account, long callerUserId, Account calle } @Override - public Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details, String uuid) { + public Account createAccount(String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map details, String uuid) { // TODO Auto-generated method stub return null; } diff --git a/server/test/com/cloud/vm/UserVmManagerTest.java b/server/test/com/cloud/vm/UserVmManagerTest.java index 637a309221..9df3f68971 100644 --- a/server/test/com/cloud/vm/UserVmManagerTest.java +++ b/server/test/com/cloud/vm/UserVmManagerTest.java @@ -17,6 +17,8 @@ package com.cloud.vm; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyFloat; @@ -37,9 +39,11 @@ import java.util.List; import java.util.UUID; +import com.cloud.network.element.UserDataServiceProvider; import com.cloud.storage.Storage; import com.cloud.user.User; import com.cloud.event.dao.UsageEventDao; +import com.cloud.uservm.UserVm; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -929,6 +933,54 @@ public void testUpdateVmNicIpFailure3() throws Exception { } } + @Test + public void testApplyUserDataInNetworkWithoutUserDataSupport() throws Exception { + UserVm userVm = mock(UserVm.class); + when(userVm.getId()).thenReturn(1L); + + when(_nicMock.getNetworkId()).thenReturn(2L); + when(_networkMock.getNetworkOfferingId()).thenReturn(3L); + when(_networkDao.findById(2L)).thenReturn(_networkMock); + + // No userdata support + assertFalse(_userVmMgr.applyUserData(HypervisorType.KVM, userVm, _nicMock)); + } + + @Test(expected = CloudRuntimeException.class) + public void testApplyUserDataInNetworkWithoutElement() throws Exception { + UserVm userVm = mock(UserVm.class); + when(userVm.getId()).thenReturn(1L); + + when(_nicMock.getNetworkId()).thenReturn(2L); + when(_networkMock.getNetworkOfferingId()).thenReturn(3L); + when(_networkDao.findById(2L)).thenReturn(_networkMock); + + UserDataServiceProvider userDataServiceProvider = mock(UserDataServiceProvider.class); + when(userDataServiceProvider.saveUserData(any(Network.class), any(NicProfile.class), any(VirtualMachineProfile.class))).thenReturn(true); + + // Userdata support, but no implementing element + when(_networkModel.areServicesSupportedByNetworkOffering(3L, Service.UserData)).thenReturn(true); + _userVmMgr.applyUserData(HypervisorType.KVM, userVm, _nicMock); + } + + @Test + public void testApplyUserDataSuccessful() throws Exception { + UserVm userVm = mock(UserVm.class); + when(userVm.getId()).thenReturn(1L); + + when(_nicMock.getNetworkId()).thenReturn(2L); + when(_networkMock.getNetworkOfferingId()).thenReturn(3L); + when(_networkDao.findById(2L)).thenReturn(_networkMock); + + UserDataServiceProvider userDataServiceProvider = mock(UserDataServiceProvider.class); + when(userDataServiceProvider.saveUserData(any(Network.class), any(NicProfile.class), any(VirtualMachineProfile.class))).thenReturn(true); + + // Userdata support with implementing element + when(_networkModel.areServicesSupportedByNetworkOffering(3L, Service.UserData)).thenReturn(true); + when(_networkModel.getUserDataUpdateProvider(_networkMock)).thenReturn(userDataServiceProvider); + assertTrue(_userVmMgr.applyUserData(HypervisorType.KVM, userVm, _nicMock)); + } + @Test public void testPersistDeviceBusInfoWithNullController() { when(_vmMock.getDetail(any(String.class))).thenReturn(null); diff --git a/server/test/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceTest.java b/server/test/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceTest.java new file mode 100644 index 0000000000..69f03ff674 --- /dev/null +++ b/server/test/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceTest.java @@ -0,0 +1,116 @@ +// 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.outofbandmanagement; + +import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.collect.ImmutableMap; +import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class OutOfBandManagementServiceTest { + + OutOfBandManagementServiceImpl oobmService = new OutOfBandManagementServiceImpl(); + + @Test + public void testOutOfBandManagementDriverResponseEvent() { + OutOfBandManagementDriverResponse r = new OutOfBandManagementDriverResponse("some result", "some error", false); + + r.setSuccess(false); + r.setAuthFailure(false); + Assert.assertEquals(r.toEvent(), OutOfBandManagement.PowerState.Event.Unknown); + + r.setSuccess(false); + r.setAuthFailure(true); + Assert.assertEquals(r.toEvent(), OutOfBandManagement.PowerState.Event.AuthError); + + r.setAuthFailure(false); + r.setSuccess(true); + r.setPowerState(OutOfBandManagement.PowerState.On); + Assert.assertEquals(r.toEvent(), OutOfBandManagement.PowerState.Event.On); + + r.setPowerState(OutOfBandManagement.PowerState.Off); + Assert.assertEquals(r.toEvent(), OutOfBandManagement.PowerState.Event.Off); + + r.setPowerState(OutOfBandManagement.PowerState.Disabled); + Assert.assertEquals(r.toEvent(), OutOfBandManagement.PowerState.Event.Disabled); + } + + private ImmutableMap buildRandomOptionsMap() { + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + builder.put(OutOfBandManagement.Option.ADDRESS, "localhost"); + builder.put(OutOfBandManagement.Option.DRIVER, "ipmitool"); + return builder.build(); + } + + @Test + public void testUpdateOutOfBandManagementConfigValid() { + OutOfBandManagement config = new OutOfBandManagementVO(123L); + Assert.assertEquals(config.getPowerState(), OutOfBandManagement.PowerState.Disabled); + config = oobmService.updateConfig(config, buildRandomOptionsMap()); + Assert.assertEquals(config.getAddress(), "localhost"); + Assert.assertEquals(config.getDriver(), "ipmitool"); + Assert.assertEquals(config.getPowerState(), OutOfBandManagement.PowerState.Disabled); + } + + @Test(expected = CloudRuntimeException.class) + public void testUpdateOutOfBandManagementNullConfigValidOptions() { + oobmService.updateConfig(null, buildRandomOptionsMap()); + Assert.fail("CloudRuntimeException was expect for out-of-band management not configured for the host"); + } + + @Test(expected = CloudRuntimeException.class) + public void testUpdateOutOfBandManagementNullConfigNullOptions() { + oobmService.updateConfig(null, null); + Assert.fail("CloudRuntimeException was expect for out-of-band management not configured for the host"); + } + + @Test + public void testUpdateOutOfBandManagementValidConfigValidOptions() { + OutOfBandManagement config = new OutOfBandManagementVO(123L); + config.setAddress(null); + config = oobmService.updateConfig(config, null); + Assert.assertEquals(config.getAddress(), null); + Assert.assertEquals(config.getPowerState(), OutOfBandManagement.PowerState.Disabled); + } + + @Test + public void testGetOutOfBandManagementOptionsValid() { + OutOfBandManagement configEmpty = new OutOfBandManagementVO(123L); + ImmutableMap optionsEmpty = oobmService.getOptions(configEmpty); + Assert.assertEquals(optionsEmpty.size(), 0); + + OutOfBandManagement config = new OutOfBandManagementVO(123L); + config.setAddress("localhost"); + config.setDriver("ipmitool"); + config.setPort(1234); + ImmutableMap options = oobmService.getOptions(config); + Assert.assertEquals(options.get(OutOfBandManagement.Option.ADDRESS), "localhost"); + Assert.assertEquals(options.get(OutOfBandManagement.Option.DRIVER), "ipmitool"); + Assert.assertEquals(options.get(OutOfBandManagement.Option.PORT), "1234"); + } + + @Test(expected = CloudRuntimeException.class) + public void testGetOutOfBandManagementOptionsInvalid() { + oobmService.getOptions(null); + Assert.fail("CloudRuntimeException was expected for finding options of host with out-of-band management configuration"); + } +} diff --git a/server/test/org/cloud/network/router/deployment/RouterDeploymentDefinitionTest.java b/server/test/org/cloud/network/router/deployment/RouterDeploymentDefinitionTest.java index 1570a2e15a..eff16c16b8 100644 --- a/server/test/org/cloud/network/router/deployment/RouterDeploymentDefinitionTest.java +++ b/server/test/org/cloud/network/router/deployment/RouterDeploymentDefinitionTest.java @@ -513,9 +513,9 @@ public void testDeployVirtualRouter() throws ConcurrentOperationException, } finally { // Assert verify(deploymentUT, times(1)).lock(); - verify(deploymentUT, times(1)).checkPreconditions(); - verify(deploymentUT, times(1)).findDestinations(); - verify(deploymentUT, times(2)).generateDeploymentPlan(); + verify(deploymentUT, times(2)).checkPreconditions(); + verify(deploymentUT, times(2)).findDestinations(); + verify(deploymentUT, times(3)).generateDeploymentPlan(); verify(deploymentUT, times(2)).executeDeployment(); //verify(deploymentUT, times(2)).planDeploymentRouters(); verify(deploymentUT, times(1)).unlock(); @@ -524,6 +524,36 @@ public void testDeployVirtualRouter() throws ConcurrentOperationException, fail(); } + @Test + public void testDeployVirtualRouterSkip() throws ConcurrentOperationException, + InsufficientCapacityException, ResourceUnavailableException { + + // Prepare + final List mockDestinations = new ArrayList<>(); + mockDestinations.add(mock(DeployDestination.class)); + mockDestinations.add(mock(DeployDestination.class)); + + final RouterDeploymentDefinition deploymentUT = spy(deployment); + doNothing().when(deploymentUT).checkPreconditions(); + doReturn(mockDestinations).when(deploymentUT).findDestinations(); + doNothing().when(deploymentUT).planDeploymentRouters(); + doNothing().when(deploymentUT).generateDeploymentPlan(); + doReturn(0).when(deploymentUT).getNumberOfRoutersToDeploy(); + + // Execute + try { + deploymentUT.findOrDeployVirtualRouter(); + } finally { + // Assert + verify(deploymentUT, times(0)).lock(); // lock shouldn't be acquired when VR already present + verify(deploymentUT, times(1)).checkPreconditions(); + verify(deploymentUT, times(1)).findDestinations(); + verify(deploymentUT, times(2)).generateDeploymentPlan(); + verify(deploymentUT, times(0)).executeDeployment(); // no need to deploy VR as already present + verify(deploymentUT, times(0)).unlock(); // same as lock + } + } + @Test public void testGetNumberOfRoutersToDeploy() { // Prepare diff --git a/server/test/resources/db.properties b/server/test/resources/db.properties index 45baf4cf97..e9355a3db3 100644 --- a/server/test/resources/db.properties +++ b/server/test/resources/db.properties @@ -26,6 +26,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -46,6 +47,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -59,6 +62,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/services/console-proxy-rdp/rdpconsole/pom.xml b/services/console-proxy-rdp/rdpconsole/pom.xml index a64b118630..628d039a6e 100755 --- a/services/console-proxy-rdp/rdpconsole/pom.xml +++ b/services/console-proxy-rdp/rdpconsole/pom.xml @@ -27,7 +27,7 @@ org.apache.cloudstack cloudstack-services - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml @@ -71,12 +71,13 @@ org.apache.tomcat.embed tomcat-embed-core - 8.0.15 + 8.0.30 org.bouncycastle bcprov-jdk16 + 1.46
diff --git a/services/console-proxy/plugin/pom.xml b/services/console-proxy/plugin/pom.xml index 14a3ffc3e2..dbaf85791c 100644 --- a/services/console-proxy/plugin/pom.xml +++ b/services/console-proxy/plugin/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-console-proxy - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/console-proxy/pom.xml b/services/console-proxy/pom.xml index 8dddaeab70..9d5feec386 100644 --- a/services/console-proxy/pom.xml +++ b/services/console-proxy/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-services - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/console-proxy/server/pom.xml b/services/console-proxy/server/pom.xml index 99d0f921b7..541d242013 100644 --- a/services/console-proxy/server/pom.xml +++ b/services/console-proxy/server/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-console-proxy - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/iam/plugin/pom.xml b/services/iam/plugin/pom.xml index c770ef2689..974d2166bf 100644 --- a/services/iam/plugin/pom.xml +++ b/services/iam/plugin/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-iam - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java index 634ce0a2e0..3072b77a5c 100644 --- a/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java +++ b/services/iam/plugin/src/org/apache/cloudstack/iam/RoleBasedAPIAccessChecker.java @@ -196,7 +196,7 @@ private void processMapping(Map configMap) { try { short cmdPermissions = Short.parseShort(roleMask); for (RoleType roleType : RoleType.values()) { - if ((cmdPermissions & roleType.getValue()) != 0) + if ((cmdPermissions & roleType.getMask()) != 0) commandsPropertiesRoleBasedApisMap.get(roleType).add(apiName); } } catch (NumberFormatException nfe) { diff --git a/services/iam/plugin/test/resources/db.properties b/services/iam/plugin/test/resources/db.properties index faa577c982..a672d63f79 100644 --- a/services/iam/plugin/test/resources/db.properties +++ b/services/iam/plugin/test/resources/db.properties @@ -27,6 +27,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -47,6 +48,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -60,6 +63,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/services/iam/server/pom.xml b/services/iam/server/pom.xml index 71bafed62e..b2ad0a4f52 100644 --- a/services/iam/server/pom.xml +++ b/services/iam/server/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-iam - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/iam/server/test/resources/db.properties b/services/iam/server/test/resources/db.properties index faa577c982..a672d63f79 100644 --- a/services/iam/server/test/resources/db.properties +++ b/services/iam/server/test/resources/db.properties @@ -27,6 +27,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -47,6 +48,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -60,6 +63,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/services/pom.xml b/services/pom.xml index c8812f75e2..f315b5e8b1 100644 --- a/services/pom.xml +++ b/services/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/secondary-storage/controller/pom.xml b/services/secondary-storage/controller/pom.xml index f242663b31..bb8878010f 100644 --- a/services/secondary-storage/controller/pom.xml +++ b/services/secondary-storage/controller/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-secondary-storage - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index 4891b71967..79c1de13a6 100644 --- a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -43,6 +43,7 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; import org.apache.cloudstack.utils.identity.ManagementServerNode; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -101,6 +102,7 @@ import com.cloud.resource.UnableDeleteHostException; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage; import com.cloud.storage.UploadVO; import com.cloud.storage.VMTemplateVO; @@ -239,6 +241,8 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar TemplateDataStoreDao _tmplStoreDao; @Inject VolumeDataStoreDao _volumeStoreDao; + @Inject + private ImageStoreDetailsUtil imageStoreDetailsUtil; private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL; private int _secStorageVmMtuSize; @@ -310,6 +314,9 @@ public boolean generateSetupCommand(Long ssHostId) { setupCmd = new SecStorageSetupCommand(ssStore.getTO(), secUrl, certs); } + Integer nfsVersion = imageStoreDetailsUtil.getNfsVersion(ssStore.getId()); + setupCmd.setNfsVersion(nfsVersion); + //template/volume file upload key String postUploadKey = _configDao.getValue(Config.SSVMPSK.key()); setupCmd.setPostUploadKey(postUploadKey); @@ -516,6 +523,76 @@ public SecondaryStorageVmVO startNew(long dataCenterId, SecondaryStorageVm.Role return null; } + /** + * Get the default network for the secondary storage VM, based on the zone it is in. Delegates to + * either {@link #getDefaultNetworkForZone(DataCenter)} or {@link #getDefaultNetworkForAdvancedSGZone(DataCenter)}, + * depending on the zone network type and whether or not security groups are enabled in the zone. + * @param dc - The zone (DataCenter) of the secondary storage VM. + * @return The default network for use with the secondary storage VM. + */ + protected NetworkVO getDefaultNetworkForCreation(DataCenter dc) { + if (dc.getNetworkType() == NetworkType.Advanced) { + return getDefaultNetworkForAdvancedZone(dc); + } else { + return getDefaultNetworkForBasicZone(dc); + } + } + + /** + * Get default network for a secondary storage VM starting up in an advanced zone. If the zone + * is security group-enabled, the first network found that supports SG services is returned. + * If the zone is not SG-enabled, the Public network is returned. + * @param dc - The zone. + * @return The selected default network. + * @throws CloudRuntimeException - If the zone is not a valid choice or a network couldn't be found. + */ + protected NetworkVO getDefaultNetworkForAdvancedZone(DataCenter dc) { + if (dc.getNetworkType() != NetworkType.Advanced) { + throw new CloudRuntimeException("Zone " + dc + " is not advanced."); + } + + if (dc.isSecurityGroupEnabled()) { + List networks = _networkDao.listByZoneSecurityGroup(dc.getId()); + if (CollectionUtils.isEmpty(networks)) { + throw new CloudRuntimeException("Can not found security enabled network in SG Zone " + dc); + } + + return networks.get(0); + } + else { + TrafficType defaultTrafficType = TrafficType.Public; + List defaultNetworks = _networkDao.listByZoneAndTrafficType(dc.getId(), defaultTrafficType); + // api should never allow this situation to happen + if (defaultNetworks.size() != 1) { + throw new CloudRuntimeException("Found " + defaultNetworks.size() + " networks of type " + defaultTrafficType + " when expect to find 1"); + } + + return defaultNetworks.get(0); + } + } + + /** + * Get default network for secondary storage VM for starting up in a basic zone. Basic zones select + * the Guest network whether or not the zone is SG-enabled. + * @param dc - The zone. + * @return The default network according to the zone's network selection rules. + * @throws CloudRuntimeException - If the zone is not a valid choice or a network couldn't be found. + */ + protected NetworkVO getDefaultNetworkForBasicZone(DataCenter dc) { + if (dc.getNetworkType() != NetworkType.Basic) { + throw new CloudRuntimeException("Zone " + dc + "is not basic."); + } + + TrafficType defaultTrafficType = TrafficType.Guest; + List defaultNetworks = _networkDao.listByZoneAndTrafficType(dc.getId(), defaultTrafficType); + // api should never allow this situation to happen + if (defaultNetworks.size() != 1) { + throw new CloudRuntimeException("Found " + defaultNetworks.size() + " networks of type " + defaultTrafficType + " when expect to find 1"); + } + + return defaultNetworks.get(0); + } + protected Map createSecStorageVmInstance(long dataCenterId, SecondaryStorageVm.Role role) { DataStore secStore = _dataStoreMgr.getImageStore(dataCenterId); if (secStore == null) { @@ -531,26 +608,7 @@ protected Map createSecStorageVmInstance(long dataCenterId, Seco DataCenterDeployment plan = new DataCenterDeployment(dataCenterId); DataCenter dc = _dcDao.findById(plan.getDataCenterId()); - NetworkVO defaultNetwork = null; - if (dc.getNetworkType() == NetworkType.Advanced && dc.isSecurityGroupEnabled()) { - List networks = _networkDao.listByZoneSecurityGroup(dataCenterId); - if (networks == null || networks.size() == 0) { - throw new CloudRuntimeException("Can not found security enabled network in SG Zone " + dc); - } - defaultNetwork = networks.get(0); - } else { - TrafficType defaultTrafficType = TrafficType.Public; - - if (dc.getNetworkType() == NetworkType.Basic || dc.isSecurityGroupEnabled()) { - defaultTrafficType = TrafficType.Guest; - } - List defaultNetworks = _networkDao.listByZoneAndTrafficType(dataCenterId, defaultTrafficType); - // api should never allow this situation to happen - if (defaultNetworks.size() != 1) { - throw new CloudRuntimeException("Found " + defaultNetworks.size() + " networks of type " + defaultTrafficType + " when expect to find 1"); - } - defaultNetwork = defaultNetworks.get(0); - } + NetworkVO defaultNetwork = getDefaultNetworkForCreation(dc); List offerings = null; if (_sNwMgr.isStorageIpRangeAvailable(dataCenterId)) { @@ -983,7 +1041,7 @@ public boolean rebootSecStorageVm(long secStorageVmId) { } if (secStorageVm.getState() == State.Running && secStorageVm.getHostId() != null) { - final RebootCommand cmd = new RebootCommand(secStorageVm.getInstanceName()); + final RebootCommand cmd = new RebootCommand(secStorageVm.getInstanceName(), _itMgr.getExecuteInSequence(secStorageVm.getHypervisorType())); final Answer answer = _agentMgr.easySend(secStorageVm.getHostId(), cmd); if (answer != null && answer.getResult()) { @@ -1046,7 +1104,6 @@ private String getSecStorageVmLockName(long id) { @Override public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { - SecondaryStorageVmVO vm = _secStorageVmDao.findById(profile.getId()); Map details = _vmDetailsDao.listDetailsKeyPairs(vm.getId()); vm.setDetails(details); @@ -1131,6 +1188,8 @@ public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, Depl if (dc.getDns2() != null) { buf.append(" dns2=").append(dc.getDns2()); } + Integer nfsVersion = imageStoreDetailsUtil != null ? imageStoreDetailsUtil.getNfsVersion(secStore.getId()) : null; + buf.append(" nfsVersion=").append(nfsVersion); String bootArgs = buf.toString(); if (s_logger.isDebugEnabled()) { @@ -1430,4 +1489,5 @@ public List getSecondaryStorageVmAllocators() { public void setSecondaryStorageVmAllocators(List ssVmAllocators) { _ssVmAllocators = ssVmAllocators; } + } diff --git a/services/secondary-storage/controller/test/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerTest.java b/services/secondary-storage/controller/test/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerTest.java new file mode 100644 index 0000000000..c42f2b130c --- /dev/null +++ b/services/secondary-storage/controller/test/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerTest.java @@ -0,0 +1,192 @@ +// 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.secondarystorage; + +import java.util.Collections; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.utils.exception.CloudRuntimeException; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.when; +import static org.mockito.AdditionalMatchers.not; +import static org.mockito.Mockito.eq; + +public class SecondaryStorageManagerTest { + @Mock + DataCenterDao _dcDao; + + @Mock + NetworkDao _networkDao; + + @InjectMocks + SecondaryStorageManagerImpl _ssMgr = new SecondaryStorageManagerImpl(); + + @Before + public void initMocks() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void getDefaultNetworkForAdvancedNonSG() { + DataCenterVO dc = mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(false); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Public))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Public)))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = _ssMgr.getDefaultNetworkForAdvancedZone(dc); + + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForAdvancedSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), any(TrafficType.class))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(network)); + + NetworkVO returnedNetwork = _ssMgr.getDefaultNetworkForAdvancedZone(dc); + + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForBasicNonSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(false); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = _ssMgr.getDefaultNetworkForBasicZone(dc); + + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + @Test + public void getDefaultNetworkForBasicSG() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + NetworkVO returnedNetwork = _ssMgr.getDefaultNetworkForBasicZone(dc); + + Assert.assertNotNull(returnedNetwork); + Assert.assertEquals(network, returnedNetwork); + Assert.assertNotEquals(badNetwork, returnedNetwork); + } + + //also test invalid input + @Test(expected=CloudRuntimeException.class) + public void getDefaultNetworkForBasicSGWrongZoneType() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Advanced); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), eq(TrafficType.Guest))) + .thenReturn(Collections.singletonList(network)); + + when(_networkDao.listByZoneAndTrafficType(anyLong(), not(eq(TrafficType.Guest)))) + .thenReturn(Collections.singletonList(badNetwork)); + + _ssMgr.getDefaultNetworkForBasicZone(dc); + } + + @Test(expected=CloudRuntimeException.class) + public void getDefaultNetworkForAdvancedWrongZoneType() { + DataCenterVO dc = Mockito.mock(DataCenterVO.class); + when(dc.getNetworkType()).thenReturn(NetworkType.Basic); + when(dc.isSecurityGroupEnabled()).thenReturn(true); + + when(_dcDao.findById(Mockito.anyLong())).thenReturn(dc); + + NetworkVO network = Mockito.mock(NetworkVO.class); + NetworkVO badNetwork = Mockito.mock(NetworkVO.class); + when(_networkDao.listByZoneAndTrafficType(anyLong(), any(TrafficType.class))) + .thenReturn(Collections.singletonList(badNetwork)); + + when(_networkDao.listByZoneSecurityGroup(anyLong())) + .thenReturn(Collections.singletonList(network)); + + _ssMgr.getDefaultNetworkForAdvancedZone(dc); + } +} diff --git a/services/secondary-storage/pom.xml b/services/secondary-storage/pom.xml index 33b5860c11..bce61d66f1 100644 --- a/services/secondary-storage/pom.xml +++ b/services/secondary-storage/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack-services - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/services/secondary-storage/server/pom.xml b/services/secondary-storage/server/pom.xml index 97e68a8c9d..50155cfb61 100644 --- a/services/secondary-storage/server/pom.xml +++ b/services/secondary-storage/server/pom.xml @@ -23,7 +23,7 @@ org.apache.cloudstack cloudstack-service-secondary-storage - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml @@ -54,7 +54,7 @@ io.netty netty-all - 4.0.25.Final + 4.0.33.Final compile diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java index 9393ee217a..c02fe8a610 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java @@ -53,10 +53,10 @@ public Answer executeRequest(Command cmd) { } @Override - synchronized public String getRootDir(String secUrl) { + synchronized public String getRootDir(String secUrl, Integer nfsVersion) { try { URI uri = new URI(secUrl); - String dir = mountUri(uri); + String dir = mountUri(uri, nfsVersion); return _parent + "/" + dir; } catch (Exception e) { String msg = "GetRootDir for " + secUrl + " failed due to " + e.toString(); @@ -66,14 +66,14 @@ synchronized public String getRootDir(String secUrl) { } @Override - protected void mount(String localRootPath, String remoteDevice, URI uri) { + protected void mount(String localRootPath, String remoteDevice, URI uri, Integer nfsVersion) { ensureLocalRootPathExists(localRootPath, uri); if (mountExists(localRootPath, uri)) { return; } - attemptMount(localRootPath, remoteDevice, uri); + attemptMount(localRootPath, remoteDevice, uri, nfsVersion); // Change permissions for the mountpoint - seems to bypass authentication Script script = new Script(true, "chmod", _timeout, s_logger); diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java index bdfe7e837f..c6f6ba81ea 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java @@ -72,7 +72,7 @@ public void disconnected() { } @Override - public String getRootDir(String url) { + public String getRootDir(String url, Integer nfsVersion) { return getRootDir(); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index f512da040c..420842f229 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -16,7 +16,91 @@ // under the License. package org.apache.cloudstack.storage.resource; +import static com.cloud.utils.storage.S3.S3Utils.putFile; +import static com.cloud.utils.StringUtils.join; +import static java.lang.String.format; +import static java.util.Arrays.asList; +import static org.apache.commons.lang.StringUtils.substringAfterLast; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.URI; +import java.net.UnknownHostException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.naming.ConfigurationException; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.storage.Storage; +import com.cloud.storage.template.TemplateConstants; +import com.cloud.utils.EncryptionUtil; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.HttpContentCompressor; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; +import org.apache.cloudstack.storage.template.UploadEntity; +import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.log4j.Logger; + import com.amazonaws.services.s3.model.S3ObjectSummary; + +import org.apache.cloudstack.framework.security.keystore.KeystoreManager; +import org.apache.cloudstack.storage.command.CopyCmdAnswer; +import org.apache.cloudstack.storage.command.CopyCommand; +import org.apache.cloudstack.storage.command.DeleteCommand; +import org.apache.cloudstack.storage.command.DownloadCommand; +import org.apache.cloudstack.storage.command.DownloadProgressCommand; +import org.apache.cloudstack.storage.command.UploadStatusAnswer; +import org.apache.cloudstack.storage.command.UploadStatusAnswer.UploadStatus; +import org.apache.cloudstack.storage.command.UploadStatusCommand; +import org.apache.cloudstack.storage.template.DownloadManager; +import org.apache.cloudstack.storage.template.DownloadManagerImpl; +import org.apache.cloudstack.storage.template.DownloadManagerImpl.ZfsPathParser; +import org.apache.cloudstack.storage.template.UploadManager; +import org.apache.cloudstack.storage.template.UploadManagerImpl; +import org.apache.cloudstack.storage.to.SnapshotObjectTO; +import org.apache.cloudstack.storage.to.TemplateObjectTO; +import org.apache.cloudstack.storage.to.VolumeObjectTO; + import com.cloud.agent.api.Answer; import com.cloud.agent.api.CheckHealthAnswer; import com.cloud.agent.api.CheckHealthCommand; @@ -51,13 +135,11 @@ import com.cloud.agent.api.to.S3TO; import com.cloud.agent.api.to.SwiftTO; import com.cloud.exception.InternalErrorException; -import com.cloud.exception.InvalidParameterValueException; import com.cloud.host.Host; import com.cloud.host.Host.Type; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ServerResourceBase; import com.cloud.storage.DataStoreRole; -import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.VMTemplateStorageResourceAssoc; @@ -67,99 +149,21 @@ import com.cloud.storage.template.QCOW2Processor; import com.cloud.storage.template.RawImageProcessor; import com.cloud.storage.template.TARProcessor; -import com.cloud.storage.template.TemplateConstants; import com.cloud.storage.template.TemplateLocation; import com.cloud.storage.template.TemplateProp; import com.cloud.storage.template.VhdProcessor; import com.cloud.storage.template.VmdkProcessor; -import com.cloud.utils.EncryptionUtil; import com.cloud.utils.NumbersUtil; +import com.cloud.utils.storage.S3.S3Utils; import com.cloud.utils.SwiftUtil; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; -import com.cloud.utils.storage.S3.S3Utils; import com.cloud.vm.SecondaryStorageVm; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.codec.http.HttpContentCompressor; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import io.netty.handler.logging.LogLevel; -import io.netty.handler.logging.LoggingHandler; -import org.apache.cloudstack.framework.security.keystore.KeystoreManager; -import org.apache.cloudstack.storage.command.CopyCmdAnswer; -import org.apache.cloudstack.storage.command.CopyCommand; -import org.apache.cloudstack.storage.command.DeleteCommand; -import org.apache.cloudstack.storage.command.DownloadCommand; -import org.apache.cloudstack.storage.command.DownloadProgressCommand; -import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; -import org.apache.cloudstack.storage.command.UploadStatusAnswer; -import org.apache.cloudstack.storage.command.UploadStatusAnswer.UploadStatus; -import org.apache.cloudstack.storage.command.UploadStatusCommand; -import org.apache.cloudstack.storage.template.DownloadManager; -import org.apache.cloudstack.storage.template.DownloadManagerImpl; -import org.apache.cloudstack.storage.template.DownloadManagerImpl.ZfsPathParser; -import org.apache.cloudstack.storage.template.UploadEntity; -import org.apache.cloudstack.storage.template.UploadManager; -import org.apache.cloudstack.storage.template.UploadManagerImpl; -import org.apache.cloudstack.storage.to.SnapshotObjectTO; -import org.apache.cloudstack.storage.to.TemplateObjectTO; -import org.apache.cloudstack.storage.to.VolumeObjectTO; -import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.log4j.Logger; import org.joda.time.DateTime; import org.joda.time.format.ISODateTimeFormat; -import javax.naming.ConfigurationException; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; -import java.net.InetAddress; -import java.net.URI; -import java.net.UnknownHostException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import static com.cloud.utils.StringUtils.join; -import static com.cloud.utils.storage.S3.S3Utils.putFile; -import static java.lang.String.format; -import static java.util.Arrays.asList; -import static org.apache.commons.lang.StringUtils.substringAfterLast; - public class NfsSecondaryStorageResource extends ServerResourceBase implements SecondaryStorageResource { public static final Logger s_logger = Logger.getLogger(NfsSecondaryStorageResource.class); @@ -201,6 +205,7 @@ public void setTimeout(int timeout) { private String _storageIp; private String _storageNetmask; private String _storageGateway; + private Integer _nfsVersion; private final List nfsIps = new ArrayList(); protected String _parent = "/mnt/SecStorage"; final private String _tmpltpp = "template.properties"; @@ -224,6 +229,26 @@ public void setInSystemVM(boolean inSystemVM) { _inSystemVM = inSystemVM; } + /** + * Retrieve converted "nfsVersion" value from params + * @param params + * @return nfsVersion value if exists, null in other case + */ + public static Integer retrieveNfsVersionFromParams(Map params){ + Integer nfsVersion = null; + if (params.get("nfsVersion") != null){ + String nfsVersionParam = (String)params.get("nfsVersion"); + try { + nfsVersion = Integer.valueOf(nfsVersionParam); + } + catch (NumberFormatException e){ + s_logger.error("Couldn't cast " + nfsVersionParam + " to integer"); + return null; + } + } + return nfsVersion; + } + @Override public Answer executeRequest(Command cmd) { if (cmd instanceof DownloadProgressCommand) { @@ -348,7 +373,7 @@ protected Answer copyFromSwiftToNfs(CopyCommand cmd, DataTO srcData, SwiftTO swi final String storagePath = destImageStore.getUrl(); final String destPath = destData.getPath(); try { - String downloadPath = determineStorageTemplatePath(storagePath, destPath); + String downloadPath = determineStorageTemplatePath(storagePath, destPath, _nfsVersion); final File downloadDirectory = _storage.getFile(downloadPath); if (downloadDirectory.exists()) { @@ -375,7 +400,7 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT try { - String downloadPath = determineStorageTemplatePath(storagePath, destPath); + String downloadPath = determineStorageTemplatePath(storagePath, destPath, _nfsVersion); final File downloadDirectory = _storage.getFile(downloadPath); if (downloadDirectory.exists()) { @@ -387,16 +412,9 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT return new CopyCmdAnswer(errMsg); } } - File destFile = new File(downloadDirectory, substringAfterLast(srcData.getPath(), S3Utils.SEPARATOR)); - S3Utils.getFile(s3, s3.getBucketName(), srcData.getPath(), destFile).waitForCompletion(); - - if (destFile == null) { - return new CopyCmdAnswer("Can't find template"); - } - return postProcessing(destFile, downloadPath, destPath, srcData, destData); } catch (Exception e) { @@ -408,7 +426,7 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, SnapshotObjectTO srcData, NfsTO srcDataStore, TemplateObjectTO destData, NfsTO destDataStore) { - String srcMountPoint = getRootDir(srcDataStore.getUrl()); + String srcMountPoint = getRootDir(srcDataStore.getUrl(), _nfsVersion); String snapshotPath = srcData.getPath(); int index = snapshotPath.lastIndexOf("/"); String snapshotName = snapshotPath.substring(index + 1); @@ -418,7 +436,7 @@ protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, Sn snapshotPath = snapshotPath.substring(0, index); snapshotPath = srcMountPoint + File.separator + snapshotPath; - String destMountPoint = getRootDir(destDataStore.getUrl()); + String destMountPoint = getRootDir(destDataStore.getUrl(), _nfsVersion); String destPath = destMountPoint + File.separator + destData.getPath(); String errMsg = null; @@ -476,8 +494,8 @@ protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObj if (srcData.getHypervisorType() == HypervisorType.XenServer) { return copySnapshotToTemplateFromNfsToNfsXenserver(cmd, srcData, srcDataStore, destData, destDataStore); } else if (srcData.getHypervisorType() == HypervisorType.KVM) { - File srcFile = getFile(srcData.getPath(), srcDataStore.getUrl()); - File destFile = getFile(destData.getPath(), destDataStore.getUrl()); + File srcFile = getFile(srcData.getPath(), srcDataStore.getUrl(), _nfsVersion); + File destFile = getFile(destData.getPath(), destDataStore.getUrl(), _nfsVersion); VolumeObjectTO volumeObjectTO = srcData.getVolume(); ImageFormat srcFormat = null; @@ -561,8 +579,8 @@ protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObj return new CopyCmdAnswer(""); } - protected File getFile(String path, String nfsPath) { - String filePath = getRootDir(nfsPath) + File.separator + path; + protected File getFile(String path, String nfsPath, Integer nfsVersion) { + String filePath = getRootDir(nfsPath, nfsVersion) + File.separator + path; File f = new File(filePath); if (!f.exists()) { _storage.mkdirs(filePath); @@ -674,7 +692,6 @@ protected Answer execute(CopyCommand cmd) { return Answer.createUnsupportedCommandAnswer(cmd); } - @SuppressWarnings("unchecked") protected String determineS3TemplateDirectory(final Long accountId, final Long templateId, final String templateUniqueName) { return join(asList(TEMPLATE_ROOT_DIR, accountId, templateId, templateUniqueName), S3Utils.SEPARATOR); } @@ -683,7 +700,6 @@ private String determineS3TemplateNameFromKey(String key) { return StringUtils.substringAfterLast(StringUtils.substringBeforeLast(key, S3Utils.SEPARATOR), S3Utils.SEPARATOR); } - @SuppressWarnings("unchecked") protected String determineS3VolumeDirectory(final Long accountId, final Long volId) { return join(asList(VOLUME_ROOT_DIR, accountId, volId), S3Utils.SEPARATOR); } @@ -692,8 +708,8 @@ protected Long determineS3VolumeIdFromKey(String key) { return Long.parseLong(StringUtils.substringAfterLast(StringUtils.substringBeforeLast(key, S3Utils.SEPARATOR), S3Utils.SEPARATOR)); } - private String determineStorageTemplatePath(final String storagePath, String dataPath) { - return join(asList(getRootDir(storagePath), dataPath), File.separator); + private String determineStorageTemplatePath(final String storagePath, String dataPath, Integer nfsVersion) { + return join(asList(getRootDir(storagePath, nfsVersion), dataPath), File.separator); } protected File downloadFromUrlToNfs(String url, NfsTO nfs, String path, String name) { @@ -707,7 +723,7 @@ protected File downloadFromUrlToNfs(String url, NfsTO nfs, String path, String n throw new CloudRuntimeException("Failed to get url: " + url); } - String nfsMountPath = getRootDir(nfs.getUrl()); + String nfsMountPath = getRootDir(nfs.getUrl(), _nfsVersion); String filePath = nfsMountPath + File.separator + path; File directory = new File(filePath); @@ -868,7 +884,7 @@ protected Answer copyFromNfsToS3(CopyCommand cmd) { final S3TO s3 = (S3TO)destDataStore; try { - final String templatePath = determineStorageTemplatePath(srcStore.getUrl(), srcData.getPath()); + final String templatePath = determineStorageTemplatePath(srcStore.getUrl(), srcData.getPath(), _nfsVersion); if (s_logger.isDebugEnabled()) { s_logger.debug("Found " + srcData.getObjectType() + " from directory " + templatePath + " to upload to S3."); @@ -999,7 +1015,7 @@ protected Answer copyFromNfsToSwift(CopyCommand cmd) { DataStoreTO srcDataStore = srcData.getDataStore(); NfsTO srcStore = (NfsTO)srcDataStore; DataStoreTO destDataStore = destData.getDataStore(); - File srcFile = getFile(srcData.getPath(), srcStore.getUrl()); + File srcFile = getFile(srcData.getPath(), srcStore.getUrl(), _nfsVersion); SwiftTO swift = (SwiftTO)destDataStore; @@ -1193,7 +1209,7 @@ public Answer execute(DeleteSnapshotsDirCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeSnapshotPath = cmd.getDirectory(); - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (relativeSnapshotPath.startsWith(File.separator)) { relativeSnapshotPath = relativeSnapshotPath.substring(1); @@ -1271,7 +1287,7 @@ private Answer execute(ComputeChecksumCommand cmd) { return new Answer(cmd, false, "can't handle non nfs data store"); } NfsTO nfsStore = (NfsTO)store; - String parent = getRootDir(nfsStore.getUrl()); + String parent = getRootDir(nfsStore.getUrl(), _nfsVersion); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1405,7 +1421,8 @@ private Answer execute(SecStorageSetupCommand cmd) { String nfsHostIp = getUriHostIp(uri); addRouteToInternalIpOrCidr(_storageGateway, _storageIp, _storageNetmask, nfsHostIp); - String dir = mountUri(uri); + + String dir = mountUri(uri, cmd.getNfsVersion()); configCerts(cmd.getCerts()); @@ -1481,7 +1498,7 @@ protected Answer deleteSnapshot(final DeleteCommand cmd) { DataStoreTO dstore = obj.getDataStore(); if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (!parent.endsWith(File.separator)) { parent += File.separator; } @@ -1652,7 +1669,7 @@ private Answer execute(ListTemplateCommand cmd) { if (store instanceof NfsTO) { NfsTO nfs = (NfsTO)store; String secUrl = nfs.getUrl(); - String root = getRootDir(secUrl); + String root = getRootDir(secUrl, cmd.getNfsVersion()); Map templateInfos = _dlMgr.gatherTemplateInfo(root); return new ListTemplateAnswer(secUrl, templateInfos); } else if (store instanceof SwiftTO) { @@ -1674,7 +1691,7 @@ private Answer execute(ListVolumeCommand cmd) { } DataStoreTO store = cmd.getDataStore(); if (store instanceof NfsTO) { - String root = getRootDir(cmd.getSecUrl()); + String root = getRootDir(cmd.getSecUrl(), _nfsVersion); Map templateInfos = _dlMgr.gatherVolumeInfo(root); return new ListVolumeAnswer(cmd.getSecUrl(), templateInfos); } else if (store instanceof S3TO) { @@ -1809,7 +1826,7 @@ protected GetStorageStatsAnswer execute(final GetStorageStatsCommand cmd) { return new GetStorageStatsAnswer(cmd, infinity, 0L); } - String rootDir = getRootDir(((NfsTO)store).getUrl()); + String rootDir = getRootDir(((NfsTO)store).getUrl(), cmd.getNfsVersion()); final long usedSize = getUsedSize(rootDir); final long totalSize = getTotalSize(rootDir); if (usedSize == -1 || totalSize == -1) { @@ -1843,7 +1860,7 @@ protected Answer deleteTemplate(DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeTemplatePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1947,7 +1964,7 @@ protected Answer deleteVolume(final DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeVolumePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (relativeVolumePath.startsWith(File.separator)) { relativeVolumePath = relativeVolumePath.substring(1); @@ -2049,13 +2066,13 @@ protected Answer deleteVolume(final DeleteCommand cmd) { } @Override - synchronized public String getRootDir(String secUrl) { + synchronized public String getRootDir(String secUrl, Integer nfsVersion) { if (!_inSystemVM) { return _parent; } try { URI uri = new URI(secUrl); - String dir = mountUri(uri); + String dir = mountUri(uri, nfsVersion); return _parent + "/" + dir; } catch (Exception e) { String msg = "GetRootDir for " + secUrl + " failed due to " + e.toString(); @@ -2212,6 +2229,7 @@ public boolean configure(String name, Map params) throws Configu startAdditionalServices(); _params.put("install.numthreads", "50"); _params.put("secondary.storage.vm", "true"); + _nfsVersion = retrieveNfsVersionFromParams(params); } try { @@ -2386,15 +2404,17 @@ private String configureIpFirewall(List ipList, boolean isAppend) { * @param uri * crresponding to the remote device. Will throw for unsupported * scheme. + * @param imgStoreId + * @param nfsVersion NFS version to use in mount command * @return name of folder in _parent that device was mounted. * @throws UnknownHostException */ - protected String mountUri(URI uri) throws UnknownHostException { + protected String mountUri(URI uri, Integer nfsVersion) throws UnknownHostException { String uriHostIp = getUriHostIp(uri); String nfsPath = uriHostIp + ":" + uri.getPath(); // Single means of calculating mount directory regardless of scheme - String dir = UUID.nameUUIDFromBytes(nfsPath.getBytes()).toString(); + String dir = UUID.nameUUIDFromBytes(nfsPath.getBytes(com.cloud.utils.StringUtils.getPreferredCharset())).toString(); String localRootPath = _parent + "/" + dir; // remote device syntax varies by scheme. @@ -2406,9 +2426,7 @@ protected String mountUri(URI uri) throws UnknownHostException { remoteDevice = nfsPath; s_logger.debug("Mounting device with nfs-style path of " + remoteDevice); } - - mount(localRootPath, remoteDevice, uri); - + mount(localRootPath, remoteDevice, uri, nfsVersion); return dir; } @@ -2435,15 +2453,15 @@ protected void umount(String localRootPath, URI uri) { s_logger.debug("Successfully umounted " + localRootPath); } - protected void mount(String localRootPath, String remoteDevice, URI uri) { - s_logger.debug("mount " + uri.toString() + " on " + localRootPath); + protected void mount(String localRootPath, String remoteDevice, URI uri, Integer nfsVersion) { + s_logger.debug("mount " + uri.toString() + " on " + localRootPath + ((nfsVersion != null) ? " nfsVersion="+nfsVersion : "")); ensureLocalRootPathExists(localRootPath, uri); if (mountExists(localRootPath, uri)) { return; } - attemptMount(localRootPath, remoteDevice, uri); + attemptMount(localRootPath, remoteDevice, uri, nfsVersion); // XXX: Adding the check for creation of snapshots dir here. Might have // to move it somewhere more logical later. @@ -2451,9 +2469,10 @@ protected void mount(String localRootPath, String remoteDevice, URI uri) { checkForVolumesDir(localRootPath); } - protected void attemptMount(String localRootPath, String remoteDevice, URI uri) { + protected void attemptMount(String localRootPath, String remoteDevice, URI uri, Integer nfsVersion) { String result; - s_logger.debug("Make cmdline call to mount " + remoteDevice + " at " + localRootPath + " based on uri " + uri); + s_logger.debug("Make cmdline call to mount " + remoteDevice + " at " + localRootPath + " based on uri " + uri + + ((nfsVersion != null) ? " nfsVersion=" + nfsVersion : "")); Script command = new Script(!_inSystemVM, "mount", _timeout, s_logger); String scheme = uri.getScheme().toLowerCase(); @@ -2465,7 +2484,7 @@ protected void attemptMount(String localRootPath, String remoteDevice, URI uri) command.add("-o", "resvport"); } if (_inSystemVM) { - command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0"); + command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0" + ((nfsVersion != null) ? ",vers=" + nfsVersion : "")); } } else if (scheme.equals("cifs")) { String extraOpts = parseCifsMountOptions(uri); @@ -2742,7 +2761,7 @@ public UploadEntity createUploadEntity(String uuid, String metadata, long conten //relative path with out ssvm mount info. uploadEntity.setTemplatePath(absolutePath); String dataStoreUrl = cmd.getDataTo(); - String installPathPrefix = this.getRootDir(dataStoreUrl) + File.separator + absolutePath; + String installPathPrefix = this.getRootDir(dataStoreUrl, cmd.getNfsVersion()) + File.separator + absolutePath; uploadEntity.setInstallPathPrefix(installPathPrefix); uploadEntity.setHvm(cmd.getRequiresHvm()); uploadEntity.setChksum(cmd.getChecksum()); @@ -2764,7 +2783,7 @@ public UploadEntity createUploadEntity(String uuid, String metadata, long conten } private synchronized void checkSecondaryStorageResourceLimit(TemplateOrVolumePostUploadCommand cmd, int contentLengthInGB) { - String rootDir = this.getRootDir(cmd.getDataTo()) + File.separator; + String rootDir = this.getRootDir(cmd.getDataTo(), cmd.getNfsVersion()) + File.separator; long accountId = cmd.getAccountId(); long accountTemplateDirSize = 0; @@ -2811,7 +2830,7 @@ private String getSnapshotPathForAccount(long accountId) { private boolean isOneTimePostUrlUsed(TemplateOrVolumePostUploadCommand cmd) { String uuid = cmd.getEntityUUID(); - String uploadPath = this.getRootDir(cmd.getDataTo()) + File.separator + cmd.getAbsolutePath(); + String uploadPath = this.getRootDir(cmd.getDataTo(), cmd.getNfsVersion()) + File.separator + cmd.getAbsolutePath(); return uploadEntityStateMap.containsKey(uuid) || new File(uploadPath).exists(); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java index 4d3f04819e..d7e0c7e93d 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java @@ -23,6 +23,6 @@ */ public interface SecondaryStorageResource extends ServerResource { - String getRootDir(String cmd); + String getRootDir(String cmd, Integer nfsVersion); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java index 9cf37e5659..40a1e1cdde 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java @@ -44,6 +44,7 @@ import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType; import org.apache.cloudstack.storage.command.DownloadProgressCommand; import org.apache.cloudstack.storage.command.DownloadProgressCommand.RequestType; +import org.apache.cloudstack.storage.resource.NfsSecondaryStorageResource; import org.apache.cloudstack.storage.resource.SecondaryStorageResource; import org.apache.log4j.Logger; @@ -89,6 +90,8 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager StorageLayer _storage; public Map _processors; + private Integer _nfsVersion; + public class Completion implements DownloadCompleteCallback { private final String jobId; @@ -708,7 +711,7 @@ public DownloadAnswer handleDownloadCommand(SecondaryStorageResource resource, D String installPathPrefix = cmd.getInstallPath(); // for NFS, we need to get mounted path if (dstore instanceof NfsTO) { - installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl()) + File.separator + installPathPrefix; + installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl(), _nfsVersion) + File.separator + installPathPrefix; } String user = null; String password = null; @@ -982,6 +985,7 @@ public boolean configure(String name, Map params) throws Configu String inSystemVM = (String)params.get("secondary.storage.vm"); if (inSystemVM != null && "true".equalsIgnoreCase(inSystemVM)) { s_logger.info("DownloadManager: starting additional services since we are inside system vm"); + _nfsVersion = NfsSecondaryStorageResource.retrieveNfsVersionFromParams(params); startAdditionalServices(); blockOutgoingOnPrivate(); } diff --git a/setup/bindir/cloud-migrate-databases.in b/setup/bindir/cloud-migrate-databases.in index 58a02d5cdf..513e60b75d 100644 --- a/setup/bindir/cloud-migrate-databases.in +++ b/setup/bindir/cloud-migrate-databases.in @@ -20,7 +20,7 @@ import os,logging,sys from optparse import OptionParser -import MySQLdb +import mysql.connector import subprocess import glob @@ -72,10 +72,10 @@ class CloudContext(cloud_utils.MigrationContext): self.database = database self.configdir = configdir self.resourcedir = resourcedir - self.conn = MySQLdb.connect(host=self.host, + self.conn = mysql.connector.connect(host=self.host, user=self.username, - passwd=self.password, - db=self.database, + password=self.password, + database=self.database, port=self.port) self.conn.autocommit(False) self.db = self.conn.cursor() diff --git a/setup/bindir/cloud-set-guest-sshkey.in b/setup/bindir/cloud-set-guest-sshkey.in index 0472a7c006..80e40646ad 100755 --- a/setup/bindir/cloud-set-guest-sshkey.in +++ b/setup/bindir/cloud-set-guest-sshkey.in @@ -27,7 +27,7 @@ user=root # Add your DHCP lease folders here -DHCP_FOLDERS="/var/lib/dhclient/* /var/lib/dhcp3/*" +DHCP_FOLDERS="/var/lib/dhclient/* /var/lib/dhcp3/* /var/lib/dhcp/*" keys_received=0 file_count=0 @@ -81,8 +81,8 @@ if [ ! -e $authorized ]; then chmod 600 $authorized fi -cat $authorized|grep -v "$publickey"|tee $authorized > /dev/null -echo "$publickey" >> $authorized +sed -i "/ cloudstack@apache.org$/d" $authorized +echo "$publickey cloudstack@apache.org" >> $authorized which restorecon && restorecon -R -v $sshdir diff --git a/setup/db/db/create-default-role-api-mappings.sql b/setup/db/db/create-default-role-api-mappings.sql new file mode 100644 index 0000000000..57601fbde1 --- /dev/null +++ b/setup/db/db/create-default-role-api-mappings.sql @@ -0,0 +1,902 @@ +-- 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. + +-- The default admin role (id:1) will be allowed all APIs so need to insert rules for admin role + +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 1, '*', 'ALLOW', 0) ON DUPLICATE KEY UPDATE rule=rule; + +-- Insert default role-api mappings for rest of the default roles: resourceadmin(id:2), domainadmin(id:3), user(id:4) +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'activateProject', 'ALLOW', 0) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addAccountToProject', 'ALLOW', 1) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addHost', 'ALLOW', 2) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addIpToNic', 'ALLOW', 3) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addLdapConfiguration', 'ALLOW', 4) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addNicToVirtualMachine', 'ALLOW', 5) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'addVpnUser', 'ALLOW', 6) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'archiveEvents', 'ALLOW', 7) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'assignCertToLoadBalancer', 'ALLOW', 8) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'assignToGlobalLoadBalancerRule', 'ALLOW', 9) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'assignToLoadBalancerRule', 'ALLOW', 10) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'assignVirtualMachine', 'ALLOW', 11) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'associateIpAddress', 'ALLOW', 12) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'associateLun', 'ALLOW', 13) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'attachIso', 'ALLOW', 14) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'attachVolume', 'ALLOW', 15) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'authorizeSamlSso', 'ALLOW', 16) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'authorizeSecurityGroupEgress', 'ALLOW', 17) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'authorizeSecurityGroupIngress', 'ALLOW', 18) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'changeServiceForRouter', 'ALLOW', 19) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'changeServiceForVirtualMachine', 'ALLOW', 20) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'configureInternalLoadBalancerElement', 'ALLOW', 21) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'configureOvsElement', 'ALLOW', 22) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'configureVirtualRouterElement', 'ALLOW', 23) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'copyIso', 'ALLOW', 24) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'copyTemplate', 'ALLOW', 25) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createAccount', 'ALLOW', 26) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createAffinityGroup', 'ALLOW', 27) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createAutoScalePolicy', 'ALLOW', 28) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createAutoScaleVmGroup', 'ALLOW', 29) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createAutoScaleVmProfile', 'ALLOW', 30) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createCondition', 'ALLOW', 31) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createDiskOffering', 'ALLOW', 32) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createEgressFirewallRule', 'ALLOW', 33) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createFirewallRule', 'ALLOW', 34) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createGlobalLoadBalancerRule', 'ALLOW', 35) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createInstanceGroup', 'ALLOW', 36) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createInternalLoadBalancerElement', 'ALLOW', 37) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createIpForwardingRule', 'ALLOW', 38) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createLBHealthCheckPolicy', 'ALLOW', 39) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createLBStickinessPolicy', 'ALLOW', 40) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createLoadBalancer', 'ALLOW', 41) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createLoadBalancerRule', 'ALLOW', 42) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createLunOnFiler', 'ALLOW', 43) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createNetwork', 'ALLOW', 44) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createNetworkACL', 'ALLOW', 45) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createNetworkACLList', 'ALLOW', 46) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createOvsElement', 'ALLOW', 47) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createPool', 'ALLOW', 48) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createPortForwardingRule', 'ALLOW', 49) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createProject', 'ALLOW', 50) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createRemoteAccessVpn', 'ALLOW', 51) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createSSHKeyPair', 'ALLOW', 52) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createSecurityGroup', 'ALLOW', 53) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createServiceOffering', 'ALLOW', 54) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createSnapshot', 'ALLOW', 55) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createSnapshotPolicy', 'ALLOW', 56) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createStaticRoute', 'ALLOW', 57) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createTags', 'ALLOW', 58) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createTemplate', 'ALLOW', 59) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createUser', 'ALLOW', 60) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVMSnapshot', 'ALLOW', 61) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVPC', 'ALLOW', 62) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVirtualRouterElement', 'ALLOW', 63) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVolume', 'ALLOW', 64) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVolumeOnFiler', 'ALLOW', 65) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVpnConnection', 'ALLOW', 66) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVpnCustomerGateway', 'ALLOW', 67) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'createVpnGateway', 'ALLOW', 68) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAccount', 'ALLOW', 69) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAccountFromProject', 'ALLOW', 70) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAffinityGroup', 'ALLOW', 71) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAutoScalePolicy', 'ALLOW', 72) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAutoScaleVmGroup', 'ALLOW', 73) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteAutoScaleVmProfile', 'ALLOW', 74) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteCondition', 'ALLOW', 75) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteDiskOffering', 'ALLOW', 76) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteEgressFirewallRule', 'ALLOW', 77) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteEvents', 'ALLOW', 78) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteFirewallRule', 'ALLOW', 79) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteGlobalLoadBalancerRule', 'ALLOW', 80) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteHost', 'ALLOW', 81) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteInstanceGroup', 'ALLOW', 82) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteIpForwardingRule', 'ALLOW', 83) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteIso', 'ALLOW', 84) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteLBHealthCheckPolicy', 'ALLOW', 85) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteLBStickinessPolicy', 'ALLOW', 86) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteLdapConfiguration', 'ALLOW', 87) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteLoadBalancer', 'ALLOW', 88) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteLoadBalancerRule', 'ALLOW', 89) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteNetwork', 'ALLOW', 90) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteNetworkACL', 'ALLOW', 91) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteNetworkACLList', 'ALLOW', 92) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deletePool', 'ALLOW', 93) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deletePortForwardingRule', 'ALLOW', 94) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteProject', 'ALLOW', 95) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteProjectInvitation', 'ALLOW', 96) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteRemoteAccessVpn', 'ALLOW', 97) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteSSHKeyPair', 'ALLOW', 98) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteSecurityGroup', 'ALLOW', 99) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteServiceOffering', 'ALLOW', 100) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteSnapshot', 'ALLOW', 101) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteSnapshotPolicies', 'ALLOW', 102) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteSslCert', 'ALLOW', 103) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteStaticRoute', 'ALLOW', 104) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteTags', 'ALLOW', 105) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteTemplate', 'ALLOW', 106) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteUser', 'ALLOW', 107) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVMSnapshot', 'ALLOW', 108) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVPC', 'ALLOW', 109) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVolume', 'ALLOW', 110) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVpnConnection', 'ALLOW', 111) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVpnCustomerGateway', 'ALLOW', 112) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deleteVpnGateway', 'ALLOW', 113) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'deployVirtualMachine', 'ALLOW', 114) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'destroyLunOnFiler', 'ALLOW', 115) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'destroyRouter', 'ALLOW', 116) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'destroyVirtualMachine', 'ALLOW', 117) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'destroyVolumeOnFiler', 'ALLOW', 118) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'detachIso', 'ALLOW', 119) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'detachVolume', 'ALLOW', 120) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'disableAccount', 'ALLOW', 121) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'disableAutoScaleVmGroup', 'ALLOW', 122) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'disableStaticNat', 'ALLOW', 123) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'disableUser', 'ALLOW', 124) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'disassociateIpAddress', 'ALLOW', 125) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'dissociateLun', 'ALLOW', 126) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'enableAccount', 'ALLOW', 127) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'enableAutoScaleVmGroup', 'ALLOW', 128) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'enableStaticNat', 'ALLOW', 129) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'enableUser', 'ALLOW', 130) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'expungeVirtualMachine', 'ALLOW', 131) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'extractIso', 'ALLOW', 132) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'extractTemplate', 'ALLOW', 133) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'extractVolume', 'ALLOW', 134) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getApiLimit', 'ALLOW', 135) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getCloudIdentifier', 'ALLOW', 136) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getSolidFireAccountId', 'ALLOW', 137) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getSolidFireVolumeAccessGroupId', 'ALLOW', 138) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getSolidFireVolumeIscsiName', 'ALLOW', 139) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getSolidFireVolumeSize', 'ALLOW', 140) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getUploadParamsForTemplate', 'ALLOW', 141) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getUploadParamsForVolume', 'ALLOW', 142) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getVMPassword', 'ALLOW', 143) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'getVirtualMachineUserData', 'ALLOW', 144) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'importLdapUsers', 'ALLOW', 145) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'issueNuageVspResourceRequest', 'ALLOW', 146) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'ldapCreateAccount', 'ALLOW', 147) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'linkDomainToLdap', 'ALLOW', 148) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAccounts', 'ALLOW', 149) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAffinityGroupTypes', 'ALLOW', 150) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAffinityGroups', 'ALLOW', 151) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAlerts', 'ALLOW', 152) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listApis', 'ALLOW', 153) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAsyncJobs', 'ALLOW', 154) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAutoScalePolicies', 'ALLOW', 155) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAutoScaleVmGroups', 'ALLOW', 156) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listAutoScaleVmProfiles', 'ALLOW', 157) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listCapabilities', 'ALLOW', 158) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listCapacity', 'ALLOW', 159) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listClusters', 'ALLOW', 160) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listConditions', 'ALLOW', 161) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listCounters', 'ALLOW', 162) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listDiskOfferings', 'ALLOW', 163) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listDomainChildren', 'ALLOW', 164) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listDomains', 'ALLOW', 165) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listEgressFirewallRules', 'ALLOW', 166) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listEventTypes', 'ALLOW', 167) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listEvents', 'ALLOW', 168) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listFirewallRules', 'ALLOW', 169) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listGlobalLoadBalancerRules', 'ALLOW', 170) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listHostTags', 'ALLOW', 171) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listHosts', 'ALLOW', 172) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listHypervisors', 'ALLOW', 173) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listInstanceGroups', 'ALLOW', 174) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listInternalLoadBalancerElements', 'ALLOW', 175) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listIpForwardingRules', 'ALLOW', 176) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listIsoPermissions', 'ALLOW', 177) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listIsos', 'ALLOW', 178) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLBHealthCheckPolicies', 'ALLOW', 179) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLBStickinessPolicies', 'ALLOW', 180) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLdapConfigurations', 'ALLOW', 181) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLdapUsers', 'ALLOW', 182) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLoadBalancerRuleInstances', 'ALLOW', 183) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLoadBalancerRules', 'ALLOW', 184) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLoadBalancers', 'ALLOW', 185) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listLunsOnFiler', 'ALLOW', 186) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listNetworkACLLists', 'ALLOW', 187) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listNetworkACLs', 'ALLOW', 188) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listNetworkOfferings', 'ALLOW', 189) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listNetworks', 'ALLOW', 190) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listNics', 'ALLOW', 191) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listOsCategories', 'ALLOW', 192) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listOsTypes', 'ALLOW', 193) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listOvsElements', 'ALLOW', 194) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listPods', 'ALLOW', 195) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listPools', 'ALLOW', 196) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listPortForwardingRules', 'ALLOW', 197) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listPrivateGateways', 'ALLOW', 198) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listProjectAccounts', 'ALLOW', 199) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listProjectInvitations', 'ALLOW', 200) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listProjects', 'ALLOW', 201) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listPublicIpAddresses', 'ALLOW', 202) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listRegions', 'ALLOW', 203) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listRemoteAccessVpns', 'ALLOW', 204) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listResourceDetails', 'ALLOW', 205) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listResourceLimits', 'ALLOW', 206) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listRouters', 'ALLOW', 207) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSSHKeyPairs', 'ALLOW', 208) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSamlAuthorization', 'ALLOW', 209) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSecurityGroups', 'ALLOW', 210) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listServiceOfferings', 'ALLOW', 211) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSnapshotPolicies', 'ALLOW', 212) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSnapshots', 'ALLOW', 213) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSslCerts', 'ALLOW', 214) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listStaticRoutes', 'ALLOW', 215) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listStoragePools', 'ALLOW', 216) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listStorageProviders', 'ALLOW', 217) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listStorageTags', 'ALLOW', 218) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listSystemVms', 'ALLOW', 219) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listTags', 'ALLOW', 220) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listTemplatePermissions', 'ALLOW', 221) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listTemplates', 'ALLOW', 222) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listUsageRecords', 'ALLOW', 223) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listUsers', 'ALLOW', 224) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVMSnapshot', 'ALLOW', 225) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVPCOfferings', 'ALLOW', 226) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVPCs', 'ALLOW', 227) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVirtualMachines', 'ALLOW', 228) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVirtualRouterElements', 'ALLOW', 229) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVolumes', 'ALLOW', 230) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVolumesOnFiler', 'ALLOW', 231) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVpnConnections', 'ALLOW', 232) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVpnCustomerGateways', 'ALLOW', 233) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVpnGateways', 'ALLOW', 234) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listVpnUsers', 'ALLOW', 235) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'listZones', 'ALLOW', 236) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'lockAccount', 'ALLOW', 237) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'lockUser', 'ALLOW', 238) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'migrateVolume', 'ALLOW', 239) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'modifyPool', 'ALLOW', 240) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'queryAsyncJobResult', 'ALLOW', 241) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'quotaBalance', 'ALLOW', 242) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'quotaIsEnabled', 'ALLOW', 243) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'quotaStatement', 'ALLOW', 244) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'quotaSummary', 'ALLOW', 245) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'quotaTariffList', 'ALLOW', 246) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'rebootRouter', 'ALLOW', 247) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'rebootVirtualMachine', 'ALLOW', 248) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'recoverVirtualMachine', 'ALLOW', 249) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'registerIso', 'ALLOW', 250) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'registerSSHKeyPair', 'ALLOW', 251) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'registerTemplate', 'ALLOW', 252) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'registerUserKeys', 'ALLOW', 253) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeCertFromLoadBalancer', 'ALLOW', 254) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeFromGlobalLoadBalancerRule', 'ALLOW', 255) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeFromLoadBalancerRule', 'ALLOW', 256) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeIpFromNic', 'ALLOW', 257) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeNicFromVirtualMachine', 'ALLOW', 258) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'removeVpnUser', 'ALLOW', 259) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'replaceNetworkACLList', 'ALLOW', 260) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'resetPasswordForVirtualMachine', 'ALLOW', 261) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'resetSSHKeyForVirtualMachine', 'ALLOW', 262) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'resetVpnConnection', 'ALLOW', 263) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'resizeVolume', 'ALLOW', 264) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'restartNetwork', 'ALLOW', 265) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'restartVPC', 'ALLOW', 266) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'restoreVirtualMachine', 'ALLOW', 267) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'revertSnapshot', 'ALLOW', 268) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'revertToVMSnapshot', 'ALLOW', 269) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'revokeSecurityGroupEgress', 'ALLOW', 270) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'revokeSecurityGroupIngress', 'ALLOW', 271) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'scaleVirtualMachine', 'ALLOW', 272) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'startRouter', 'ALLOW', 273) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'startVirtualMachine', 'ALLOW', 274) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'stopRouter', 'ALLOW', 275) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'stopVirtualMachine', 'ALLOW', 276) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'suspendProject', 'ALLOW', 277) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateAccount', 'ALLOW', 278) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateAutoScalePolicy', 'ALLOW', 279) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateAutoScaleVmGroup', 'ALLOW', 280) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateAutoScaleVmProfile', 'ALLOW', 281) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateDefaultNicForVirtualMachine', 'ALLOW', 282) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateDiskOffering', 'ALLOW', 283) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateEgressFirewallRule', 'ALLOW', 284) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateFirewallRule', 'ALLOW', 285) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateGlobalLoadBalancerRule', 'ALLOW', 286) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateInstanceGroup', 'ALLOW', 287) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateIpAddress', 'ALLOW', 288) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateIso', 'ALLOW', 289) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateIsoPermissions', 'ALLOW', 290) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateLBHealthCheckPolicy', 'ALLOW', 291) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateLBStickinessPolicy', 'ALLOW', 292) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateLoadBalancer', 'ALLOW', 293) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateLoadBalancerRule', 'ALLOW', 294) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateNetwork', 'ALLOW', 295) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateNetworkACLItem', 'ALLOW', 296) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateNetworkACLList', 'ALLOW', 297) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updatePortForwardingRule', 'ALLOW', 298) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateProject', 'ALLOW', 299) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateProjectInvitation', 'ALLOW', 300) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateRemoteAccessVpn', 'ALLOW', 301) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateResourceCount', 'ALLOW', 302) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateResourceLimit', 'ALLOW', 303) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateServiceOffering', 'ALLOW', 304) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateSnapshotPolicy', 'ALLOW', 305) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateTemplate', 'ALLOW', 306) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateTemplatePermissions', 'ALLOW', 307) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateUser', 'ALLOW', 308) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVMAffinityGroup', 'ALLOW', 309) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVPC', 'ALLOW', 310) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVirtualMachine', 'ALLOW', 311) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVmNicIp', 'ALLOW', 312) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVpnConnection', 'ALLOW', 313) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVpnCustomerGateway', 'ALLOW', 314) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'updateVpnGateway', 'ALLOW', 315) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'uploadSslCert', 'ALLOW', 316) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'uploadVolume', 'ALLOW', 317) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'activateProject', 'ALLOW', 0) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'addAccountToProject', 'ALLOW', 1) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'addIpToNic', 'ALLOW', 2) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'addNicToVirtualMachine', 'ALLOW', 3) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'addVpnUser', 'ALLOW', 4) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'archiveEvents', 'ALLOW', 5) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'assignCertToLoadBalancer', 'ALLOW', 6) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'assignToGlobalLoadBalancerRule', 'ALLOW', 7) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'assignToLoadBalancerRule', 'ALLOW', 8) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'assignVirtualMachine', 'ALLOW', 9) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'associateIpAddress', 'ALLOW', 10) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'associateLun', 'ALLOW', 11) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'attachIso', 'ALLOW', 12) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'attachVolume', 'ALLOW', 13) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'authorizeSamlSso', 'ALLOW', 14) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'authorizeSecurityGroupEgress', 'ALLOW', 15) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'authorizeSecurityGroupIngress', 'ALLOW', 16) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'changeServiceForRouter', 'ALLOW', 17) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'changeServiceForVirtualMachine', 'ALLOW', 18) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'configureInternalLoadBalancerElement', 'ALLOW', 19) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'configureOvsElement', 'ALLOW', 20) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'configureVirtualRouterElement', 'ALLOW', 21) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'copyIso', 'ALLOW', 22) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'copyTemplate', 'ALLOW', 23) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createAccount', 'ALLOW', 24) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createAffinityGroup', 'ALLOW', 25) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createAutoScalePolicy', 'ALLOW', 26) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createAutoScaleVmGroup', 'ALLOW', 27) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createAutoScaleVmProfile', 'ALLOW', 28) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createCondition', 'ALLOW', 29) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createDiskOffering', 'ALLOW', 30) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createEgressFirewallRule', 'ALLOW', 31) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createFirewallRule', 'ALLOW', 32) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createGlobalLoadBalancerRule', 'ALLOW', 33) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createInstanceGroup', 'ALLOW', 34) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createInternalLoadBalancerElement', 'ALLOW', 35) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createIpForwardingRule', 'ALLOW', 36) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createLBHealthCheckPolicy', 'ALLOW', 37) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createLBStickinessPolicy', 'ALLOW', 38) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createLoadBalancer', 'ALLOW', 39) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createLoadBalancerRule', 'ALLOW', 40) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createLunOnFiler', 'ALLOW', 41) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createNetwork', 'ALLOW', 42) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createNetworkACL', 'ALLOW', 43) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createNetworkACLList', 'ALLOW', 44) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createOvsElement', 'ALLOW', 45) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createPool', 'ALLOW', 46) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createPortForwardingRule', 'ALLOW', 47) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createProject', 'ALLOW', 48) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createRemoteAccessVpn', 'ALLOW', 49) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createSSHKeyPair', 'ALLOW', 50) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createSecurityGroup', 'ALLOW', 51) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createServiceOffering', 'ALLOW', 52) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createSnapshot', 'ALLOW', 53) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createSnapshotPolicy', 'ALLOW', 54) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createStaticRoute', 'ALLOW', 55) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createTags', 'ALLOW', 56) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createTemplate', 'ALLOW', 57) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createUser', 'ALLOW', 58) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVMSnapshot', 'ALLOW', 59) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVPC', 'ALLOW', 60) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVirtualRouterElement', 'ALLOW', 61) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVolume', 'ALLOW', 62) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVolumeOnFiler', 'ALLOW', 63) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVpnConnection', 'ALLOW', 64) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVpnCustomerGateway', 'ALLOW', 65) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'createVpnGateway', 'ALLOW', 66) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAccount', 'ALLOW', 67) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAccountFromProject', 'ALLOW', 68) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAffinityGroup', 'ALLOW', 69) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAutoScalePolicy', 'ALLOW', 70) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAutoScaleVmGroup', 'ALLOW', 71) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteAutoScaleVmProfile', 'ALLOW', 72) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteCondition', 'ALLOW', 73) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteDiskOffering', 'ALLOW', 74) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteEgressFirewallRule', 'ALLOW', 75) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteEvents', 'ALLOW', 76) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteFirewallRule', 'ALLOW', 77) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteGlobalLoadBalancerRule', 'ALLOW', 78) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteInstanceGroup', 'ALLOW', 79) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteIpForwardingRule', 'ALLOW', 80) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteIso', 'ALLOW', 81) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteLBHealthCheckPolicy', 'ALLOW', 82) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteLBStickinessPolicy', 'ALLOW', 83) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteLoadBalancer', 'ALLOW', 84) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteLoadBalancerRule', 'ALLOW', 85) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteNetwork', 'ALLOW', 86) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteNetworkACL', 'ALLOW', 87) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteNetworkACLList', 'ALLOW', 88) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deletePool', 'ALLOW', 89) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deletePortForwardingRule', 'ALLOW', 90) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteProject', 'ALLOW', 91) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteProjectInvitation', 'ALLOW', 92) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteRemoteAccessVpn', 'ALLOW', 93) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteSSHKeyPair', 'ALLOW', 94) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteSecurityGroup', 'ALLOW', 95) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteServiceOffering', 'ALLOW', 96) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteSnapshot', 'ALLOW', 97) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteSnapshotPolicies', 'ALLOW', 98) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteSslCert', 'ALLOW', 99) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteStaticRoute', 'ALLOW', 100) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteTags', 'ALLOW', 101) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteTemplate', 'ALLOW', 102) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteUser', 'ALLOW', 103) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVMSnapshot', 'ALLOW', 104) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVPC', 'ALLOW', 105) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVolume', 'ALLOW', 106) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVpnConnection', 'ALLOW', 107) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVpnCustomerGateway', 'ALLOW', 108) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deleteVpnGateway', 'ALLOW', 109) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'deployVirtualMachine', 'ALLOW', 110) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'destroyLunOnFiler', 'ALLOW', 111) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'destroyRouter', 'ALLOW', 112) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'destroyVirtualMachine', 'ALLOW', 113) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'destroyVolumeOnFiler', 'ALLOW', 114) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'detachIso', 'ALLOW', 115) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'detachVolume', 'ALLOW', 116) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'disableAccount', 'ALLOW', 117) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'disableAutoScaleVmGroup', 'ALLOW', 118) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'disableStaticNat', 'ALLOW', 119) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'disableUser', 'ALLOW', 120) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'disassociateIpAddress', 'ALLOW', 121) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'dissociateLun', 'ALLOW', 122) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'enableAccount', 'ALLOW', 123) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'enableAutoScaleVmGroup', 'ALLOW', 124) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'enableStaticNat', 'ALLOW', 125) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'enableUser', 'ALLOW', 126) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'expungeVirtualMachine', 'ALLOW', 127) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'extractIso', 'ALLOW', 128) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'extractTemplate', 'ALLOW', 129) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'extractVolume', 'ALLOW', 130) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getApiLimit', 'ALLOW', 131) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getCloudIdentifier', 'ALLOW', 132) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getSolidFireAccountId', 'ALLOW', 133) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getSolidFireVolumeAccessGroupId', 'ALLOW', 134) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getSolidFireVolumeIscsiName', 'ALLOW', 135) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getSolidFireVolumeSize', 'ALLOW', 136) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getUploadParamsForTemplate', 'ALLOW', 137) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getUploadParamsForVolume', 'ALLOW', 138) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getVMPassword', 'ALLOW', 139) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'getVirtualMachineUserData', 'ALLOW', 140) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'issueNuageVspResourceRequest', 'ALLOW', 141) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAccounts', 'ALLOW', 142) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAffinityGroupTypes', 'ALLOW', 143) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAffinityGroups', 'ALLOW', 144) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listApis', 'ALLOW', 145) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAsyncJobs', 'ALLOW', 146) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAutoScalePolicies', 'ALLOW', 147) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAutoScaleVmGroups', 'ALLOW', 148) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listAutoScaleVmProfiles', 'ALLOW', 149) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listCapabilities', 'ALLOW', 150) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listConditions', 'ALLOW', 151) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listCounters', 'ALLOW', 152) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listDiskOfferings', 'ALLOW', 153) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listDomainChildren', 'ALLOW', 154) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listDomains', 'ALLOW', 155) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listEgressFirewallRules', 'ALLOW', 156) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listEventTypes', 'ALLOW', 157) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listEvents', 'ALLOW', 158) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listFirewallRules', 'ALLOW', 159) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listGlobalLoadBalancerRules', 'ALLOW', 160) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listHostTags', 'ALLOW', 161) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listHypervisors', 'ALLOW', 162) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listInstanceGroups', 'ALLOW', 163) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listInternalLoadBalancerElements', 'ALLOW', 164) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listIpForwardingRules', 'ALLOW', 165) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listIsoPermissions', 'ALLOW', 166) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listIsos', 'ALLOW', 167) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLBHealthCheckPolicies', 'ALLOW', 168) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLBStickinessPolicies', 'ALLOW', 169) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLdapConfigurations', 'ALLOW', 170) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLoadBalancerRuleInstances', 'ALLOW', 171) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLoadBalancerRules', 'ALLOW', 172) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLoadBalancers', 'ALLOW', 173) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listLunsOnFiler', 'ALLOW', 174) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listNetworkACLLists', 'ALLOW', 175) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listNetworkACLs', 'ALLOW', 176) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listNetworkOfferings', 'ALLOW', 177) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listNetworks', 'ALLOW', 178) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listNics', 'ALLOW', 179) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listOsCategories', 'ALLOW', 180) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listOsTypes', 'ALLOW', 181) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listOvsElements', 'ALLOW', 182) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listPools', 'ALLOW', 183) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listPortForwardingRules', 'ALLOW', 184) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listPrivateGateways', 'ALLOW', 185) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listProjectAccounts', 'ALLOW', 186) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listProjectInvitations', 'ALLOW', 187) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listProjects', 'ALLOW', 188) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listPublicIpAddresses', 'ALLOW', 189) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listRegions', 'ALLOW', 190) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listRemoteAccessVpns', 'ALLOW', 191) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listResourceDetails', 'ALLOW', 192) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listResourceLimits', 'ALLOW', 193) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listRouters', 'ALLOW', 194) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSSHKeyPairs', 'ALLOW', 195) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSamlAuthorization', 'ALLOW', 196) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSecurityGroups', 'ALLOW', 197) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listServiceOfferings', 'ALLOW', 198) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSnapshotPolicies', 'ALLOW', 199) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSnapshots', 'ALLOW', 200) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listSslCerts', 'ALLOW', 201) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listStaticRoutes', 'ALLOW', 202) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listStorageTags', 'ALLOW', 203) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listTags', 'ALLOW', 204) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listTemplatePermissions', 'ALLOW', 205) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listTemplates', 'ALLOW', 206) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listUsageRecords', 'ALLOW', 207) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listUsers', 'ALLOW', 208) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVMSnapshot', 'ALLOW', 209) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVPCOfferings', 'ALLOW', 210) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVPCs', 'ALLOW', 211) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVirtualMachines', 'ALLOW', 212) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVirtualRouterElements', 'ALLOW', 213) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVolumes', 'ALLOW', 214) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVolumesOnFiler', 'ALLOW', 215) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVpnConnections', 'ALLOW', 216) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVpnCustomerGateways', 'ALLOW', 217) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVpnGateways', 'ALLOW', 218) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listVpnUsers', 'ALLOW', 219) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listZones', 'ALLOW', 220) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'lockAccount', 'ALLOW', 221) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'lockUser', 'ALLOW', 222) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'migrateVolume', 'ALLOW', 223) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'modifyPool', 'ALLOW', 224) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'queryAsyncJobResult', 'ALLOW', 225) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'quotaBalance', 'ALLOW', 226) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'quotaIsEnabled', 'ALLOW', 227) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'quotaStatement', 'ALLOW', 228) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'quotaSummary', 'ALLOW', 229) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'quotaTariffList', 'ALLOW', 230) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'rebootRouter', 'ALLOW', 231) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'rebootVirtualMachine', 'ALLOW', 232) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'recoverVirtualMachine', 'ALLOW', 233) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'registerIso', 'ALLOW', 234) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'registerSSHKeyPair', 'ALLOW', 235) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'registerTemplate', 'ALLOW', 236) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'registerUserKeys', 'ALLOW', 237) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeCertFromLoadBalancer', 'ALLOW', 238) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeFromGlobalLoadBalancerRule', 'ALLOW', 239) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeFromLoadBalancerRule', 'ALLOW', 240) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeIpFromNic', 'ALLOW', 241) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeNicFromVirtualMachine', 'ALLOW', 242) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'removeVpnUser', 'ALLOW', 243) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'replaceNetworkACLList', 'ALLOW', 244) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'resetPasswordForVirtualMachine', 'ALLOW', 245) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'resetSSHKeyForVirtualMachine', 'ALLOW', 246) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'resetVpnConnection', 'ALLOW', 247) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'resizeVolume', 'ALLOW', 248) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'restartNetwork', 'ALLOW', 249) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'restartVPC', 'ALLOW', 250) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'restoreVirtualMachine', 'ALLOW', 251) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'revertSnapshot', 'ALLOW', 252) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'revertToVMSnapshot', 'ALLOW', 253) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'revokeSecurityGroupEgress', 'ALLOW', 254) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'revokeSecurityGroupIngress', 'ALLOW', 255) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'scaleVirtualMachine', 'ALLOW', 256) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'startRouter', 'ALLOW', 257) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'startVirtualMachine', 'ALLOW', 258) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'stopRouter', 'ALLOW', 259) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'stopVirtualMachine', 'ALLOW', 260) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'suspendProject', 'ALLOW', 261) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateAccount', 'ALLOW', 262) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateAutoScalePolicy', 'ALLOW', 263) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateAutoScaleVmGroup', 'ALLOW', 264) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateAutoScaleVmProfile', 'ALLOW', 265) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateDefaultNicForVirtualMachine', 'ALLOW', 266) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateDiskOffering', 'ALLOW', 267) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateEgressFirewallRule', 'ALLOW', 268) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateFirewallRule', 'ALLOW', 269) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateGlobalLoadBalancerRule', 'ALLOW', 270) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateInstanceGroup', 'ALLOW', 271) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateIpAddress', 'ALLOW', 272) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateIso', 'ALLOW', 273) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateIsoPermissions', 'ALLOW', 274) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateLBHealthCheckPolicy', 'ALLOW', 275) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateLBStickinessPolicy', 'ALLOW', 276) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateLoadBalancer', 'ALLOW', 277) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateLoadBalancerRule', 'ALLOW', 278) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateNetwork', 'ALLOW', 279) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateNetworkACLItem', 'ALLOW', 280) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateNetworkACLList', 'ALLOW', 281) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updatePortForwardingRule', 'ALLOW', 282) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateProject', 'ALLOW', 283) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateProjectInvitation', 'ALLOW', 284) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateRemoteAccessVpn', 'ALLOW', 285) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateResourceCount', 'ALLOW', 286) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateResourceLimit', 'ALLOW', 287) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateServiceOffering', 'ALLOW', 288) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateSnapshotPolicy', 'ALLOW', 289) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateTemplate', 'ALLOW', 290) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateTemplatePermissions', 'ALLOW', 291) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateUser', 'ALLOW', 292) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVMAffinityGroup', 'ALLOW', 293) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVPC', 'ALLOW', 294) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVirtualMachine', 'ALLOW', 295) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVmNicIp', 'ALLOW', 296) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVpnConnection', 'ALLOW', 297) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVpnCustomerGateway', 'ALLOW', 298) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateVpnGateway', 'ALLOW', 299) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'uploadSslCert', 'ALLOW', 300) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'uploadVolume', 'ALLOW', 301) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'activateProject', 'ALLOW', 0) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'addAccountToProject', 'ALLOW', 1) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'addIpToNic', 'ALLOW', 2) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'addNicToVirtualMachine', 'ALLOW', 3) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'addVpnUser', 'ALLOW', 4) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'archiveEvents', 'ALLOW', 5) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'assignCertToLoadBalancer', 'ALLOW', 6) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'assignToGlobalLoadBalancerRule', 'ALLOW', 7) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'assignToLoadBalancerRule', 'ALLOW', 8) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'associateIpAddress', 'ALLOW', 9) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'associateLun', 'ALLOW', 10) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'attachIso', 'ALLOW', 11) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'attachVolume', 'ALLOW', 12) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'authorizeSecurityGroupEgress', 'ALLOW', 13) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'authorizeSecurityGroupIngress', 'ALLOW', 14) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'changeServiceForVirtualMachine', 'ALLOW', 15) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'copyIso', 'ALLOW', 16) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'copyTemplate', 'ALLOW', 17) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createAffinityGroup', 'ALLOW', 18) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createAutoScalePolicy', 'ALLOW', 19) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createAutoScaleVmGroup', 'ALLOW', 20) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createAutoScaleVmProfile', 'ALLOW', 21) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createCondition', 'ALLOW', 22) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createEgressFirewallRule', 'ALLOW', 23) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createFirewallRule', 'ALLOW', 24) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createGlobalLoadBalancerRule', 'ALLOW', 25) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createInstanceGroup', 'ALLOW', 26) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createIpForwardingRule', 'ALLOW', 27) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createLBHealthCheckPolicy', 'ALLOW', 28) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createLBStickinessPolicy', 'ALLOW', 29) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createLoadBalancer', 'ALLOW', 30) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createLoadBalancerRule', 'ALLOW', 31) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createLunOnFiler', 'ALLOW', 32) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createNetwork', 'ALLOW', 33) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createNetworkACL', 'ALLOW', 34) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createNetworkACLList', 'ALLOW', 35) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createPool', 'ALLOW', 36) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createPortForwardingRule', 'ALLOW', 37) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createProject', 'ALLOW', 38) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createRemoteAccessVpn', 'ALLOW', 39) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createSSHKeyPair', 'ALLOW', 40) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createSecurityGroup', 'ALLOW', 41) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createSnapshot', 'ALLOW', 42) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createSnapshotPolicy', 'ALLOW', 43) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createStaticRoute', 'ALLOW', 44) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createTags', 'ALLOW', 45) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createTemplate', 'ALLOW', 46) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVMSnapshot', 'ALLOW', 47) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVPC', 'ALLOW', 48) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVolume', 'ALLOW', 49) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVolumeOnFiler', 'ALLOW', 50) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVpnConnection', 'ALLOW', 51) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVpnCustomerGateway', 'ALLOW', 52) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'createVpnGateway', 'ALLOW', 53) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteAccountFromProject', 'ALLOW', 54) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteAffinityGroup', 'ALLOW', 55) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteAutoScalePolicy', 'ALLOW', 56) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteAutoScaleVmGroup', 'ALLOW', 57) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteAutoScaleVmProfile', 'ALLOW', 58) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteCondition', 'ALLOW', 59) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteEgressFirewallRule', 'ALLOW', 60) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteEvents', 'ALLOW', 61) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteFirewallRule', 'ALLOW', 62) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteGlobalLoadBalancerRule', 'ALLOW', 63) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteInstanceGroup', 'ALLOW', 64) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteIpForwardingRule', 'ALLOW', 65) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteIso', 'ALLOW', 66) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteLBHealthCheckPolicy', 'ALLOW', 67) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteLBStickinessPolicy', 'ALLOW', 68) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteLoadBalancer', 'ALLOW', 69) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteLoadBalancerRule', 'ALLOW', 70) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteNetwork', 'ALLOW', 71) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteNetworkACL', 'ALLOW', 72) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteNetworkACLList', 'ALLOW', 73) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deletePool', 'ALLOW', 74) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deletePortForwardingRule', 'ALLOW', 75) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteProject', 'ALLOW', 76) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteProjectInvitation', 'ALLOW', 77) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteRemoteAccessVpn', 'ALLOW', 78) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteSSHKeyPair', 'ALLOW', 79) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteSecurityGroup', 'ALLOW', 80) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteSnapshot', 'ALLOW', 81) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteSnapshotPolicies', 'ALLOW', 82) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteSslCert', 'ALLOW', 83) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteStaticRoute', 'ALLOW', 84) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteTags', 'ALLOW', 85) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteTemplate', 'ALLOW', 86) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVMSnapshot', 'ALLOW', 87) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVPC', 'ALLOW', 88) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVolume', 'ALLOW', 89) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVpnConnection', 'ALLOW', 90) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVpnCustomerGateway', 'ALLOW', 91) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deleteVpnGateway', 'ALLOW', 92) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'deployVirtualMachine', 'ALLOW', 93) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'destroyLunOnFiler', 'ALLOW', 94) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'destroyVirtualMachine', 'ALLOW', 95) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'destroyVolumeOnFiler', 'ALLOW', 96) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'detachIso', 'ALLOW', 97) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'detachVolume', 'ALLOW', 98) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'disableAutoScaleVmGroup', 'ALLOW', 99) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'disableStaticNat', 'ALLOW', 100) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'disassociateIpAddress', 'ALLOW', 101) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'dissociateLun', 'ALLOW', 102) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'enableAutoScaleVmGroup', 'ALLOW', 103) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'enableStaticNat', 'ALLOW', 104) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'expungeVirtualMachine', 'ALLOW', 105) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'extractIso', 'ALLOW', 106) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'extractTemplate', 'ALLOW', 107) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'extractVolume', 'ALLOW', 108) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getApiLimit', 'ALLOW', 109) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getCloudIdentifier', 'ALLOW', 110) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getSolidFireAccountId', 'ALLOW', 111) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getSolidFireVolumeAccessGroupId', 'ALLOW', 112) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getSolidFireVolumeIscsiName', 'ALLOW', 113) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getSolidFireVolumeSize', 'ALLOW', 114) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getUploadParamsForTemplate', 'ALLOW', 115) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getUploadParamsForVolume', 'ALLOW', 116) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getVMPassword', 'ALLOW', 117) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'getVirtualMachineUserData', 'ALLOW', 118) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'issueNuageVspResourceRequest', 'ALLOW', 119) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAccounts', 'ALLOW', 120) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAffinityGroupTypes', 'ALLOW', 121) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAffinityGroups', 'ALLOW', 122) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listApis', 'ALLOW', 123) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAsyncJobs', 'ALLOW', 124) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAutoScalePolicies', 'ALLOW', 125) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAutoScaleVmGroups', 'ALLOW', 126) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listAutoScaleVmProfiles', 'ALLOW', 127) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listCapabilities', 'ALLOW', 128) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listConditions', 'ALLOW', 129) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listCounters', 'ALLOW', 130) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listDiskOfferings', 'ALLOW', 131) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listEgressFirewallRules', 'ALLOW', 132) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listEventTypes', 'ALLOW', 133) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listEvents', 'ALLOW', 134) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listFirewallRules', 'ALLOW', 135) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listGlobalLoadBalancerRules', 'ALLOW', 136) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listHypervisors', 'ALLOW', 137) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listInstanceGroups', 'ALLOW', 138) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listIpForwardingRules', 'ALLOW', 139) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listIsoPermissions', 'ALLOW', 140) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listIsos', 'ALLOW', 141) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLBHealthCheckPolicies', 'ALLOW', 142) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLBStickinessPolicies', 'ALLOW', 143) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLdapConfigurations', 'ALLOW', 144) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLoadBalancerRuleInstances', 'ALLOW', 145) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLoadBalancerRules', 'ALLOW', 146) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLoadBalancers', 'ALLOW', 147) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listLunsOnFiler', 'ALLOW', 148) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listNetworkACLLists', 'ALLOW', 149) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listNetworkACLs', 'ALLOW', 150) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listNetworkOfferings', 'ALLOW', 151) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listNetworks', 'ALLOW', 152) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listNics', 'ALLOW', 153) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listOsCategories', 'ALLOW', 154) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listOsTypes', 'ALLOW', 155) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listPools', 'ALLOW', 156) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listPortForwardingRules', 'ALLOW', 157) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listPrivateGateways', 'ALLOW', 158) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listProjectAccounts', 'ALLOW', 159) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listProjectInvitations', 'ALLOW', 160) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listProjects', 'ALLOW', 161) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listPublicIpAddresses', 'ALLOW', 162) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listRegions', 'ALLOW', 163) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listRemoteAccessVpns', 'ALLOW', 164) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listResourceDetails', 'ALLOW', 165) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listResourceLimits', 'ALLOW', 166) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listSSHKeyPairs', 'ALLOW', 167) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listSecurityGroups', 'ALLOW', 168) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listServiceOfferings', 'ALLOW', 169) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listSnapshotPolicies', 'ALLOW', 170) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listSnapshots', 'ALLOW', 171) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listSslCerts', 'ALLOW', 172) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listStaticRoutes', 'ALLOW', 173) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listTags', 'ALLOW', 174) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listTemplatePermissions', 'ALLOW', 175) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listTemplates', 'ALLOW', 176) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listUsers', 'ALLOW', 177) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVMSnapshot', 'ALLOW', 178) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVPCOfferings', 'ALLOW', 179) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVPCs', 'ALLOW', 180) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVirtualMachines', 'ALLOW', 181) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVolumes', 'ALLOW', 182) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVolumesOnFiler', 'ALLOW', 183) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVpnConnections', 'ALLOW', 184) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVpnCustomerGateways', 'ALLOW', 185) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVpnGateways', 'ALLOW', 186) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listVpnUsers', 'ALLOW', 187) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'listZones', 'ALLOW', 188) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'migrateVolume', 'ALLOW', 189) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'modifyPool', 'ALLOW', 190) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'queryAsyncJobResult', 'ALLOW', 191) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'quotaBalance', 'ALLOW', 192) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'quotaIsEnabled', 'ALLOW', 193) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'quotaStatement', 'ALLOW', 194) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'quotaSummary', 'ALLOW', 195) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'quotaTariffList', 'ALLOW', 196) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'rebootVirtualMachine', 'ALLOW', 197) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'recoverVirtualMachine', 'ALLOW', 198) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'registerIso', 'ALLOW', 199) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'registerSSHKeyPair', 'ALLOW', 200) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'registerTemplate', 'ALLOW', 201) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'registerUserKeys', 'ALLOW', 202) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeCertFromLoadBalancer', 'ALLOW', 203) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeFromGlobalLoadBalancerRule', 'ALLOW', 204) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeFromLoadBalancerRule', 'ALLOW', 205) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeIpFromNic', 'ALLOW', 206) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeNicFromVirtualMachine', 'ALLOW', 207) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'removeVpnUser', 'ALLOW', 208) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'replaceNetworkACLList', 'ALLOW', 209) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'resetPasswordForVirtualMachine', 'ALLOW', 210) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'resetSSHKeyForVirtualMachine', 'ALLOW', 211) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'resetVpnConnection', 'ALLOW', 212) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'resizeVolume', 'ALLOW', 213) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'restartNetwork', 'ALLOW', 214) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'restartVPC', 'ALLOW', 215) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'restoreVirtualMachine', 'ALLOW', 216) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'revertSnapshot', 'ALLOW', 217) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'revertToVMSnapshot', 'ALLOW', 218) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'revokeSecurityGroupEgress', 'ALLOW', 219) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'revokeSecurityGroupIngress', 'ALLOW', 220) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'scaleVirtualMachine', 'ALLOW', 221) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'startVirtualMachine', 'ALLOW', 222) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'stopVirtualMachine', 'ALLOW', 223) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'suspendProject', 'ALLOW', 224) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateAutoScalePolicy', 'ALLOW', 225) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateAutoScaleVmGroup', 'ALLOW', 226) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateAutoScaleVmProfile', 'ALLOW', 227) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateDefaultNicForVirtualMachine', 'ALLOW', 228) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateEgressFirewallRule', 'ALLOW', 229) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateFirewallRule', 'ALLOW', 230) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateGlobalLoadBalancerRule', 'ALLOW', 231) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateInstanceGroup', 'ALLOW', 232) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateIpAddress', 'ALLOW', 233) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateIso', 'ALLOW', 234) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateIsoPermissions', 'ALLOW', 235) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateLBHealthCheckPolicy', 'ALLOW', 236) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateLBStickinessPolicy', 'ALLOW', 237) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateLoadBalancer', 'ALLOW', 238) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateLoadBalancerRule', 'ALLOW', 239) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateNetwork', 'ALLOW', 240) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateNetworkACLItem', 'ALLOW', 241) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateNetworkACLList', 'ALLOW', 242) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updatePortForwardingRule', 'ALLOW', 243) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateProject', 'ALLOW', 244) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateProjectInvitation', 'ALLOW', 245) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateRemoteAccessVpn', 'ALLOW', 246) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateSnapshotPolicy', 'ALLOW', 247) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateTemplate', 'ALLOW', 248) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateTemplatePermissions', 'ALLOW', 249) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateUser', 'ALLOW', 250) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVMAffinityGroup', 'ALLOW', 251) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVPC', 'ALLOW', 252) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVirtualMachine', 'ALLOW', 253) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVmNicIp', 'ALLOW', 254) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVpnConnection', 'ALLOW', 255) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVpnCustomerGateway', 'ALLOW', 256) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'updateVpnGateway', 'ALLOW', 257) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'uploadSslCert', 'ALLOW', 258) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'uploadVolume', 'ALLOW', 259) ON DUPLICATE KEY UPDATE rule=rule; diff --git a/setup/db/db/schema-471to480.sql b/setup/db/db/schema-471to480.sql index b79af7f544..5db5ac642a 100644 --- a/setup/db/db/schema-471to480.sql +++ b/setup/db/db/schema-471to480.sql @@ -27,3 +27,4 @@ ALTER TABLE `cloud`.`image_store` MODIFY COLUMN `url` varchar(2048); ALTER TABLE `cloud`.`template_store_ref` MODIFY COLUMN `url` varchar(2048); ALTER TABLE `cloud`.`volume_store_ref` MODIFY COLUMN `url` varchar(2048); ALTER TABLE `cloud`.`volume_store_ref` MODIFY COLUMN `download_url` varchar(2048); +ALTER TABLE `cloud`.`upload` MODIFY COLUMN `url` varchar(2048); diff --git a/setup/db/db/schema-481to490-cleanup.sql b/setup/db/db/schema-481to490-cleanup.sql new file mode 100644 index 0000000000..0ab02d8308 --- /dev/null +++ b/setup/db/db/schema-481to490-cleanup.sql @@ -0,0 +1,350 @@ +-- 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. + +--; +-- Schema cleanup from 4.8.1 to 4.9.0; +--; + +-- Added in CLOUDSTACK-9340: General DB optimization, 4 cases: + +----- 1) Incorrect PRIMARY key +ALTER TABLE `cloud`.`ovs_tunnel_network` +DROP PRIMARY KEY, +ADD PRIMARY KEY (`id`), +DROP INDEX `id` , +ADD UNIQUE INDEX `i_to_from_network_id` (`to` ASC, `from` ASC, `network_id` ASC); + +----- 2) Duplicate PRIMARY KEY +ALTER TABLE `cloud`.`user_vm` DROP INDEX `id_2` ,DROP INDEX `id` ; +ALTER TABLE `cloud`.`domain_router` DROP INDEX `id_2` ,DROP INDEX `id` ; +ALTER TABLE `cloud`.`vm_instance` DROP INDEX `id_2` ,DROP INDEX `id` ; +ALTER TABLE `cloud`.`account_vlan_map` DROP INDEX `id` ; +ALTER TABLE `cloud`.`account_vnet_map` DROP INDEX `id` ; +ALTER TABLE `cloud`.`baremetal_rct` DROP INDEX `id` ; +ALTER TABLE `cloud`.`cluster` DROP INDEX `id` ; +ALTER TABLE `cloud`.`conditions` DROP INDEX `id` ; +ALTER TABLE `cloud`.`counter` DROP INDEX `id` ; +ALTER TABLE `cloud`.`data_center` DROP INDEX `id` ; +ALTER TABLE `cloud`.`dc_storage_network_ip_range` DROP INDEX `id` ; +ALTER TABLE `cloud`.`dedicated_resources` DROP INDEX `id` ; +ALTER TABLE `cloud`.`host_pod_ref` DROP INDEX `id` ; +ALTER TABLE `cloud`.`iam_group` DROP INDEX `id` ; +ALTER TABLE `cloud`.`iam_policy` DROP INDEX `id` ; +ALTER TABLE `cloud`.`iam_policy_permission` DROP INDEX `id` ; +ALTER TABLE `cloud`.`image_store_details` DROP INDEX `id` ; +ALTER TABLE `cloud`.`instance_group` DROP INDEX `id` ; +ALTER TABLE `cloud`.`netapp_lun` DROP INDEX `id` ; +ALTER TABLE `cloud`.`netapp_pool` DROP INDEX `id` ; +ALTER TABLE `cloud`.`netapp_volume` DROP INDEX `id` ; +ALTER TABLE `cloud`.`network_acl_item_cidrs` DROP INDEX `id` ; +ALTER TABLE `cloud`.`network_offerings` DROP INDEX `id` ; +ALTER TABLE `cloud`.`nic_secondary_ips` DROP INDEX `id` ; +ALTER TABLE `cloud`.`nics` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_ha_work` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_host` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_host_transfer` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_networks` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_nwgrp_work` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_vm_ruleset_log` DROP INDEX `id` ; +ALTER TABLE `cloud`.`op_vpc_distributed_router_sequence_no` DROP INDEX `id` ; +ALTER TABLE `cloud`.`pod_vlan_map` DROP INDEX `id` ; +ALTER TABLE `cloud`.`portable_ip_address` DROP INDEX `id` ; +ALTER TABLE `cloud`.`portable_ip_range` DROP INDEX `id` ; +ALTER TABLE `cloud`.`region` DROP INDEX `id` ; +ALTER TABLE `cloud`.`remote_access_vpn` DROP INDEX `id` ; +ALTER TABLE `cloud`.`snapshot_details` DROP INDEX `id` ; +ALTER TABLE `cloud`.`snapshots` DROP INDEX `id` ; +ALTER TABLE `cloud`.`storage_pool` DROP INDEX `id` ; +ALTER TABLE `cloud`.`storage_pool_details` DROP INDEX `id` ; +ALTER TABLE `cloud`.`storage_pool_work` DROP INDEX `id` ; +ALTER TABLE `cloud`.`user_ip_address` DROP INDEX `id` ; +ALTER TABLE `cloud`.`user_ipv6_address` DROP INDEX `id` ; +ALTER TABLE `cloud`.`user_statistics` DROP INDEX `id` ; +ALTER TABLE `cloud`.`version` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vlan` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vm_disk_statistics` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vm_snapshot_details` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vm_work_job` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vpc_gateways` DROP INDEX `id` ; +ALTER TABLE `cloud`.`vpn_users` DROP INDEX `id` ; + +-- Dynamic roles changes +DROP VIEW IF EXISTS `cloud`.`account_view`; +CREATE VIEW `cloud`.`account_view` AS + select + account.id, + account.uuid, + account.account_name, + account.type, + account.role_id, + account.state, + account.removed, + account.cleanup_needed, + account.network_domain, + account.default, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + data_center.id data_center_id, + data_center.uuid data_center_uuid, + data_center.name data_center_name, + account_netstats_view.bytesReceived, + account_netstats_view.bytesSent, + vmlimit.max vmLimit, + vmcount.count vmTotal, + runningvm.vmcount runningVms, + stoppedvm.vmcount stoppedVms, + iplimit.max ipLimit, + ipcount.count ipTotal, + free_ip_view.free_ip ipFree, + volumelimit.max volumeLimit, + volumecount.count volumeTotal, + snapshotlimit.max snapshotLimit, + snapshotcount.count snapshotTotal, + templatelimit.max templateLimit, + templatecount.count templateTotal, + vpclimit.max vpcLimit, + vpccount.count vpcTotal, + projectlimit.max projectLimit, + projectcount.count projectTotal, + networklimit.max networkLimit, + networkcount.count networkTotal, + cpulimit.max cpuLimit, + cpucount.count cpuTotal, + memorylimit.max memoryLimit, + memorycount.count memoryTotal, + primary_storage_limit.max primaryStorageLimit, + primary_storage_count.count primaryStorageTotal, + secondary_storage_limit.max secondaryStorageLimit, + secondary_storage_count.count secondaryStorageTotal, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id + from + `cloud`.`free_ip_view`, + `cloud`.`account` + inner join + `cloud`.`domain` ON account.domain_id = domain.id + left join + `cloud`.`data_center` ON account.default_zone_id = data_center.id + left join + `cloud`.`account_netstats_view` ON account.id = account_netstats_view.account_id + left join + `cloud`.`resource_limit` vmlimit ON account.id = vmlimit.account_id + and vmlimit.type = 'user_vm' + left join + `cloud`.`resource_count` vmcount ON account.id = vmcount.account_id + and vmcount.type = 'user_vm' + left join + `cloud`.`account_vmstats_view` runningvm ON account.id = runningvm.account_id + and runningvm.state = 'Running' + left join + `cloud`.`account_vmstats_view` stoppedvm ON account.id = stoppedvm.account_id + and stoppedvm.state = 'Stopped' + left join + `cloud`.`resource_limit` iplimit ON account.id = iplimit.account_id + and iplimit.type = 'public_ip' + left join + `cloud`.`resource_count` ipcount ON account.id = ipcount.account_id + and ipcount.type = 'public_ip' + left join + `cloud`.`resource_limit` volumelimit ON account.id = volumelimit.account_id + and volumelimit.type = 'volume' + left join + `cloud`.`resource_count` volumecount ON account.id = volumecount.account_id + and volumecount.type = 'volume' + left join + `cloud`.`resource_limit` snapshotlimit ON account.id = snapshotlimit.account_id + and snapshotlimit.type = 'snapshot' + left join + `cloud`.`resource_count` snapshotcount ON account.id = snapshotcount.account_id + and snapshotcount.type = 'snapshot' + left join + `cloud`.`resource_limit` templatelimit ON account.id = templatelimit.account_id + and templatelimit.type = 'template' + left join + `cloud`.`resource_count` templatecount ON account.id = templatecount.account_id + and templatecount.type = 'template' + left join + `cloud`.`resource_limit` vpclimit ON account.id = vpclimit.account_id + and vpclimit.type = 'vpc' + left join + `cloud`.`resource_count` vpccount ON account.id = vpccount.account_id + and vpccount.type = 'vpc' + left join + `cloud`.`resource_limit` projectlimit ON account.id = projectlimit.account_id + and projectlimit.type = 'project' + left join + `cloud`.`resource_count` projectcount ON account.id = projectcount.account_id + and projectcount.type = 'project' + left join + `cloud`.`resource_limit` networklimit ON account.id = networklimit.account_id + and networklimit.type = 'network' + left join + `cloud`.`resource_count` networkcount ON account.id = networkcount.account_id + and networkcount.type = 'network' + left join + `cloud`.`resource_limit` cpulimit ON account.id = cpulimit.account_id + and cpulimit.type = 'cpu' + left join + `cloud`.`resource_count` cpucount ON account.id = cpucount.account_id + and cpucount.type = 'cpu' + left join + `cloud`.`resource_limit` memorylimit ON account.id = memorylimit.account_id + and memorylimit.type = 'memory' + left join + `cloud`.`resource_count` memorycount ON account.id = memorycount.account_id + and memorycount.type = 'memory' + left join + `cloud`.`resource_limit` primary_storage_limit ON account.id = primary_storage_limit.account_id + and primary_storage_limit.type = 'primary_storage' + left join + `cloud`.`resource_count` primary_storage_count ON account.id = primary_storage_count.account_id + and primary_storage_count.type = 'primary_storage' + left join + `cloud`.`resource_limit` secondary_storage_limit ON account.id = secondary_storage_limit.account_id + and secondary_storage_limit.type = 'secondary_storage' + left join + `cloud`.`resource_count` secondary_storage_count ON account.id = secondary_storage_count.account_id + and secondary_storage_count.type = 'secondary_storage' + left join + `cloud`.`async_job` ON async_job.instance_id = account.id + and async_job.instance_type = 'Account' + and async_job.job_status = 0; + +DROP VIEW IF EXISTS `cloud`.`user_view`; +CREATE VIEW `cloud`.`user_view` AS + select + user.id, + user.uuid, + user.username, + user.password, + user.firstname, + user.lastname, + user.email, + user.state, + user.api_key, + user.secret_key, + user.created, + user.removed, + user.timezone, + user.registration_token, + user.is_registered, + user.incorrect_login_attempts, + user.default, + account.id account_id, + account.uuid account_uuid, + account.account_name account_name, + account.type account_type, + account.role_id account_role_id, + domain.id domain_id, + domain.uuid domain_uuid, + domain.name domain_name, + domain.path domain_path, + async_job.id job_id, + async_job.uuid job_uuid, + async_job.job_status job_status, + async_job.account_id job_account_id + from + `cloud`.`user` + inner join + `cloud`.`account` ON user.account_id = account.id + inner join + `cloud`.`domain` ON account.domain_id = domain.id + left join + `cloud`.`async_job` ON async_job.instance_id = user.id + and async_job.instance_type = 'User' + and async_job.job_status = 0; + +-- Out-of-band management +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, + host_tags.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` + 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; diff --git a/setup/db/db/schema-481to490.sql b/setup/db/db/schema-481to490.sql new file mode 100644 index 0000000000..bd1dd82d1a --- /dev/null +++ b/setup/db/db/schema-481to490.sql @@ -0,0 +1,547 @@ +-- 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. + +--; +-- Schema upgrade from 4.8.1 to 4.9.0; +--; + +ALTER TABLE `event` ADD INDEX `archived` (`archived`); +ALTER TABLE `event` ADD INDEX `state` (`state`); + +DROP VIEW IF EXISTS `cloud`.`template_view`; +CREATE +VIEW `template_view` AS + SELECT + `vm_template`.`id` AS `id`, + `vm_template`.`uuid` AS `uuid`, + `vm_template`.`unique_name` AS `unique_name`, + `vm_template`.`name` AS `name`, + `vm_template`.`public` AS `public`, + `vm_template`.`featured` AS `featured`, + `vm_template`.`type` AS `type`, + `vm_template`.`hvm` AS `hvm`, + `vm_template`.`bits` AS `bits`, + `vm_template`.`url` AS `url`, + `vm_template`.`format` AS `format`, + `vm_template`.`created` AS `created`, + `vm_template`.`checksum` AS `checksum`, + `vm_template`.`display_text` AS `display_text`, + `vm_template`.`enable_password` AS `enable_password`, + `vm_template`.`dynamically_scalable` AS `dynamically_scalable`, + `vm_template`.`state` AS `template_state`, + `vm_template`.`guest_os_id` AS `guest_os_id`, + `guest_os`.`uuid` AS `guest_os_uuid`, + `guest_os`.`display_name` AS `guest_os_name`, + `vm_template`.`bootable` AS `bootable`, + `vm_template`.`prepopulate` AS `prepopulate`, + `vm_template`.`cross_zones` AS `cross_zones`, + `vm_template`.`hypervisor_type` AS `hypervisor_type`, + `vm_template`.`extractable` AS `extractable`, + `vm_template`.`template_tag` AS `template_tag`, + `vm_template`.`sort_key` AS `sort_key`, + `vm_template`.`removed` AS `removed`, + `vm_template`.`enable_sshkey` AS `enable_sshkey`, + `source_template`.`id` AS `source_template_id`, + `source_template`.`uuid` AS `source_template_uuid`, + `account`.`id` AS `account_id`, + `account`.`uuid` AS `account_uuid`, + `account`.`account_name` AS `account_name`, + `account`.`type` AS `account_type`, + `domain`.`id` AS `domain_id`, + `domain`.`uuid` AS `domain_uuid`, + `domain`.`name` AS `domain_name`, + `domain`.`path` AS `domain_path`, + `projects`.`id` AS `project_id`, + `projects`.`uuid` AS `project_uuid`, + `projects`.`name` AS `project_name`, + `data_center`.`id` AS `data_center_id`, + `data_center`.`uuid` AS `data_center_uuid`, + `data_center`.`name` AS `data_center_name`, + `launch_permission`.`account_id` AS `lp_account_id`, + `template_store_ref`.`store_id` AS `store_id`, + `image_store`.`scope` AS `store_scope`, + `template_store_ref`.`state` AS `state`, + `template_store_ref`.`download_state` AS `download_state`, + `template_store_ref`.`download_pct` AS `download_pct`, + `template_store_ref`.`error_str` AS `error_str`, + `template_store_ref`.`size` AS `size`, + `template_store_ref`.`destroyed` AS `destroyed`, + `template_store_ref`.`created` AS `created_on_store`, + `vm_template_details`.`name` AS `detail_name`, + `vm_template_details`.`value` AS `detail_value`, + `resource_tags`.`id` AS `tag_id`, + `resource_tags`.`uuid` AS `tag_uuid`, + `resource_tags`.`key` AS `tag_key`, + `resource_tags`.`value` AS `tag_value`, + `resource_tags`.`domain_id` AS `tag_domain_id`, + `domain`.`uuid` AS `tag_domain_uuid`, + `domain`.`name` AS `tag_domain_name`, + `resource_tags`.`account_id` AS `tag_account_id`, + `account`.`account_name` AS `tag_account_name`, + `resource_tags`.`resource_id` AS `tag_resource_id`, + `resource_tags`.`resource_uuid` AS `tag_resource_uuid`, + `resource_tags`.`resource_type` AS `tag_resource_type`, + `resource_tags`.`customer` AS `tag_customer`, + CONCAT(`vm_template`.`id`, + '_', + IFNULL(`data_center`.`id`, 0)) AS `temp_zone_pair` + FROM + ((((((((((((`vm_template` + JOIN `guest_os` ON ((`guest_os`.`id` = `vm_template`.`guest_os_id`))) + JOIN `account` ON ((`account`.`id` = `vm_template`.`account_id`))) + JOIN `domain` ON ((`domain`.`id` = `account`.`domain_id`))) + LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`))) + LEFT JOIN `vm_template_details` ON ((`vm_template_details`.`template_id` = `vm_template`.`id`))) + LEFT JOIN `vm_template` `source_template` ON ((`source_template`.`id` = `vm_template`.`source_template_id`))) + LEFT JOIN `template_store_ref` ON (((`template_store_ref`.`template_id` = `vm_template`.`id`) + AND (`template_store_ref`.`store_role` = 'Image') + AND (`template_store_ref`.`destroyed` = 0)))) + LEFT JOIN `image_store` ON ((ISNULL(`image_store`.`removed`) + AND (`template_store_ref`.`store_id` IS NOT NULL) + AND (`image_store`.`id` = `template_store_ref`.`store_id`)))) + LEFT JOIN `template_zone_ref` ON (((`template_zone_ref`.`template_id` = `vm_template`.`id`) + AND ISNULL(`template_store_ref`.`store_id`) + AND ISNULL(`template_zone_ref`.`removed`)))) + LEFT JOIN `data_center` ON (((`image_store`.`data_center_id` = `data_center`.`id`) + OR (`template_zone_ref`.`zone_id` = `data_center`.`id`)))) + LEFT JOIN `launch_permission` ON ((`launch_permission`.`template_id` = `vm_template`.`id`))) + LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_template`.`id`) + AND ((`resource_tags`.`resource_type` = 'Template') + OR (`resource_tags`.`resource_type` = 'ISO'))))); + +DROP VIEW IF EXISTS `cloud`.`volume_view`; +CREATE +VIEW `volume_view` AS + SELECT + `volumes`.`id` AS `id`, + `volumes`.`uuid` AS `uuid`, + `volumes`.`name` AS `name`, + `volumes`.`device_id` AS `device_id`, + `volumes`.`volume_type` AS `volume_type`, + `volumes`.`provisioning_type` AS `provisioning_type`, + `volumes`.`size` AS `size`, + `volumes`.`min_iops` AS `min_iops`, + `volumes`.`max_iops` AS `max_iops`, + `volumes`.`created` AS `created`, + `volumes`.`state` AS `state`, + `volumes`.`attached` AS `attached`, + `volumes`.`removed` AS `removed`, + `volumes`.`pod_id` AS `pod_id`, + `volumes`.`display_volume` AS `display_volume`, + `volumes`.`format` AS `format`, + `volumes`.`path` AS `path`, + `volumes`.`chain_info` AS `chain_info`, + `account`.`id` AS `account_id`, + `account`.`uuid` AS `account_uuid`, + `account`.`account_name` AS `account_name`, + `account`.`type` AS `account_type`, + `domain`.`id` AS `domain_id`, + `domain`.`uuid` AS `domain_uuid`, + `domain`.`name` AS `domain_name`, + `domain`.`path` AS `domain_path`, + `projects`.`id` AS `project_id`, + `projects`.`uuid` AS `project_uuid`, + `projects`.`name` AS `project_name`, + `data_center`.`id` AS `data_center_id`, + `data_center`.`uuid` AS `data_center_uuid`, + `data_center`.`name` AS `data_center_name`, + `data_center`.`networktype` AS `data_center_type`, + `vm_instance`.`id` AS `vm_id`, + `vm_instance`.`uuid` AS `vm_uuid`, + `vm_instance`.`name` AS `vm_name`, + `vm_instance`.`state` AS `vm_state`, + `vm_instance`.`vm_type` AS `vm_type`, + `user_vm`.`display_name` AS `vm_display_name`, + `volume_store_ref`.`size` AS `volume_store_size`, + `volume_store_ref`.`download_pct` AS `download_pct`, + `volume_store_ref`.`download_state` AS `download_state`, + `volume_store_ref`.`error_str` AS `error_str`, + `volume_store_ref`.`created` AS `created_on_store`, + `disk_offering`.`id` AS `disk_offering_id`, + `disk_offering`.`uuid` AS `disk_offering_uuid`, + `disk_offering`.`name` AS `disk_offering_name`, + `disk_offering`.`display_text` AS `disk_offering_display_text`, + `disk_offering`.`use_local_storage` AS `use_local_storage`, + `disk_offering`.`system_use` AS `system_use`, + `disk_offering`.`bytes_read_rate` AS `bytes_read_rate`, + `disk_offering`.`bytes_write_rate` AS `bytes_write_rate`, + `disk_offering`.`iops_read_rate` AS `iops_read_rate`, + `disk_offering`.`iops_write_rate` AS `iops_write_rate`, + `disk_offering`.`cache_mode` AS `cache_mode`, + `storage_pool`.`id` AS `pool_id`, + `storage_pool`.`uuid` AS `pool_uuid`, + `storage_pool`.`name` AS `pool_name`, + `cluster`.`hypervisor_type` AS `hypervisor_type`, + `vm_template`.`id` AS `template_id`, + `vm_template`.`uuid` AS `template_uuid`, + `vm_template`.`extractable` AS `extractable`, + `vm_template`.`type` AS `template_type`, + `vm_template`.`name` AS `template_name`, + `vm_template`.`display_text` AS `template_display_text`, + `iso`.`id` AS `iso_id`, + `iso`.`uuid` AS `iso_uuid`, + `iso`.`name` AS `iso_name`, + `iso`.`display_text` AS `iso_display_text`, + `resource_tags`.`id` AS `tag_id`, + `resource_tags`.`uuid` AS `tag_uuid`, + `resource_tags`.`key` AS `tag_key`, + `resource_tags`.`value` AS `tag_value`, + `resource_tags`.`domain_id` AS `tag_domain_id`, + `domain`.`uuid` AS `tag_domain_uuid`, + `domain`.`name` AS `tag_domain_name`, + `resource_tags`.`account_id` AS `tag_account_id`, + `account`.`account_name` AS `tag_account_name`, + `resource_tags`.`resource_id` AS `tag_resource_id`, + `resource_tags`.`resource_uuid` AS `tag_resource_uuid`, + `resource_tags`.`resource_type` AS `tag_resource_type`, + `resource_tags`.`customer` AS `tag_customer`, + `async_job`.`id` AS `job_id`, + `async_job`.`uuid` AS `job_uuid`, + `async_job`.`job_status` AS `job_status`, + `async_job`.`account_id` AS `job_account_id` + FROM + ((((((((((((((`volumes` + JOIN `account` ON ((`volumes`.`account_id` = `account`.`id`))) + JOIN `domain` ON ((`volumes`.`domain_id` = `domain`.`id`))) + LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`))) + LEFT JOIN `data_center` ON ((`volumes`.`data_center_id` = `data_center`.`id`))) + LEFT JOIN `vm_instance` ON ((`volumes`.`instance_id` = `vm_instance`.`id`))) + LEFT JOIN `user_vm` ON ((`user_vm`.`id` = `vm_instance`.`id`))) + LEFT JOIN `volume_store_ref` ON ((`volumes`.`id` = `volume_store_ref`.`volume_id`))) + LEFT JOIN `disk_offering` ON ((`volumes`.`disk_offering_id` = `disk_offering`.`id`))) + LEFT JOIN `storage_pool` ON ((`volumes`.`pool_id` = `storage_pool`.`id`))) + LEFT JOIN `cluster` ON ((`storage_pool`.`cluster_id` = `cluster`.`id`))) + LEFT JOIN `vm_template` ON ((`volumes`.`template_id` = `vm_template`.`id`))) + LEFT JOIN `vm_template` `iso` ON ((`iso`.`id` = `volumes`.`iso_id`))) + LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `volumes`.`id`) + AND (`resource_tags`.`resource_type` = 'Volume')))) + LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `volumes`.`id`) + AND (`async_job`.`instance_type` = 'Volume') + AND (`async_job`.`job_status` = 0)))); + +DROP VIEW IF EXISTS `cloud`.`user_vm_view`; +CREATE +VIEW `user_vm_view` AS + SELECT + `vm_instance`.`id` AS `id`, + `vm_instance`.`name` AS `name`, + `user_vm`.`display_name` AS `display_name`, + `user_vm`.`user_data` AS `user_data`, + `account`.`id` AS `account_id`, + `account`.`uuid` AS `account_uuid`, + `account`.`account_name` AS `account_name`, + `account`.`type` AS `account_type`, + `domain`.`id` AS `domain_id`, + `domain`.`uuid` AS `domain_uuid`, + `domain`.`name` AS `domain_name`, + `domain`.`path` AS `domain_path`, + `projects`.`id` AS `project_id`, + `projects`.`uuid` AS `project_uuid`, + `projects`.`name` AS `project_name`, + `instance_group`.`id` AS `instance_group_id`, + `instance_group`.`uuid` AS `instance_group_uuid`, + `instance_group`.`name` AS `instance_group_name`, + `vm_instance`.`uuid` AS `uuid`, + `vm_instance`.`user_id` AS `user_id`, + `vm_instance`.`last_host_id` AS `last_host_id`, + `vm_instance`.`vm_type` AS `type`, + `vm_instance`.`limit_cpu_use` AS `limit_cpu_use`, + `vm_instance`.`created` AS `created`, + `vm_instance`.`state` AS `state`, + `vm_instance`.`removed` AS `removed`, + `vm_instance`.`ha_enabled` AS `ha_enabled`, + `vm_instance`.`hypervisor_type` AS `hypervisor_type`, + `vm_instance`.`instance_name` AS `instance_name`, + `vm_instance`.`guest_os_id` AS `guest_os_id`, + `vm_instance`.`display_vm` AS `display_vm`, + `guest_os`.`uuid` AS `guest_os_uuid`, + `vm_instance`.`pod_id` AS `pod_id`, + `host_pod_ref`.`uuid` AS `pod_uuid`, + `vm_instance`.`private_ip_address` AS `private_ip_address`, + `vm_instance`.`private_mac_address` AS `private_mac_address`, + `vm_instance`.`vm_type` AS `vm_type`, + `data_center`.`id` AS `data_center_id`, + `data_center`.`uuid` AS `data_center_uuid`, + `data_center`.`name` AS `data_center_name`, + `data_center`.`is_security_group_enabled` AS `security_group_enabled`, + `data_center`.`networktype` AS `data_center_type`, + `host`.`id` AS `host_id`, + `host`.`uuid` AS `host_uuid`, + `host`.`name` AS `host_name`, + `vm_template`.`id` AS `template_id`, + `vm_template`.`uuid` AS `template_uuid`, + `vm_template`.`name` AS `template_name`, + `vm_template`.`display_text` AS `template_display_text`, + `vm_template`.`enable_password` AS `password_enabled`, + `iso`.`id` AS `iso_id`, + `iso`.`uuid` AS `iso_uuid`, + `iso`.`name` AS `iso_name`, + `iso`.`display_text` AS `iso_display_text`, + `service_offering`.`id` AS `service_offering_id`, + `svc_disk_offering`.`uuid` AS `service_offering_uuid`, + `disk_offering`.`uuid` AS `disk_offering_uuid`, + `disk_offering`.`id` AS `disk_offering_id`, + (CASE + WHEN ISNULL(`service_offering`.`cpu`) THEN `custom_cpu`.`value` + ELSE `service_offering`.`cpu` + END) AS `cpu`, + (CASE + WHEN ISNULL(`service_offering`.`speed`) THEN `custom_speed`.`value` + ELSE `service_offering`.`speed` + END) AS `speed`, + (CASE + WHEN ISNULL(`service_offering`.`ram_size`) THEN `custom_ram_size`.`value` + ELSE `service_offering`.`ram_size` + END) AS `ram_size`, + `svc_disk_offering`.`name` AS `service_offering_name`, + `disk_offering`.`name` AS `disk_offering_name`, + `storage_pool`.`id` AS `pool_id`, + `storage_pool`.`uuid` AS `pool_uuid`, + `storage_pool`.`pool_type` AS `pool_type`, + `volumes`.`id` AS `volume_id`, + `volumes`.`uuid` AS `volume_uuid`, + `volumes`.`device_id` AS `volume_device_id`, + `volumes`.`volume_type` AS `volume_type`, + `security_group`.`id` AS `security_group_id`, + `security_group`.`uuid` AS `security_group_uuid`, + `security_group`.`name` AS `security_group_name`, + `security_group`.`description` AS `security_group_description`, + `nics`.`id` AS `nic_id`, + `nics`.`uuid` AS `nic_uuid`, + `nics`.`network_id` AS `network_id`, + `nics`.`ip4_address` AS `ip_address`, + `nics`.`ip6_address` AS `ip6_address`, + `nics`.`ip6_gateway` AS `ip6_gateway`, + `nics`.`ip6_cidr` AS `ip6_cidr`, + `nics`.`default_nic` AS `is_default_nic`, + `nics`.`gateway` AS `gateway`, + `nics`.`netmask` AS `netmask`, + `nics`.`mac_address` AS `mac_address`, + `nics`.`broadcast_uri` AS `broadcast_uri`, + `nics`.`isolation_uri` AS `isolation_uri`, + `vpc`.`id` AS `vpc_id`, + `vpc`.`uuid` AS `vpc_uuid`, + `networks`.`uuid` AS `network_uuid`, + `networks`.`name` AS `network_name`, + `networks`.`traffic_type` AS `traffic_type`, + `networks`.`guest_type` AS `guest_type`, + `user_ip_address`.`id` AS `public_ip_id`, + `user_ip_address`.`uuid` AS `public_ip_uuid`, + `user_ip_address`.`public_ip_address` AS `public_ip_address`, + `ssh_keypairs`.`keypair_name` AS `keypair_name`, + `resource_tags`.`id` AS `tag_id`, + `resource_tags`.`uuid` AS `tag_uuid`, + `resource_tags`.`key` AS `tag_key`, + `resource_tags`.`value` AS `tag_value`, + `resource_tags`.`domain_id` AS `tag_domain_id`, + `domain`.`uuid` AS `tag_domain_uuid`, + `domain`.`name` AS `tag_domain_name`, + `resource_tags`.`account_id` AS `tag_account_id`, + `account`.`account_name` AS `tag_account_name`, + `resource_tags`.`resource_id` AS `tag_resource_id`, + `resource_tags`.`resource_uuid` AS `tag_resource_uuid`, + `resource_tags`.`resource_type` AS `tag_resource_type`, + `resource_tags`.`customer` AS `tag_customer`, + `async_job`.`id` AS `job_id`, + `async_job`.`uuid` AS `job_uuid`, + `async_job`.`job_status` AS `job_status`, + `async_job`.`account_id` AS `job_account_id`, + `affinity_group`.`id` AS `affinity_group_id`, + `affinity_group`.`uuid` AS `affinity_group_uuid`, + `affinity_group`.`name` AS `affinity_group_name`, + `affinity_group`.`description` AS `affinity_group_description`, + `vm_instance`.`dynamically_scalable` AS `dynamically_scalable` + FROM + ((((((((((((((((((((((((((((((((`user_vm` + JOIN `vm_instance` ON (((`vm_instance`.`id` = `user_vm`.`id`) + AND ISNULL(`vm_instance`.`removed`)))) + JOIN `account` ON ((`vm_instance`.`account_id` = `account`.`id`))) + JOIN `domain` ON ((`vm_instance`.`domain_id` = `domain`.`id`))) + LEFT JOIN `guest_os` ON ((`vm_instance`.`guest_os_id` = `guest_os`.`id`))) + LEFT JOIN `host_pod_ref` ON ((`vm_instance`.`pod_id` = `host_pod_ref`.`id`))) + LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`))) + LEFT JOIN `instance_group_vm_map` ON ((`vm_instance`.`id` = `instance_group_vm_map`.`instance_id`))) + LEFT JOIN `instance_group` ON ((`instance_group_vm_map`.`group_id` = `instance_group`.`id`))) + LEFT JOIN `data_center` ON ((`vm_instance`.`data_center_id` = `data_center`.`id`))) + LEFT JOIN `host` ON ((`vm_instance`.`host_id` = `host`.`id`))) + LEFT JOIN `vm_template` ON ((`vm_instance`.`vm_template_id` = `vm_template`.`id`))) + LEFT JOIN `vm_template` `iso` ON ((`iso`.`id` = `user_vm`.`iso_id`))) + LEFT JOIN `service_offering` ON ((`vm_instance`.`service_offering_id` = `service_offering`.`id`))) + LEFT JOIN `disk_offering` `svc_disk_offering` ON ((`vm_instance`.`service_offering_id` = `svc_disk_offering`.`id`))) + LEFT JOIN `disk_offering` ON ((`vm_instance`.`disk_offering_id` = `disk_offering`.`id`))) + LEFT JOIN `volumes` ON ((`vm_instance`.`id` = `volumes`.`instance_id`))) + LEFT JOIN `storage_pool` ON ((`volumes`.`pool_id` = `storage_pool`.`id`))) + LEFT JOIN `security_group_vm_map` ON ((`vm_instance`.`id` = `security_group_vm_map`.`instance_id`))) + LEFT JOIN `security_group` ON ((`security_group_vm_map`.`security_group_id` = `security_group`.`id`))) + LEFT JOIN `nics` ON (((`vm_instance`.`id` = `nics`.`instance_id`) + AND ISNULL(`nics`.`removed`)))) + LEFT JOIN `networks` ON ((`nics`.`network_id` = `networks`.`id`))) + LEFT JOIN `vpc` ON (((`networks`.`vpc_id` = `vpc`.`id`) + AND ISNULL(`vpc`.`removed`)))) + LEFT JOIN `user_ip_address` ON ((`user_ip_address`.`vm_id` = `vm_instance`.`id`))) + LEFT JOIN `user_vm_details` `ssh_details` ON (((`ssh_details`.`vm_id` = `vm_instance`.`id`) + AND (`ssh_details`.`name` = 'SSH.PublicKey')))) + LEFT JOIN `ssh_keypairs` ON (((`ssh_keypairs`.`public_key` = `ssh_details`.`value`) + AND (`ssh_keypairs`.`account_id` = `account`.`id`)))) + LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_instance`.`id`) + AND (`resource_tags`.`resource_type` = 'UserVm')))) + LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `vm_instance`.`id`) + AND (`async_job`.`instance_type` = 'VirtualMachine') + AND (`async_job`.`job_status` = 0)))) + LEFT JOIN `affinity_group_vm_map` ON ((`vm_instance`.`id` = `affinity_group_vm_map`.`instance_id`))) + LEFT JOIN `affinity_group` ON ((`affinity_group_vm_map`.`affinity_group_id` = `affinity_group`.`id`))) + LEFT JOIN `user_vm_details` `custom_cpu` ON (((`custom_cpu`.`vm_id` = `vm_instance`.`id`) + AND (`custom_cpu`.`name` = 'CpuNumber')))) + LEFT JOIN `user_vm_details` `custom_speed` ON (((`custom_speed`.`vm_id` = `vm_instance`.`id`) + AND (`custom_speed`.`name` = 'CpuSpeed')))) + LEFT JOIN `user_vm_details` `custom_ram_size` ON (((`custom_ram_size`.`vm_id` = `vm_instance`.`id`) + AND (`custom_ram_size`.`name` = 'memory')))); + +-- Add cluster.storage.operations.exclude property +INSERT INTO `cloud`.`configuration` (`category`, `instance`, `component`, `name`, `description`, `default_value`, `updated`, `scope`, `is_dynamic`) VALUES ('Advanced', 'DEFAULT', 'CapacityManager', 'cluster.storage.operations.exclude', 'Exclude cluster from storage operations', 'false', now(), 'Cluster', '1'); + +----- 3) Missing indexes (Add indexes to avoid full table scans) +ALTER TABLE `cloud`.`op_it_work` ADD INDEX `i_type_and_updated` (`type` ASC, `updated_at` ASC); +ALTER TABLE `cloud`.`vm_root_disk_tags` ADD INDEX `i_vm_id` (`vm_id` ASC); +ALTER TABLE `cloud`.`vm_compute_tags` ADD INDEX `i_vm_id` (`vm_id` ASC); +ALTER TABLE `cloud`.`vm_network_map` ADD INDEX `i_vm_id` (`vm_id` ASC); +ALTER TABLE `cloud`.`ssh_keypairs` ADD INDEX `i_public_key` (`public_key` (64) ASC); +ALTER TABLE `cloud`.`user_vm_details` ADD INDEX `i_name_vm_id` (`vm_id` ASC, `name` ASC); +ALTER TABLE `cloud`.`instance_group` ADD INDEX `i_name` (`name` ASC); + +----- 4) Some views query (Change view to improve account retrieval speed) +CREATE OR REPLACE +VIEW `account_vmstats_view` AS + SELECT + `vm_instance`.`account_id` AS `account_id`, + `vm_instance`.`state` AS `state`, + COUNT(0) AS `vmcount` + FROM + `vm_instance` + WHERE + (`vm_instance`.`vm_type` = 'User' and `vm_instance`.`removed` is NULL) + GROUP BY `vm_instance`.`account_id` , `vm_instance`.`state`; +-- End CLOUDSTACK-9340 + +-- Dynamic roles +CREATE TABLE IF NOT EXISTS `cloud`.`roles` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(255) UNIQUE, + `name` varchar(255) COMMENT 'unique name of the dynamic role', + `role_type` varchar(255) NOT NULL COMMENT 'the type of the role', + `removed` datetime COMMENT 'date removed', + `description` text COMMENT 'description of the role', + PRIMARY KEY (`id`), + KEY `i_roles__name` (`name`), + KEY `i_roles__role_type` (`role_type`), + UNIQUE KEY (`name`, `role_type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `cloud`.`role_permissions` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(255) UNIQUE, + `role_id` bigint(20) unsigned NOT NULL COMMENT 'id of the role', + `rule` varchar(255) NOT NULL COMMENT 'rule for the role, api name or wildcard', + `permission` varchar(255) NOT NULL COMMENT 'access authority, allow or deny', + `description` text COMMENT 'description of the rule', + `sort_order` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT 'permission sort order', + PRIMARY KEY (`id`), + KEY `fk_role_permissions__role_id` (`role_id`), + KEY `i_role_permissions__sort_order` (`sort_order`), + UNIQUE KEY (`role_id`, `rule`), + CONSTRAINT `fk_role_permissions__role_id` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Default CloudStack roles +INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (1, UUID(), 'Root Admin', 'Admin', 'Default root admin role') ON DUPLICATE KEY UPDATE name=name; +INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (2, UUID(), 'Resource Admin', 'ResourceAdmin', 'Default resource admin role') ON DUPLICATE KEY UPDATE name=name; +INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (3, UUID(), 'Domain Admin', 'DomainAdmin', 'Default domain admin role') ON DUPLICATE KEY UPDATE name=name; +INSERT INTO `cloud`.`roles` (`id`, `uuid`, `name`, `role_type`, `description`) values (4, UUID(), 'User', 'User', 'Default Root Admin role') ON DUPLICATE KEY UPDATE name=name; + +-- Out-of-band management +CREATE TABLE IF NOT EXISTS `cloud`.`oobm` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `host_id` bigint(20) unsigned DEFAULT NULL COMMENT 'foreign key to host', + `enabled` int(1) unsigned DEFAULT '0' COMMENT 'is out-of-band management enabled for host', + `power_state` varchar(32) DEFAULT 'Disabled' COMMENT 'out-of-band management power status', + `driver` varchar(32) DEFAULT NULL COMMENT 'out-of-band management driver', + `address` varchar(255) DEFAULT NULL COMMENT 'out-of-band management interface address', + `port` int(10) unsigned DEFAULT NULL COMMENT 'out-of-band management interface port', + `username` varchar(255) DEFAULT NULL COMMENT 'out-of-band management interface username', + `password` varchar(255) DEFAULT NULL COMMENT 'out-of-band management interface password', + `update_count` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'atomic increase count making status update operation atomical', + `update_time` datetime COMMENT 'last power state update datetime', + `mgmt_server_id` bigint(20) unsigned DEFAULT NULL COMMENT 'management server id which owns out-of-band management for the host', + PRIMARY KEY (`id`), + KEY `fk_oobm__host_id` (`host_id`), + KEY `i_oobm__enabled` (`enabled`), + KEY `i_oobm__power_state` (`power_state`), + KEY `i_oobm__update_time` (`update_time`), + KEY `i_oobm__mgmt_server_id` (`mgmt_server_id`), + CONSTRAINT `fk_oobm__host_id` FOREIGN KEY (`host_id`) REFERENCES `host` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centosGuest', 171, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centosGuest', 171, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centosGuest', 171, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centosGuest', 171, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centosGuest', 171, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centos64Guest', 172, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centos64Guest', 172, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centos64Guest', 172, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centos64Guest', 172, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 172, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centosGuest', 177, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centosGuest', 177, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centosGuest', 177, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centosGuest', 177, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centosGuest', 177, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centos64Guest', 178, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centos64Guest', 178, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centos64Guest', 178, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centos64Guest', 178, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 178, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centosGuest', 179, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centosGuest', 179, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centosGuest', 179, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centosGuest', 179, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centosGuest', 179, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centos64Guest', 180, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centos64Guest', 180, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centos64Guest', 180, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centos64Guest', 180, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 180, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centosGuest', 181, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centosGuest', 181, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centosGuest', 181, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centosGuest', 181, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centosGuest', 181, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centos64Guest', 182, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centos64Guest', 182, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centos64Guest', 182, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centos64Guest', 182, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 182, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centosGuest', 227, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centosGuest', 227, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centosGuest', 227, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centosGuest', 227, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centosGuest', 227, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.0', 'centos64Guest', 228, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '4.1', 'centos64Guest', 228, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.0', 'centos64Guest', 228, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.1', 'centos64Guest', 228, now(), 0); +INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(), 'VMware', '5.5', 'centos64Guest', 228, now(), 0); diff --git a/setup/db/server-setup.sql b/setup/db/server-setup.sql index b7f5c3fc30..df2c924855 100644 --- a/setup/db/server-setup.sql +++ b/setup/db/server-setup.sql @@ -25,4 +25,5 @@ INSERT INTO `cloud`.`domain` (id, uuid, name, parent, path, owner) VALUES (1, UU INSERT INTO `cloud`.`configuration` (category, instance, component, name, value, description) VALUES ('Hidden', 'DEFAULT', 'none', 'init', null, null); -- INSERT INTO `cloud`.`configuration` (category, instance, component, name, value, description) VALUES ('Advanced', 'DEFAULT', 'AgentManager', 'xenserver.public.network.device', 'public-network', "[OPTIONAL]The name of the XenServer network containing the physical network interface that is connected to the public network "); - +-- Enable dynamic RBAC by default for fresh deployments +INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) VALUES ('Advanced', 'DEFAULT', 'RoleService', 'dynamic.apichecker.enabled', 'true'); diff --git a/setup/db/server-setup.xml b/setup/db/server-setup.xml index bb8878f8d3..178f29aea3 100755 --- a/setup/db/server-setup.xml +++ b/setup/db/server-setup.xml @@ -239,6 +239,13 @@ under the License. qatest-vmops.com + + dynamic.apichecker.enabled + true + + - - Apache CloudStack v4.6.0 Root Admin API Reference + + + Apache CloudStack v4.9.0 Root Admin API Reference

@@ -65,16 +65,16 @@ version="1.0"> - +
- +
-
-

Request parameters

- - - +
+

Request parameters

+
Parameter Name
+ + @@ -87,7 +87,7 @@ version="1.0"> - + @@ -95,16 +95,16 @@ version="1.0">
Parameter Name Description Required
- - -
-

Response Tags

- - - + + +
+

Response Tags

+
Response Name
+ + - + @@ -112,31 +112,31 @@ version="1.0"> - + - + - - + + - - - - - + + + + +
Response Name Description
- - - + + - - + + + @@ -149,10 +149,10 @@ version="1.0"> - @@ -161,4 +161,3 @@ version="1.0"> - diff --git a/tools/apidoc/generatedomainadmincommands.xsl b/tools/apidoc/generatedomainadmincommands.xsl deleted file mode 100644 index e260b4fab4..0000000000 --- a/tools/apidoc/generatedomainadmincommands.xsl +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - - -Apache CloudStack | The Power Behind Your Cloud - - - -
-
-
-
- -
-
- -
-
- -
- -
- -
-
- - -
- -
- -
-
-
-
- - - - Apache CloudStack v4.6.0 Domain Admin API Reference - -

-

-

-
-
- - -
- -
-
-
-

Request parameters

- - - - - - - - - - - - - - - - - - - - - -
Parameter NameDescriptionRequired
-
- - -
-

Response Tags

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Response NameDescription
- -
- - -
-
- - -
-
- - -
-
- - -
-
- diff --git a/tools/apidoc/generatetoc.xsl b/tools/apidoc/generatetoc.xsl index 2cd1b0059a..687e626a5d 100644 --- a/tools/apidoc/generatetoc.xsl +++ b/tools/apidoc/generatetoc.xsl @@ -25,7 +25,7 @@ version="1.0"> -

Cloudstack API Version 4.6.0

+

Cloudstack API Version 4.9.0


Table of Contents

diff --git a/tools/apidoc/generatetoc_header.xsl b/tools/apidoc/generatetoc_header.xsl index f760430964..6362ab8610 100644 --- a/tools/apidoc/generatetoc_header.xsl +++ b/tools/apidoc/generatetoc_header.xsl @@ -52,7 +52,7 @@ version="1.0">
-

Apache CloudStack API Documentation (v4.6.0)

+

Apache CloudStack API Documentation (v4.9.0)

diff --git a/tools/apidoc/generateusercommands.xsl b/tools/apidoc/generateusercommands.xsl deleted file mode 100644 index c9ec8572e3..0000000000 --- a/tools/apidoc/generateusercommands.xsl +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - - - - -Apache CloudStack | The Power Behind Your Cloud - - - -
-
-
-
-
- -
-
- -
- -
- -
-
- -
- -
- -
-
-
-
- - - - Apache CloudStack v4.6.0 User API Reference - -

-

-

-
-
- - -
- -
-
-
-

Request parameters

-

Name

- - - - - - - - - - - - - - - - - - - - -
Parameter NameDescriptionRequired
- - - -
-

Response Tags

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Response NameDescription
- -
- - - - - - - - - - - - - - - - - diff --git a/tools/apidoc/pom.xml b/tools/apidoc/pom.xml index fb84b7a572..63af063bfc 100644 --- a/tools/apidoc/pom.xml +++ b/tools/apidoc/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloud-tools - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml @@ -61,8 +61,6 @@ ${client.config.jars} ${client.config.jars} ./target - -f - ${client.config.conf}/commands.properties diff --git a/tools/checkstyle/pom.xml b/tools/checkstyle/pom.xml index 1c2655fe9f..c0c39c956d 100644 --- a/tools/checkstyle/pom.xml +++ b/tools/checkstyle/pom.xml @@ -24,13 +24,8 @@ Apache CloudStack Developer Tools - Checkstyle Configuration org.apache.cloudstack checkstyle - 4.8.1-SNAPSHOT - - - - 3.0.4 - - + 4.9.0-SNAPSHOT + diff --git a/tools/devcloud-kvm/pom.xml b/tools/devcloud-kvm/pom.xml index ce01784211..b0e12341c3 100644 --- a/tools/devcloud-kvm/pom.xml +++ b/tools/devcloud-kvm/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloud-tools - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml @@ -83,7 +83,7 @@ org.gjt.mm.mysql.Driver - jdbc:mysql://${db.cloud.host}:${db.cloud.port}/cloud + ${db.cloud.driver}://${db.cloud.host}:${db.cloud.port}/cloud ${db.cloud.username} ${db.cloud.password} diff --git a/tools/devcloud/pom.xml b/tools/devcloud/pom.xml index 38750e5ae1..8644ff45a5 100644 --- a/tools/devcloud/pom.xml +++ b/tools/devcloud/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloud-tools - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml @@ -83,7 +83,7 @@ org.gjt.mm.mysql.Driver - jdbc:mysql://${db.cloud.host}:${db.cloud.port}/cloud + ${db.cloud.driver}://${db.cloud.host}:${db.cloud.port}/cloud ${db.cloud.username} ${db.cloud.password} diff --git a/tools/devcloud4/pom.xml b/tools/devcloud4/pom.xml index 586c195ae9..e3cee0c2b8 100644 --- a/tools/devcloud4/pom.xml +++ b/tools/devcloud4/pom.xml @@ -17,7 +17,7 @@ org.apache.cloudstack cloud-tools - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml @@ -83,7 +83,7 @@ org.gjt.mm.mysql.Driver - jdbc:mysql://${db.cloud.host}:${db.cloud.port}/cloud + ${db.cloud.driver}://${db.cloud.host}:${db.cloud.port}/cloud ${db.cloud.username} ${db.cloud.password} diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index aa7b18ff6c..d044fdd0eb 100644 --- a/tools/marvin/marvin/cloudstackConnection.py +++ b/tools/marvin/marvin/cloudstackConnection.py @@ -143,7 +143,7 @@ def __sign(self, payload): ["=".join( [str.lower(r[0]), str.lower( - urllib.quote_plus(str(r[1])) + urllib.quote_plus(str(r[1]), safe="*") ).replace("+", "%20")] ) for r in params] ) diff --git a/tools/marvin/marvin/codes.py b/tools/marvin/marvin/codes.py index c81e7e901a..e23069bf94 100644 --- a/tools/marvin/marvin/codes.py +++ b/tools/marvin/marvin/codes.py @@ -115,6 +115,31 @@ ''' ALLOCATED = "Allocated" +''' +Host states +''' +HOST_CREATING = "Creating" +HOST_CONNECTING = "Connecting" +HOST_UP = "Up" +HOST_DOWN = "Down" +HOST_DISCONNECTED = "Disconnected" +HOST_ALERT = "Alert" +HOST_REMOVED = "Removed" +HOST_ERROR = "Error" +HOST_REBALANCING = "Rebalancing" +HOST_UNKNOWN = "Unknown" + +''' +Host resource states +''' +HOST_RS_CREATING = "Creating" +HOST_RS_ENABLED = "Enabled" +HOST_RS_DISABLED = "Disabled" +HOST_RS_PREPARE_FOR_MAINTENANCE = "PrepareForMaintenance" +HOST_RS_ERROR_IN_MAINTENANCE = "ErrorInMaintenance" +HOST_RS_MAINTENANCE = "Maintenance" +HOST_RS_ERROR = "Error" + ''' Storage Tags ''' diff --git a/tools/marvin/marvin/config/Baremetal_AdvZone_Vmware.cfg b/tools/marvin/marvin/config/Baremetal_AdvZone_Vmware.cfg new file mode 100644 index 0000000000..a382e33b8f --- /dev/null +++ b/tools/marvin/marvin/config/Baremetal_AdvZone_Vmware.cfg @@ -0,0 +1,208 @@ +# 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. +{ + "zones": [ + { + "name": "ZoneBaremetal", + "guestcidraddress": "10.1.1.0/24", + "providers": [ + { + "broadcastdomainrange": "ZONE", + "name": "VirtualRouter" + } + ], + "dns1": "10.x.x.x", + + "physical_networks": [ + { + "broadcastdomainrange": "Zone", + "name": "Sandbox-pnet", + "vlan": "1020-1025", + "traffictypes": [ + { + "typ": "Guest" + }, + { + "typ": "Management" + }, + { + "typ": "Public" + } + ], + "providers": [ + { + "broadcastdomainrange": "ZONE", + "name": "VirtualRouter" + } + ] + } + ], + "ipranges": [ + { + "startip": "10.x.x.x", + "endip": "10.x.x.x", + "netmask": "255.255.255.0", + "vlan": "1220", + "gateway": "10.x.x.1" + } + ], + "networktype": "Advanced", + "pods": [ + { + "endip": "10.x.x.x", + "name": "POD01", + "startip": "10.x.x.x", + "netmask": "255.255.255.192", + "vmwaredc":{"name":"dc-baremetal","vcenter":"10.x.x.x","username":"Administrator@vsphere.local","password":"Password"}, + "clusters": [ + { + "clustername": "10.x.x.x/dc-baremetal/cluster1", + "hypervisor": "VmWare", + "username": "Administrator@vsphere.local", + "clustertype": "ExternalManaged", + "password": "Password", + "url": "http://10.x.x.x/dc-baremetal/cluster1", + "hosts": [ + { + "username": "root", + "url": "http://10.x.x.x", + "password": "password" + }, + { + "username": "root", + "url": "http://10.x.x.x", + "password": "password" + } + ], + "primaryStorages": [ + { + "url": "nfs://10.x.x.x:/export/home/primary", + "name": "PS0" + } + ] + }, + { + "clustername": "C1", + "hypervisor": "BareMetal", + "hosts": [ + { + "username": "root", + "url": "http://10.x.x.x", + "password": "password", + "hostmac": "xx:xx:xx:xx:xx:xx", + "cpunumber": "1", + "cpuspeed": "1000", + "memory": "1024", + "hosttags": "host15" + } + ], + "clustertype": "CloudManaged" + } + ], + "gateway": "10.x.x.x" + } + ], + "internaldns1": "10.x.x.x", + "baremetalrcturl": "http://10.x.x.x/baremetal/baremetalrct.json", + "secondaryStorages": [ + { + "url": "nfs://10.x.x.x:/export/home/secondary", + "provider": "nfs", + "name":"secondary" + } + ] + } + ], + "logger": { + "LogFolderPath": "/tmp/" + }, + "dbSvr": { + "dbSvr": "10.22.13.12", + "passwd": "password", + "db": "cloud", + "port": 3306, + "user": "root" + }, + + "globalConfig": [ + { + "name": "network.gc.wait", + "value": "60" + }, + { + "name": "storage.cleanup.interval", + "value": "30" + }, + { + "name": "account.cleanup.interval", + "value": "60" + }, + { + "name": "secstorage.allowed.internal.sites", + "value": "10.x.x.0/24" + }, + { + "name": "vm.op.wait.interval", + "value": "5" + }, + { + "name": "network.gc.interval", + "value": "60" + }, + { + "name": "guest.domain.suffix", + "value": "auto.advanced" + }, + { + "name": "expunge.delay", + "value": "60" + }, + { + "name": "vm.allocation.algorithm", + "value": "userdispersing" + }, + { + "name": "expunge.interval", + "value": "60" + }, + { + "name": "instance.name", + "value": "QA" + }, + { + "name": "expunge.workers", + "value": "3" + }, + { + "name": "baremetal.internal.storage.server.ip", + "value": "10.2.1.2" + }, + { + "name": "check.pod.cidrs", + "value": "true" + } + ], + "mgtSvr": [ + { + "mgtSvrIp": "10.22.10.12", + "port": 8096, + "user": "root", + "password": "password", + "hypervisor": "vmware" + } + ] +} diff --git a/tools/marvin/marvin/config/setup.cfg b/tools/marvin/marvin/config/setup.cfg index 23981f0f34..f694bbadae 100644 --- a/tools/marvin/marvin/config/setup.cfg +++ b/tools/marvin/marvin/config/setup.cfg @@ -142,6 +142,10 @@ "LogFolderPath": "/tmp/" }, "globalConfig": [ + { + "name": "quota.enable.service", + "value": "true" + }, { "name": "network.gc.wait", "value": "60" diff --git a/tools/marvin/marvin/config/test_data.py b/tools/marvin/marvin/config/test_data.py index 3d4745d0cd..c9bb7c603d 100644 --- a/tools/marvin/marvin/config/test_data.py +++ b/tools/marvin/marvin/config/test_data.py @@ -735,6 +735,34 @@ "publicport": 22, "protocol": 'TCP' }, + "internal_lbrule": { + "name": "SSH", + "algorithm": "roundrobin", + # Algorithm used for load balancing + "sourceport": 22, + "instanceport": 22, + "scheme": "internal", + "protocol": "TCP", + "cidrlist": '0.0.0.0/0', + }, + "internal_lbrule_http": { + "name": "HTTP", + "algorithm": "roundrobin", + # Algorithm used for load balancing + "sourceport": 80, + "instanceport": 80, + "scheme": "internal", + "protocol": "TCP", + "cidrlist": '0.0.0.0/0', + }, + "http_rule": { + "privateport": 80, + "publicport": 80, + "startport": 80, + "endport": 80, + "protocol": "TCP", + "cidrlist": '0.0.0.0/0', + }, "icmprule": { "icmptype": -1, "icmpcode": -1, @@ -1695,5 +1723,101 @@ "ostype": 'CentOS 5.3 (64-bit)', "mode": 'HTTP_DOWNLOAD' } + }, + # Nuage VSP SDN plugin specific test data + "nuagevsp": { + # Services supported by the Nuage VSP plugin for Isolated networks + "isolated_network_offering": { + "name": 'nuage_marvin', + "displaytext": 'nuage_marvin', + "guestiptype": 'Isolated', + "supportedservices": 'Dhcp,SourceNat,Connectivity,StaticNat,UserData,Firewall', + "traffictype": 'GUEST', + "availability": 'Optional', + "serviceProviderList": { + "Dhcp": 'NuageVsp', + "StaticNat": 'NuageVsp', + "SourceNat": 'NuageVsp', + "Firewall": 'NuageVsp', + "Connectivity": 'NuageVsp', + "UserData": 'VirtualRouter' + }, + "serviceCapabilityList": { + "SourceNat": {"SupportedSourceNatTypes": "perzone"} + } + }, + # Services supported by the Nuage VSP plugin for VPC networks + "vpc_network_offering": { + "name": 'nuage_vpc_marvin', + "displaytext": 'nuage_vpc_marvin', + "guestiptype": 'Isolated', + "supportedservices": 'Dhcp,StaticNat,SourceNat,NetworkACL,Connectivity,UserData', + "traffictype": 'GUEST', + "availability": 'Optional', + "useVpc": 'on', + "ispersistent": 'True', + "serviceProviderList": { + "Dhcp": "NuageVsp", + "StaticNat": "NuageVsp", + "SourceNat": "NuageVsp", + "NetworkACL": "NuageVsp", + "Connectivity": "NuageVsp", + "UserData": "VpcVirtualRouter" + }, + "serviceCapabilityList": { + "SourceNat": {"SupportedSourceNatTypes": "perzone"} + } + }, + "vpc_network_offering_internal_lb": { + "name": "nuage_vpc_marvin_internal_lb", + "displaytext": "nuage_vpc_marvin_internal_lb", + "guestiptype": 'Isolated', + "supportedservices": 'Dhcp,Lb,StaticNat,SourceNat,NetworkACL,Connectivity,UserData', + "traffictype": 'GUEST', + "availability": 'Optional', + "useVpc": 'on', + "ispersistent": 'True', + "serviceProviderList": { + "Dhcp": "NuageVsp", + "Lb": "InternalLbVm", + "StaticNat": "NuageVsp", + "SourceNat": "NuageVsp", + "NetworkACL": "NuageVsp", + "Connectivity": "NuageVsp", + "UserData": "VpcVirtualRouter" + }, + "serviceCapabilityList": { + "SourceNat": {"SupportedSourceNatTypes": "perzone"}, + "Lb": {"lbSchemes": "internal", "SupportedLbIsolation": "dedicated"} + } + }, + # Services supported by the Nuage VSP plugin for VPCs + "vpc_offering": { + "name": 'Nuage VSP VPC offering', + "displaytext": 'Nuage VSP VPC offering', + "supportedservices": 'Dhcp,StaticNat,SourceNat,NetworkACL,Connectivity,UserData', + "serviceProviderList": { + "Dhcp": "NuageVsp", + "StaticNat": "NuageVsp", + "SourceNat": "NuageVsp", + "NetworkACL": "NuageVsp", + "Connectivity": "NuageVsp", + "UserData": "VpcVirtualRouter" + } + }, + "vpc_offering_lb": { + "name": 'Nuage VSP VPC offering with Lb', + "displaytext": 'Nuage VSP VPC offering with Lb', + "supportedservices": 'Dhcp,Lb,StaticNat,SourceNat,NetworkACL,Connectivity,UserData', + "serviceProviderList": { + "Dhcp": "NuageVsp", + "Lb": "InternalLbVm", + "StaticNat": "NuageVsp", + "SourceNat": "NuageVsp", + "NetworkACL": "NuageVsp", + "Connectivity": "NuageVsp", + "UserData": "VpcVirtualRouter" + } } + } } diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index 91b30a6587..24133289ed 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -133,6 +133,12 @@ def addHosts(self, hosts, zoneId, podId, clusterId, hypervisor): hostcmd.username = host.username hostcmd.zoneid = zoneId hostcmd.hypervisor = hypervisor + if hostcmd.hypervisor.lower() == "baremetal": + hostcmd.hostmac=host.hostmac + hostcmd.cpunumber=host.cpunumber + hostcmd.cpuspeed=host.cpuspeed + hostcmd.memory=host.memory + hostcmd.hosttags=host.hosttags ret = self.__apiClient.addHost(hostcmd) if ret: self.__tcRunLogger.debug("=== Add Host Successful ===") @@ -164,6 +170,25 @@ def addVmWareDataCenter(self, vmwareDc): self.__tcRunLogger.exception("=== Adding VmWare DC Failed===") self.__cleanAndExit() + def addBaremetalRct(self, config): + networktype= config.zones[0].networktype + baremetalrcturl= config.zones[0].baremetalrcturl + if networktype is None or baremetalrcturl is None: + return + if networktype.lower()=="advanced": + + try: + brctcmd = addBaremetalRct.addBaremetalRctCmd() + brctcmd.baremetalrcturl=baremetalrcturl + ret = self.__apiClient.addBaremetalRct(brctcmd) + if ret.id: + self.__tcRunLogger.debug("=== Adding Baremetal Rct file Successful===") + self.__addToCleanUp("BaremetalRct", ret.id) + except Exception as e: + print "Exception Occurred: %s" % GetDetailExceptionInfo(e) + self.__tcRunLogger.exception("=== Adding Baremetal Rct file Failed===") + self.__cleanAndExit() + def createClusters(self, clusters, zoneId, podId, vmwareDc=None): try: if clusters is None: @@ -193,10 +218,12 @@ def createClusters(self, clusters, zoneId, podId, vmwareDc=None): self.addHosts(cluster.hosts, zoneId, podId, clusterId, cluster.hypervisor) self.waitForHost(zoneId, clusterId) - self.createPrimaryStorages(cluster.primaryStorages, - zoneId, - podId, - clusterId) + if cluster.hypervisor.lower() != "baremetal": + self.createPrimaryStorages(cluster.primaryStorages, + zoneId, + podId, + clusterId) + except Exception as e: print "Exception Occurred %s" % GetDetailExceptionInfo(e) self.__tcRunLogger.exception("====Cluster %s Creation Failed" @@ -534,7 +561,7 @@ def configureProviders(self, phynetwrk, providers): netprov.physicalnetworkid = phynetwrk.id result = self.__apiClient.addNetworkServiceProvider(netprov) self.enableProvider(result.id) - elif provider.name in ['Netscaler', 'JuniperSRX', 'F5BigIp', 'NiciraNvp']: + elif provider.name in ['Netscaler', 'JuniperSRX', 'F5BigIp', 'NiciraNvp', 'NuageVsp']: netprov = addNetworkServiceProvider.\ addNetworkServiceProviderCmd() netprov.name = provider.name @@ -604,6 +631,21 @@ def configureProviders(self, phynetwrk, providers): self.__tcRunLogger.\ debug("==== AddNiciraNvp Successful =====") self.__addToCleanUp("NiciraNvp", ret.id) + elif provider.name == 'NuageVsp': + dev = addNuageVspDevice.addNuageVspDeviceCmd() + dev.hostname = device.hostname + dev.port = device.port + dev.username = device.username + dev.password = device.password + dev.retrycount = device.retrycount + dev.retryinterval = device.retryinterval + dev.physicalnetworkid = phynetwrk.id + ret = self.__apiClient.addNuageVspDevice(dev) + if ret.id: + self.__tcRunLogger.\ + debug("==== addNuageVspDevice " + "Successful=====") + self.__addToCleanUp("addNuageVspDevice", ret.id) else: raise InvalidParameterException( "Device %s doesn't match " @@ -888,6 +930,12 @@ def deploy(self): self.__persistDcConfig() print "\n====Deploy DC Successful=====" self.__tcRunLogger.debug("\n====Deploy DC Successful====") + ''' + Upload baremetalSwitch configuration(.rct) file if enabled zone has baremetal isolated network. + ''' + self.addBaremetalRct(self.__config) + self.__tcRunLogger.debug("\n==== AddbaremetalRct Successful====") + return SUCCESS except Exception as e: print "\nException Occurred Under deploy :%s" % \ diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index 835613d701..1be0a3c209 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -23,9 +23,10 @@ from marvin.cloudstackAPI import * from marvin.codes import (FAILED, FAIL, PASS, RUNNING, STOPPED, STARTING, DESTROYED, EXPUNGING, - STOPPING, BACKED_UP, BACKING_UP) + STOPPING, BACKED_UP, BACKING_UP, + HOST_RS_MAINTENANCE) from marvin.cloudstackException import GetDetailExceptionInfo, CloudstackAPIException -from marvin.lib.utils import validateList, is_server_ssh_ready, random_gen +from marvin.lib.utils import validateList, is_server_ssh_ready, random_gen, wait_until # Import System modules import time import hashlib @@ -86,13 +87,96 @@ def list(cls, apiclient, **kwargs): return(apiclient.listDomains(cmd)) +class Role: + """Manage Role""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, domainid=None): + """Create role""" + cmd = createRole.createRoleCmd() + cmd.name = services["name"] + cmd.type = services["type"] + if "description" in services: + cmd.description = services["description"] + + return Role(apiclient.createRole(cmd).__dict__) + + def delete(self, apiclient): + """Delete Role""" + + cmd = deleteRole.deleteRoleCmd() + cmd.id = self.id + apiclient.deleteRole(cmd) + + def update(self, apiclient, **kwargs): + """Update the role""" + + cmd = updateRole.updateRoleCmd() + cmd.id = self.id + [setattr(cmd, k, v) for k, v in kwargs.items()] + return apiclient.updateRole(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all Roles matching criteria""" + + cmd = listRoles.listRolesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listRoles(cmd)) + + +class RolePermission: + """Manage Role Permission""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def create(cls, apiclient, services, domainid=None): + """Create role permission""" + cmd = createRolePermission.createRolePermissionCmd() + cmd.roleid = services["roleid"] + cmd.rule = services["rule"] + cmd.permission = services["permission"] + if "description" in services: + cmd.description = services["description"] + + return RolePermission(apiclient.createRolePermission(cmd).__dict__) + + def delete(self, apiclient): + """Delete role permission""" + + cmd = deleteRolePermission.deleteRolePermissionCmd() + cmd.id = self.id + apiclient.deleteRolePermission(cmd) + + def update(self, apiclient, **kwargs): + """Update the role permission""" + + cmd = updateRolePermission.updateRolePermissionCmd() + cmd.roleid = self.roleid + [setattr(cmd, k, v) for k, v in kwargs.items()] + return apiclient.updateRolePermission(cmd) + + @classmethod + def list(cls, apiclient, **kwargs): + """List all role permissions matching criteria""" + + cmd = listRolePermissions.listRolePermissionsCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listRolePermissions(cmd)) + + class Account: """ Account Life Cycle """ def __init__(self, items): self.__dict__.update(items) @classmethod - def create(cls, apiclient, services, admin=False, domainid=None): + def create(cls, apiclient, services, admin=False, domainid=None, roleid=None): """Creates an account""" cmd = createAccount.createAccountCmd() @@ -120,6 +204,10 @@ def create(cls, apiclient, services, admin=False, domainid=None): if domainid: cmd.domainid = domainid + + if roleid: + cmd.roleid = roleid + account = apiclient.createAccount(cmd) return Account(account.__dict__) @@ -1205,8 +1293,8 @@ def create_from_snapshot(cls, apiclient, snapshot, services, random_gen() ]) if random_name else services["name"] - if services["ispublic"]: - cmd.ispublic = services["ispublic"] + if "ispublic" in services: + cmd.ispublic = services["ispublic"] if "ostypeid" in services: cmd.ostypeid = services["ostypeid"] @@ -2459,26 +2547,46 @@ def create(cls, apiclient, cluster, services, zoneid=None, podid=None, hyperviso GetDetailExceptionInfo(e) return FAILED + @staticmethod + def _check_resource_state(apiclient, hostid, resourcestate): + hosts = Host.list(apiclient, id=hostid, listall=True) + + validationresult = validateList(hosts) + + assert validationresult is not None, "'validationresult' should not be equal to 'None'." + + assert isinstance(validationresult, list), "'validationresult' should be a 'list'." + + assert len(validationresult) == 3, "'validationresult' should be a list with three items in it." + + if validationresult[0] == FAIL: + raise Exception("Host list validation failed: %s" % validationresult[2]) + + if str(hosts[0].resourcestate).lower().decode("string_escape") == str(resourcestate).lower(): + return True, None + + return False, "Host is not in the following state: " + str(resourcestate) + def delete(self, apiclient): """Delete Host""" # Host must be in maintenance mode before deletion cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() cmd.id = self.id apiclient.prepareHostForMaintenance(cmd) - time.sleep(30) + + retry_interval = 10 + num_tries = 10 + + wait_result, return_val = wait_until(retry_interval, num_tries, Host._check_resource_state, apiclient, self.id, HOST_RS_MAINTENANCE) + + if not wait_result: + raise Exception(return_val) cmd = deleteHost.deleteHostCmd() cmd.id = self.id apiclient.deleteHost(cmd) return - def enableMaintenance(self, apiclient): - """enables maintenance mode Host""" - - cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd() - cmd.id = self.id - return apiclient.prepareHostForMaintenance(cmd) - @classmethod def enableMaintenance(cls, apiclient, id): """enables maintenance mode Host""" @@ -2487,13 +2595,6 @@ def enableMaintenance(cls, apiclient, id): cmd.id = id return apiclient.prepareHostForMaintenance(cmd) - def cancelMaintenance(self, apiclient): - """Cancels maintenance mode Host""" - - cmd = cancelHostMaintenance.cancelHostMaintenanceCmd() - cmd.id = self.id - return apiclient.cancelHostMaintenance(cmd) - @classmethod def cancelMaintenance(cls, apiclient, id): """Cancels maintenance mode Host""" @@ -2643,13 +2744,6 @@ def delete(self, apiclient): apiclient.deleteStoragePool(cmd) return - def enableMaintenance(self, apiclient): - """enables maintenance mode Storage pool""" - - cmd = enableStorageMaintenance.enableStorageMaintenanceCmd() - cmd.id = self.id - return apiclient.enableStorageMaintenance(cmd) - @classmethod def enableMaintenance(cls, apiclient, id): """enables maintenance mode Storage pool""" @@ -2711,7 +2805,7 @@ def getState(cls, apiclient, poolid, state, timeout=600): id=poolid, listAll=True) validationresult = validateList(pools) if validationresult[0] == FAIL: - raise Exception("Host list validation failed: %s" % validationresult[2]) + raise Exception("Pool list validation failed: %s" % validationresult[2]) elif str(pools[0].state).lower().decode("string_escape") == str(state).lower(): returnValue = [PASS, None] break @@ -3961,6 +4055,61 @@ def list(cls, apiclient, **kwargs): return(apiclient.listNetworkServiceProviders(cmd)) +class Nuage: + """Manage external nuage VSD device""" + + def __init__(self, items): + self.__dict__.update(items) + + @classmethod + def add(cls, apiclient, services, physicalnetworkid, username=None, password=None): + """Add external nuage VSD device to cloudstack""" + + cmd = addNuageVspDevice.addNuageVspDeviceCmd() + cmd.physicalnetworkid = physicalnetworkid + if username: + cmd.username = username + else: + cmd.username = services["username"] + + if password: + cmd.password = password + else: + cmd.password = services["password"] + + cmd.hostname = services["hostname"] + cmd.port = services["port"] + cmd.retrycount = services["retrycount"] + cmd.retryinterval = services["retryinterval"] + cmd.apiversion = services["apiversion"] + + return Nuage(apiclient.addNuageVspDevice(cmd).__dict__) + + def update(self, apiclient, **kwargs): + """Deletes a nuage VSD device from CloudStack""" + + cmd = updateNuageVspDevice.updateNuageVspDeviceCmd() + cmd.physicalnetworkid = self.physicalnetworkid + [setattr(cmd, k, v) for k, v in kwargs.items()] + return apiclient.updateNuageVspDevice(cmd) + + def delete(self, apiclient): + """Deletes a nuage VSD device from CloudStack""" + + cmd = deleteNuageVspDevice.deleteNuageVspDeviceCmd() + cmd.vspdeviceid = self.vspdeviceid + apiclient.deleteNuageVspDevice(cmd) + return + + @classmethod + def list(cls, apiclient, **kwargs): + """List already registered netscaler devices""" + + cmd = listNuageVspDevices.listNuageVspDevicesCmd() + [setattr(cmd, k, v) for k, v in kwargs.items()] + return(apiclient.listNuageVspDevices(cmd)) + + class Router: """Manage router life cycle""" @@ -4622,7 +4771,7 @@ def __init__(self, items): @classmethod def create(cls, apiclient, services, name=None, sourceport=None, instanceport=22, algorithm="roundrobin", scheme="internal", - sourcenetworkid=None, networkid=None): + sourcenetworkid=None, networkid=None, sourceipaddress=None): """Create Application Load Balancer""" cmd = createLoadBalancer.createLoadBalancerCmd() @@ -4661,6 +4810,11 @@ def create(cls, apiclient, services, name=None, sourceport=None, elif networkid: cmd.networkid = networkid + if "sourceipaddress" in services: + cmd.sourceipaddress = services["sourceipaddress"] + elif sourceipaddress: + cmd.sourceipaddress = sourceipaddress + return LoadBalancerRule(apiclient.createLoadBalancer(cmd).__dict__) def delete(self, apiclient): diff --git a/tools/marvin/marvin/lib/utils.py b/tools/marvin/marvin/lib/utils.py index 97b80ac308..68fb336901 100644 --- a/tools/marvin/marvin/lib/utils.py +++ b/tools/marvin/marvin/lib/utils.py @@ -520,4 +520,24 @@ def verifyRouterState(apiclient, routerid, allowedstates): if routers[0].state.lower() not in allowedstates: return [FAIL, "state of the router should be in %s but is %s" % (allowedstates, routers[0].state)] - return [PASS, None] \ No newline at end of file + return [PASS, None] + + +def wait_until(retry_interval=2, no_of_times=2, callback=None, *callback_args): + """ Utility method to try out the callback method at most no_of_times with a interval of retry_interval, + Will return immediately if callback returns True. The callback method should be written to return a list of values first being a boolean """ + + if callback is None: + raise ("Bad value for callback method !") + + wait_result = False + for i in range(0,no_of_times): + time.sleep(retry_interval) + wait_result, return_val = callback(*callback_args) + if not(isinstance(wait_result, bool)): + raise ("Bad parameter returned from callback !") + if wait_result : + break + + return wait_result, return_val + diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index e9c8c78347..391987be4b 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloud-tools - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/tools/marvin/setup.py b/tools/marvin/setup.py index 43bc454424..7f3d9c8ca3 100644 --- a/tools/marvin/setup.py +++ b/tools/marvin/setup.py @@ -27,7 +27,7 @@ raise RuntimeError("python setuptools is required to build Marvin") -VERSION = "4.8.1-SNAPSHOT" +VERSION = "4.9.0-SNAPSHOT" setup(name="Marvin", version=VERSION, @@ -52,7 +52,8 @@ "nose >= 1.3.3", "ddt >= 0.4.0", "pyvmomi >= 5.5.0", - "netaddr >= 0.7.14" + "netaddr >= 0.7.14", + "ipmisim >= 0.7" ], py_modules=['marvin.marvinPlugin'], zip_safe=False, diff --git a/tools/pom.xml b/tools/pom.xml index 6c8577f424..02ad3185db 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -27,7 +27,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml diff --git a/tools/transifex/.tx/config b/tools/transifex/.tx/config index 9804e76f86..fa4bc1f4d4 100644 --- a/tools/transifex/.tx/config +++ b/tools/transifex/.tx/config @@ -108,3 +108,22 @@ trans.pt_BR = work-dir/messages_pt_BR.properties trans.ru_RU = work-dir/messages_ru_RU.properties trans.zh_CN = work-dir/messages_zh_CN.properties +[CloudStack_UI.49xmessagesproperties] +source_file = work-dir/messages.properties +source_lang = en +trans.ar = work-dir/messages_ar.properties +trans.ca = work-dir/messages_ca.properties +trans.de_DE = work-dir/messages_de_DE.properties +trans.es = work-dir/messages_es.properties +trans.fr_FR = work-dir/messages_fr_FR.properties +trans.hu = work-dir/messages_hu.properties +trans.it_IT = work-dir/messages_it_IT.properties +trans.ja_JP = work-dir/messages_ja_JP.properties +trans.ko_KR = work-dir/messages_ko_KR.properties +trans.nb_NO = work-dir/messages_nb_NO.properties +trans.nl_NL = work-dir/messages_nl_NL.properties +trans.pl = work-dir/messages_pl.properties +trans.pt_BR = work-dir/messages_pt_BR.properties +trans.ru_RU = work-dir/messages_ru_RU.properties +trans.zh_CN = work-dir/messages_zh_CN.properties + diff --git a/tools/travis/before_install.sh b/tools/travis/before_install.sh index b90a0999c4..99195c265a 100755 --- a/tools/travis/before_install.sh +++ b/tools/travis/before_install.sh @@ -49,12 +49,21 @@ javac -version echo -e "\nMaven Version: " mvn -v +echo -e "\nPython Version: " +python --version + +echo -e "\nPip Version: " +pip --version + echo -e "\nDisk Status: " df echo -e "\nMemory Status: " free +echo -e "\nTotal CPUs: " +nproc + echo -e "\nCheck Git status" git status @@ -66,21 +75,30 @@ sudo apt-get -q -y update > /dev/null echo -e "\nInstalling MySQL: " -sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password your_password' -sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password your_password' +export DEBIAN_FRONTEND=noninteractive +sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password password' +sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password password' sudo apt-get -q -y install mysql-server > /dev/null -#Restart mysql if running to release deleted file locks on filesystem, if aready running -sudo status mysql | grep start && sudo stop mysql -sudo start mysql +mysql -uroot -ppassword -e "SET PASSWORD = PASSWORD(''); FLUSH PRIVILEGES;" +sudo service mysql restart echo -e "\nInstalling Development tools: " RETRY_COUNT=3 -sudo apt-get -q -y install uuid-runtime genisoimage python-setuptools python-pip netcat > /dev/null +sudo apt-get -q -y install uuid-runtime genisoimage netcat > /dev/null if [[ $? -ne 0 ]]; then echo -e "\napt-get packages failed to install" fi + +# Use latest ipmitool 1.8.16 +sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1397BC53640DB551 +sudo sh -c 'echo "deb http://archive.ubuntu.com/ubuntu xenial main universe" >> /etc/apt/sources.list' +sudo apt-get update -q -y > /dev/null +sudo apt-get -q -y -V install freeipmi-common libfreeipmi16 libgcrypt20 libgpg-error-dev libgpg-error0 libopenipmi0 ipmitool --no-install-recommends > /dev/null + +ipmitool -V + echo " @@ -94,9 +112,11 @@ echo " echo -e "\nInstalling some python packages: " +pip install --user --upgrade pip + for ((i=0;i<$RETRY_COUNT;i++)) do - sudo pip install --upgrade lxml texttable paramiko > /tmp/piplog + pip install --user --upgrade lxml paramiko nose texttable ipmisim > /tmp/piplog if [[ $? -eq 0 ]]; then echo -e "\npython packages installed successfully" break; diff --git a/tools/travis/before_script.sh b/tools/travis/before_script.sh index 40e67001a2..beb8acc89a 100755 --- a/tools/travis/before_script.sh +++ b/tools/travis/before_script.sh @@ -41,4 +41,4 @@ mvn -Dsimulator -pl :cloud-client-ui jetty:run 2>&1 > /tmp/jetty-log & while ! nc -vzw 5 localhost 8096 2>&1 > /dev/null; do grep Exception /tmp/jetty-log; sleep 10; done echo -e "\nStarting DataCenter deployment" -python -m marvin.deployDataCenter -i setup/dev/advanced.cfg 2>&1 || true +python tools/marvin/marvin/deployDataCenter.py -i setup/dev/advanced.cfg 2>&1 || true diff --git a/tools/travis/install.sh b/tools/travis/install.sh index 28f4ed4fbe..bbea5503df 100755 --- a/tools/travis/install.sh +++ b/tools/travis/install.sh @@ -34,24 +34,19 @@ if [ $MOD -ne 0 ]; then fi fi -export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=500m -Djava.security.egd=file:/dev/./urandom" +export MAVEN_OPTS="-Xmx2048m -XX:MaxPermSize=500m -Djava.security.egd=file:/dev/./urandom" if [ $TEST_SEQUENCE_NUMBER -eq 1 ]; then - mvn -q -Pimpatient -Dsimulator clean install + mvn -Pdeveloper,systemvm -Dsimulator clean install -T4 | egrep "Building|Tests|SUCCESS|FAILURE" else - mvn -q -Pimpatient -Dsimulator clean install -DskipTests=true + mvn -Pdeveloper -Dsimulator clean install -DskipTests=true -T4 | egrep "Building|Tests|SUCCESS|FAILURE" fi -# Compile API Docs -cd tools/apidoc -mvn -q clean install -cd ../../ +# Install mysql-connector-python +pip install --user --upgrade http://cdn.mysql.com/Downloads/Connector-Python/mysql-connector-python-2.0.4.zip#md5=3df394d89300db95163f17c843ef49df 2>&1 > /dev/null -# Compile marvin -cd tools/marvin -mvn -q clean install -sudo python setup.py install 2>&1 > /dev/null -cd ../../ +# Install marvin +pip install --user --upgrade tools/marvin/dist/Marvin-*.tar.gz # Deploy the database mvn -q -Pdeveloper -pl developer -Ddeploydb diff --git a/tools/travis/script.sh b/tools/travis/script.sh index 7e7c497016..dc955b004c 100755 --- a/tools/travis/script.sh +++ b/tools/travis/script.sh @@ -37,10 +37,11 @@ fi mkdir -p integration-test-results/smoke/misc mkdir -p integration-test-results/component +TESTS=($@) +echo "Running tests: " ${TESTS[@]} -for suite in $1; do +for suite in "${TESTS[@]}" ; do nosetests --with-xunit --xunit-file=integration-test-results/$suite.xml --with-marvin --marvin-config=setup/dev/advanced.cfg test/integration/$suite.py -s -a tags=advanced,required_hardware=false --zone=Sandbox-simulator --hypervisor=simulator || true ; done - python ./tools/travis/xunit-reader.py integration-test-results/ diff --git a/tools/travis/xunit-reader.py b/tools/travis/xunit-reader.py index c492c01e44..80e228b382 100755 --- a/tools/travis/xunit-reader.py +++ b/tools/travis/xunit-reader.py @@ -61,6 +61,8 @@ def _generate_args(): def _generate_file_list(args): path = args.pop('path') file_path_list = [] + if path.endswith('.xml') and os.path.isfile(path): + file_path_list.append(path) for (root, dirnames, filenames) in os.walk(path): for filename in filenames: if filename.endswith('.xml'): @@ -71,7 +73,7 @@ def _generate_file_list(args): def parse_reports(file_path_list): table = texttable.Texttable() - table.header(['Test', 'Result']) + table.header(['Test', 'Result', 'Time']) exit_code = 0 @@ -80,16 +82,24 @@ def parse_reports(file_path_list): for event, elem in data: name = '' status = 'Success' + time = '' if 'name' in elem.attrib: name = elem.attrib['name'] + if 'time' in elem.attrib: + time = elem.attrib['time'] for children in elem.getchildren(): if 'skipped' == children.tag: status = 'Skipped' elif 'failure' == children.tag: exit_code = 1 status = 'Failure' + elif 'error' == children.tag: + exit_code = 1 + status = 'Error' + if 'type' in children.attrib: + status = children.attrib['type'] - table.add_row([name, status]) + table.add_row([name, status, time]) print table.draw() diff --git a/tools/whisker/LICENSE b/tools/whisker/LICENSE index 61ebc50f10..da8aaedfd9 100644 --- a/tools/whisker/LICENSE +++ b/tools/whisker/LICENSE @@ -2896,7 +2896,7 @@ Within the target/jar directory cloud-axis.jar from http://axis.apache.org/axis/ cloud-cglib.jar from http://cglib.sourceforge.net/ cloud-commons-codec-1.5.jar from http://commons.apache.org/codec/ - cloud-commons-collections-3.2.1.jar from http://commons.apache.org/collections/ + cloud-commons-collections-3.2.2.jar from http://commons.apache.org/collections/ cloud-commons-configuration-1.8.jar from http://commons.apache.org/configuration/ cloud-commons-dbcp-1.4.jar from http://commons.apache.org/dbcp/ cloud-commons-httpclient-3.1.jar from http://hc.apache.org/httpclient-3.x/ diff --git a/tools/whisker/descriptor-for-packaging.xml b/tools/whisker/descriptor-for-packaging.xml index 1a68a0d9c5..01e60269f4 100644 --- a/tools/whisker/descriptor-for-packaging.xml +++ b/tools/whisker/descriptor-for-packaging.xml @@ -2673,7 +2673,7 @@ Copyright (C) 2008 Tóth István <stoty@tvnet.hu> 2009-2011 Bryan Kearney <bkearney@redhat.com> - + @@ -2683,7 +2683,7 @@ Copyright (c) 2012 The Apache Software Foundation - + diff --git a/tools/wix-cloudstack-maven-plugin/pom.xml b/tools/wix-cloudstack-maven-plugin/pom.xml index 6359537e22..deb4284b3d 100644 --- a/tools/wix-cloudstack-maven-plugin/pom.xml +++ b/tools/wix-cloudstack-maven-plugin/pom.xml @@ -16,7 +16,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../../pom.xml diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index a211a6e1ba..16ee0b7baa 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -2904,6 +2904,15 @@ div.detail-group.actions td { background-position: -366px -239px; } +#navigation ul li.roles span.icon { + background-position: -460px -80px; +} + +#navigation ul li.roles.active span.icon, +#navigation ul li.roles:hover span.icon { + background-position: -469px -750px; +} + #navigation ul li.accounts span.icon { background-position: -458px -19px; } @@ -3555,7 +3564,7 @@ div.toolbar div.section-switcher div.section-select label { /*Breadcrumbs*/ div.toolbar div.filters { margin: 5px 0px 0 12px; - width: 168px; + width: 200px; float: left; } @@ -12694,6 +12703,54 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it background-position: -137px -614px; } +.blankOutOfBandManagement .icon { + background-position: -266px -31px; +} + +.blankOutOfBandManagement:hover .icon { + background-position: -266px -31px; +} + +.configureOutOfBandManagement .icon { + background-position: -168px -31px; +} + +.configureOutOfBandManagement:hover .icon { + background-position: -168px -613px; +} + +.enableOutOfBandManagement .icon { + background-position: -138px -65px; +} + +.enableOutOfBandManagement:hover .icon { + background-position: -138px -647px; +} + +.disableOutOfBandManagement .icon { + background-position: -138px -123px; +} + +.disableOutOfBandManagement:hover .icon { + background-position: -138px -705px; +} + +.issueOutOfBandManagementPowerAction .icon { + background-position: -266px -3px; +} + +.issueOutOfBandManagementPowerAction:hover .icon { + background-position: -265px -584px; +} + +.changeOutOfBandManagementPassword .icon { + background-position: -68px -30px; +} + +.changeOutOfBandManagementPassword:hover .icon { + background-position: -68px -612px; +} + .enableMaintenanceMode .icon { background-position: -138px -65px; } @@ -13162,3 +13219,10 @@ div.gpugroups div.list-view { background: transparent url("../images/icons.png") no-repeat -626px -209px; padding: 0 0 3px 18px; } + +ul.ui-autocomplete.ui-menu { + width: 250px; + background: #ddd; + font-size: 13px; + padding: 5px; +} diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp index b97141ca3b..b0642997d2 100644 --- a/ui/dictionary.jsp +++ b/ui/dictionary.jsp @@ -871,6 +871,7 @@ dictionary = { 'label.metrics.property': '', 'label.metrics.scope': '', 'label.metrics.state': '', +'label.metrics.outofbandmanagementpowerstate': '', 'label.metrics.storagepool': '', 'label.metrics.vm.name': '', 'label.migrate.instance.to': '', @@ -987,6 +988,26 @@ dictionary = { 'label.port.forwarding': '', 'label.port.forwarding.policies': '', 'label.port.range': '', +'label.powerstate': '', +'label.outofbandmanagement': '', +'label.outofbandmanagement.action.issue': '', +'label.outofbandmanagement.action': '', +'label.outofbandmanagement.address': '', +'label.outofbandmanagement.changepassword': '', +'label.outofbandmanagement.configure': '', +'label.outofbandmanagement.driver': '', +'label.outofbandmanagement.disable': '', +'label.outofbandmanagement.enable': '', +'label.outofbandmanagement.password': '', +'label.outofbandmanagement.port': '', +'label.outofbandmanagement.timeout': '', +'label.outofbandmanagement.username': '', +'message.outofbandmanagement.changepassword': '', +'message.outofbandmanagement.configure': '', +'message.outofbandmanagement.disable': '', +'message.outofbandmanagement.enable': '', +'message.outofbandmanagement.issue': '', +'message.outofbandmanagement.action.maintenance': '', 'label.PreSetup': '', 'label.prev': '', 'label.previous': '', @@ -1120,7 +1141,14 @@ dictionary = { 'label.retry.interval': '', 'label.review': '', 'label.revoke.project.invite': '', +'label.permission': '', 'label.role': '', +'label.roles': '', +'label.roletype': '', +'label.add.role': '', +'label.edit.role': '', +'label.delete.role': '', +'message.role.ordering.fail': '', 'label.root.disk.controller': '', 'label.root.disk.offering': '', 'message.configure.firewall.rules.allow.traffic': '', diff --git a/ui/dictionary2.jsp b/ui/dictionary2.jsp index 4268104d82..f919b156d7 100644 --- a/ui/dictionary2.jsp +++ b/ui/dictionary2.jsp @@ -26,6 +26,7 @@ under the License. + diff --git a/ui/plugins/plugins.js b/ui/plugins/plugins.js index b629e3095b..21da7a07f4 100644 --- a/ui/plugins/plugins.js +++ b/ui/plugins/plugins.js @@ -16,7 +16,7 @@ // under the License. (function($, cloudStack) { cloudStack.plugins = [ - 'quota', - //'testPlugin' + //'testPlugin', + 'quota' ]; }(jQuery, cloudStack)); diff --git a/ui/plugins/quota/quota.js b/ui/plugins/quota/quota.js index 94a8730b5e..4505b9687e 100644 --- a/ui/plugins/quota/quota.js +++ b/ui/plugins/quota/quota.js @@ -25,12 +25,18 @@ id: 'quota', title: 'Quota', preFilter: function(args) { - var retval = $.ajax({ - url: createURL("quotaIsEnabled"), - async: false + var pluginEnabled = false; + $.ajax({ + url: createURL("quotaIsEnabled"), + async: false, + success: function(json) { + pluginEnabled = json.quotaisenabledresponse.isenabled.isenabled; + }, + error: function(data) { + pluginEnabled = false; + } }); - var json = JSON.parse(retval.responseText); - return json.quotaisenabledresponse.isenabled.isenabled; + return pluginEnabled; }, showOnNavigation: true, sectionSelect: { @@ -79,9 +85,9 @@ indicator: { 'enabled': 'on', 'disabled': 'off', - 'locked': 'off', + 'locked': 'off' } - }, + } }, dataProvider: function(args) { var data = { @@ -171,7 +177,7 @@ label: 'label.quota.enforcequota', isBoolean: true, isChecked: false - }, + } } }, @@ -196,7 +202,7 @@ }); $(window).trigger('cloudStack.fullRefresh'); } - }, + } }, tabs: { details: { @@ -207,10 +213,10 @@ } }, { startdate: { - label: 'label.quota.date', + label: 'label.quota.date' }, startquota: { - label: 'label.quota.value', + label: 'label.quota.value' } }], dataProvider: function(args) { @@ -235,8 +241,7 @@ } }); } - }, - + } } } } @@ -277,9 +282,9 @@ indicator: { 'enabled': 'on', 'disabled': 'off', - 'locked': 'off', + 'locked': 'off' } - }, + } }, dataProvider: function(args) { var data = { @@ -329,13 +334,6 @@ }); }, detailView: { - viewAll: [{ - path: 'quota.quotastatement', - label: 'label.quota.statement.quota' - },{ - path: 'quota.balancestatement', - label: 'label.quota.statement.balance' - }], actions: { add: { label: 'label.quota.add.credits', @@ -369,7 +367,7 @@ label: 'label.quota.enforcequota', isBoolean: true, isChecked: false - }, + } } }, @@ -394,7 +392,7 @@ }); $(window).trigger('cloudStack.fullRefresh'); } - }, + } }, tabs: { details: { @@ -405,10 +403,10 @@ } }, { startdate: { - label: 'label.quota.date', + label: 'label.quota.date' }, startquota: { - label: 'label.quota.value', + label: 'label.quota.value' } }], dataProvider: function(args) { @@ -433,7 +431,7 @@ } }); } - }, + } } } } @@ -668,7 +666,7 @@ action: function(args) { if (isAdmin()) { var data = { - usagetype: args.data.jsonObj.usageType, + usagetype: args.data.jsonObj.usageType }; var tariffVal = args.data.tariffValue.split(' '); if (tariffVal.length==2){ @@ -697,7 +695,7 @@ validation: { required: true } - }, + } } }, after: function(argsLocal) { @@ -769,7 +767,7 @@ input.datepicker({ defaultDate: new Date(), changeMonth: true, - dateFormat: "yy-mm-dd", + dateFormat: "yy-mm-dd" }); input.parent().attr('title', _l('label.quota.effectivedate')); }, @@ -800,7 +798,7 @@ label: 'label.usage.unit' }, tariffValue: { - label: 'label.quota.tariff.value', + label: 'label.quota.tariff.value' }, description: { label: 'label.quota.description', @@ -832,7 +830,7 @@ input.datepicker({ defaultDate: new Date(), changeMonth: true, - dateFormat: "yy-mm-dd", + dateFormat: "yy-mm-dd" }); input.parent().attr('title', _l('label.quota.effectivedate')); }, @@ -854,7 +852,7 @@ disableInfiniteScrolling: true, fields: { templatetype: { - label: 'label.quota.email.template', + label: 'label.quota.email.template' }, templatesubject: { label: 'label.quota.email.subject', @@ -867,7 +865,7 @@ last_updated: { label: 'label.quota.email.lastupdated', truncate: true - }, + } }, dataProvider: function(args) { var data = {}; @@ -941,8 +939,8 @@ textArea: true }, last_updated: { - label: 'label.quota.email.lastupdated', - }, + label: 'label.quota.email.lastupdated' + } }], dataProvider: function(args) { diff --git a/ui/scripts/accounts.js b/ui/scripts/accounts.js index db0ab3fc34..913f81ff51 100644 --- a/ui/scripts/accounts.js +++ b/ui/scripts/accounts.js @@ -17,6 +17,7 @@ (function(cloudStack) { var domainObjs; + var roleObjs; cloudStack.sections.accounts = { title: 'label.accounts', @@ -38,11 +39,11 @@ name: { label: 'label.name' }, - accounttype: { - label: 'label.role', - converter: function(args) { - return cloudStack.converters.toRole(args); - } + rolename: { + label: 'label.role' + }, + roletype: { + label: 'label.roletype' }, domain: { label: 'label.domain' @@ -678,11 +679,11 @@ id: { label: 'label.id' }, - accounttype: { - label: 'label.role', - converter: function(args) { - return cloudStack.converters.toRole(args); - } + rolename: { + label: 'label.role' + }, + roletype: { + label: 'label.roletype' }, domain: { label: 'label.domain' @@ -1337,7 +1338,7 @@ $.ajax({ url: createURL('listSamlAuthorization'), data: { - userid: context.users[0].id, + userid: context.users[0].id }, success: function(json) { var authorization = json.listsamlauthorizationsresponse.samlauthorization[0]; @@ -1570,11 +1571,11 @@ account: { label: 'label.account.name' }, - accounttype: { - label: 'label.role', - converter: function(args) { - return cloudStack.converters.toRole(args); - } + rolename: { + label: 'label.role' + }, + roletype: { + label: 'label.roletype' }, domain: { label: 'label.domain' @@ -1881,7 +1882,7 @@ if (!args.context.projects) { $.extend(data, { domainid: args.context.sshkeypairs[0].domainid, - account: args.context.sshkeypairs[0].account, + account: args.context.sshkeypairs[0].account }); } $.ajax({ diff --git a/ui/scripts/accountsWizard.js b/ui/scripts/accountsWizard.js index 633821edb1..7fc4014de6 100644 --- a/ui/scripts/accountsWizard.js +++ b/ui/scripts/accountsWizard.js @@ -110,24 +110,28 @@ required: false } }, - accounttype: { - label: 'label.type', + roleid: { + label: 'label.role', docID: 'helpAccountType', validation: { required: true }, select: function(args) { - var items = []; - items.push({ - id: 0, - description: "User" - }); //regular-user - items.push({ - id: 1, - description: "Admin" - }); //root-admin - args.response.success({ - data: items + $.ajax({ + url: createURL("listRoles"), + success: function(json) { + var items = []; + roleObjs = json.listrolesresponse.role; + $(roleObjs).each(function() { + items.push({ + id: this.id, + description: this.name + ' (' + this.type + ')' + }); + }); + args.response.success({ + data: items + }); + } }); } }, @@ -226,13 +230,9 @@ array1.push("&account=" + account); } - var accountType = args.data.accounttype; - if (accountType == "1") { //if "admin" is selected in account type dropdown - if (rootDomainId == undefined || args.data.domainid != rootDomainId ) { //but current login has no visibility to root domain object, or the selected domain is not root domain - accountType = "2"; // change accountType from root-domain("1") to domain-admin("2") - } + if (args.data.roleid) { + array1.push("&roleid=" + args.data.roleid); } - array1.push("&accounttype=" + accountType); if (args.data.timezone !== null && args.data.timezone.length > 0) { array1.push("&timezone=" + args.data.timezone); diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js index 6e41607fb4..b712d6cdfc 100644 --- a/ui/scripts/cloudStack.js +++ b/ui/scripts/cloudStack.js @@ -22,7 +22,7 @@ var sections = []; if (isAdmin()) { - sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects", "regions", "affinityGroups"]; + sections = ["dashboard", "instances", "storage", "network", "templates", "roles", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects", "regions", "affinityGroups"]; } else if (isDomainAdmin()) { sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "projects", "configuration", "regions", "affinityGroups"]; } else if (g_userProjectsEnabled) { @@ -52,6 +52,7 @@ templates: {}, events: {}, projects: {}, + roles: {}, accounts: {}, domains: {}, //domain-admin and root-admin only @@ -181,7 +182,7 @@ } }, error: function(xhr) { // ignore any errors, fallback to the default - }, + } }); diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js index 14b0e156ff..4f7947aadb 100644 --- a/ui/scripts/configuration.js +++ b/ui/scripts/configuration.js @@ -3583,7 +3583,10 @@ }); networkServiceObjs.push({ name: 'Lb', - provider: [{name: 'VpcVirtualRouter'}] + provider: [ + {name: 'VpcVirtualRouter'}, + {name: 'InternalLbVm'} + ] }); networkServiceObjs.push({ name: 'Gateway', diff --git a/ui/scripts/dashboard.js b/ui/scripts/dashboard.js index f2b5682078..bd328634bb 100644 --- a/ui/scripts/dashboard.js +++ b/ui/scripts/dashboard.js @@ -184,9 +184,9 @@ }, capacity: function(data) { if (window.fetchLatestflag == 1) { - data.fetchLastest = true; + data.fetchLatest = true; } else { - data.fetchLastest = false; + data.fetchLatest = false; } window.fetchLatestflag = 0; dataFns.alerts(data); diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index a367f46beb..19db257029 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -310,7 +310,7 @@ return 'label.metrics'; } } - }, + } }, dataProvider: function(args) { diff --git a/ui/scripts/metrics.js b/ui/scripts/metrics.js index 6ac376e6f1..3ce8470af3 100644 --- a/ui/scripts/metrics.js +++ b/ui/scripts/metrics.js @@ -23,7 +23,7 @@ name: { label: 'metrics' } - }, + } } }; @@ -153,7 +153,7 @@ $.ajax({ url: createURL('listClusters'), - data: {zoneid: zone.id}, + data: {zoneid: zone.id, pagesize: -1}, success: function(json) { if (json && json.listclustersresponse && json.listclustersresponse.cluster && json.listclustersresponse.count) { items[idx].clusters += parseInt(json.listclustersresponse.count); @@ -163,7 +163,7 @@ } $.ajax({ url: createURL('listHosts'), - data: {clusterid: cluster.id, type: 'routing'}, + data: {clusterid: cluster.id, type: 'routing', pagesize: -1}, success: function(json) { if (json && json.listhostsresponse && json.listhostsresponse.host && json.listhostsresponse.count) { items[idx].hosts += parseInt(json.listhostsresponse.count); @@ -415,7 +415,7 @@ $.ajax({ url: createURL('listHosts'), - data: {clusterid: cluster.id, type: 'routing'}, + data: {clusterid: cluster.id, type: 'routing', pagesize: -1}, success: function(json) { if (json && json.listhostsresponse && json.listhostsresponse.host && json.listhostsresponse.count) { items[idx].hosts += parseInt(json.listhostsresponse.count); @@ -546,7 +546,20 @@ 'Error': 'off', 'Connecting': 'transition', 'Rebalancing': 'transition', - 'Alert': 'warning', + 'Alert': 'warning' + }, + compact: true + }, + outofbandmanagementpowerstate: { + label: 'label.metrics.outofbandmanagementpowerstate', + converter: function (str) { + // For localization + return str; + }, + indicator: { + 'On': 'on', + 'Off': 'off', + 'Unknown': 'warning' }, compact: true }, @@ -558,7 +571,7 @@ collapsible: true, columns: { cores: { - label: 'label.metrics.num.cpu.cores', + label: 'label.metrics.num.cpu.cores' }, cputotal: { label: 'label.metrics.cpu.total' @@ -633,6 +646,9 @@ var items = json.listhostsresponse.host; if (items) { $.each(items, function(idx, host) { + if (host && host.outofbandmanagement) { + items[idx].outofbandmanagementpowerstate = host.outofbandmanagement.powerstate; + } items[idx].cores = host.cpunumber; items[idx].cputotal = (parseFloat(host.cpunumber) * parseFloat(host.cpuspeed) / 1000.0).toFixed(2); if (host.cpuused) { @@ -778,7 +794,7 @@ 'Stopping': 'transition', 'Starting': 'transition', 'Migrating': 'transition', - 'Shutdowned': 'warning', + 'Shutdowned': 'warning' }, compact: true }, @@ -793,13 +809,13 @@ collapsible: true, columns: { cores: { - label: 'label.metrics.num.cpu.cores', + label: 'label.metrics.num.cpu.cores' }, cputotal: { label: 'label.metrics.cpu.total' }, cpuused: { - label: 'label.metrics.cpu.used.avg', + label: 'label.metrics.cpu.used.avg' } } }, @@ -922,7 +938,7 @@ 'Expunging': 'off', 'Migrating': 'warning', 'UploadOp': 'transition', - 'Snapshotting': 'warning', + 'Snapshotting': 'warning' }, compact: true }, @@ -937,7 +953,7 @@ }, storagepool: { label: 'label.metrics.storagepool' - }, + } }, dataProvider: function(args) { var data = {listAll: true}; @@ -1000,7 +1016,7 @@ 'ErrorInMaintenance': 'off', 'PrepareForMaintenance': 'transition', 'CancelMaintenance': 'warning', - 'Maintenance': 'warning', + 'Maintenance': 'warning' }, compact: true }, @@ -1009,7 +1025,7 @@ }, type: { label: 'label.metrics.disk.storagetype' - }, + } } }, disk: { diff --git a/ui/scripts/roles.js b/ui/scripts/roles.js new file mode 100644 index 0000000000..eae088fafa --- /dev/null +++ b/ui/scripts/roles.js @@ -0,0 +1,388 @@ +// 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. +(function($, cloudStack) { + var apiList = []; + var rolePermissions = []; + cloudStack.sections.roles = { + title: 'label.roles', + id: 'roles', + listView: { + id: 'roles', + fields: { + name: { + label: 'label.name' + }, + type: { + label: 'label.type' + }, + description: { + label: 'label.description' + } + }, + disableInfiniteScrolling: true, + dataProvider: function(args) { + var data = {}; + if (args.filterBy.search && args.filterBy.search.value) { + data['name'] = args.filterBy.search.value; + } + $.ajax({ + url: createURL("listRoles"), + data: data, + dataType: "json", + async: true, + success: function(json) { + var jsonObj; + jsonObj = json.listrolesresponse.role; + args.response.success({ + data: jsonObj + }); + } + }); + }, + actions: { + add: { + label: 'label.add.role', + preFilter: function(args) { + if (isAdmin()) + return true; + }, + messages: { + notification: function() { + return 'label.add.role'; + } + }, + createForm: { + title: 'label.add.role', + fields: { + name: { + label: 'label.name', + validation: { + required: true + } + }, + description: { + label: 'label.description', + }, + type: { + label: 'label.type', + validation: { + required: true + }, + select: function(args) { + var items = []; + items.push({ + id: "Admin", + description: "Admin" + }); + items.push({ + id: "DomainAdmin", + description: "Domain Admin" + }); + items.push({ + id: "User", + description: "User" + }); + args.response.success({ + data: items + }); + } + } + } + }, + action: function(args) { + $.ajax({ + url: createURL('createRole'), + data: args.data, + success: function(json) { + var item = json.createroleresponse.role; + args.response.success({ + data: item + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + detailView: { + tabs: { + details: { + title: 'label.details', + fields: { + id: { + label: 'label.id' + }, + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + }, + type: { + label: 'label.type' + }, + description: { + label: 'label.description', + isEditable: true + } + }, + dataProvider: function(args) { + $.ajax({ + url: createURL("listRoles&id=" + args.context.roles[0].id), + dataType: "json", + async: true, + success: function(json) { + var response = json.listrolesresponse.role[0]; + args.response.success({ + data: response + }); + } + }); + } + }, + rules: { + title: 'label.rules', + custom: function(args) { + var context = args.context; + + return $('
').multiEdit({ + context: context, + noSelect: true, + noHeaderActionsColumn: true, + reorder: { + moveDrag: { + action: function(args) { + var rule = args.context.multiRule[0]; + var prevItemId = args.prevItem ? args.prevItem.id : 0; + + var ruleOrder = []; + $.each(rolePermissions, function(idx, item) { + var itemId = item.id; + if (idx == 0 && prevItemId == 0) { + ruleOrder.push(rule.id); + } + if (itemId == rule.id) { + return true; + } + ruleOrder.push(item.id); + if (prevItemId == itemId) { + ruleOrder.push(rule.id); + } + }); + + $.ajax({ + url: createURL('updateRolePermission'), + data: { + roleid: rule.roleid, + ruleorder: ruleOrder.join() + }, + success: function(json) { + args.response.success(); + $(window).trigger('cloudStack.fullRefresh'); + }, + error: function(json) { + cloudStack.dialog.notice({ + message: 'message.role.ordering.fail' + }); + } + }); + } + } + }, + fields: { + 'rule': { + edit: true, + label: 'label.rule', + isOptional: false + }, + 'permission': { + label: 'label.permission', + select: function(args) { + args.response.success({ + data: [{ + name: 'allow', + description: 'Allow' + }, { + name: 'deny', + description: 'Deny' + }] + }); + } + }, + 'description': { + edit: true, + label: 'label.description', + isOptional: true + }, + 'always-hide': { + label: 'label.action', + addButton: true + } + }, + add: { + label: 'label.add', + action: function(args) { + var data = { + rule: args.data.rule, + permission: args.data.permission, + description: args.data.description, + roleid: args.context.roles[0].id + }; + + $.ajax({ + url: createURL('createRolePermission'), + data: data, + dataType: 'json', + success: function(json) { + var response = json.createrolepermissionresponse.rolepermission; + args.response.success({ + data: response + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }, + actions: { + destroy: { + label: 'label.remove.rule', + action: function(args) { + $.ajax({ + url: createURL('deleteRolePermission'), + data: { + id: args.context.multiRule[0].id + }, + dataType: 'json', + success: function(data) { + args.response.success(); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }, + dataProvider: function(args) { + $.ajax({ + url: createURL('listRolePermissions'), + data: { + roleid: args.context.roles[0].id + }, + dataType: 'json', + success: function(json) { + var rules = json.listrolepermissionsresponse.rolepermission; + if (rules) { + rolePermissions = rules; + } + args.response.success({ + data: rules + }); + } + }); + var setupAutocompletion = function() { + $($.find('input[name="rule"]')).autocomplete("destroy"); + $($.find('input[name="rule"]')).autocomplete({ + source: apiList, + autoFocus:true + }); + }; + if (apiList.length == 0) { + $.ajax({ + url: createURL("listApis"), + dataType: "json", + success: function(json) { + var response = json.listapisresponse.api; + $.each(response, function(idx, api) { + apiList.push(api.name); + }); + setupAutocompletion(); + } + }); + } else { + setupAutocompletion(); + } + } + }); + } + } + }, + actions: { + edit: { + label: 'label.edit.role', + action: function(args) { + var data = { + id: args.context.roles[0].id, + name: args.data.name, + description: args.data.description + }; + + $.ajax({ + url: createURL('updateRole'), + data: data, + success: function(json) { + args.response.success(); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }, + remove: { + label: 'label.delete.role', + messages: { + confirm: function(args) { + return 'label.delete.role'; + }, + notification: function(args) { + return 'label.delete.role'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("deleteRole&id=" + args.context.roles[0].id), + dataType: "json", + success: function(json) { + var response = json.deleteroleresponse; + args.response.success({ + data: response + }); + } + }); + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + } + } + } + } +})(jQuery, cloudStack); diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index 7b4b26a0ca..88d728e76f 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -1112,6 +1112,17 @@ cloudStack.converters = { return "Domain-Admin"; } }, + toAccountType: function(roleType) { + if (roleType == 'User') { + return 0; + } else if (roleType == 'Admin') { + return 1; + } else if (roleType == 'DomainAdmin') { + return 2; + } else if (roleType == 'ResourceAdmin') { + return 3; + } + }, toAlertType: function(alertCode) { switch (alertCode) { case 0: diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js index 39dfccf2eb..29cd4c1cdc 100644 --- a/ui/scripts/storage.js +++ b/ui/scripts/storage.js @@ -1550,6 +1550,8 @@ preFilter: function(args) { if (args.context.volumes != null && args.context.volumes[0].type == 'ROOT') { args.$form.find('.form-item[rel=newdiskoffering]').hide(); + + selectedDiskOfferingObj = null; } else { args.$form.find('.form-item[rel=newsize]').hide(); } diff --git a/ui/scripts/system.js b/ui/scripts/system.js index faa388c17c..2eef6b1908 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -870,7 +870,7 @@ var data = { id: args.context.multiRule[0].id, zoneid: args.context.multiRule[0].zoneid, - domainid: args.data.domainid, + domainid: args.data.domainid }; if (args.data.account) { $.extend(data, { @@ -7109,7 +7109,7 @@ }, apiversion: { label: 'label.api.version', - defaultValue: 'v1_0', + defaultValue: 'v3_2', validation: { required: true }, @@ -7872,7 +7872,7 @@ return 'label.metrics'; } } - }, + } }, detailView: { @@ -8241,6 +8241,82 @@ } }); } + }, + enableOutOfBandManagement: { + label: 'label.outofbandmanagement.enable', + action: function (args) { + var data = { + zoneid: args.context.physicalResources[0].id + }; + $.ajax({ + url: createURL("enableOutOfBandManagementForZone"), + data: data, + success: function (json) { + var jid = json.enableoutofbandmanagementforzoneresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return zoneActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.enable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disableOutOfBandManagement: { + label: 'label.outofbandmanagement.disable', + action: function (args) { + var data = { + zoneid: args.context.physicalResources[0].id + }; + $.ajax({ + url: createURL("disableOutOfBandManagementForZone"), + data: data, + success: function (json) { + var jid = json.disableoutofbandmanagementforzoneresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return zoneActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.disable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } } }, tabs: { @@ -9058,8 +9134,17 @@ url: createURL('listHosts'), data: data, success: function (json) { + var items = json.listhostsresponse.host; + if (items) { + $.each(items, function(idx, host) { + if (host && host.outofbandmanagement) { + items[idx].powerstate = host.outofbandmanagement.powerstate; + } + }); + } + args.response.success({ - data: json.listhostsresponse.host + data: items }); }, error: function (json) { @@ -13100,7 +13185,7 @@ }, apiversion: { label: 'label.api.version', - defaultValue: 'v1_0' + defaultValue: 'v3_2' }, retrycount: { label: 'label.numretries', @@ -13171,7 +13256,7 @@ dataType: "json", async: false, success: function(json) { - var items = json.listnuagevspdeviceresponse.nuagevspdevice; + var items = json.listnuagevspdevicesresponse.nuagevspdevice; args.response.success({ data: items }); @@ -13240,7 +13325,7 @@ dataType: "json", async: true, success: function(json) { - var item = json.listnuagevspdeviceresponse.nuagevspdevice[0]; + var item = json.listnuagevspdevicesresponse.nuagevspdevice[0]; args.response.success({ data: item }); @@ -14970,7 +15055,85 @@ args.complete(); } } + }, + + enableOutOfBandManagement: { + label: 'label.outofbandmanagement.enable', + action: function (args) { + var data = { + clusterid: args.context.clusters[0].id, + }; + $.ajax({ + url: createURL("enableOutOfBandManagementForCluster"), + data: data, + success: function (json) { + var jid = json.enableoutofbandmanagementforclusterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return clusterActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.enable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + disableOutOfBandManagement: { + label: 'label.outofbandmanagement.disable', + action: function (args) { + var data = { + clusterid: args.context.clusters[0].id, + }; + $.ajax({ + url: createURL("disableOutOfBandManagementForCluster"), + data: data, + success: function (json) { + var jid = json.disableoutofbandmanagementforclusterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return clusterActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.disable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } } + }, tabs: { @@ -15328,7 +15491,15 @@ 'Alert': 'off', 'Error': 'off' } - } + }, + powerstate: { + label: 'label.powerstate', + indicator: { + 'On': 'on', + 'Off': 'off', + 'Unknown': 'warning' + }, + }, }, dataProvider: function (args) { @@ -15355,13 +15526,20 @@ //Instances menu > Instance detailView > View Hosts array1.push("&id=" + args.context.instances[0].hostid); } - $.ajax({ url: createURL("listHosts&type=Routing" + array1.join("") + "&page=" + args.page + "&pagesize=" + pageSize), dataType: "json", async: true, success: function (json) { var items = json.listhostsresponse.host; + if (items) { + $.each(items, function(idx, host) { + if (host && host.outofbandmanagement) { + items[idx].powerstate = host.outofbandmanagement.powerstate; + } + }); + } + args.response.success({ actionFilter: hostActionfilter, data: items @@ -15998,6 +16176,7 @@ } }, + dedicate: { label: 'label.dedicate.host', messages: { @@ -16336,8 +16515,11 @@ } }); - if (args.context.hosts[0].hypervisor == "XenServer"){ - cloudStack.dialog.notice({ message: _s("The host has been deleted. Please eject the host from XenServer Pool") }) + if (args.context.hosts[0].hypervisor == "XenServer") { + cloudStack.dialog.notice({ message: _s("The host has been removed. Please eject the host from the XenServer Resource Pool.") }) + } + else if (args.context.hosts[0].hypervisor == "VMware") { + cloudStack.dialog.notice({ message: _s("The host has been removed. Please eject the host from the vSphere Cluster.") }) } } }); @@ -16347,13 +16529,331 @@ args.complete(); } } + }, + + blankOutOfBandManagement: { + label: '', + action: function (args) { + } + }, + + configureOutOfBandManagement: { + label: 'label.outofbandmanagement.configure', + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.configure'; + }, + notification: function (args) { + return 'message.outofbandmanagement.configure'; + } + }, + createForm: { + title: 'label.outofbandmanagement.configure', + fields: { + address: { + label: 'label.outofbandmanagement.address', + validation: { + required: true + } + }, + port: { + label: 'label.outofbandmanagement.port', + validation: { + required: true + } + }, + username: { + label: 'label.outofbandmanagement.username', + validation: { + required: false + } + }, + password: { + label: 'label.outofbandmanagement.password', + isPassword: true, + validation: { + required: false + }, + }, + driver: { + label: 'label.outofbandmanagement.driver', + validation: { + required: true + }, + select: function (args) { + var oobm = args.context.hosts[0].outofbandmanagement; + if (oobm) { + args.$form.find('input[name=address]').val(oobm.address); + args.$form.find('input[name=port]').val(oobm.port); + args.$form.find('input[name=username]').val(oobm.username); + + args.$form.find('input[name=address]').change(function() { + $this.find('input[name=address]').val(oobm.address); + }); + } + + var items = []; + items.push({ + id: 'ipmitool', + description: 'ipmitool - ipmitool based shell driver' + }); + args.response.success({ + data: items + }); + } + } + } + }, + action: function (args) { + var data = args.data; + data.hostid = args.context.hosts[0].id; + + $.ajax({ + url: createURL('configureOutOfBandManagement'), + data: data, + dataType: 'json', + success: function (json) { + var response = json.configureoutofbandmanagementresponse; + args.response.success({ + actionFilter: hostActionfilter, + data: response + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + enableOutOfBandManagement: { + label: 'label.outofbandmanagement.enable', + action: function (args) { + var data = { + hostid: args.context.hosts[0].id, + }; + $.ajax({ + url: createURL("enableOutOfBandManagementForHost"), + data: data, + success: function (json) { + var jid = json.enableoutofbandmanagementforhostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.enable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + disableOutOfBandManagement: { + label: 'label.outofbandmanagement.disable', + action: function (args) { + var data = { + hostid: args.context.hosts[0].id, + }; + $.ajax({ + url: createURL("disableOutOfBandManagementForHost"), + data: data, + success: function (json) { + var jid = json.disableoutofbandmanagementforhostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.disable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + issueOutOfBandManagementPowerAction: { + label: 'label.outofbandmanagement.action.issue', + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.issue'; + }, + notification: function (args) { + return 'message.outofbandmanagement.issue'; + } + }, + createForm: { + title: 'label.outofbandmanagement.action.issue', + desc: function(args) { + var host = args.context.hosts[0]; + if (host.resourcestate == 'Maintenance' || host.resourcestate == 'PrepareForMaintenance' || host.resourcestate == 'ErrorInMaintenance') { + return _l('message.outofbandmanagement.action.maintenance'); + } + }, + fields: { + action: { + label: 'label.outofbandmanagement.action', + validation: { + required: true + }, + select: function (args) { + var items = []; + items.push({ + id: 'ON', + description: 'ON - turn on host' + }); + items.push({ + id: 'OFF', + description: 'OFF - turn off host' + }); + items.push({ + id: 'CYCLE', + description: 'CYCLE - power cycle the host' + }); + items.push({ + id: 'RESET', + description: 'RESET - power reset the host' + }); + items.push({ + id: 'SOFT', + description: 'SOFT - soft shutdown the host using ACPI etc' + }); + items.push({ + id: 'STATUS', + description: 'STATUS - update power status of the host' + }); + args.response.success({ + data: items + }); + } + }, + } + }, + action: function (args) { + var data = args.data; + data.hostid = args.context.hosts[0].id; + $.ajax({ + url: createURL('issueOutOfBandManagementPowerAction'), + data: data, + dataType: 'json', + success: function (json) { + var jid = json.issueoutofbandmanagementpoweractionresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + changeOutOfBandManagementPassword: { + label: 'label.outofbandmanagement.changepassword', + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.changepassword'; + }, + notification: function (args) { + return 'message.outofbandmanagement.changepassword'; + } + }, + createForm: { + title: 'label.outofbandmanagement.changepassword', + fields: { + password: { + label: 'label.outofbandmanagement.password', + isPassword: true, + validation: { + required: false + }, + }, + } + }, + action: function (args) { + var data = args.data; + data.hostid = args.context.hosts[0].id; + $.ajax({ + url: createURL('changeOutOfBandManagementPassword'), + data: data, + dataType: 'json', + success: function (json) { + var jid = json.changeoutofbandmanagementpasswordresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } } + }, tabFilter: function (args) { var hiddenTabs =[]; - if (args.context.hosts[0].gpugroup == null) { + var host = args.context.hosts[0]; + if (host.gpugroup == null) { hiddenTabs.push("gpu"); } + if (host.outofbandmanagement == null || !host.outofbandmanagement.enabled) { + hiddenTabs.push("outofbandmanagement"); + } return hiddenTabs; }, tabs: { @@ -16390,6 +16890,9 @@ state: { label: 'label.state' }, + powerstate: { + label: 'label.powerstate' + }, type: { label: 'label.type' }, @@ -16501,6 +17004,10 @@ async: true, success: function (json) { var item = json.listhostsresponse.host[0]; + if (item && item.outofbandmanagement) { + item.powerstate = item.outofbandmanagement.powerstate; + } + $.ajax({ url: createURL("listDedicatedHosts&hostid=" + args.context.hosts[0].id), dataType: "json", @@ -16532,6 +17039,44 @@ } }, + outofbandmanagement: { + title: 'label.outofbandmanagement', + fields: { + powerstate: { + label: 'label.powerstate' + }, + driver: { + label: 'label.outofbandmanagement.driver' + }, + username: { + label: 'label.outofbandmanagement.username' + }, + address: { + label: 'label.outofbandmanagement.address' + }, + port: { + label: 'label.outofbandmanagement.port' + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listHosts&id=" + args.context.hosts[0].id), + dataType: "json", + async: true, + success: function (json) { + var host = json.listhostsresponse.host[0]; + var oobm = {}; + if (host && host.outofbandmanagement) { + oobm = host.outofbandmanagement; + } + args.response.success({ + data: oobm + }); + } + }); + } + }, + stats: { title: 'label.statistics', fields: { @@ -20807,6 +21352,13 @@ allowedActions.push("disable"); allowedActions.push("remove"); + + if (jsonObj.hasOwnProperty('resourcedetails') && jsonObj['resourcedetails'].hasOwnProperty('outOfBandManagementEnabled') && jsonObj['resourcedetails']['outOfBandManagementEnabled'] == 'false') { + allowedActions.push("enableOutOfBandManagement"); + } else { + allowedActions.push("disableOutOfBandManagement"); + } + return allowedActions; } @@ -20892,6 +21444,12 @@ allowedActions.push("remove"); + if (jsonObj.hasOwnProperty('resourcedetails') && jsonObj['resourcedetails'].hasOwnProperty('outOfBandManagementEnabled') && jsonObj['resourcedetails']['outOfBandManagementEnabled'] == 'false') { + allowedActions.push("enableOutOfBandManagement"); + } else { + allowedActions.push("disableOutOfBandManagement"); + } + return allowedActions; } @@ -20928,6 +21486,16 @@ allowedActions.push("remove"); } + allowedActions.push("blankOutOfBandManagement"); + allowedActions.push("configureOutOfBandManagement"); + if (jsonObj.hasOwnProperty("outofbandmanagement") && jsonObj.outofbandmanagement.enabled) { + allowedActions.push("issueOutOfBandManagementPowerAction"); + allowedActions.push("changeOutOfBandManagementPassword"); + allowedActions.push("disableOutOfBandManagement"); + } else { + allowedActions.push("enableOutOfBandManagement"); + } + if ((jsonObj.state == "Down" || jsonObj.state == "Alert" || jsonObj.state == "Disconnected") && ($.inArray("remove", allowedActions) == -1)) { allowedActions.push("remove"); } diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js index ddd7265774..2ce72a2578 100644 --- a/ui/scripts/ui/widgets/detailView.js +++ b/ui/scripts/ui/widgets/detailView.js @@ -301,7 +301,7 @@ }), // Window options - 'menubar=0,resizable=0,' + 'width=' + externalLinkAction.width + ',' + 'height=' + externalLinkAction.height + 'menubar=0,resizable=1,' + 'width=' + externalLinkAction.width + ',' + 'height=' + externalLinkAction.height ); } else { notification.desc = messages.notification(messageArgs); diff --git a/usage/conf/db.properties.in b/usage/conf/db.properties.in index 0dd49ede8b..35a40def7b 100644 --- a/usage/conf/db.properties.in +++ b/usage/conf/db.properties.in @@ -19,6 +19,7 @@ db.usage.username=@DBUSER@ db.usage.password=@DBPW@ db.usage.host=@DBHOST@ +db.usage.driver=@DBDRIVER@ db.usage.port=3306 db.usage.name=cloud_usage diff --git a/usage/pom.xml b/usage/pom.xml index 0e6f720ec9..dd80e82ce7 100644 --- a/usage/pom.xml +++ b/usage/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT @@ -53,17 +53,17 @@ org.slf4j slf4j-api - 1.7.7 + 1.7.21 org.slf4j slf4j-log4j12 - 1.7.7 + 1.7.21 org.dbunit dbunit - 2.4.9 + 2.5.2 test diff --git a/usage/test/resources/db.properties b/usage/test/resources/db.properties index a458b2306f..e8e94121fe 100644 --- a/usage/test/resources/db.properties +++ b/usage/test/resources/db.properties @@ -26,6 +26,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -46,6 +47,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -59,6 +62,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/utils/conf/db.properties b/utils/conf/db.properties index 49fd68aa93..c7aeaad264 100644 --- a/utils/conf/db.properties +++ b/utils/conf/db.properties @@ -29,6 +29,7 @@ db.cloud.username=cloud db.cloud.password=cloud db.root.password= db.cloud.host=localhost +db.cloud.driver=jdbc:mysql db.cloud.port=3306 db.cloud.name=cloud @@ -49,6 +50,8 @@ db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLi db.usage.username=cloud db.usage.password=cloud db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql db.usage.port=3306 db.usage.name=cloud_usage @@ -62,6 +65,8 @@ db.usage.autoReconnect=true db.simulator.username=cloud db.simulator.password=cloud db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql db.simulator.port=3306 db.simulator.name=simulator db.simulator.maxActive=250 diff --git a/utils/pom.xml b/utils/pom.xml index 34ff4c3925..206eb1896a 100755 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -26,7 +26,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT ../pom.xml @@ -69,7 +69,7 @@ org.bouncycastle - bcprov-jdk16 + bcprov-jdk15on com.jcraft @@ -157,7 +157,7 @@ commons-net commons-net - 3.3 + 3.4 com.google.code.gson diff --git a/utils/src/main/java/com/cloud/utils/ListUtils.java b/utils/src/main/java/com/cloud/utils/ListUtils.java new file mode 100644 index 0000000000..fa9332f119 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/ListUtils.java @@ -0,0 +1,31 @@ +// 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.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ListUtils { + public static List toListOfInterface(final List items) { + if (items != null) { + return new ArrayList<>(items); + } + return Collections.emptyList(); + } +} diff --git a/utils/src/main/java/com/cloud/utils/Profiler.java b/utils/src/main/java/com/cloud/utils/Profiler.java index f8e44bd323..addee2db20 100644 --- a/utils/src/main/java/com/cloud/utils/Profiler.java +++ b/utils/src/main/java/com/cloud/utils/Profiler.java @@ -24,7 +24,6 @@ public class Profiler { private static final long MILLIS_FACTOR = 1000l; private static final double EXPONENT = 2d; - private Long startTickNanoSeconds; private Long stopTickNanoSeconds; @@ -46,8 +45,7 @@ public long stop() { */ public long getDuration() { if (startTickNanoSeconds != null && stopTickNanoSeconds != null) { - final long timeInNanoSeconds = stopTickNanoSeconds - startTickNanoSeconds; - return timeInNanoSeconds; + return stopTickNanoSeconds - startTickNanoSeconds; } return -1; @@ -61,8 +59,7 @@ public long getDuration() { */ public long getDurationInMillis() { if (startTickNanoSeconds != null && stopTickNanoSeconds != null) { - final long timeInMillis = (stopTickNanoSeconds - startTickNanoSeconds) / (long)Math.pow(MILLIS_FACTOR, EXPONENT); - return timeInMillis; + return (stopTickNanoSeconds - startTickNanoSeconds) / (long)Math.pow(MILLIS_FACTOR, EXPONENT); } return -1; diff --git a/utils/src/main/java/com/cloud/utils/PropertiesUtil.java b/utils/src/main/java/com/cloud/utils/PropertiesUtil.java index 4cb89f7531..c0da87a192 100644 --- a/utils/src/main/java/com/cloud/utils/PropertiesUtil.java +++ b/utils/src/main/java/com/cloud/utils/PropertiesUtil.java @@ -34,6 +34,10 @@ public class PropertiesUtil { private static final Logger s_logger = Logger.getLogger(PropertiesUtil.class); + public static String getDefaultApiCommandsFileName() { + return "commands.properties"; + } + /** * Searches the class path and local paths to find the config file. * @param path path to find. if it starts with / then it's absolute path. diff --git a/utils/src/main/java/com/cloud/utils/SerialVersionUID.java b/utils/src/main/java/com/cloud/utils/SerialVersionUID.java index 0683c8c151..b45e028a55 100644 --- a/utils/src/main/java/com/cloud/utils/SerialVersionUID.java +++ b/utils/src/main/java/com/cloud/utils/SerialVersionUID.java @@ -65,7 +65,6 @@ public interface SerialVersionUID { public static final long CallFailedException = Base | 0x28; public static final long UnableDeleteHostException = Base | 0x29; public static final long AffinityConflictException = Base | 0x2a; - public static final long JobCancellationException = Base | 0x2b; public static final long NioConnectionException = Base | 0x2c; public static final long TaskExecutionException = Base | 0x2d; } diff --git a/utils/src/main/java/com/cloud/utils/Utils.java b/utils/src/main/java/com/cloud/utils/Utils.java new file mode 100644 index 0000000000..53f0a8059c --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/Utils.java @@ -0,0 +1,38 @@ +// +// 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.utils; + +import java.util.Map; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +public class Utils { + public static Map getImmutableMap(Map map) { + Map filteredMap = Maps.filterValues(map, new Predicate() { + public boolean apply(final V input) { + return input != null; + } + }); + + return ImmutableMap.builder().putAll(filteredMap).build(); + } +} diff --git a/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java b/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java index 431d961a41..f03974a00f 100644 --- a/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java +++ b/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java @@ -45,10 +45,20 @@ public StateMachine2() { } + public void addInitialTransition(E event, S toState) { + addTransition(null, event, toState); + } + public void addTransition(S currentState, E event, S toState) { addTransition(new Transition(currentState, event, toState, null)); } + @SafeVarargs + public final void addTransitionFromStates(E event, S toState, S... fromStates) { + for (S fromState : fromStates) { + addTransition(fromState, event, toState); + } + } public void addTransition(Transition transition) { S currentState = transition.getCurrentState(); diff --git a/utils/src/main/java/com/cloud/utils/nio/Link.java b/utils/src/main/java/com/cloud/utils/nio/Link.java index 6d6306a53b..02ffaab4e0 100644 --- a/utils/src/main/java/com/cloud/utils/nio/Link.java +++ b/utils/src/main/java/com/cloud/utils/nio/Link.java @@ -19,37 +19,33 @@ package com.cloud.utils.nio; +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.db.DbProperties; +import org.apache.cloudstack.utils.security.SSLUtils; +import org.apache.log4j.Logger; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; -import java.net.SocketTimeoutException; import java.nio.ByteBuffer; -import java.nio.channels.Channels; import java.nio.channels.ClosedChannelException; -import java.nio.channels.ReadableByteChannel; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.util.concurrent.ConcurrentLinkedQueue; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; - -import org.apache.cloudstack.utils.security.SSLUtils; -import org.apache.log4j.Logger; - -import com.cloud.utils.PropertiesUtil; -import com.cloud.utils.db.DbProperties; - /** */ public class Link { @@ -453,115 +449,188 @@ public static SSLContext initSSLContext(boolean isClient) throws GeneralSecurity return sslContext; } - public static void doHandshake(SocketChannel ch, SSLEngine sslEngine, boolean isClient) throws IOException { - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: begin Handshake, isClient: " + isClient); + public static ByteBuffer enlargeBuffer(ByteBuffer buffer, final int sessionProposedCapacity) { + if (buffer == null || sessionProposedCapacity < 0) { + return buffer; } - - SSLEngineResult engResult; - SSLSession sslSession = sslEngine.getSession(); - HandshakeStatus hsStatus; - ByteBuffer in_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); - ByteBuffer in_appBuf = ByteBuffer.allocate(sslSession.getApplicationBufferSize() + 40); - ByteBuffer out_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); - ByteBuffer out_appBuf = ByteBuffer.allocate(sslSession.getApplicationBufferSize() + 40); - int count; - ch.socket().setSoTimeout(60 * 1000); - InputStream inStream = ch.socket().getInputStream(); - // Use readCh to make sure the timeout on reading is working - ReadableByteChannel readCh = Channels.newChannel(inStream); - - if (isClient) { - hsStatus = SSLEngineResult.HandshakeStatus.NEED_WRAP; + if (sessionProposedCapacity > buffer.capacity()) { + buffer = ByteBuffer.allocate(sessionProposedCapacity); } else { - hsStatus = SSLEngineResult.HandshakeStatus.NEED_UNWRAP; + buffer = ByteBuffer.allocate(buffer.capacity() * 2); } + return buffer; + } - while (hsStatus != SSLEngineResult.HandshakeStatus.FINISHED) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Handshake status " + hsStatus); + public static ByteBuffer handleBufferUnderflow(final SSLEngine engine, ByteBuffer buffer) { + if (engine == null || buffer == null) { + return buffer; + } + if (buffer.position() < buffer.limit()) { + return buffer; + } + ByteBuffer replaceBuffer = enlargeBuffer(buffer, engine.getSession().getPacketBufferSize()); + buffer.flip(); + replaceBuffer.put(buffer); + return replaceBuffer; + } + + private static boolean doHandshakeUnwrap(final SocketChannel socketChannel, final SSLEngine sslEngine, + ByteBuffer peerAppData, ByteBuffer peerNetData, final int appBufferSize) throws IOException { + if (socketChannel == null || sslEngine == null || peerAppData == null || peerNetData == null || appBufferSize < 0) { + return false; + } + if (socketChannel.read(peerNetData) < 0) { + if (sslEngine.isInboundDone() && sslEngine.isOutboundDone()) { + return false; } - engResult = null; - if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP) { - out_pkgBuf.clear(); - out_appBuf.clear(); - out_appBuf.put("Hello".getBytes()); - engResult = sslEngine.wrap(out_appBuf, out_pkgBuf); - out_pkgBuf.flip(); - int remain = out_pkgBuf.limit(); - while (remain != 0) { - remain -= ch.write(out_pkgBuf); - if (remain < 0) { - throw new IOException("Too much bytes sent?"); - } - } - } else if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) { - in_appBuf.clear(); - // One packet may contained multiply operation - if (in_pkgBuf.position() == 0 || !in_pkgBuf.hasRemaining()) { - in_pkgBuf.clear(); - count = 0; - try { - count = readCh.read(in_pkgBuf); - } catch (SocketTimeoutException ex) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("Handshake reading time out! Cut the connection"); - } - count = -1; - } - if (count == -1) { - throw new IOException("Connection closed with -1 on reading size."); - } - in_pkgBuf.flip(); + try { + sslEngine.closeInbound(); + } catch (SSLException e) { + s_logger.warn("This SSL engine was forced to close inbound due to end of stream."); + } + sslEngine.closeOutbound(); + // After closeOutbound the engine will be set to WRAP state, + // in order to try to send a close message to the client. + return true; + } + peerNetData.flip(); + SSLEngineResult result = null; + try { + result = sslEngine.unwrap(peerNetData, peerAppData); + peerNetData.compact(); + } catch (SSLException sslException) { + s_logger.error("SSL error occurred while processing unwrap data: " + sslException.getMessage()); + sslEngine.closeOutbound(); + return true; + } + switch (result.getStatus()) { + case OK: + break; + case BUFFER_OVERFLOW: + // Will occur when peerAppData's capacity is smaller than the data derived from peerNetData's unwrap. + peerAppData = enlargeBuffer(peerAppData, appBufferSize); + break; + case BUFFER_UNDERFLOW: + // Will occur either when no data was read from the peer or when the peerNetData buffer + // was too small to hold all peer's data. + peerNetData = handleBufferUnderflow(sslEngine, peerNetData); + break; + case CLOSED: + if (sslEngine.isOutboundDone()) { + return false; + } else { + sslEngine.closeOutbound(); + break; } - engResult = sslEngine.unwrap(in_pkgBuf, in_appBuf); - ByteBuffer tmp_pkgBuf = ByteBuffer.allocate(sslSession.getPacketBufferSize() + 40); - int loop_count = 0; - while (engResult.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) { - // The client is too slow? Cut it and let it reconnect - if (loop_count > 10) { - throw new IOException("Too many times in SSL BUFFER_UNDERFLOW, disconnect guest."); - } - // We need more packets to complete this operation - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Buffer underflowed, getting more packets"); - } - tmp_pkgBuf.clear(); - count = ch.read(tmp_pkgBuf); - if (count == -1) { - throw new IOException("Connection closed with -1 on reading size."); - } - tmp_pkgBuf.flip(); - - in_pkgBuf.mark(); - in_pkgBuf.position(in_pkgBuf.limit()); - in_pkgBuf.limit(in_pkgBuf.limit() + tmp_pkgBuf.limit()); - in_pkgBuf.put(tmp_pkgBuf); - in_pkgBuf.reset(); + default: + throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + } + return true; + } - in_appBuf.clear(); - engResult = sslEngine.unwrap(in_pkgBuf, in_appBuf); - loop_count++; + private static boolean doHandshakeWrap(final SocketChannel socketChannel, final SSLEngine sslEngine, + ByteBuffer myAppData, ByteBuffer myNetData, ByteBuffer peerNetData, + final int netBufferSize) throws IOException { + if (socketChannel == null || sslEngine == null || myNetData == null || peerNetData == null + || myAppData == null || netBufferSize < 0) { + return false; + } + myNetData.clear(); + SSLEngineResult result = null; + try { + result = sslEngine.wrap(myAppData, myNetData); + } catch (SSLException sslException) { + s_logger.error("SSL error occurred while processing wrap data: " + sslException.getMessage()); + sslEngine.closeOutbound(); + return true; + } + switch (result.getStatus()) { + case OK : + myNetData.flip(); + while (myNetData.hasRemaining()) { + socketChannel.write(myNetData); } - } else if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) { - Runnable run; - while ((run = sslEngine.getDelegatedTask()) != null) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Running delegated task!"); + break; + case BUFFER_OVERFLOW: + // Will occur if there is not enough space in myNetData buffer to write all the data + // that would be generated by the method wrap. Since myNetData is set to session's packet + // size we should not get to this point because SSLEngine is supposed to produce messages + // smaller or equal to that, but a general handling would be the following: + myNetData = enlargeBuffer(myNetData, netBufferSize); + break; + case BUFFER_UNDERFLOW: + throw new SSLException("Buffer underflow occurred after a wrap. We should not reach here."); + case CLOSED: + try { + myNetData.flip(); + while (myNetData.hasRemaining()) { + socketChannel.write(myNetData); } - run.run(); + // At this point the handshake status will probably be NEED_UNWRAP + // so we make sure that peerNetData is clear to read. + peerNetData.clear(); + } catch (Exception e) { + s_logger.error("Failed to send server's CLOSE message due to socket channel's failure."); } - } else if (hsStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { - throw new IOException("NOT a handshaking!"); + break; + default: + throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + } + return true; + } + + public static boolean doHandshake(final SocketChannel socketChannel, final SSLEngine sslEngine, final boolean isClient) throws IOException { + if (socketChannel == null || sslEngine == null) { + return false; + } + final int appBufferSize = sslEngine.getSession().getApplicationBufferSize(); + final int netBufferSize = sslEngine.getSession().getPacketBufferSize(); + ByteBuffer myAppData = ByteBuffer.allocate(appBufferSize); + ByteBuffer peerAppData = ByteBuffer.allocate(appBufferSize); + ByteBuffer myNetData = ByteBuffer.allocate(netBufferSize); + ByteBuffer peerNetData = ByteBuffer.allocate(netBufferSize); + + final long startTimeMills = System.currentTimeMillis(); + + HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); + while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED + && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { + final long timeTaken = System.currentTimeMillis() - startTimeMills; + if (timeTaken > 15000L) { + s_logger.warn("SSL Handshake has taken more than 15s to connect to: " + socketChannel.getRemoteAddress() + + ". Please investigate this connection."); + return false; } - if (engResult != null && engResult.getStatus() != SSLEngineResult.Status.OK) { - throw new IOException("Fail to handshake! " + engResult.getStatus()); + switch (handshakeStatus) { + case NEED_UNWRAP: + if (!doHandshakeUnwrap(socketChannel, sslEngine, peerAppData, peerNetData, appBufferSize)) { + return false; + } + break; + case NEED_WRAP: + if (!doHandshakeWrap(socketChannel, sslEngine, myAppData, myNetData, peerNetData, netBufferSize)) { + return false; + } + break; + case NEED_TASK: + Runnable task; + while ((task = sslEngine.getDelegatedTask()) != null) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("SSL: Running delegated task!"); + } + task.run(); + } + break; + case FINISHED: + break; + case NOT_HANDSHAKING: + break; + default: + throw new IllegalStateException("Invalid SSL status: " + handshakeStatus); } - if (engResult != null) - hsStatus = engResult.getHandshakeStatus(); - else - hsStatus = sslEngine.getHandshakeStatus(); + handshakeStatus = sslEngine.getHandshakeStatus(); } + return true; } } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioClient.java b/utils/src/main/java/com/cloud/utils/nio/NioClient.java index d989f306c5..dc4f670de1 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioClient.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioClient.java @@ -36,7 +36,6 @@ public class NioClient extends NioConnection { private static final Logger s_logger = Logger.getLogger(NioClient.class); protected String _host; - protected String _bindAddress; protected SocketChannel _clientConnection; public NioClient(final String name, final String host, final int port, final int workers, final HandlerFactory factory) { @@ -44,10 +43,6 @@ public NioClient(final String name, final String host, final int port, final int _host = host; } - public void setBindAddress(final String ipAddress) { - _bindAddress = ipAddress; - } - @Override protected void init() throws IOException { _selector = Selector.open(); @@ -55,33 +50,25 @@ protected void init() throws IOException { try { _clientConnection = SocketChannel.open(); - _clientConnection.configureBlocking(true); - s_logger.info("Connecting to " + _host + ":" + _port); - - if (_bindAddress != null) { - s_logger.info("Binding outbound interface at " + _bindAddress); - - final InetSocketAddress bindAddr = new InetSocketAddress(_bindAddress, 0); - _clientConnection.socket().bind(bindAddr); - } + s_logger.info("Connecting to " + _host + ":" + _port); final InetSocketAddress peerAddr = new InetSocketAddress(_host, _port); _clientConnection.connect(peerAddr); - - SSLEngine sslEngine = null; - // Begin SSL handshake in BLOCKING mode - _clientConnection.configureBlocking(true); + _clientConnection.configureBlocking(false); final SSLContext sslContext = Link.initSSLContext(true); - sslEngine = sslContext.createSSLEngine(_host, _port); + SSLEngine sslEngine = sslContext.createSSLEngine(_host, _port); sslEngine.setUseClientMode(true); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - - Link.doHandshake(_clientConnection, sslEngine, true); + sslEngine.beginHandshake(); + if (!Link.doHandshake(_clientConnection, sslEngine, true)) { + s_logger.error("SSL Handshake failed while connecting to host: " + _host + " port: " + _port); + _selector.close(); + throw new IOException("SSL Handshake failed while connecting to host: " + _host + " port: " + _port); + } s_logger.info("SSL: Handshake done"); s_logger.info("Connected to " + _host + ":" + _port); - _clientConnection.configureBlocking(false); final Link link = new Link(peerAddr, this); link.setSSLEngine(sslEngine); final SelectionKey key = _clientConnection.register(_selector, SelectionKey.OP_READ); diff --git a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java index 249f512d9c..9d755d6bce 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioConnection.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioConnection.java @@ -19,8 +19,13 @@ package com.cloud.utils.nio; -import static com.cloud.utils.AutoCloseableUtil.closeAutoCloseable; +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.exception.NioConnectionException; +import org.apache.cloudstack.utils.security.SSLUtils; +import org.apache.log4j.Logger; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; @@ -44,14 +49,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; - -import org.apache.cloudstack.utils.security.SSLUtils; -import org.apache.log4j.Logger; - -import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.exception.NioConnectionException; +import static com.cloud.utils.AutoCloseableUtil.closeAutoCloseable; /** * NioConnection abstracts the NIO socket operations. The Java implementation @@ -71,6 +69,7 @@ public abstract class NioConnection implements Callable { protected HandlerFactory _factory; protected String _name; protected ExecutorService _executor; + protected ExecutorService _sslHandshakeExecutor; public NioConnection(final String name, final int port, final int workers, final HandlerFactory factory) { _name = name; @@ -79,6 +78,7 @@ public NioConnection(final String name, final int port, final int workers, final _port = port; _factory = factory; _executor = new ThreadPoolExecutor(workers, 5 * workers, 1, TimeUnit.DAYS, new LinkedBlockingQueue(), new NamedThreadFactory(name + "-Handler")); + _sslHandshakeExecutor = Executors.newCachedThreadPool(new NamedThreadFactory(name + "-SSLHandshakeHandler")); } public void start() throws NioConnectionException { @@ -125,7 +125,7 @@ public boolean isStartup() { public Boolean call() throws NioConnectionException { while (_isRunning) { try { - _selector.select(); + _selector.select(1000); // Someone is ready for I/O, get the ready keys final Set readyKeys = _selector.selectedKeys(); @@ -185,8 +185,9 @@ public Boolean call() throws NioConnectionException { protected void accept(final SelectionKey key) throws IOException { final ServerSocketChannel serverSocketChannel = (ServerSocketChannel)key.channel(); - final SocketChannel socketChannel = serverSocketChannel.accept(); + socketChannel.configureBlocking(false); + final Socket socket = socketChannel.socket(); socket.setKeepAlive(true); @@ -194,43 +195,52 @@ protected void accept(final SelectionKey key) throws IOException { s_logger.trace("Connection accepted for " + socket); } - // Begin SSL handshake in BLOCKING mode - socketChannel.configureBlocking(true); - - SSLEngine sslEngine = null; + final SSLEngine sslEngine; try { final SSLContext sslContext = Link.initSSLContext(false); sslEngine = sslContext.createSSLEngine(); sslEngine.setUseClientMode(false); sslEngine.setNeedClientAuth(false); sslEngine.setEnabledProtocols(SSLUtils.getSupportedProtocols(sslEngine.getEnabledProtocols())); - - Link.doHandshake(socketChannel, sslEngine, false); - + final NioConnection nioConnection = this; + _sslHandshakeExecutor.submit(new Runnable() { + @Override + public void run() { + _selector.wakeup(); + try { + sslEngine.beginHandshake(); + if (!Link.doHandshake(socketChannel, sslEngine, false)) { + throw new IOException("SSL handshake timed out with " + socketChannel.getRemoteAddress()); + } + if (s_logger.isTraceEnabled()) { + s_logger.trace("SSL: Handshake done"); + } + final InetSocketAddress saddr = (InetSocketAddress)socket.getRemoteSocketAddress(); + final Link link = new Link(saddr, nioConnection); + link.setSSLEngine(sslEngine); + link.setKey(socketChannel.register(key.selector(), SelectionKey.OP_READ, link)); + final Task task = _factory.create(Task.Type.CONNECT, link, null); + registerLink(saddr, link); + _executor.submit(task); + } catch (IOException e) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("Connection closed due to failure: " + e.getMessage()); + } + closeAutoCloseable(socket, "accepting socket"); + closeAutoCloseable(socketChannel, "accepting socketChannel"); + } finally { + _selector.wakeup(); + } + } + }); } catch (final Exception e) { if (s_logger.isTraceEnabled()) { - s_logger.trace("Socket " + socket + " closed on read. Probably -1 returned: " + e.getMessage()); + s_logger.trace("Connection closed due to failure: " + e.getMessage()); } + closeAutoCloseable(socket, "accepting socket"); closeAutoCloseable(socketChannel, "accepting socketChannel"); - closeAutoCloseable(socket, "opened socket"); - return; - } - - if (s_logger.isTraceEnabled()) { - s_logger.trace("SSL: Handshake done"); - } - socketChannel.configureBlocking(false); - final InetSocketAddress saddr = (InetSocketAddress)socket.getRemoteSocketAddress(); - final Link link = new Link(saddr, this); - link.setSSLEngine(sslEngine); - link.setKey(socketChannel.register(key.selector(), SelectionKey.OP_READ, link)); - final Task task = _factory.create(Task.Type.CONNECT, link, null); - registerLink(saddr, link); - - try { - _executor.submit(task); - } catch (final Exception e) { - s_logger.warn("Exception occurred when submitting the task", e); + } finally { + _selector.wakeup(); } } diff --git a/utils/src/main/java/com/cloud/utils/nio/NioServer.java b/utils/src/main/java/com/cloud/utils/nio/NioServer.java index 539c2bb13d..b655f1838b 100644 --- a/utils/src/main/java/com/cloud/utils/nio/NioServer.java +++ b/utils/src/main/java/com/cloud/utils/nio/NioServer.java @@ -43,6 +43,10 @@ public NioServer(final String name, final int port, final int workers, final Han _links = new WeakHashMap(1024); } + public int getPort() { + return _serverSocket.socket().getLocalPort(); + } + @Override protected void init() throws IOException { _selector = SelectorProvider.provider().openSelector(); @@ -55,7 +59,7 @@ protected void init() throws IOException { _serverSocket.register(_selector, SelectionKey.OP_ACCEPT, null); - s_logger.info("NioConnection started and listening on " + _localAddr.toString()); + s_logger.info("NioConnection started and listening on " + _serverSocket.socket().getLocalSocketAddress()); } @Override diff --git a/utils/src/main/java/com/cloud/utils/ssh/SshHelper.java b/utils/src/main/java/com/cloud/utils/ssh/SshHelper.java index d3c88c8367..4d7a852d41 100644 --- a/utils/src/main/java/com/cloud/utils/ssh/SshHelper.java +++ b/utils/src/main/java/com/cloud/utils/ssh/SshHelper.java @@ -20,18 +20,26 @@ package com.cloud.utils.ssh; import java.io.File; +import java.io.IOException; import java.io.InputStream; import org.apache.log4j.Logger; import com.trilead.ssh2.ChannelCondition; - +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.Session; import com.cloud.utils.Pair; public class SshHelper { private static final int DEFAULT_CONNECT_TIMEOUT = 180000; private static final int DEFAULT_KEX_TIMEOUT = 60000; + /** + * Waiting time to check if the SSH session was successfully opened. This value (of 1000 + * milliseconds) represents one (1) second. + */ + private static final long WAITING_OPEN_SSH_SESSION = 1000; + private static final Logger s_logger = Logger.getLogger(SshHelper.class); public static Pair sshExecute(String host, int port, String user, File pemKeyFile, String password, String command) throws Exception { @@ -40,19 +48,19 @@ public static Pair sshExecute(String host, int port, String use } public static void scpTo(String host, int port, String user, File pemKeyFile, String password, String remoteTargetDirectory, String localFile, String fileMode) - throws Exception { + throws Exception { scpTo(host, port, user, pemKeyFile, password, remoteTargetDirectory, localFile, fileMode, DEFAULT_CONNECT_TIMEOUT, DEFAULT_KEX_TIMEOUT); } public static void scpTo(String host, int port, String user, File pemKeyFile, String password, String remoteTargetDirectory, byte[] data, String remoteFileName, - String fileMode) throws Exception { + String fileMode) throws Exception { scpTo(host, port, user, pemKeyFile, password, remoteTargetDirectory, data, remoteFileName, fileMode, DEFAULT_CONNECT_TIMEOUT, DEFAULT_KEX_TIMEOUT); } public static void scpTo(String host, int port, String user, File pemKeyFile, String password, String remoteTargetDirectory, String localFile, String fileMode, - int connectTimeoutInMs, int kexTimeoutInMs) throws Exception { + int connectTimeoutInMs, int kexTimeoutInMs) throws Exception { com.trilead.ssh2.Connection conn = null; com.trilead.ssh2.SCPClient scpClient = null; @@ -88,7 +96,7 @@ public static void scpTo(String host, int port, String user, File pemKeyFile, St } public static void scpTo(String host, int port, String user, File pemKeyFile, String password, String remoteTargetDirectory, byte[] data, String remoteFileName, - String fileMode, int connectTimeoutInMs, int kexTimeoutInMs) throws Exception { + String fileMode, int connectTimeoutInMs, int kexTimeoutInMs) throws Exception { com.trilead.ssh2.Connection conn = null; com.trilead.ssh2.SCPClient scpClient = null; @@ -123,7 +131,8 @@ public static void scpTo(String host, int port, String user, File pemKeyFile, St } public static Pair sshExecute(String host, int port, String user, File pemKeyFile, String password, String command, int connectTimeoutInMs, - int kexTimeoutInMs, int waitResultTimeoutInMs) throws Exception { + int kexTimeoutInMs, + int waitResultTimeoutInMs) throws Exception { com.trilead.ssh2.Connection conn = null; com.trilead.ssh2.Session sess = null; @@ -144,7 +153,7 @@ public static Pair sshExecute(String host, int port, String use throw new Exception(msg); } } - sess = conn.openSession(); + sess = openConnectionSession(conn); sess.execCommand(command); @@ -156,22 +165,22 @@ public static Pair sshExecute(String host, int port, String use int currentReadBytes = 0; while (true) { + throwSshExceptionIfStdoutOrStdeerIsNull(stdout, stderr); + if ((stdout.available() == 0) && (stderr.available() == 0)) { - int conditions = - sess.waitForCondition(ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA | ChannelCondition.EOF | ChannelCondition.EXIT_STATUS, + int conditions = sess.waitForCondition(ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA | ChannelCondition.EOF | ChannelCondition.EXIT_STATUS, waitResultTimeoutInMs); - if ((conditions & ChannelCondition.TIMEOUT) != 0) { - String msg = "Timed out in waiting SSH execution result"; - s_logger.error(msg); - throw new Exception(msg); - } + throwSshExceptionIfConditionsTimeout(conditions); if ((conditions & ChannelCondition.EXIT_STATUS) != 0) { - if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0) { - break; - } + break; + } + + if (canEndTheSshConnection(waitResultTimeoutInMs, sess, conditions)) { + break; } + } while (stdout.available() > 0) { @@ -189,11 +198,12 @@ public static Pair sshExecute(String host, int port, String use if (sess.getExitStatus() == null) { //Exit status is NOT available. Returning failure result. + s_logger.error(String.format("SSH execution of command %s has no exit status set. Result output: %s", command, result)); return new Pair(false, result); } if (sess.getExitStatus() != null && sess.getExitStatus().intValue() != 0) { - s_logger.error("SSH execution of command " + command + " has an error status code in return. result output: " + result); + s_logger.error(String.format("SSH execution of command %s has an error status code in return. Result output: %s", command, result)); return new Pair(false, result); } @@ -206,4 +216,66 @@ public static Pair sshExecute(String host, int port, String use conn.close(); } } + + /** + * It gets a {@link Session} from the given {@link Connection}; then, it waits + * {@value #WAITING_OPEN_SSH_SESSION} milliseconds before returning the session, given a time to + * ensure that the connection is open before proceeding the execution. + */ + protected static Session openConnectionSession(Connection conn) throws IOException, InterruptedException { + Session sess = conn.openSession(); + Thread.sleep(WAITING_OPEN_SSH_SESSION); + return sess; + } + + /** + * Handles the SSH connection in case of timeout or exit. If the session ends with a timeout + * condition, it throws an exception; if the channel reaches an end of file condition, but it + * does not have an exit status, it returns true to break the loop; otherwise, it returns + * false. + */ + protected static boolean canEndTheSshConnection(int waitResultTimeoutInMs, com.trilead.ssh2.Session sess, int conditions) throws SshException { + if (isChannelConditionEof(conditions)) { + int newConditions = sess.waitForCondition(ChannelCondition.EXIT_STATUS, waitResultTimeoutInMs); + throwSshExceptionIfConditionsTimeout(newConditions); + if ((newConditions & ChannelCondition.EXIT_STATUS) != 0) { + return true; + } + } + return false; + } + + /** + * It throws a {@link SshException} if the channel condition is {@link ChannelCondition#TIMEOUT} + */ + protected static void throwSshExceptionIfConditionsTimeout(int conditions) throws SshException { + if ((conditions & ChannelCondition.TIMEOUT) != 0) { + String msg = "Timed out in waiting for SSH execution exit status"; + s_logger.error(msg); + throw new SshException(msg); + } + } + + /** + * Checks if the channel condition mask is of {@link ChannelCondition#EOF} and not + * {@link ChannelCondition#STDERR_DATA} or {@link ChannelCondition#STDOUT_DATA}. + */ + protected static boolean isChannelConditionEof(int conditions) { + if ((conditions & ChannelCondition.EOF) != 0) { + return true; + } + return false; + } + + /** + * Checks if the SSH session {@link com.trilead.ssh2.Session#getStdout()} or + * {@link com.trilead.ssh2.Session#getStderr()} is null. + */ + protected static void throwSshExceptionIfStdoutOrStdeerIsNull(InputStream stdout, InputStream stderr) throws SshException { + if (stdout == null || stderr == null) { + String msg = "Stdout or Stderr of SSH session is null"; + s_logger.error(msg); + throw new SshException(msg); + } + } } diff --git a/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessResult.java b/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessResult.java new file mode 100644 index 0000000000..b50a7ab8c7 --- /dev/null +++ b/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessResult.java @@ -0,0 +1,46 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.utils.process; + +public final class ProcessResult { + private final String stdOutput; + private final String stdError; + private final int returnCode; + + public ProcessResult(String stdOutput, String stdError, int returnCode) { + this.stdOutput = stdOutput; + this.stdError = stdError; + this.returnCode = returnCode; + } + + public String getStdOutput() { + return stdOutput; + } + + public String getStdError() { + return stdError; + } + + public int getReturnCode() { + return returnCode; + } + + public boolean isSuccess() { + return returnCode == 0; + } +} diff --git a/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessRunner.java b/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessRunner.java new file mode 100644 index 0000000000..c8ea6bf59a --- /dev/null +++ b/utils/src/main/java/org/apache/cloudstack/utils/process/ProcessRunner.java @@ -0,0 +1,115 @@ +// +// 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.utils.process; + +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.io.CharStreams; +import org.apache.log4j.Logger; +import org.joda.time.Duration; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public final class ProcessRunner { + public static final Logger LOG = Logger.getLogger(ProcessRunner.class); + + // Default maximum timeout of 5 minutes for any command + public static final Duration DEFAULT_MAX_TIMEOUT = new Duration(5 * 60 * 1000); + private final ExecutorService executor; + + public ProcessRunner(ExecutorService executor) { + this.executor = executor; + } + + /** + * Executes a process with provided list of commands with a max default timeout + * of 5 minutes + * @param commands list of string commands + * @return returns process result + */ + public ProcessResult executeCommands(final List commands) { + return executeCommands(commands, DEFAULT_MAX_TIMEOUT); + } + + /** + * Executes a process with provided list of commands with a given timeout that is less + * than or equal to DEFAULT_MAX_TIMEOUT + * @param commands list of string commands + * @param timeOut timeout duration + * @return returns process result + */ + public ProcessResult executeCommands(final List commands, final Duration timeOut) { + Preconditions.checkArgument(commands != null && timeOut != null + && timeOut.getStandardSeconds() > 0L + && (timeOut.compareTo(DEFAULT_MAX_TIMEOUT) <= 0) + && executor != null); + + int retVal = -2; + String stdOutput = null; + String stdError = null; + + try { + final Process process = new ProcessBuilder().command(commands).start(); + final Future processFuture = executor.submit(new Callable() { + @Override + public Integer call() throws Exception { + return process.waitFor(); + } + }); + try { + retVal = processFuture.get(timeOut.getStandardSeconds(), TimeUnit.SECONDS); + } catch (ExecutionException e) { + retVal = -2; + stdError = e.getMessage(); + if (LOG.isTraceEnabled()) { + LOG.trace("Failed to complete the requested command due to execution error: " + e.getMessage()); + } + } catch (TimeoutException e) { + retVal = -1; + stdError = "Operation timed out, aborted"; + if (LOG.isTraceEnabled()) { + LOG.trace("Failed to complete the requested command within timeout: " + e.getMessage()); + } + } finally { + if (Strings.isNullOrEmpty(stdError)) { + stdOutput = CharStreams.toString(new InputStreamReader(process.getInputStream())); + stdError = CharStreams.toString(new InputStreamReader(process.getErrorStream())); + } + process.destroy(); + } + if (LOG.isTraceEnabled()) { + LOG.trace("Process standard output: " + stdOutput); + LOG.trace("Process standard error output: " + stdError); + } + } catch (IOException | InterruptedException e) { + stdError = e.getMessage(); + LOG.error("Exception caught error running commands: " + e.getMessage()); + } + return new ProcessResult(stdOutput, stdError, retVal); + } +} \ No newline at end of file diff --git a/utils/src/test/java/com/cloud/utils/SwiftUtilTest.java b/utils/src/test/java/com/cloud/utils/SwiftUtilTest.java index 55f7a3479e..20c1623d82 100644 --- a/utils/src/test/java/com/cloud/utils/SwiftUtilTest.java +++ b/utils/src/test/java/com/cloud/utils/SwiftUtilTest.java @@ -19,9 +19,11 @@ package com.cloud.utils; + import org.junit.Test; import org.mockito.Mockito; +import java.io.File; import java.net.URL; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -32,7 +34,6 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; - public class SwiftUtilTest { @Test @@ -72,7 +73,7 @@ public void testGenerateTempUrl() { @Test public void testSplitSwiftPath(){ - String input = "container/object"; + String input = "container" + File.separator + "object"; String[] output = SwiftUtil.splitSwiftPath(input); String[] expected = {"container", "object"}; diff --git a/utils/src/test/java/com/cloud/utils/TestProfiler.java b/utils/src/test/java/com/cloud/utils/TestProfiler.java index f0e163e63f..0e68175133 100644 --- a/utils/src/test/java/com/cloud/utils/TestProfiler.java +++ b/utils/src/test/java/com/cloud/utils/TestProfiler.java @@ -19,84 +19,79 @@ package com.cloud.utils; -import org.apache.log4j.Logger; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import com.cloud.utils.testcase.Log4jEnabledTestCase; +@RunWith(PowerMockRunner.class) +@PrepareForTest({Profiler.class}) public class TestProfiler extends Log4jEnabledTestCase { - protected final static Logger s_logger = Logger.getLogger(TestProfiler.class); - private static final long MILLIS_FACTOR = 1000l; - private static final int MARGIN = 100; - // Profiler uses System.nanoTime which is not reliable on the millisecond - // A sleep of 1000 milliseconds CAN be measured as 999 milliseconds - // Therefore make the second larger, by 10% of the margin - private static final long ONE_SECOND = 1000l + (MARGIN / 10); - private static final double EXPONENT = 3d; + private static final long SLEEP_TIME_NANO = 1000000000L; + private static Profiler pf; + + @Before + public void setUp() { + pf = new Profiler(); + PowerMockito.mockStatic(System.class); + PowerMockito.when(System.nanoTime()).thenReturn(0L, SLEEP_TIME_NANO); + } @Test public void testProfilerInMillis() { - s_logger.info("testProfiler() started"); + //Given + final long sleepTimeMillis = SLEEP_TIME_NANO / 1000000L; - final Profiler pf = new Profiler(); + //When pf.start(); - try { - Thread.sleep(ONE_SECOND); - } catch (final InterruptedException e) { - } pf.stop(); - final long durationInMillis = pf.getDurationInMillis(); - s_logger.info("Duration in Millis: " + durationInMillis); - - // An error margin in order to cover the time taken by the star/stop calls. - // 100 milliseconds margin seems too much, but it will avoid assertion error - // and also fail in case a duration in nanoseconds is used instead. - Assert.assertTrue(durationInMillis >= MILLIS_FACTOR && durationInMillis <= MILLIS_FACTOR + MARGIN); - - s_logger.info("testProfiler() stopped"); + //Then + Assert.assertTrue(pf.getDurationInMillis() == sleepTimeMillis); } @Test public void testProfilerInNano() { - final Profiler pf = new Profiler(); + //Given + final long sleepTimeNano = SLEEP_TIME_NANO; + + //When pf.start(); - try { - Thread.sleep(ONE_SECOND); - } catch (final InterruptedException e) { - } pf.stop(); - final long duration = pf.getDuration(); - s_logger.info("Duration in Nano: " + duration); - Assert.assertTrue(duration >= Math.pow(MILLIS_FACTOR, EXPONENT)); + //Then + Assert.assertTrue(pf.getDuration() == sleepTimeNano); } @Test public void testProfilerNoStart() { - final Profiler pf = new Profiler(); - try { - Thread.sleep(20); - } catch (final InterruptedException e) { - } + //Given + final long expectedAnswer = -1; + + //When pf.stop(); - Assert.assertTrue(pf.getDurationInMillis() == -1); + //Then + Assert.assertTrue(pf.getDurationInMillis() == expectedAnswer); Assert.assertFalse(pf.isStarted()); } @Test public void testProfilerNoStop() { - final Profiler pf = new Profiler(); + //Given + final long expectedAnswer = -1; + + //When pf.start(); - try { - Thread.sleep(20); - } catch (final InterruptedException e) { - } - Assert.assertTrue(pf.getDurationInMillis() == -1); + //Then + Assert.assertTrue(pf.getDurationInMillis() == expectedAnswer); Assert.assertFalse(pf.isStopped()); } } \ No newline at end of file diff --git a/utils/src/test/java/com/cloud/utils/ssh/SshHelperTest.java b/utils/src/test/java/com/cloud/utils/ssh/SshHelperTest.java new file mode 100644 index 0000000000..355a51416b --- /dev/null +++ b/utils/src/test/java/com/cloud/utils/ssh/SshHelperTest.java @@ -0,0 +1,151 @@ +// +// 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.utils.ssh; + +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.trilead.ssh2.ChannelCondition; +import com.trilead.ssh2.Connection; +import com.trilead.ssh2.Session; + +@PrepareForTest({ Thread.class, SshHelper.class }) +@RunWith(PowerMockRunner.class) +public class SshHelperTest { + + @Test + public void canEndTheSshConnectionTest() throws Exception { + PowerMockito.spy(SshHelper.class); + Session mockedSession = Mockito.mock(Session.class); + + PowerMockito.doReturn(true).when(SshHelper.class, "isChannelConditionEof", Mockito.anyInt()); + Mockito.when(mockedSession.waitForCondition(ChannelCondition.EXIT_STATUS, 1l)).thenReturn(0); + PowerMockito.doNothing().when(SshHelper.class, "throwSshExceptionIfConditionsTimeout", Mockito.anyInt()); + + SshHelper.canEndTheSshConnection(1, mockedSession, 0); + + PowerMockito.verifyStatic(); + SshHelper.isChannelConditionEof(Mockito.anyInt()); + SshHelper.throwSshExceptionIfConditionsTimeout(Mockito.anyInt()); + + Mockito.verify(mockedSession).waitForCondition(ChannelCondition.EXIT_STATUS, 1l); + } + + @Test(expected = SshException.class) + public void throwSshExceptionIfConditionsTimeout() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.TIMEOUT); + } + + @Test + public void doNotThrowSshExceptionIfConditionsClosed() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.CLOSED); + } + + @Test + public void doNotThrowSshExceptionIfConditionsStdout() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.STDOUT_DATA); + } + + @Test + public void doNotThrowSshExceptionIfConditionsStderr() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.STDERR_DATA); + } + + @Test + public void doNotThrowSshExceptionIfConditionsEof() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.EOF); + } + + @Test + public void doNotThrowSshExceptionIfConditionsExitStatus() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.EXIT_STATUS); + } + + @Test + public void doNotThrowSshExceptionIfConditionsExitSignal() throws SshException { + SshHelper.throwSshExceptionIfConditionsTimeout(ChannelCondition.EXIT_SIGNAL); + } + + @Test + public void isChannelConditionEofTestTimeout() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.TIMEOUT)); + } + + @Test + public void isChannelConditionEofTestClosed() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.CLOSED)); + } + + @Test + public void isChannelConditionEofTestStdout() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.STDOUT_DATA)); + } + + @Test + public void isChannelConditionEofTestStderr() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.STDERR_DATA)); + } + + @Test + public void isChannelConditionEofTestEof() { + Assert.assertTrue(SshHelper.isChannelConditionEof(ChannelCondition.EOF)); + } + + @Test + public void isChannelConditionEofTestExitStatus() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.EXIT_STATUS)); + } + + @Test + public void isChannelConditionEofTestExitSignal() { + Assert.assertFalse(SshHelper.isChannelConditionEof(ChannelCondition.EXIT_SIGNAL)); + } + + @Test(expected = SshException.class) + public void throwSshExceptionIfStdoutOrStdeerIsNullTestNull() throws SshException { + SshHelper.throwSshExceptionIfStdoutOrStdeerIsNull(null, null); + } + + @Test + public void throwSshExceptionIfStdoutOrStdeerIsNullTestNotNull() throws SshException { + InputStream inputStream = Mockito.mock(InputStream.class); + SshHelper.throwSshExceptionIfStdoutOrStdeerIsNull(inputStream, inputStream); + } + + @Test + public void openConnectionSessionTest() throws IOException, InterruptedException { + Connection conn = Mockito.mock(Connection.class); + PowerMockito.mockStatic(Thread.class); + SshHelper.openConnectionSession(conn); + + Mockito.verify(conn).openSession(); + + PowerMockito.verifyStatic(); + Thread.sleep(Mockito.anyLong()); + } +} diff --git a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java index d8510cfcac..894aa1adc8 100644 --- a/utils/src/test/java/com/cloud/utils/testcase/NioTest.java +++ b/utils/src/test/java/com/cloud/utils/testcase/NioTest.java @@ -19,14 +19,7 @@ package com.cloud.utils.testcase; -import java.nio.channels.ClosedChannelException; -import java.util.Random; - -import junit.framework.TestCase; - -import org.apache.log4j.Logger; -import org.junit.Assert; - +import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.exception.NioConnectionException; import com.cloud.utils.nio.HandlerFactory; import com.cloud.utils.nio.Link; @@ -34,131 +27,199 @@ import com.cloud.utils.nio.NioServer; import com.cloud.utils.nio.Task; import com.cloud.utils.nio.Task.Type; +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** - * - * - * - * + * NioTest demonstrates that NioServer can function without getting its main IO + * loop blocked when an aggressive or malicious client connects to the server but + * fail to participate in SSL handshake. In this test, we run bunch of clients + * that send a known payload to the server, to which multiple malicious clients + * also try to connect and hang. + * A malicious client could cause denial-of-service if the server's main IO loop + * along with SSL handshake was blocking. A passing tests shows that NioServer + * can still function in case of connection load and that the main IO loop along + * with SSL handshake is non-blocking with some internal timeout mechanism. */ -public class NioTest extends TestCase { +public class NioTest { + + private static final Logger LOGGER = Logger.getLogger(NioTest.class); - private static final Logger s_logger = Logger.getLogger(NioTest.class); + // Test should fail in due time instead of looping forever + private static final int TESTTIMEOUT = 60000; - private NioServer _server; - private NioClient _client; + final private int totalTestCount = 2; + private int completedTestCount = 0; - private Link _clientLink; + private NioServer server; + private List clients = new ArrayList<>(); + private List maliciousClients = new ArrayList<>(); - private int _testCount; - private int _completedCount; + private ExecutorService clientExecutor = Executors.newFixedThreadPool(totalTestCount, new NamedThreadFactory("NioClientHandler"));; + private ExecutorService maliciousExecutor = Executors.newFixedThreadPool(totalTestCount, new NamedThreadFactory("MaliciousNioClientHandler"));; + + private Random randomGenerator = new Random(); + private byte[] testBytes; private boolean isTestsDone() { boolean result; synchronized (this) { - result = _testCount == _completedCount; + result = totalTestCount == completedTestCount; } return result; } - private void getOneMoreTest() { - synchronized (this) { - _testCount++; - } - } - private void oneMoreTestDone() { synchronized (this) { - _completedCount++; + completedTestCount++; } } - @Override + @Before public void setUp() { - s_logger.info("Test"); + LOGGER.info("Setting up Benchmark Test"); - _testCount = 0; - _completedCount = 0; + completedTestCount = 0; + testBytes = new byte[1000000]; + randomGenerator.nextBytes(testBytes); - _server = new NioServer("NioTestServer", 7777, 5, new NioTestServer()); + server = new NioServer("NioTestServer", 0, 1, new NioTestServer()); try { - _server.start(); + server.start(); } catch (final NioConnectionException e) { - fail(e.getMessage()); + Assert.fail(e.getMessage()); } - _client = new NioClient("NioTestServer", "127.0.0.1", 7777, 5, new NioTestClient()); - try { - _client.start(); - } catch (final NioConnectionException e) { - fail(e.getMessage()); - } + for (int i = 0; i < totalTestCount; i++) { + final NioClient maliciousClient = new NioMaliciousClient("NioMaliciousTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioMaliciousTestClient()); + maliciousClients.add(maliciousClient); + maliciousExecutor.submit(new ThreadedNioClient(maliciousClient)); - while (_clientLink == null) { - try { - s_logger.debug("Link is not up! Waiting ..."); - Thread.sleep(1000); - } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + final NioClient client = new NioClient("NioTestClient-" + i, "127.0.0.1", server.getPort(), 1, new NioTestClient()); + clients.add(client); + clientExecutor.submit(new ThreadedNioClient(client)); } } - @Override + @After public void tearDown() { + stopClient(); + stopServer(); + } + + protected void stopClient() { + for (NioClient client : clients) { + client.stop(); + } + for (NioClient maliciousClient : maliciousClients) { + maliciousClient.stop(); + } + LOGGER.info("Clients stopped."); + } + + protected void stopServer() { + server.stop(); + LOGGER.info("Server stopped."); + } + + @Test(timeout=TESTTIMEOUT) + public void testConnection() { while (!isTestsDone()) { try { - s_logger.debug(_completedCount + "/" + _testCount + " tests done. Waiting for completion"); + LOGGER.debug(completedTestCount + "/" + totalTestCount + " tests done. Waiting for completion"); Thread.sleep(1000); } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Assert.fail(e.getMessage()); } } - stopClient(); - stopServer(); + LOGGER.debug(completedTestCount + "/" + totalTestCount + " tests done."); } - protected void stopClient() { - _client.stop(); - s_logger.info("Client stopped."); + protected void doServerProcess(final byte[] data) { + oneMoreTestDone(); + Assert.assertArrayEquals(testBytes, data); + LOGGER.info("Verify data received by server done."); } - protected void stopServer() { - _server.stop(); - s_logger.info("Server stopped."); + public byte[] getTestBytes() { + return testBytes; } - protected void setClientLink(final Link link) { - _clientLink = link; + public class ThreadedNioClient implements Runnable { + final private NioClient client; + ThreadedNioClient(final NioClient client) { + this.client = client; + } + + @Override + public void run() { + try { + client.start(); + } catch (NioConnectionException e) { + Assert.fail(e.getMessage()); + } + } } - Random randomGenerator = new Random(); + public class NioMaliciousClient extends NioClient { - byte[] _testBytes; + public NioMaliciousClient(String name, String host, int port, int workers, HandlerFactory factory) { + super(name, host, port, workers, factory); + } - public void testConnection() { - _testBytes = new byte[1000000]; - randomGenerator.nextBytes(_testBytes); - try { - getOneMoreTest(); - _clientLink.send(_testBytes); - s_logger.info("Client: Data sent"); - getOneMoreTest(); - _clientLink.send(_testBytes); - s_logger.info("Client: Data sent"); - } catch (final ClosedChannelException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + @Override + protected void init() throws IOException { + _selector = Selector.open(); + try { + _clientConnection = SocketChannel.open(); + LOGGER.info("Connecting to " + _host + ":" + _port); + final InetSocketAddress peerAddr = new InetSocketAddress(_host, _port); + _clientConnection.connect(peerAddr); + // This is done on purpose, the malicious client would connect + // to the server and then do nothing, hence using a large sleep value + Thread.sleep(Long.MAX_VALUE); + } catch (final IOException e) { + _selector.close(); + throw e; + } catch (InterruptedException e) { + LOGGER.debug(e.getMessage()); + } } } - protected void doServerProcess(final byte[] data) { - oneMoreTestDone(); - Assert.assertArrayEquals(_testBytes, data); - s_logger.info("Verify done."); + public class NioMaliciousTestClient implements HandlerFactory { + + @Override + public Task create(final Type type, final Link link, final byte[] data) { + return new NioMaliciousTestClientHandler(type, link, data); + } + + public class NioMaliciousTestClientHandler extends Task { + + public NioMaliciousTestClientHandler(final Type type, final Link link, final byte[] data) { + super(type, link, data); + } + + @Override + public void doTask(final Task task) { + LOGGER.info("Malicious Client: Received task " + task.getType().toString()); + } + } } public class NioTestClient implements HandlerFactory { @@ -177,18 +238,23 @@ public NioTestClientHandler(final Type type, final Link link, final byte[] data) @Override public void doTask(final Task task) { if (task.getType() == Task.Type.CONNECT) { - s_logger.info("Client: Received CONNECT task"); - setClientLink(task.getLink()); + LOGGER.info("Client: Received CONNECT task"); + try { + LOGGER.info("Sending data to server"); + task.getLink().send(getTestBytes()); + } catch (ClosedChannelException e) { + LOGGER.error(e.getMessage()); + e.printStackTrace(); + } } else if (task.getType() == Task.Type.DATA) { - s_logger.info("Client: Received DATA task"); + LOGGER.info("Client: Received DATA task"); } else if (task.getType() == Task.Type.DISCONNECT) { - s_logger.info("Client: Received DISCONNECT task"); + LOGGER.info("Client: Received DISCONNECT task"); stopClient(); } else if (task.getType() == Task.Type.OTHER) { - s_logger.info("Client: Received OTHER task"); + LOGGER.info("Client: Received OTHER task"); } } - } } @@ -208,18 +274,17 @@ public NioTestServerHandler(final Type type, final Link link, final byte[] data) @Override public void doTask(final Task task) { if (task.getType() == Task.Type.CONNECT) { - s_logger.info("Server: Received CONNECT task"); + LOGGER.info("Server: Received CONNECT task"); } else if (task.getType() == Task.Type.DATA) { - s_logger.info("Server: Received DATA task"); + LOGGER.info("Server: Received DATA task"); doServerProcess(task.getData()); } else if (task.getType() == Task.Type.DISCONNECT) { - s_logger.info("Server: Received DISCONNECT task"); + LOGGER.info("Server: Received DISCONNECT task"); stopServer(); } else if (task.getType() == Task.Type.OTHER) { - s_logger.info("Server: Received OTHER task"); + LOGGER.info("Server: Received OTHER task"); } } - } } } diff --git a/utils/src/test/java/org/apache/cloudstack/utils/hypervisor/HypervisorUtilsTest.java b/utils/src/test/java/org/apache/cloudstack/utils/hypervisor/HypervisorUtilsTest.java index 54d002f8f8..f68776760d 100644 --- a/utils/src/test/java/org/apache/cloudstack/utils/hypervisor/HypervisorUtilsTest.java +++ b/utils/src/test/java/org/apache/cloudstack/utils/hypervisor/HypervisorUtilsTest.java @@ -57,7 +57,7 @@ public void checkVolumeFileForActivitySmallFileTest() throws IOException { public void checkVolumeFileForActivityTest() throws IOException { System.out.print("Testing block on modified files - "); String filePath = "./testfileinactive"; - int timeoutSeconds = 5; + int timeoutSeconds = 8; long thresholdMilliseconds = 2000; File file = new File(filePath); diff --git a/utils/src/test/java/org/apache/cloudstack/utils/process/ProcessTest.java b/utils/src/test/java/org/apache/cloudstack/utils/process/ProcessTest.java new file mode 100644 index 0000000000..2c158c800a --- /dev/null +++ b/utils/src/test/java/org/apache/cloudstack/utils/process/ProcessTest.java @@ -0,0 +1,68 @@ +// +// 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.utils.process; + +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.google.common.base.Strings; +import org.joda.time.Duration; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.Arrays; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@RunWith(MockitoJUnitRunner.class) +public class ProcessTest { + + private static final ExecutorService executor = Executors.newFixedThreadPool(10, new NamedThreadFactory("IpmiToolDriverTest")); + private static final ProcessRunner RUNNER = new ProcessRunner(executor); + + @Test + public void testProcessRunner() { + ProcessResult result = RUNNER.executeCommands(Arrays.asList("sleep", "0")); + Assert.assertEquals(result.getReturnCode(), 0); + Assert.assertTrue(Strings.isNullOrEmpty(result.getStdError())); + } + + @Test + public void testProcessRunnerWithTimeout() { + ProcessResult result = RUNNER.executeCommands(Arrays.asList("sleep", "5"), Duration.standardSeconds(1)); + Assert.assertNotEquals(result.getReturnCode(), 0); + Assert.assertTrue(result.getStdError().length() > 0); + Assert.assertEquals(result.getStdError(), "Operation timed out, aborted"); + } + + @Test + public void testProcessRunnerWithTimeoutAndException() { + ProcessResult result = RUNNER.executeCommands(Arrays.asList("ls", "/some/dir/that/should/not/exist"), Duration.standardSeconds(2)); + Assert.assertNotEquals(result.getReturnCode(), 0); + Assert.assertTrue(result.getStdError().length() > 0); + Assert.assertNotEquals(result.getStdError(), "Operation timed out, aborted"); + } + + @Test(expected = IllegalArgumentException.class) + public void testProcessRunnerWithMoreThanMaxAllowedTimeout() { + RUNNER.executeCommands(Arrays.asList("ls", "/some/dir/that/should/not/exist"), ProcessRunner.DEFAULT_MAX_TIMEOUT.plus(1000)); + Assert.fail("Illegal argument exception was expected"); + } +} diff --git a/vmware-base/pom.xml b/vmware-base/pom.xml index 9df193a055..e18dc8ea14 100644 --- a/vmware-base/pom.xml +++ b/vmware-base/pom.xml @@ -24,7 +24,7 @@ org.apache.cloudstack cloudstack - 4.8.1-SNAPSHOT + 4.9.0-SNAPSHOT