Merge release branch 4.8 to 4.9
* 4.8:
CLOUDSTACK-9410: Data Disk shown as detached in XS
diff --git a/.gitignore b/.gitignore
index 58eafaf..48aa29b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -96,3 +96,5 @@
.pydevproject
systemvm/.pydevproject
test/.pydevprojec
+plugins/hypervisors/kvm/.pydevproject
+scripts/.pydevproject
diff --git a/.java-version b/.java-version
new file mode 100644
index 0000000..d3bdbdf
--- /dev/null
+++ b/.java-version
@@ -0,0 +1 @@
+1.7
diff --git a/.python-version b/.python-version
new file mode 100644
index 0000000..5643833
--- /dev/null
+++ b/.python-version
@@ -0,0 +1 @@
+cloudstack
diff --git a/.travis.yml b/.travis.yml
index 200f199..34220fe 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 @@
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 9924ba9..8a83fb0 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -38,6 +38,23 @@
$ 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 <root CloudStack source tree>/requirements.txt # Install cloudstack Python dependencies
+ # jenv add <path to JDK 1.7 installation> # 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/LICENSE b/LICENSE
index 9d53cbc..982b158 100644
--- a/LICENSE
+++ b/LICENSE
@@ -221,10 +221,7 @@
Copyright (c) 2012 The Apache Software Foundation
from The Apache Software Foundation http://www.apache.org/
httpd.conf
- ports.conf
- sites-available/default
- sites-available/default-ssl
- vhostexample.conf
+ vhost.template
Within the patches/systemvm/debian/config/etc/ssh/ directory
licensed under the BSD (2-clause) http://www.opensource.org/licenses/BSD-2-Clause (as follows)
diff --git a/agent/pom.xml b/agent/pom.xml
index f92bc8b..e984990 100644
--- a/agent/pom.xml
+++ b/agent/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
diff --git a/agent/src/com/cloud/agent/AgentShell.java b/agent/src/com/cloud/agent/AgentShell.java
index 961c106..5e0da68 100644
--- a/agent/src/com/cloud/agent/AgentShell.java
+++ b/agent/src/com/cloud/agent/AgentShell.java
@@ -409,12 +409,7 @@
/* 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 10046e1..ef9535b 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
diff --git a/api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java b/api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java
deleted file mode 100644
index 60d74f6..0000000
--- a/api/src/com/cloud/agent/api/storage/CreateVolumeOVAAnswer.java
+++ /dev/null
@@ -1,26 +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.storage;
-
-import com.cloud.agent.api.Answer;
-
-public class CreateVolumeOVAAnswer extends Answer {
- public CreateVolumeOVAAnswer(CreateVolumeOVACommand cmd, boolean result, String details) {
- super(cmd, result, details);
- }
-
-}
diff --git a/api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java b/api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java
deleted file mode 100644
index dad660b..0000000
--- a/api/src/com/cloud/agent/api/storage/PrepareOVAPackingAnswer.java
+++ /dev/null
@@ -1,26 +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.storage;
-
-import com.cloud.agent.api.Answer;
-
-public class PrepareOVAPackingAnswer extends Answer {
- public PrepareOVAPackingAnswer(PrepareOVAPackingCommand cmd, boolean result, String details) {
- super(cmd, result, details);
- }
-
-}
diff --git a/api/src/com/cloud/agent/api/to/NfsTO.java b/api/src/com/cloud/agent/api/to/NfsTO.java
index 51d1aad..1cf7218 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 @@
private DataStoreRole _role;
private String uuid;
private static final String pathSeparator = "/";
+ private Integer nfsVersion;
public NfsTO() {
@@ -71,4 +72,12 @@
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 7349c1f..3cc4eac 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 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 @@
// 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 @@
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 @@
// 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 7461455..7050b97 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 @@
Cluster getCluster(Long clusterId);
+ DataCenter getZone(Long zoneId);
+
List<HypervisorType> 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 b912e51..58cedcd 100644
--- a/api/src/com/cloud/user/Account.java
+++ b/api/src/com/cloud/user/Account.java
@@ -46,6 +46,8 @@
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 7cc1e30..959a710 100644
--- a/api/src/com/cloud/user/AccountService.java
+++ b/api/src/com/cloud/user/AccountService.java
@@ -57,9 +57,9 @@
* @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<String, String> details, String accountUUID, String userUUID);
+ short accountType, Long roleId, Long domainId, String networkDomain, Map<String, String> 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<String, String> 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 2b79438..1c23c01 100644
--- a/api/src/com/cloud/vm/VmStats.java
+++ b/api/src/com/cloud/vm/VmStats.java
@@ -32,4 +32,10 @@
public double getDiskWriteKBs();
+ public double getMemoryKBs();
+
+ public double getIntFreeMemoryKBs();
+
+ public double getTargetMemoryKBs();
+
}
diff --git a/api/src/com/cloud/vm/snapshot/VMSnapshotService.java b/api/src/com/cloud/vm/snapshot/VMSnapshotService.java
index 839da73..12767b3 100644
--- a/api/src/com/cloud/vm/snapshot/VMSnapshotService.java
+++ b/api/src/com/cloud/vm/snapshot/VMSnapshotService.java
@@ -27,11 +27,12 @@
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.uservm.UserVm;
+import com.cloud.utils.Pair;
import com.cloud.vm.VirtualMachine;
public interface VMSnapshotService {
- List<? extends VMSnapshot> listVMSnapshots(ListVMSnapshotCmd cmd);
+ Pair<List<? extends VMSnapshot>, Integer> listVMSnapshots(ListVMSnapshotCmd cmd);
VMSnapshot getVMSnapshotById(Long id);
diff --git a/api/src/com/cloud/exception/MissingParameterValueException.java b/api/src/org/apache/cloudstack/acl/Role.java
similarity index 74%
rename from api/src/com/cloud/exception/MissingParameterValueException.java
rename to api/src/org/apache/cloudstack/acl/Role.java
index 4bcaa56..b05d886 100644
--- a/api/src/com/cloud/exception/MissingParameterValueException.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.exception;
-import com.cloud.utils.exception.CloudRuntimeException;
+package org.apache.cloudstack.acl;
-public class MissingParameterValueException extends CloudRuntimeException {
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
- public MissingParameterValueException(String message) {
- super(message);
- }
-}
\ No newline at end of file
+public interface Role extends InternalIdentity, Identity {
+ String getName();
+ RoleType getRoleType();
+ String getDescription();
+}
diff --git a/api/src/com/cloud/exception/MissingParameterValueException.java b/api/src/org/apache/cloudstack/acl/RolePermission.java
similarity index 68%
copy from api/src/com/cloud/exception/MissingParameterValueException.java
copy to api/src/org/apache/cloudstack/acl/RolePermission.java
index 4bcaa56..0157a66 100644
--- a/api/src/com/cloud/exception/MissingParameterValueException.java
+++ b/api/src/org/apache/cloudstack/acl/RolePermission.java
@@ -14,13 +14,18 @@
// 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.acl;
-public class MissingParameterValueException extends CloudRuntimeException {
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
- public MissingParameterValueException(String message) {
- super(message);
- }
-}
\ No newline at end of file
+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 0000000..59eef51
--- /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<Boolean> 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<RolePermission> newOrder);
+ boolean deleteRolePermission(final RolePermission rolePermission);
+
+ List<Role> listRoles();
+ List<Role> findRolesByName(final String name);
+ List<Role> findRolesByType(final RoleType roleType);
+ List<RolePermission> 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 90e3d1e..a8a64a5 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 0000000..2792010
--- /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 2b827eb..ad711ec 100644
--- a/api/src/org/apache/cloudstack/alert/AlertService.java
+++ b/api/src/org/apache/cloudstack/alert/AlertService.java
@@ -66,6 +66,7 @@
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/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java b/api/src/org/apache/cloudstack/api/ApiArgValidator.java
similarity index 81%
copy from plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java
copy to api/src/org/apache/cloudstack/api/ApiArgValidator.java
index 4e1cc43..bd2294c 100644
--- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java
+++ b/api/src/org/apache/cloudstack/api/ApiArgValidator.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,12 +14,10 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
-//
-package com.cloud.network.sync;
+package org.apache.cloudstack.api;
-
-public interface NuageVspSync {
-
- public void syncWithNuageVsp(String nuageVspEntity);
+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 ef4ff9a..1d0b4a3 100644
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -21,6 +21,7 @@
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 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 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 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 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 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 6147408..aeeb7b6 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<String, Object[]> requestParameters, Long userId) throws ServerApiException;
@@ -27,7 +29,7 @@
public Long fetchDomainId(String domainUUID);
public ResponseObject loginUser(HttpSession session, String username, String password, Long domainId, String domainPath, InetAddress loginIpAddress,
- Map<String, Object[]> requestParameters) throws CloudAuthenticationException;
+ Map<String, Object[]> requestParameters) throws CloudAuthenticationException;
public void logoutUser(long userId);
@@ -40,4 +42,8 @@
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 360b277..5be7519 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 @@
@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 @@
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 05de218..45016c1 100644
--- a/api/src/org/apache/cloudstack/api/BaseResponse.java
+++ b/api/src/org/apache/cloudstack/api/BaseResponse.java
@@ -24,31 +24,6 @@
private transient String responseName;
private transient String objectName;
- @Override
- public String getResponseName() {
- return responseName;
- }
-
- @Override
- public void setResponseName(String responseName) {
- this.responseName = responseName;
- }
-
- @Override
- public String getObjectName() {
- return objectName;
- }
-
- @Override
- public void setObjectName(String objectName) {
- this.objectName = objectName;
- }
-
- @Override
- 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;
@@ -57,6 +32,38 @@
@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 final String getResponseName() {
+ return responseName;
+ }
+
+ @Override
+ public final void setResponseName(String responseName) {
+ this.responseName = responseName;
+ }
+
+ @Override
+ public final String getObjectName() {
+ return objectName;
+ }
+
+ @Override
+ public final void setObjectName(String objectName) {
+ this.objectName = objectName;
+ }
+
+ @Override
+ public String getObjectId() {
+ return null;
+ }
+
@Override
public String getJobId() {
return jobId;
diff --git a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireAccountIdResponse.java b/api/src/org/apache/cloudstack/api/BaseResponseWithTagInformation.java
old mode 100644
new mode 100755
similarity index 62%
copy from plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireAccountIdResponse.java
copy to api/src/org/apache/cloudstack/api/BaseResponseWithTagInformation.java
index ad77c74..3d694a3
--- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireAccountIdResponse.java
+++ b/api/src/org/apache/cloudstack/api/BaseResponseWithTagInformation.java
@@ -14,24 +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.api.response;
+package org.apache.cloudstack.api;
+
+import java.util.Set;
+
+import org.apache.cloudstack.api.response.ResourceTagResponse;
import com.cloud.serializer.Param;
-
import com.google.gson.annotations.SerializedName;
-import org.apache.cloudstack.api.BaseResponse;
+public abstract class BaseResponseWithTagInformation extends BaseResponse {
-public class ApiSolidFireAccountIdResponse extends BaseResponse {
- @SerializedName("solidFireAccountId")
- @Param(description = "SolidFire Account ID")
- private long solidFireAccountId;
+ @SerializedName(ApiConstants.TAGS)
+ @Param(description = "the list of resource tags associated", responseObject = ResourceTagResponse.class)
+ protected Set<ResourceTagResponse> tags;
- public ApiSolidFireAccountIdResponse(long sfAccountId) {
- solidFireAccountId = sfAccountId;
+ public void addTag(ResourceTagResponse tag) {
+ this.tags.add(tag);
}
- public long getSolidFireAccountId() {
- return solidFireAccountId;
+ public Set<ResourceTagResponse> 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 7ee6897..fa6075d 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 b55ce71..2e1fbd6 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 @@
@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 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 @@
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 @@
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 0000000..994573d
--- /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 0000000..aeb3f4e
--- /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 0000000..bd4a7cd
--- /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 0000000..9c7dc7c
--- /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 0000000..f20abf4
--- /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<RolePermission> rolePermissions, final Long roleId) {
+ final Role roleProvided = roleService.findRole(roleId);
+ final ListResponse<RolePermissionResponse> response = new ListResponse<>();
+ final List<RolePermissionResponse> 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<RolePermission> 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 0000000..5cf870b
--- /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<Role> roles) {
+ final ListResponse<RoleResponse> response = new ListResponse<>();
+ final List<RoleResponse> 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<Role> 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 0000000..e17fc6f
--- /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 0000000..055265c
--- /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<Long> rulePermissionOrder;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getRoleId() {
+ return roleId;
+ }
+
+ public List<Long> 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<RolePermission> 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 0124d59..45f790f 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 @@
return cfgName;
}
+ public void setCfgName(final String cfgName) {
+ this.cfgName = cfgName;
+ }
+
public String getValue() {
return value;
}
@@ -117,6 +123,12 @@
@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 d7aa18b..424fc05 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 @@
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 @@
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 0000000..ea2e3cd
--- /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 0000000..db22410
--- /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<OutOfBandManagement.Option, String> getHostPMOptions() {
+ final ImmutableMap.Builder<OutOfBandManagement.Option, String> 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 0000000..67d84d5
--- /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 0000000..009d0d3
--- /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 0000000..82e92a7
--- /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 0000000..64279c3
--- /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 0000000..7467256
--- /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 0000000..cae2181
--- /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 0000000..8d6bdd3
--- /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 6b673cf..839d64d 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 @@
@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 cfe4383..194179d 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 @@
//////////////// 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 f1d3fe9..32000c6 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 @@
@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=<uuid>&migrateto[volume-index].pool=<uuid>Where, [volume-index] indicates the index to identify the volume that you " +
+ "want to migrate, volume=<uuid> indicates the UUID of the volume that you want to migrate, and pool=<uuid> 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=<a382f181-3d2b-4413-b92d-b8931befa7e1>&" +
+ "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 24486a3..9c52656 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 @@
Map<String, Object> 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 85f6008..a400a01 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 @@
@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 a1cb478..599aac1 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 @@
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 47a6876..97bb187 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 @@
@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<Long> 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 @@
setResponseObject(response);
}
+
+ public List<Long> 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 b8fbb02..4708aff 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 c8d6ce3..59c4abe 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 @@
@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 c88b5e3..48d3e14 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 @@
@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 7a2a158..772ca27 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 @@
@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<Long> ids;
+
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the template name")
private String templateName;
@@ -132,4 +136,8 @@
response.setResponseName(getCommandName());
setResponseObject(response);
}
+
+ public List<Long> 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 8de30f6..8ff0b6b 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 @@
@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 7769ff8..da0ce2a 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 @@
return displayVm;
}
- public List<Long> getSecurityGroupIdList() {
- if (securityGroupNameList != null && securityGroupIdList != null) {
- throw new InvalidParameterValueException("securitygroupids parameter is mutually exclusive with securitygroupnames parameter");
- }
+ public List<String> getSecurityGroupNameList() {
+ return securityGroupNameList;
+ }
- //transform group names to ids here
- if (securityGroupNameList != null) {
- List<Long> securityGroupIds = new ArrayList<Long>();
- 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<Long> getSecurityGroupIdList() {
+ return securityGroupIdList;
}
public Long getServiceOfferingId() {
@@ -328,7 +309,7 @@
return startVm == null ? true : startVm;
}
- private Map<Long, IpAddresses> getIpToNetworkMap() {
+ public Map<Long, IpAddresses> 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 @@
return ipToNetworkMap;
}
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
public String getIp6Address() {
if (ip6Address == null) {
return null;
@@ -392,6 +377,11 @@
}
}
+ public String getKeyboard() {
+ // TODO Auto-generated method stub
+ return keyboard;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@@ -478,129 +468,11 @@
}
}
- // 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<String, String> 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 e4c2f7d..661100b 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 @@
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<String, String> getDetails() {
- return details;
+ Map<String, String> customparameterMap = new HashMap<String, String>();
+ if (details != null && details.size() != 0) {
+ Collection parameterCollection = details.values();
+ Iterator iter = parameterCollection.iterator();
+ while (iter.hasNext()) {
+ HashMap<String, String> value = (HashMap<String, String>)iter.next();
+ for (String key : value.keySet()) {
+ customparameterMap.put(key, value.get(key));
+ }
+ }
+ }
+ return customparameterMap;
}
/////////////////////////////////////////////////////
@@ -142,4 +159,4 @@
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to scale vm");
}
}
-}
+}
\ No newline at end of file
diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java b/api/src/org/apache/cloudstack/api/command/user/vm/SecurityGroupAction.java
similarity index 77%
copy from plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java
copy to api/src/org/apache/cloudstack/api/command/user/vm/SecurityGroupAction.java
index 4e1cc43..87a829e 100644
--- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/SecurityGroupAction.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,12 +14,12 @@
// 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.vm;
-package com.cloud.network.sync;
+import java.util.List;
-
-public interface NuageVspSync {
-
- public void syncWithNuageVsp(String nuageVspEntity);
+public interface SecurityGroupAction {
+ List<Long> getSecurityGroupIdList();
+ List<String> 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 458122d..4508f7e 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 @@
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, description = "Details in key/value pairs.")
protected Map<String, String> 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<Long> 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<String> securityGroupNameList;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -145,7 +165,15 @@
return (Map<String, String>) (paramsCollection.toArray())[0];
}
-/////////////////////////////////////////////////////
+ public List<Long> getSecurityGroupIdList() {
+ return securityGroupIdList;
+ }
+
+ public List<String> 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 bc9c1c8..b105555 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 Map<String, String> getDetails() {
- return details;
+ Map<String, String> customparameterMap = new HashMap<String, String>();
+ if (details != null && details.size() != 0) {
+ Collection parameterCollection = details.values();
+ Iterator iter = parameterCollection.iterator();
+ while (iter.hasNext()) {
+ HashMap<String, String> value = (HashMap<String, String>)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 c9bc243..9b2634d 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
@@ -28,6 +28,7 @@
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VMSnapshotResponse;
+import com.cloud.utils.Pair;
import com.cloud.vm.snapshot.VMSnapshot;
@APICommand(name = "listVMSnapshot", description = "List virtual machine snapshot by conditions", responseObject = VMSnapshotResponse.class, since = "4.2.0", entityType = {VMSnapshot.class},
@@ -39,6 +40,9 @@
@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<Long> ids;
+
@Parameter(name = ApiConstants.STATE, type = CommandType.STRING, description = "state of the virtual machine snapshot")
private String state;
@@ -66,15 +70,15 @@
@Override
public void execute() {
- List<? extends VMSnapshot> result = _vmSnapshotService.listVMSnapshots(this);
+ Pair<List<? extends VMSnapshot>,Integer> result = _vmSnapshotService.listVMSnapshots(this);
ListResponse<VMSnapshotResponse> response = new ListResponse<VMSnapshotResponse>();
List<VMSnapshotResponse> snapshotResponses = new ArrayList<VMSnapshotResponse>();
- for (VMSnapshot r : result) {
+ for (VMSnapshot r : result.first()) {
VMSnapshotResponse vmSnapshotResponse = _responseGenerator.createVMSnapshotResponse(r);
vmSnapshotResponse.setObjectName("vmSnapshot");
snapshotResponses.add(vmSnapshotResponse);
}
- response.setResponses(snapshotResponses);
+ response.setResponses(snapshotResponses, result.second());
response.setResponseName(getCommandName());
setResponseObject(response);
}
@@ -84,4 +88,8 @@
return s_name;
}
+ public List<Long> 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 049396c..fc536d3 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 @@
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 cc218f7..059def7 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 @@
@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<Long> ids;
+
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name of the disk volume")
private String volumeName;
@@ -153,4 +157,8 @@
response.setResponseName(getCommandName());
setResponseObject(response);
}
+
+ public List<Long> 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 c360c14..2174961 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 @@
@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 0fb496c..e113109 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 @@
@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 3b188b8..bb59141 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 @@
@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 2e50c51..7b48a1e 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 @@
@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 @@
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 0725d40..0000000
--- 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/AlertResponse.java b/api/src/org/apache/cloudstack/api/response/AlertResponse.java
index 2016bcf..faa64b0 100644
--- a/api/src/org/apache/cloudstack/api/response/AlertResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/AlertResponse.java
@@ -36,11 +36,13 @@
@SerializedName(ApiConstants.TYPE)
@Param(description = "One of the following alert types: "
- + "MEMORY = 0, CPU = 1, STORAGE = 2, STORAGE_ALLOCATED = 3, PUBLIC_IP = 4, PRIVATE_IP = 5, HOST = 6, USERVM = 7, "
- + "DOMAIN_ROUTER = 8, CONSOLE_PROXY = 9, ROUTING = 10: lost connection to default route (to the gateway), "
- + "STORAGE_MISC = 11: lost connection to default route (to the gateway), " + "USAGE_SERVER = 12: lost connection to default route (to the gateway), "
- + "MANAGMENT_NODE = 13: lost connection to default route (to the gateway), "
- + "DOMAIN_ROUTER_MIGRATE = 14, CONSOLE_PROXY_MIGRATE = 15, USERVM_MIGRATE = 16, VLAN = 17, SSVM = 18, " + "USAGE_SERVER_RESULT = 19")
+ + "MEMORY = 0, CPU = 1, STORAGE = 2, STORAGE_ALLOCATED = 3, PUBLIC_IP = 4, PRIVATE_IP = 5, SECONDARY_STORAGE = 6, "
+ + "HOST = 7, USERVM = 8, DOMAIN_ROUTER = 9, CONSOLE_PROXY = 10, "
+ + "ROUTING = 11: lost connection to default route (to the gateway), "
+ + "STORAGE_MISC = 12, USAGE_SERVER = 13, MANAGMENT_NODE = 14, DOMAIN_ROUTER_MIGRATE = 15, CONSOLE_PROXY_MIGRATE = 16, "
+ + "USERVM_MIGRATE = 17, VLAN = 18, SSVM = 19, USAGE_SERVER_RESULT = 20, STORAGE_DELETE = 21, UPDATE_RESOURCE_COUNT = 22, "
+ + "USAGE_SANITY_RESULT = 23, DIRECT_ATTACHED_PUBLIC_IP = 24, LOCAL_STORAGE = 25, RESOURCE_LIMIT_EXCEEDED = 26, "
+ + "SYNC = 27, UPLOAD_FAILED = 28, OOBM_AUTH_ERROR = 29")
private Short alertType;
@SerializedName(ApiConstants.NAME)
diff --git a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java
index 623a0a2..bcdad46 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 @@
@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 @@
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 df01e09..754baa2 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 @@
@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<String, String> resourceDetails;
+
public String getId() {
return id;
}
@@ -197,4 +203,11 @@
public String getOvm3Vip() {
return ovm3vip;
}
+
+ public void setResourceDetails(Map<String, String> 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 c6697fb..ab9c8c3 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 @@
@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 @@
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/NicDetailResponse.java b/api/src/org/apache/cloudstack/api/response/NicDetailResponse.java
deleted file mode 100644
index 152d101..0000000
--- a/api/src/org/apache/cloudstack/api/response/NicDetailResponse.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 NicDetailResponse extends BaseResponse {
- @SerializedName(ApiConstants.ID)
- @Param(description = "ID of the nic")
- 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;
-
- @SerializedName(ApiConstants.DISPLAY_NIC)
- @Param(description = "an optional field whether to the display the nic to the end user or not.")
- private Boolean displayNic;
-
- 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 getDisplayNic() {
- return displayNic;
- }
-
- public void setDisplayNic(Boolean displayNic) {
- this.displayNic = displayNic;
- }
-}
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 0000000..19594d2
--- /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 ae61347..4432556 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 @@
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 0000000..ac1c529
--- /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/RoleResponse.java b/api/src/org/apache/cloudstack/api/response/RoleResponse.java
new file mode 100644
index 0000000..fd4bf28
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/response/RoleResponse.java
@@ -0,0 +1,63 @@
+// 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.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;
+
+@EntityReference(value = Role.class)
+public class RoleResponse extends BaseResponse {
+ @SerializedName(ApiConstants.ID)
+ @Param(description = "the ID of the role")
+ private String id;
+
+ @SerializedName(ApiConstants.NAME)
+ @Param(description = "the name of the role")
+ private String roleName;
+
+ @SerializedName(ApiConstants.TYPE)
+ @Param(description = "the type of the role")
+ private String roleType;
+
+ @SerializedName(ApiConstants.DESCRIPTION)
+ @Param(description = "the description of the role")
+ private String roleDescription;
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setRoleName(String roleName) {
+ this.roleName = roleName;
+ }
+
+ public void setRoleType(RoleType roleType) {
+ if (roleType != null) {
+ this.roleType = roleType.name();
+ }
+ }
+
+ 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 3e21043..237f181 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 @@
@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<TemplateZoneResponse> zones;
-
- @SerializedName(ApiConstants.TAGS)
- @Param(description = "the list of resource tags associated with tempate", responseObject = ResourceTagResponse.class)
- private Set<ResourceTagResponse> tags;
-
@SerializedName(ApiConstants.SSHKEY_ENABLED)
@Param(description = "true if template is sshkey enabled, false otherwise")
private Boolean sshKeyEnabled;
@@ -188,7 +178,6 @@
private Boolean isDynamicallyScalable;
public TemplateResponse() {
- // zones = new LinkedHashSet<TemplateZoneResponse>();
tags = new LinkedHashSet<ResourceTagResponse>();
}
@@ -346,10 +335,6 @@
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 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 f2e7725..0000000
--- 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 c42b64b..0000000
--- 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 36611ae..cc986b3 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 @@
@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 @@
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 e8d1a9e..b681d4f 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 @@
@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 @@
@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<ResourceTagResponse> tags;
-
transient Set<Long> tagIds;
@SerializedName(ApiConstants.DETAILS)
@@ -466,6 +474,18 @@
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 @@
return instanceName;
}
- public Set<ResourceTagResponse> getTags() {
- return tags;
- }
-
public String getKeyPairName() {
return keyPairName;
}
@@ -645,6 +661,18 @@
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 @@
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 957fb48..0000000
--- 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 eeb4af9..a934563 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 @@
@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<ResourceTagResponse> 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 @@
this.projectName = projectName;
}
- public void setTags(Set<ResourceTagResponse> 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 void setTemplateDisplayText(String templateDisplayText) {
this.templateDisplayText = templateDisplayText;
}
+
+ public void setTags(Set<ResourceTagResponse> 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 7aee448..4266077 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 setResourceDetails(Map<String, String> 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 0000000..1a22328
--- /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<OutOfBandManagement.PowerState>, 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<PowerState, Event, OutOfBandManagement> FSM = new StateMachine2<PowerState, Event, OutOfBandManagement>();
+ 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<PowerState, Event, OutOfBandManagement> getStateMachine() {
+ return FSM;
+ }
+
+ public PowerState getNextPowerState(Event e) throws NoTransitionException {
+ return FSM.getNextState(this, e);
+ }
+
+ public Set<Event> getPossibleEvents() {
+ return FSM.getPossibleEvents(this);
+ }
+
+ }
+}
diff --git a/api/src/org/apache/cloudstack/api/response/StatusResponse.java b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementDriver.java
similarity index 65%
copy from api/src/org/apache/cloudstack/api/response/StatusResponse.java
copy to api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementDriver.java
index fa2b4b2..3848963 100644
--- a/api/src/org/apache/cloudstack/api/response/StatusResponse.java
+++ b/api/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementDriver.java
@@ -14,21 +14,12 @@
// 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.outofbandmanagement;
-import com.google.gson.annotations.SerializedName;
+import com.cloud.utils.component.Adapter;
+import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverCommand;
+import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse;
-import org.apache.cloudstack.api.BaseResponse;
-
-public class StatusResponse extends BaseResponse {
- @SerializedName("status")
- private Boolean status;
-
- public Boolean getStatus() {
- return status;
- }
-
- public void setStatus(Boolean status) {
- this.status = status;
- }
+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 0000000..699b2c6
--- /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<Long> ActionTimeout = new ConfigKey<Long>("Advanced", Long.class, "outofbandmanagement.action.timeout", "60",
+ "The out of band management action timeout in seconds, configurable by cluster", true, ConfigKey.Scope.Cluster);
+
+ ConfigKey<Long> SyncThreadInterval = new ConfigKey<Long>("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<Integer> SyncThreadPoolSize = new ConfigKey<Integer>("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<? extends Host> 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<OutOfBandManagement.Option, String> 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 0000000..943339e
--- /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<OutOfBandManagement.Option, String> 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 0000000..999b10c
--- /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<OutOfBandManagement.Option, String> options;
+ private final Duration timeout;
+
+ public OutOfBandManagementDriverCommand(final ImmutableMap<OutOfBandManagement.Option, String> 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<OutOfBandManagement.Option, String> 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 0000000..406be3b
--- /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<OutOfBandManagement.Option, String> 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 0000000..78a25da
--- /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 0000000..611b761
--- /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 0000000..08bd775
--- /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 c0a046d..b50b226 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 @@
@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 @@
} 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 @@
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 @@
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 63c4a03..65b9330 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;
@@ -49,21 +50,45 @@
}
@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 @@
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 3983b10..9e0b65c 100644
--- a/build/replace.properties
+++ b/build/replace.properties
@@ -21,6 +21,7 @@
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 fbdedda..289e04f 100644
--- a/client/WEB-INF/classes/resources/messages.properties
+++ b/client/WEB-INF/classes/resources/messages.properties
@@ -876,6 +876,7 @@
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,26 @@
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.reenterpassword=Re-enter 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 +1116,17 @@
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 3ba58ec..d1832c4 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.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 d51598e..30d1811 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.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
@@ -1160,6 +1160,10 @@
label.os.preference=OS Pr\u00e4ferenz
label.os.type=OS Typ
label.other=Andere
+label.outofbandmanagement.action=Aktion
+label.outofbandmanagement.password=Passwort
+label.outofbandmanagement.port=Port
+label.outofbandmanagement.username=Benutzername
label.override.guest.traffic=Gast-Datenverkehr \u00fcberschreiben
label.override.public.traffic=\u00d6ffentlichen Datenverkehr \u00fcberschreiben
label.ovm3.cluster=Natives Clustering
diff --git a/client/WEB-INF/classes/resources/messages_es.properties b/client/WEB-INF/classes/resources/messages_es.properties
index 0982795..8150845 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.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.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.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.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=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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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
@@ -1160,6 +1160,10 @@
label.os.preference=OS Preferencia
label.os.type=tipo de Sistema Operativo
label.other=Otro
+label.outofbandmanagement.action=Acci\u00f3n
+label.outofbandmanagement.password=Contrase\u00f1a
+label.outofbandmanagement.port=Puerto
+label.outofbandmanagement.username=Nombre de usuario
label.override.guest.traffic=Sobreescribir Tr\u00e1fico Guest
label.override.public.traffic=Sobreescribir Tr\u00e1fico Public
label.ovm3.cluster=Cluster Nativo
@@ -1174,11 +1178,11 @@
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 +1195,7 @@
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 +1218,12 @@
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 +1236,11 @@
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 +1277,7 @@
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 +1359,7 @@
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 +1386,7 @@
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 +1420,12 @@
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 +1440,7 @@
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 +1451,13 @@
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 +1494,7 @@
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 +1512,7 @@
label.step.2=Paso 2
label.step.2.title=Paso 2\: <strong> Oferta de Servicio </strong>
label.step.3=Paso 3
-label.step.3.title=Paso 3\: <strong id\="step3_label"> Seleccione una Oferta de Disco </strong>
+label.step.3.title=Paso 3\: <strong id\="step3_label"> Seleccione un disco Ofrenda </strong>
label.step.4=Paso 4
label.step.4.title=Paso 4\: <strong> Red </strong>
label.step.5=Paso 5
@@ -1516,13 +1520,13 @@
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 +1537,9 @@
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\: <span id\="submitted_by"> </span>]
@@ -1564,8 +1568,8 @@
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 +1589,7 @@
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 +1610,21 @@
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 +1640,11 @@
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 +1665,7 @@
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 +1709,7 @@
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 +1769,22 @@
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.<br/>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 +1793,30 @@
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 +1834,7 @@
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 +1850,13 @@
message.activate.project=Usted esta seguro que quiere activar este proyecto?
message.add.cluster=A\u00f1adir un hipervisor administradas por cl\u00faster de <b> zona <span id\="zone_name"> </span> </b>, la consola de <b> <span id\="pod_name"> </span> </b>
message.add.cluster.zone=A\u00f1adir un hipervisor administradas por cl\u00faster de <b> zona <span id\="zone_name"> </span> </b>
-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 +1876,7 @@
message.add.secondary.storage=A\u00f1adir un nuevo almacenamiento de <b> zona <span id\="zone_name"> </span> </b>
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 +1889,7 @@
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 * <b> no <u> </u> * </b> 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 +1904,7 @@
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 +1914,30 @@
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 +1946,7 @@
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 +1965,17 @@
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 <b id\="copy_template_name_text">XXX</b> desde la zona <b id\="copy_template_source_zone_text"></b> hacia
+message.copy.template.confirm=\u00bfDesea copiar esta plantilla?
+message.copy.template=Copia plantilla <b id\="copy_template_name_text"> XXX </b> de la zona <b id\="copy_template_source_zone_text"> </b>
message.create.template=Esta seguro que quiere crear un template?
-message.create.template.vm=Crear VM desde el template <b id\="p_name"> </b>
-message.create.template.volume=Por favor, especifique la siguiente informaci\u00f3n antes de crear un template desde su volumen de disco\: <b> <span id\="volume_name"> </span> </b>. 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 <b id\="p_name"> </b>
+message.create.template.volume=Por favor, especifique la siguiente informaci\u00f3n antes de crear una plantilla de su volumen de disco\: <b> <span id\="volume_name"> </span> </b>. 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 +1997,14 @@
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.<br/><br/>1. Si la clave p\u00fablica esta definida, CloudStack la registrar\u00e1. Uds puede usarla por medio de la clave privada.<br/><br/>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.<br/>
-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.<br/><br/>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.<br/><br/>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.<br/><br/>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.<br/><br/>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 +2017,7 @@
message.disabling.vpc.offering=Deshabilitando oferta VPC
message.disallowed.characters=Caracteres no permitidos\: \\<\\,\\>
message.download.ISO=Por favor haga click <a href\="\#">00000</a>para descargar el ISO
-message.download.template=Por favor haga click <a href\="\#">00000</a>para descargar el template
+message.download.template=Por favor haga click <a href\="\#">00000</a>para descargar la plantilla
message.download.volume.confirm=Por favor confirme que desea descargar este volumen.
message.download.volume=Por favor, haga clic <a href\="\#">00000</a> para bajar el volumen
message.edit.account=Editar ("-1" indica que no hay limite a la cantidad de recursos creados)
@@ -2042,24 +2046,24 @@
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.<br/><br/>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. <br/><br/>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. <br/><br/>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.<br/><br/>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.<br/><br/> 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. <br/><br/>El <strong>Almacenamiento Primario</strong> 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\: <ul> <li> 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 </li><li>Im\u00e1genes ISO - im\u00e1genes del Sistema Operativo que pueden ser boteables o no boteables </li><li>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</ul>
+message.installWizard.copy.whatIsSecondaryStorage=El almacenamiento secundario est\u00e1 asociado a una zona, y almacena lo siguiente\: <ul> <li> 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 </li><li>Im\u00e1genes ISO - im\u00e1genes del Sistema Operativo que pueden ser boteables o no boteables </li><li>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</ul>
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 +2079,7 @@
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 +2090,23 @@
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.<br/>Por favor dile a tu administrador que cree uno nuevo.
-message.no.projects=No tienes ning\u00fan proyecto.<br/>Por favor crea uno nuevo desde la secci\u00f3n de Proyectos.
-message.number.clusters=<h2> <span> \# de </span> Clusters</h2>
-message.number.hosts=<h2> <span> \# de </span> Servidores</h2>
+message.no.projects=No tienes ning\u00fan proyecto.<br/>Pro favor crear uno nuevo desde la secci\u00f3n de Proyectos.
+message.number.clusters=<h2> <span> \# de </span> Grupos </h2>
+message.number.hosts=<h2> <span> \# de </span> Anfitri\u00f3n </h2>
message.number.pods=<h2> <span> \# de </span> Las vainas </h2>
message.number.storage=<h2> <span> \# de </span> Almacenamiento primario </h2>
message.number.zones=<h2> <span> \# de </span> Zonas </h2>
@@ -2115,7 +2119,7 @@
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 +2129,15 @@
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 +2154,39 @@
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.<br/><br/>Puedes tambi\u00e9n <strong>arrastrar y soltar</strong> 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.<br/><br/>Puedes tambi\u00e9n <strong>arrastrar y soltar</strong> 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.<br/><br/><strong>Arrastre y suelte uno o m\u00e1s tipos de tr\u00e1fico</strong> 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 +2194,36 @@
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\:<br/><br/>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.<br/><br/>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.<br/><br/><br/>\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\:<br/><br/>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.<br/><br/>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.<br/><br/><br/>\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 17a68c5..4dc9082 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.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.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.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
@@ -1039,6 +1042,7 @@
label.metrics.network.usage=Util. R\u00e9seau
label.metrics.network.write=\u00c9criture
label.metrics.num.cpu.cores=Cores
+label.metrics.outofbandmanagementpowerstate=Status Alimentation
label.metrics.property=Propri\u00e9t\u00e9
label.metrics.scope=Port\u00e9e
label.metrics.state=\u00c9tat
@@ -1160,6 +1164,18 @@
label.os.preference=Pr\u00e9f\u00e9rence OS
label.os.type=Type du OS
label.other=Autre
+label.outofbandmanagement.action=Action
+label.outofbandmanagement.action.issue=Probl\u00e8me dans l\\'allumage via la gestion du flux administration
+label.outofbandmanagement.address=Adresse
+label.outofbandmanagement.changepassword=Modifier le mot de passe du flux d\\'administration
+label.outofbandmanagement.configure=Configurer la gestion du flux d\\'administration
+label.outofbandmanagement.disable=D\u00e9sactiver la gestion du flux d\\'administration
+label.outofbandmanagement.driver=Pilote
+label.outofbandmanagement.enable=Activer la gestion du flux d\\'administration
+label.outofbandmanagement=Gestion flux administration
+label.outofbandmanagement.password=Mot de passe
+label.outofbandmanagement.port=Port
+label.outofbandmanagement.username=Identifiant
label.override.guest.traffic=Remplacer Trafic-invit\u00e9
label.override.public.traffic=Remplacer Trafic-public
label.ovm3.cluster=Cluster natif
@@ -1183,6 +1199,7 @@
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
@@ -1211,6 +1228,7 @@
label.port.forwarding=Redirection de port
label.port=Port
label.port.range=Plage de ports
+label.powerstate=Status Alimentation
label.PreSetup=PreSetup
label.previous=Retour
label.prev=Pr\u00e9c\u00e9dent
@@ -1380,6 +1398,8 @@
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 +1408,7 @@
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 +1604,7 @@
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
@@ -2106,6 +2127,12 @@
message.number.pods=<h2><span> \# de </span> Pods</h2>
message.number.storage=<h2><span> \# de </span> Volumes de Stockage Primaire</h2>
message.number.zones=<h2><span> \# de </span> Zones</h2>
+message.outofbandmanagement.action.maintenance=L\\'h\u00f4te en avertissement est en mode maintenance
+message.outofbandmanagement.changepassword=Modifier le mot de passe du flux d\\'administration
+message.outofbandmanagement.configure=Configurer la gestion du flux d\\'administration
+message.outofbandmanagement.disable=D\u00e9sactiver la gestion du flux d\\'administration
+message.outofbandmanagement.enable=Activer la gestion du flux d\\'administration
+message.outofbandmanagement.issue=Probl\u00e8me dans l\\'allumage via la gestion du flux administration.
message.password.has.been.reset.to=Le mot de passe a \u00e9t\u00e9 r\u00e9-initialiser en
message.password.of.the.vm.has.been.reset.to=Le mot de passe de la VM a \u00e9t\u00e9 r\u00e9-initialis\u00e9 en
message.pending.projects.1=Vous avez des invitations projet en attente \:
@@ -2142,6 +2169,7 @@
message.restart.vpc=Confirmer le red\u00e9marrage du VPC
message.restart.vpc.remark=Veuillez confirmer que vous voulez red\u00e9marrer le VPC <p><small><i>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</i>.</small></p>
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 <strong>Ctrl-clic</strong> 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_hu.properties b/client/WEB-INF/classes/resources/messages_hu.properties
index 6dd3675..3386f03 100644
--- a/client/WEB-INF/classes/resources/messages_hu.properties
+++ b/client/WEB-INF/classes/resources/messages_hu.properties
@@ -1144,6 +1144,10 @@
label.os.preference=OS preferencia
label.os.type=OS t\u00edpus
label.other=M\u00e1s
+label.outofbandmanagement.action=M\u0171velet
+label.outofbandmanagement.password=Jelsz\u00f3
+label.outofbandmanagement.port=Port
+label.outofbandmanagement.username=Felhaszn\u00e1l\u00f3n\u00e9v
label.override.guest.traffic=Vend\u00e9g forgalom fel\u00fclb\u00edr\u00e1l\u00e1sa
label.override.public.traffic=Publikus forgalom fel\u00fclb\u00edr\u00e1l\u00e1sa
label.ovm3.cluster=Nat\u00edv f\u00fcrt\u00f6z\u00e9s
diff --git a/client/WEB-INF/classes/resources/messages_it_IT.properties b/client/WEB-INF/classes/resources/messages_it_IT.properties
index 45bb43a..6fd390f 100644
--- a/client/WEB-INF/classes/resources/messages_it_IT.properties
+++ b/client/WEB-INF/classes/resources/messages_it_IT.properties
@@ -643,6 +643,7 @@
label.number.of.zones=Numero di Zone
label.ok=OK
label.order=Ordine
+label.outofbandmanagement.port=Porta
label.perfect.forward.secrecy=Segretezza di Forward perfetta
label.physical.network.ID=ID della rete fisica
label.please.specify.netscaler.info=Si prega di specificare le informazioni per Netscaler
@@ -697,6 +698,7 @@
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 5fc7adf..2ed3ce6 100644
--- a/client/WEB-INF/classes/resources/messages_ja_JP.properties
+++ b/client/WEB-INF/classes/resources/messages_ja_JP.properties
@@ -1138,6 +1138,10 @@
label.os.preference=OS \u57fa\u672c\u8a2d\u5b9a
label.os.type=OS \u306e\u7a2e\u985e
label.other=\u305d\u306e\u307b\u304b
+label.outofbandmanagement.action=\u64cd\u4f5c
+label.outofbandmanagement.password=\u30d1\u30b9\u30ef\u30fc\u30c9
+label.outofbandmanagement.port=\u30dd\u30fc\u30c8
+label.outofbandmanagement.username=\u30e6\u30fc\u30b6\u30fc\u540d
label.override.guest.traffic=\u30b2\u30b9\u30c8 \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3092\u30aa\u30fc\u30d0\u30fc\u30e9\u30a4\u30c9\u3059\u308b
label.override.public.traffic=\u30d1\u30d6\u30ea\u30c3\u30af \u30c8\u30e9\u30d5\u30a3\u30c3\u30af\u3092\u30aa\u30fc\u30d0\u30fc\u30e9\u30a4\u30c9\u3059\u308b
label.ovm3.cluster=\u30cd\u30a4\u30c6\u30a3\u30d6\u30af\u30e9\u30b9\u30bf\u30fc
@@ -1321,6 +1325,7 @@
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 +1647,7 @@
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 6123623..f7bebd6 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.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.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
@@ -803,6 +803,8 @@
label.order=\uc21c\uc11c
label.os.preference=OS \uae30\ubcf8 \uc124\uc815
label.os.type=OS \uc885\ub958
+label.outofbandmanagement.password=\uc554\ud638
+label.outofbandmanagement.username=\uc0ac\uc6a9\uc790\uba85
label.owned.public.ips=\uc18c\uc720 \uacf5\uac1c IP \uc8fc\uc18c
label.owner.account=\uc18c\uc720\uc790 \uacc4\uc815 \uc815\ubcf4
label.owner.domain=\uc18c\uc720\uc790 \ub3c4\uba54\uc778
@@ -1336,7 +1338,7 @@
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 +1347,13 @@
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 +1461,7 @@
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 a4851d0..d3117c0 100644
--- a/client/WEB-INF/classes/resources/messages_nb_NO.properties
+++ b/client/WEB-INF/classes/resources/messages_nb_NO.properties
@@ -1160,6 +1160,10 @@
label.os.preference=OS-preferanse
label.os.type=OS-type
label.other=Andre
+label.outofbandmanagement.action=Handling
+label.outofbandmanagement.password=Passord
+label.outofbandmanagement.port=Port
+label.outofbandmanagement.username=Brukernavn
label.override.guest.traffic=Overstyr Gjeste Trafikk
label.override.public.traffic=Overstyr Offentlig Trafikk
label.ovm3.cluster=Innebygd Klynge Funksjon
@@ -1469,8 +1473,8 @@
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 +2110,7 @@
message.number.pods=<h2><span> \# av </span> Pods</h2>
message.number.storage=<h2><span> \# av </span> Prim\u00e6rlagringsvolumer</h2>
message.number.zones=<h2><span> \# av </span> Soner</h2>
-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 5cb7413..a1e1347 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.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
@@ -1160,6 +1160,10 @@
label.os.preference=OS Voorkeur
label.os.type=OS Type
label.other=anders
+label.outofbandmanagement.action=Actie
+label.outofbandmanagement.password=Wachtwoord
+label.outofbandmanagement.port=Poort
+label.outofbandmanagement.username=Gebruikersnaam
label.override.guest.traffic=Overschrijf Gast Verkeer
label.override.public.traffic=Overschrijf Publiek Verkeer
label.ovm3.cluster=inheems clustering
@@ -2105,7 +2109,7 @@
message.number.pods=<h2><span> Aantal </span> Pods</h2>
message.number.storage=<h2><span> Aantal </span> Primaire Opslag Volumes</h2>
message.number.zones=<h2><span> Aantal </span> Zones</h2>
-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_pl.properties b/client/WEB-INF/classes/resources/messages_pl.properties
index 687de4f..be5ca74 100644
--- a/client/WEB-INF/classes/resources/messages_pl.properties
+++ b/client/WEB-INF/classes/resources/messages_pl.properties
@@ -348,6 +348,8 @@
label.number.of.hosts=Liczba host\u00f3w
label.ok=OK
label.order=Zadanie
+label.outofbandmanagement.password=Has\u0142o
+label.outofbandmanagement.username=Nazwa u\u017cytkownika
label.password=Has\u0142o
label.path=\u015acie\u017cka
label.please.wait=Prosz\u0119 czeka\u0107
diff --git a/client/WEB-INF/classes/resources/messages_pt_BR.properties b/client/WEB-INF/classes/resources/messages_pt_BR.properties
index 444bb15..2ad2760 100644
--- a/client/WEB-INF/classes/resources/messages_pt_BR.properties
+++ b/client/WEB-INF/classes/resources/messages_pt_BR.properties
@@ -1160,6 +1160,10 @@
label.os.preference=Prefer\u00eancia de SO
label.os.type=Tipo de SO
label.other=Outro
+label.outofbandmanagement.action=A\u00e7\u00e3o
+label.outofbandmanagement.password=Senha
+label.outofbandmanagement.port=Porta
+label.outofbandmanagement.username=Nome de usu\u00e1rio
label.override.guest.traffic=Anula Tr\u00e1fego Convidado
label.override.public.traffic=Sobrep\u00f5e Tr\u00e1fego P\u00fablico
label.ovm3.cluster=Native Clustering
@@ -1622,7 +1626,7 @@
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 +2110,7 @@
message.number.pods=<h2>PODs</h2>
message.number.storage=<h2>Volumes do Storage Prim\u00e1rio</h2>
message.number.zones=<h2>Zonas</h2>
-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_ru_RU.properties b/client/WEB-INF/classes/resources/messages_ru_RU.properties
index 9e123c6..2225fad 100644
--- a/client/WEB-INF/classes/resources/messages_ru_RU.properties
+++ b/client/WEB-INF/classes/resources/messages_ru_RU.properties
@@ -898,6 +898,9 @@
label.order=\u041e\u0447\u0435\u0440\u0435\u0434\u044c
label.os.preference=\u041f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u041e\u0421
label.os.type=\u0422\u0438\u043f \u041e\u0421
+label.outofbandmanagement.action=\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f
+label.outofbandmanagement.password=\u041f\u0430\u0440\u043e\u043b\u044c
+label.outofbandmanagement.username=\u0418\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f
label.owned.public.ips=\u041f\u0440\u0438\u0441\u0432\u043e\u0435\u043d\u043d\u044b\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0438\u0440\u0443\u0435\u043c\u044b\u0435 IP \u0430\u0434\u0440\u0435\u0441\u0430
label.owner.account=\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430
label.owner.domain=\u0414\u043e\u043c\u0435\u043d \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430
diff --git a/client/WEB-INF/classes/resources/messages_zh_CN.properties b/client/WEB-INF/classes/resources/messages_zh_CN.properties
index 66f99b2..11530f9 100644
--- a/client/WEB-INF/classes/resources/messages_zh_CN.properties
+++ b/client/WEB-INF/classes/resources/messages_zh_CN.properties
@@ -1136,6 +1136,10 @@
label.os.preference=\u64cd\u4f5c\u7cfb\u7edf\u9996\u9009\u9879
label.os.type=\u64cd\u4f5c\u7cfb\u7edf\u7c7b\u578b
label.other=\u5176\u4ed6
+label.outofbandmanagement.action=\u64cd\u4f5c
+label.outofbandmanagement.password=\u5bc6\u7801
+label.outofbandmanagement.port=\u7aef\u53e3
+label.outofbandmanagement.username=\u7528\u6237\u540d
label.override.guest.traffic=\u66ff\u4ee3\u6765\u5bbe\u6d41\u91cf
label.override.public.traffic=\u66ff\u4ee3\u516c\u5171\u6d41\u91cf
label.ovm3.cluster=\u672c\u5730\u96c6\u7fa4
@@ -1319,6 +1323,7 @@
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 +1333,7 @@
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 c64bc8f..9db5078 100755
--- a/client/bindir/cloud-update-xenserver-licenses.in
+++ b/client/bindir/cloud-update-xenserver-licenses.in
@@ -24,7 +24,7 @@
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 @@
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 e9e396b..49c9d5f 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -53,6 +53,11 @@
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-plugin-acl-dynamic-role-based</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-dedicated-resources</artifactId>
<version>${project.version}</version>
</dependency>
@@ -239,6 +244,11 @@
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-plugin-outofbandmanagement-driver-ipmitool</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-mom-rabbitmq</artifactId>
<version>${project.version}</version>
</dependency>
@@ -430,9 +440,9 @@
</configuration>
</plugin>
<plugin>
- <groupId>org.mortbay.jetty</groupId>
- <artifactId>maven-jetty-plugin</artifactId>
- <version>6.1.26</version>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <version>${cs.jetty.version}</version>
<dependencies>
<!-- specify the dependent jdbc driver here -->
<dependency>
diff --git a/client/tomcatconf/catalina.properties.in b/client/tomcatconf/catalina.properties.in
index 282892b..e0baf61 100644
--- a/client/tomcatconf/catalina.properties.in
+++ b/client/tomcatconf/catalina.properties.in
@@ -44,7 +44,7 @@
# "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 32f33c9..0000000
--- 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 74b9263..1c2b55f 100644
--- a/client/tomcatconf/db.properties.in
+++ b/client/tomcatconf/db.properties.in
@@ -25,6 +25,7 @@
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.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.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 b78dee9..0967c26 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
@@ -47,6 +47,11 @@
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-compress</artifactId>
+ <version>1.10</version>
+ </dependency>
</dependencies>
<build>
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 f1566b1..1a33fa2 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 @@
<property name="registry" ref="userPasswordEncodersRegistry" />
<property name="typeClass" value="com.cloud.server.auth.UserAuthenticator" />
</bean>
-
</beans>
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 5e2dc7b..d36f98d 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">
<property name="excludeKey" value="data.motion.strategies.exclude" />
</bean>
-
+
+ <bean id="outOfBandManagementDriversRegistry"
+ class="org.apache.cloudstack.spring.lifecycle.registry.ExtensionRegistry">
+ <property name="orderConfigDefault" value="IPMITOOL" />
+ </bean>
+
</beans>
diff --git a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup b/core/resources/META-INF/cloudstack/outofbandmanagement/module.properties
old mode 100755
new mode 100644
similarity index 66%
rename from systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
rename to core/resources/META-INF/cloudstack/outofbandmanagement/module.properties
index 9d254d3..73d4bec
--- a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
+++ b/core/resources/META-INF/cloudstack/outofbandmanagement/module.properties
@@ -1,5 +1,4 @@
-#!/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
@@ -16,12 +15,7 @@
# KIND, either express or implied. See the License for the
# 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"
-
-[ "$output" != "" ] && logger -t cloud $output
-[ -z "$output" ] && logger -t cloud "No files removed"
-
-exit 0
+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 0000000..6a25a2e
--- /dev/null
+++ b/core/resources/META-INF/cloudstack/outofbandmanagement/spring-core-lifecycle-outofbandmanagement-context-inheritable.xml
@@ -0,0 +1,36 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context-3.0.xsd"
+ >
+
+ <bean class="org.apache.cloudstack.spring.lifecycle.registry.RegistryLifecycle">
+ <property name="registry" ref="outOfBandManagementDriversRegistry" />
+ <property name="typeClass" value="org.apache.cloudstack.outofbandmanagement.OutOfBandManagementDriver" />
+ </bean>
+</beans>
diff --git a/core/src/com/cloud/agent/api/BackupSnapshotCommand.java b/core/src/com/cloud/agent/api/BackupSnapshotCommand.java
index 2a46610..2c8c0cc 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 getSecHostId() {
return secHostId;
}
+
}
diff --git a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java
index 7ac2dde..30b59ff 100644
--- a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java
+++ b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java
@@ -72,4 +72,5 @@
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 3025147..38a2f94 100644
--- a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java
+++ b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java
@@ -99,4 +99,5 @@
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 90a5e39..52746fe 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 @@
private boolean _createDatastore;
private Map<String, String> _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 fa9a4d5..4526ce7 100644
--- a/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java
+++ b/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java
@@ -50,4 +50,5 @@
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 23e8f9e..94a574c 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 @@
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 b92bb72..6e6dadc 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<String, TemplateProp> templateInfo;
- String localDatastoreName = null;
-
- protected ModifyStoragePoolAnswer() {
- }
+ private StoragePoolInfo poolInfo;
+ private Map<String, TemplateProp> templateInfo;
+ private String localDatastoreName;
public ModifyStoragePoolAnswer(ModifyStoragePoolCommand cmd, long capacityBytes, long availableBytes, Map<String, TemplateProp> 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<String, TemplateProp> getTemplateInfo() {
- return templateInfo;
+ public StoragePoolInfo getPoolInfo() {
+ return poolInfo;
}
public void setTemplateInfo(Map<String, TemplateProp> templateInfo) {
this.templateInfo = templateInfo;
}
- public String getLocalDatastoreName() {
- return localDatastoreName;
+ public Map<String, TemplateProp> 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 136eb09..c2ab0ab 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 4e1cc43..c192e4a 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 0000000..424d797
--- /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<Map<String, String>> targets;
+
+ public void setAdd(boolean add) {
+ this.add = add;
+ }
+
+ public boolean getAdd() {
+ return add;
+ }
+
+ public void setTargets(List<Map<String, String>> targets) {
+ this.targets = targets;
+ }
+
+ public List<Map<String, String>> 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 d8f1ce9..eecf7f6 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 149ac5d..6d6c0a9 100644
--- a/core/src/com/cloud/agent/api/RebootRouterCommand.java
+++ b/core/src/com/cloud/agent/api/RebootRouterCommand.java
@@ -27,7 +27,7 @@
}
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 28e55c2..061346c 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 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 b9bdef5..09f9266 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<IpPortAndProto> ingressRuleSet;
+ private List<IpPortAndProto> egressRuleSet;
+ private final List<String> 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<String> 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<String> getAllowedCidrs() {
return allowedCidrs;
}
- public void setAllowedCidrs(String[] allowedCidrs) {
- this.allowedCidrs = allowedCidrs;
+ public void setAllowedCidrs(final String... allowedCidrs) {
+ this.allowedCidrs = new ArrayList<String>();
+ for (final String allowedCidr : allowedCidrs) {
+ this.allowedCidrs.add(allowedCidr);
+ }
}
public String getProto() {
@@ -74,52 +91,28 @@
}
- String guestIp;
- String vmName;
- String guestMac;
- String signature;
- Long seqNum;
- Long vmId;
- Long msId;
- IpPortAndProto[] ingressRuleSet;
- IpPortAndProto[] egressRuleSet;
- private List<String> secIps;
-
- public SecurityGroupRulesCmd() {
- super();
- }
-
- public SecurityGroupRulesCmd(String guestIp, String guestMac, String vmName, Long vmId, String signature, Long seqNum, IpPortAndProto[] ingressRuleSet,
- IpPortAndProto[] egressRuleSet) {
- 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<String> 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);
- }
- }
-
- public SecurityGroupRulesCmd(String guestIp, String guestMac, String vmName, Long vmId, String signature, Long seqNum, IpPortAndProto[] ingressRuleSet,
- IpPortAndProto[] egressRuleSet, List<String> secIps) {
- 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);
+ } else {
+ this.signature = signature;
}
this.secIps = secIps;
}
@@ -129,20 +122,26 @@
return true;
}
- public IpPortAndProto[] getIngressRuleSet() {
+ public List<IpPortAndProto> getIngressRuleSet() {
return ingressRuleSet;
}
- public void setIngressRuleSet(IpPortAndProto[] ingressRuleSet) {
- this.ingressRuleSet = ingressRuleSet;
+ public void setIngressRuleSet(final IpPortAndProto... ingressRuleSet) {
+ this.ingressRuleSet = new ArrayList<IpPortAndProto>();
+ for(final IpPortAndProto rule: ingressRuleSet) {
+ this.ingressRuleSet.add(rule);
+ }
}
- public IpPortAndProto[] getEgressRuleSet() {
+ public List<IpPortAndProto> getEgressRuleSet() {
return egressRuleSet;
}
- public void setEgressRuleSet(IpPortAndProto[] egressRuleSet) {
- this.egressRuleSet = egressRuleSet;
+ public void setEgressRuleSet(final IpPortAndProto... egressRuleSet) {
+ this.egressRuleSet = new ArrayList<IpPortAndProto>();
+ for(final IpPortAndProto rule: egressRuleSet) {
+ this.egressRuleSet.add(rule);
+ }
}
public String getGuestIp() {
@@ -157,105 +156,77 @@
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<String> ips = getSecIps();
+ final StringBuilder sb = new StringBuilder();
+ final List<String> 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 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(",");
- }
- 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()) {
- //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(" ");
- }
+ 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() {
+ 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<IpPortAndProto> 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 ");
+ }
+ }
+
+ private String represent(final String cidr, final boolean compressed) {
+ if (compressed) {
+ return compressCidrToHexRepresentation(cidr);
+ } else {
+ return cidr;
+ }
+ }
+
+ /**
* 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 @@
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 cf4eeb5..0e527e2 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 c413836..b459f88 100644
--- a/core/src/com/cloud/agent/api/StartupRoutingCommand.java
+++ b/core/src/com/cloud/agent/api/StartupRoutingCommand.java
@@ -35,7 +35,7 @@
long memory;
long dom0MinMemory;
boolean poolSync;
-
+ private boolean supportsClonedVolumes;
String caps;
String pool;
@@ -180,4 +180,12 @@
public void setGpuGroupDetails(HashMap<String, HashMap<String, VgpuTypesInfo>> 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 c4948cd..b723d74 100644
--- a/core/src/com/cloud/agent/api/StopCommand.java
+++ b/core/src/com/cloud/agent/api/StopCommand.java
@@ -26,7 +26,6 @@
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 @@
}
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 0f30b6a..e6063b9 100644
--- a/core/src/com/cloud/agent/api/VmStatsEntry.java
+++ b/core/src/com/cloud/agent/api/VmStatsEntry.java
@@ -30,13 +30,19 @@
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 @@
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 43c84ee..a75e9ba 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 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 8550952..6f60933 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 @@
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 ce8ed21..725bd0c 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 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 3b121e1..22cff13 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;
+
+ /* 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 @@
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 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 187ae03..575b245 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 a6719c4..429755c 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/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsCommand.java b/core/src/com/cloud/agent/api/storage/StorageNfsVersionCommand.java
old mode 100644
new mode 100755
similarity index 65%
copy from plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsCommand.java
copy to core/src/com/cloud/agent/api/storage/StorageNfsVersionCommand.java
index 2ffbe04..b99713d
--- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetClientDefaultsCommand.java
+++ b/core/src/com/cloud/agent/api/storage/StorageNfsVersionCommand.java
@@ -16,23 +16,29 @@
// specific language governing permissions and limitations
// under the License.
//
-
-package com.cloud.agent.api.manager;
+package com.cloud.agent.api.storage;
import com.cloud.agent.api.Command;
-/**
- * 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 abstract class StorageNfsVersionCommand extends Command {
- public GetClientDefaultsCommand() {
+ protected StorageNfsVersionCommand(){
super();
}
- @Override
- public boolean executeInSequence() {
- return false;
+ protected StorageNfsVersionCommand(Integer nfsVersion){
+ super();
+ this.nfsVersion = nfsVersion;
}
-}
\ No newline at end of file
+
+ 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 e2bf1b7..e5832cc 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 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 fc771e0..d9d2993 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 @@
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/com/cloud/storage/template/HttpTemplateDownloader.java b/core/src/com/cloud/storage/template/HttpTemplateDownloader.java
index 76d1ac9..bdf4990 100644
--- a/core/src/com/cloud/storage/template/HttpTemplateDownloader.java
+++ b/core/src/com/cloud/storage/template/HttpTemplateDownloader.java
@@ -25,7 +25,6 @@
import java.io.RandomAccessFile;
import java.net.URI;
import java.net.URISyntaxException;
-import java.net.URL;
import java.util.Date;
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
@@ -117,7 +116,7 @@
request = new GetMethod(downloadUrl);
request.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, myretryhandler);
completionCallback = callback;
- //this.request.setFollowRedirects(false);
+ this.request.setFollowRedirects(true);
File f = File.createTempFile("dnld", "tmp_", new File(toDir));
@@ -232,8 +231,7 @@
remoteSize = maxTemplateSizeInBytes;
}
- URL url = new URL(getDownloadUrl());
- InputStream in = url.openStream();
+ InputStream in = request.getResponseBodyAsStream();
RandomAccessFile out = new RandomAccessFile(file, "rw");
out.seek(localFileSize);
diff --git a/core/src/com/cloud/storage/template/VhdProcessor.java b/core/src/com/cloud/storage/template/VhdProcessor.java
index 605d2a3..cb13d06 100644
--- a/core/src/com/cloud/storage/template/VhdProcessor.java
+++ b/core/src/com/cloud/storage/template/VhdProcessor.java
@@ -19,20 +19,24 @@
package com.cloud.storage.template;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Map;
-
-import javax.naming.ConfigurationException;
-
import com.cloud.exception.InternalErrorException;
-import org.apache.log4j.Logger;
-
import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.StorageLayer;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.AdapterBase;
+import org.apache.commons.compress.compressors.CompressorException;
+import org.apache.commons.compress.compressors.CompressorInputStream;
+import org.apache.commons.compress.compressors.CompressorStreamFactory;
+import org.apache.log4j.Logger;
+
+import javax.naming.ConfigurationException;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
/**
* VhdProcessor processes the downloaded template for VHD. It
@@ -45,10 +49,12 @@
private static final Logger s_logger = Logger.getLogger(VhdProcessor.class);
StorageLayer _storage;
private int vhdFooterSize = 512;
+ private int vhdCookieOffset = 8;
private int vhdFooterCreatorAppOffset = 28;
private int vhdFooterCreatorVerOffset = 32;
private int vhdFooterCurrentSizeOffset = 48;
private byte[][] citrixCreatorApp = { {0x74, 0x61, 0x70, 0x00}, {0x43, 0x54, 0x58, 0x53}}; /*"tap ", and "CTXS"*/
+ private String vhdIdentifierCookie = "conectix";
@Override
public FormatInfo process(String templatePath, ImageFormat format, String templateName) throws InternalErrorException {
@@ -93,10 +99,32 @@
protected long getTemplateVirtualSize(File file) throws IOException {
byte[] currentSize = new byte[8];
+ byte[] cookie = new byte[8];
byte[] creatorApp = new byte[4];
- try (FileInputStream strm = new FileInputStream(file)) {
- long skipped = strm.skip(file.length() - vhdFooterSize + vhdFooterCreatorAppOffset);
+
+ BufferedInputStream fileStream = new BufferedInputStream(new FileInputStream(file));
+ InputStream strm = fileStream;
+
+ boolean isCompressed = checkCompressed(file.getAbsolutePath());
+
+ if ( isCompressed ) {
+ try {
+ strm = new CompressorStreamFactory().createCompressorInputStream(fileStream);
+ } catch (CompressorException e) {
+ s_logger.info("error opening compressed VHD file " + file.getName());
+ return file.length();
+ }
+ } try {
+
+ //read the backup footer present at the top of the VHD file
+ strm.read(cookie);
+ if (! new String(cookie).equals(vhdIdentifierCookie)) {
+ strm.close();
+ return file.length();
+ }
+
+ long skipped = strm.skip(vhdFooterCreatorAppOffset - vhdCookieOffset);
if (skipped == -1) {
throw new IOException("Unexpected end-of-file");
}
@@ -104,7 +132,7 @@
if (read == -1) {
throw new IOException("Unexpected end-of-file");
}
- skipped = strm.skip(vhdFooterCurrentSizeOffset - vhdFooterCreatorVerOffset);
+ skipped = strm.skip(vhdFooterCurrentSizeOffset - vhdFooterCreatorVerOffset - vhdCookieOffset);
if (skipped == -1) {
throw new IOException("Unexpected end-of-file");
}
@@ -112,6 +140,13 @@
if (read == -1) {
throw new IOException("Unexpected end-of-file");
}
+ } catch (IOException e) {
+ s_logger.warn("Error reading virtual size from VHD file " + e.getMessage() + " VHD: " + file.getName());
+ return file.length();
+ } finally {
+ if (strm != null) {
+ strm.close();
+ }
}
return NumbersUtil.bytesToLong(currentSize);
@@ -128,4 +163,30 @@
return true;
}
+ private boolean checkCompressed(String fileName) throws IOException {
+
+ FileInputStream fin = null;
+ BufferedInputStream bin = null;
+ CompressorInputStream cin = null;
+
+ try {
+ fin = new FileInputStream(fileName);
+ bin = new BufferedInputStream(fin);
+ cin = new CompressorStreamFactory().createCompressorInputStream(bin);
+
+ } catch (CompressorException e) {
+ s_logger.warn(e.getMessage());
+ return false;
+
+ } catch (FileNotFoundException e) {
+ s_logger.warn(e.getMessage());
+ return false;
+ } finally {
+ if (cin != null)
+ cin.close();
+ else if (bin != null)
+ bin.close();
+ }
+ return true;
+ }
}
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 0000000..071f6a9
--- /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/core/src/org/apache/cloudstack/storage/command/ResignatureCommand.java b/core/src/org/apache/cloudstack/storage/command/ResignatureCommand.java
new file mode 100644
index 0000000..beb4b65
--- /dev/null
+++ b/core/src/org/apache/cloudstack/storage/command/ResignatureCommand.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.command;
+
+import com.cloud.utils.Utils;
+
+import java.util.Map;
+
+public final class ResignatureCommand extends StorageSubSystemCommand {
+ private final Map<String, String> details;
+
+ private boolean executeInSequence = true;
+
+ public ResignatureCommand(final Map<String, String> details) {
+ this.details = Utils.getImmutableMap(details);
+ }
+
+ public Map<String, String> getDetails() {
+ return details;
+ }
+
+ @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 5d1e56b..29fdd19 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 @@
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 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 a69f357..9b711bc 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 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 0000000..37b15eb
--- /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<String> secIps = new Vector<String>();
+ 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/core/test/com/cloud/storage/template/VhdProcessorTest.java b/core/test/com/cloud/storage/template/VhdProcessorTest.java
index b8b362a..3c695d7 100644
--- a/core/test/com/cloud/storage/template/VhdProcessorTest.java
+++ b/core/test/com/cloud/storage/template/VhdProcessorTest.java
@@ -32,6 +32,8 @@
import java.io.File;
import java.io.IOException;
+import java.net.URLDecoder;
+import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
@@ -107,4 +109,36 @@
Assert.assertEquals(virtualSize, processor.getVirtualSize(mockFile));
Mockito.verify(mockFile,Mockito.times(0)).length();
}
-}
\ No newline at end of file
+
+ @Test
+ public void testVhdGetVirtualSize() throws Exception {
+ String vhdPath = URLDecoder.decode(getClass().getResource("/vhds/test.vhd").getFile(), Charset.defaultCharset().name());
+ long expectedVirtualSizeBytes = 104857600;
+ long actualVirtualSizeBytes = processor.getVirtualSize(new File(vhdPath));
+ Assert.assertEquals(expectedVirtualSizeBytes, actualVirtualSizeBytes);
+ }
+
+ @Test
+ public void testGzipVhdGetVirtualSize() throws Exception {
+ String gzipVhdPath = URLDecoder.decode(getClass().getResource("/vhds/test.vhd.gz").getFile(), Charset.defaultCharset().name());
+ long expectedVirtualSizeBytes = 104857600;
+ long actualVirtualSizeBytes = processor.getVirtualSize(new File(gzipVhdPath));
+ Assert.assertEquals(expectedVirtualSizeBytes, actualVirtualSizeBytes);
+ }
+
+ @Test
+ public void testBzip2VhdGetVirtualSize() throws Exception {
+ String bzipVhdPath = URLDecoder.decode(getClass().getResource("/vhds/test.vhd.bz2").getFile(), Charset.defaultCharset().name());
+ long expectedVirtualSizeBytes = 104857600;
+ long actualVirtualSizeBytes = processor.getVirtualSize(new File(bzipVhdPath));
+ Assert.assertEquals(expectedVirtualSizeBytes, actualVirtualSizeBytes);
+ }
+
+ @Test
+ public void testZipVhdGetVirtualSize() throws Exception {
+ String zipVhdPath = URLDecoder.decode(getClass().getResource("/vhds/test.vhd.zip").getFile(), Charset.defaultCharset().name());
+ long expectedVirtualSizeBytes = 341; //Zip is not a supported format, virtual size should return the filesize as a fallback
+ long actualVirtualSizeBytes = processor.getVirtualSize(new File(zipVhdPath));
+ Assert.assertEquals(expectedVirtualSizeBytes, actualVirtualSizeBytes);
+ }
+}
diff --git a/core/test/resources/vhds/test.vhd b/core/test/resources/vhds/test.vhd
new file mode 100644
index 0000000..87d5f27
--- /dev/null
+++ b/core/test/resources/vhds/test.vhd
Binary files differ
diff --git a/core/test/resources/vhds/test.vhd.bz2 b/core/test/resources/vhds/test.vhd.bz2
new file mode 100644
index 0000000..02821b63
--- /dev/null
+++ b/core/test/resources/vhds/test.vhd.bz2
Binary files differ
diff --git a/core/test/resources/vhds/test.vhd.gz b/core/test/resources/vhds/test.vhd.gz
new file mode 100644
index 0000000..e48bf2b
--- /dev/null
+++ b/core/test/resources/vhds/test.vhd.gz
Binary files differ
diff --git a/core/test/resources/vhds/test.vhd.zip b/core/test/resources/vhds/test.vhd.zip
new file mode 100644
index 0000000..4857d5a
--- /dev/null
+++ b/core/test/resources/vhds/test.vhd.zip
Binary files differ
diff --git a/debian/changelog b/debian/changelog
index 559751a..384fe8e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,20 +1,26 @@
-cloudstack (4.8.2.0-SNAPSHOT) unstable; urgency=low
+cloudstack (4.9.1.0) unstable; urgency=low
- * Update the version to 4.8.2.0-SNAPSHOT
+ * Update the version to 4.9.1.0
- -- the Apache CloudStack project <dev@cloudstack.apache.org> Mon, 08 Aug 2016 10:06:20 -0400
+ -- the Apache CloudStack project <dev@cloudstack.apache.org> Fri, 19 Aug 2016 13:48:00 +0530
-cloudstack (4.8.2.0-SNAPSHOT-SNAPSHOT) unstable; urgency=low
+cloudstack (4.9.0) unstable; urgency=low
+
+ * Update the version to 4.9.0
+
+ -- the Apache CloudStack project <dev@cloudstack.apache.org> Mon, 25 Jul 2016 16:56:03 -0400
+
+cloudstack (4.9.0-SNAPSHOT) unstable; urgency=low
[ Remi Bergsma ]
- * Update the version to 4.8.2.0-SNAPSHOT-SNAPSHOT
+ * Update the version to 4.9.0.snapshot
-- the Apache CloudStack project <dev@cloudstack.apache.org> Wed, 20 Jan 2016 23:43:35 +0100
cloudstack (4.8.0-SNAPSHOT) unstable; urgency=low
[ Remi Bergsma ]
- * Update the version to 4.8.2.0-SNAPSHOT.snapshot
+ * Update the version to 4.8.0.snapshot
-- the Apache CloudStack project <dev@cloudstack.apache.org> Sun, 21 Dec 2015 22:11:55 +0100
diff --git a/debian/cloudstack-agent.dirs b/debian/cloudstack-agent.dirs
new file mode 100644
index 0000000..96c8719
--- /dev/null
+++ b/debian/cloudstack-agent.dirs
@@ -0,0 +1 @@
+/var/log/cloudstack/agent
diff --git a/debian/cloudstack-agent.install b/debian/cloudstack-agent.install
index 82fce9f..184d922 100644
--- a/debian/cloudstack-agent.install
+++ b/debian/cloudstack-agent.install
@@ -18,12 +18,12 @@
/etc/cloudstack/agent/agent.properties
/etc/cloudstack/agent/environment.properties
/etc/cloudstack/agent/log4j-cloud.xml
+/etc/default/cloudstack-agent
/etc/profile.d/cloudstack-agent-profile.sh
/etc/logrotate.d/cloudstack-agent
/etc/init.d/cloudstack-agent
/usr/bin/cloudstack-setup-agent
/usr/bin/cloudstack-ssh
/usr/bin/cloudstack-agent-upgrade
-/var/log/cloudstack/agent
/usr/share/cloudstack-agent/lib/*
/usr/share/cloudstack-agent/plugins
diff --git a/debian/cloudstack-management.install b/debian/cloudstack-management.install
index 4e016df..c669382 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/cloudstack-management.postinst b/debian/cloudstack-management.postinst
index 145d1ea..e70a1a4 100644
--- a/debian/cloudstack-management.postinst
+++ b/debian/cloudstack-management.postinst
@@ -55,9 +55,17 @@
fi
fi
- chmod 0640 /etc/cloudstack/management/db.properties
- chgrp cloud /etc/cloudstack/management/db.properties
+ CONFDIR="/etc/cloudstack/management"
+ DBPROPS="db.properties"
+
+ chmod 0640 ${CONFDIR}/${DBPROPS}
+ chgrp cloud ${CONFDIR}/${DBPROPS}
invoke-rc.d tomcat6 stop || true
+
+ # Add jdbc MySQL driver settings to db.properties if not present
+ grep -s -q "db.cloud.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS} || sed -i -e "\$adb.cloud.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS}
+ grep -s -q "db.usage.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS} || sed -i -e "\$adb.usage.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS}
+ grep -s -q "db.simulator.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS} || sed -i -e "\$adb.simulator.driver=jdbc:mysql" ${CONFDIR}/${DBPROPS}
fi
#DEBHELPER#
diff --git a/debian/cloudstack-usage.dirs b/debian/cloudstack-usage.dirs
new file mode 100644
index 0000000..3f64b79
--- /dev/null
+++ b/debian/cloudstack-usage.dirs
@@ -0,0 +1 @@
+/var/log/cloudstack/usage
diff --git a/debian/cloudstack-usage.install b/debian/cloudstack-usage.install
index 4722e68..c0cc95a 100644
--- a/debian/cloudstack-usage.install
+++ b/debian/cloudstack-usage.install
@@ -18,5 +18,5 @@
/usr/share/cloudstack-usage/lib/*
/usr/share/cloudstack-usage/plugins
/etc/init.d/cloudstack-usage
-/var/log/cloudstack/usage
/etc/cloudstack/usage/*
+/etc/default/cloudstack-usage
diff --git a/debian/control b/debian/control
index 5e9c056..9855bed 100644
--- a/debian/control
+++ b/debian/control
@@ -2,8 +2,8 @@
Section: libs
Priority: extra
Maintainer: Wido den Hollander <wido@widodh.nl>
-Build-Depends: debhelper (>= 9), openjdk-8-jdk | openjdk-7-jdk, genisoimage,
- python-mysqldb, maven (>= 3) | maven3, python (>= 2.7)
+Build-Depends: debhelper (>= 9), openjdk-8-jdk | java8-sdk | java8-jdk | openjdk-7-jdk, genisoimage,
+ python-mysql.connector, maven (>= 3) | maven3, python (>= 2.7), lsb-release, dh-systemd
Standards-Version: 3.8.1
Homepage: http://www.cloudstack.org/
@@ -15,14 +15,15 @@
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: ${python:Depends}, openjdk-8-jre-headless | java8-runtime-headless | java8-runtime | 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
+Recommends: init-system-helpers
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
@@ -31,7 +32,8 @@
Package: cloudstack-usage
Architecture: all
-Depends: ${misc:Depends}, openjdk-8-jre-headless | openjdk-7-jre-headless, cloudstack-common (= ${source:Version}), jsvc, libmysql-java
+Depends: openjdk-8-jre-headless | java8-runtime-headless | java8-runtime | openjdk-7-jre-headless, cloudstack-common (= ${source:Version}), jsvc, libmysql-java
+Recommends: init-system-helpers
Description: CloudStack usage monitor
The CloudStack usage monitor provides usage accounting across the entire cloud for
cloud operators to charge based on usage parameters.
diff --git a/debian/rules b/debian/rules
index f996699..cfe7514 100755
--- a/debian/rules
+++ b/debian/rules
@@ -6,7 +6,7 @@
DESTDIR = "debian/tmp"
%:
- dh $@ --with python2
+ dh $@ --with python2,systemd
override_dh_auto_configure:
cp packaging/debian/replace.properties replace.properties.tmp
@@ -26,6 +26,8 @@
# Common packages
mkdir -p $(DESTDIR)/$(SYSCONFDIR)/$(PACKAGE)
mkdir -p $(DESTDIR)/$(SYSCONFDIR)/init.d
+ mkdir -p $(DESTDIR)/$(SYSCONFDIR)/default
+
mkdir -p $(DESTDIR)/var/cache/$(PACKAGE)
mkdir -p $(DESTDIR)/var/log/$(PACKAGE)
mkdir -p $(DESTDIR)/var/lib/$(PACKAGE)
@@ -35,13 +37,20 @@
# cloudstack-agent
mkdir $(DESTDIR)/$(SYSCONFDIR)/$(PACKAGE)/agent
mkdir $(DESTDIR)/$(SYSCONFDIR)/profile.d
- mkdir $(DESTDIR)/var/log/$(PACKAGE)/agent
mkdir $(DESTDIR)/usr/share/$(PACKAGE)-agent
mkdir $(DESTDIR)/usr/share/$(PACKAGE)-agent/plugins
install -D agent/target/cloud-agent-$(VERSION).jar $(DESTDIR)/usr/share/$(PACKAGE)-agent/lib/$(PACKAGE)-agent.jar
install -D plugins/hypervisors/kvm/target/cloud-plugin-hypervisor-kvm-$(VERSION).jar $(DESTDIR)/usr/share/$(PACKAGE)-agent/lib/
install -D plugins/hypervisors/kvm/target/dependencies/* $(DESTDIR)/usr/share/$(PACKAGE)-agent/lib/
- install -D packaging/debian/init/cloud-agent $(DESTDIR)/$(SYSCONFDIR)/init.d/$(PACKAGE)-agent
+
+ install -m0755 packaging/debian/$(PACKAGE)-agent.init $(DESTDIR)/$(SYSCONFDIR)/init.d/$(PACKAGE)-agent
+ install -d -m0755 debian/$(PACKAGE)-agent/lib/systemd/system
+ # Fix libvirt service name for Debian/Ubuntu
+ sed -i 's/Requires=libvirtd.service/Requires=libvirt-bin.service/g' packaging/systemd/$(PACKAGE)-agent.service
+ sed -i 's/After=libvirtd.service/After=libvirt-bin.service/g' packaging/systemd/$(PACKAGE)-agent.service
+ install -m0644 packaging/systemd/$(PACKAGE)-agent.service debian/$(PACKAGE)-agent/lib/systemd/system/$(PACKAGE)-agent.service
+ install -m0644 packaging/systemd/$(PACKAGE)-agent.default $(DESTDIR)/$(SYSCONFDIR)/default/$(PACKAGE)-agent
+
install -D agent/target/transformed/cloud-setup-agent $(DESTDIR)/usr/bin/cloudstack-setup-agent
install -D agent/target/transformed/cloud-ssh $(DESTDIR)/usr/bin/cloudstack-ssh
install -D agent/target/transformed/cloudstack-agent-profile.sh $(DESTDIR)/$(SYSCONFDIR)/profile.d/cloudstack-agent-profile.sh
@@ -116,14 +125,17 @@
# cloudstack-usage
mkdir $(DESTDIR)/$(SYSCONFDIR)/$(PACKAGE)/usage
- mkdir $(DESTDIR)/var/log/$(PACKAGE)/usage
mkdir $(DESTDIR)/usr/share/$(PACKAGE)-usage
mkdir $(DESTDIR)/usr/share/$(PACKAGE)-usage/plugins
install -D usage/target/cloud-usage-$(VERSION).jar $(DESTDIR)/usr/share/$(PACKAGE)-usage/lib/$(PACKAGE)-usage.jar
install -D usage/target/dependencies/* $(DESTDIR)/usr/share/$(PACKAGE)-usage/lib/
cp usage/target/transformed/db.properties $(DESTDIR)/$(SYSCONFDIR)/$(PACKAGE)/usage/
cp usage/target/transformed/log4j-cloud_usage.xml $(DESTDIR)/$(SYSCONFDIR)/$(PACKAGE)/usage/log4j-cloud.xml
- install -D packaging/debian/init/cloud-usage $(DESTDIR)/$(SYSCONFDIR)/init.d/$(PACKAGE)-usage
+
+ install -D -m0755 packaging/debian/$(PACKAGE)-usage.init $(DESTDIR)/$(SYSCONFDIR)/init.d/$(PACKAGE)-usage
+ install -d -m0755 debian/$(PACKAGE)-usage/lib/systemd/system
+ install -m0644 packaging/systemd/$(PACKAGE)-usage.service debian/$(PACKAGE)-usage/lib/systemd/system/$(PACKAGE)-usage.service
+ install -m0644 packaging/systemd/$(PACKAGE)-usage.default $(DESTDIR)/$(SYSCONFDIR)/default/$(PACKAGE)-usage
# cloudstack-marvin
mkdir -p $(DESTDIR)/usr/share/$(PACKAGE)-marvin
@@ -136,5 +148,8 @@
override_dh_installinit:
dh_installinit -pcloudstack-management -pcloudstack-agent -pcloudstack-usage --onlyscripts --no-start
+override_dh_systemd_enable:
+ dh_systemd_enable -pcloudstack-agent -pcloudstack-usage
+
override_dh_installdocs:
dh_installdocs -A tools/whisker/LICENSE tools/whisker/NOTICE INSTALL.md
diff --git a/deps/install-non-oss.sh b/deps/install-non-oss.sh
index 7d38d53..2f5027c 100755
--- a/deps/install-non-oss.sh
+++ b/deps/install-non-oss.sh
@@ -35,3 +35,6 @@
# 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 3097203..132659e 100644
--- a/developer/developer-prefill.sql
+++ b/developer/developer-prefill.sql
@@ -64,6 +64,10 @@
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');
INSERT INTO `cloud`.`configuration` (category, instance, component, name, value)
@@ -78,6 +82,47 @@
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 4df739d..30c8ea3 100644
--- a/developer/pom.xml
+++ b/developer/pom.xml
@@ -18,7 +18,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
diff --git a/engine/api/pom.xml b/engine/api/pom.xml
index f2d07e4..e15bc12 100644
--- a/engine/api/pom.xml
+++ b/engine/api/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
@@ -38,7 +38,7 @@
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-bundle-jaxrs</artifactId>
- <version>2.7.13</version>
+ <version>2.7.18</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
diff --git a/engine/api/src/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/com/cloud/vm/VirtualMachineManager.java
index 8b22656..d68f348 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<Boolean> ExecuteInSequence = new ConfigKey<Boolean>("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<String> VmConfigDriveLabel = new ConfigKey<String>("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 @@
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 b5601e9..5d552c4 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 @@
StrategyPriority canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost);
- Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback);
+ void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback);
- Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback);
-
- Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback);
-
+ void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> 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 09883c6..2cde5bd 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 d643d7f..e476d8f 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 @@
DataStoreProvider getDefaultImageDataStoreProvider();
DataStoreProvider getDefaultCacheDataStoreProvider();
+
+ List<DataStoreProvider> 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 4d6465b..0613a11 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 @@
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 82ba8b6..d7e8522 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 465b7eb..a399758 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<VolumeInfo> 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 0c6bd93..6dcdf4f 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<CreateCmdResult> 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<CommandResult> callback);
+ void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback);
+
+ void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback<CommandResult> 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 f08d9a4..7f2f4dc 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 @@
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 88ce932..ff204c6 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 @@
public TemplateApiResult(TemplateInfo template) {
super();
+
this.template = template;
}
@@ -52,6 +53,8 @@
AsyncCallFuture<TemplateApiResult> prepareTemplateOnPrimary(TemplateInfo srcTemplate, StoragePool pool);
+ AsyncCallFuture<TemplateApiResult> 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 8352682..75a7ad9 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 @@
}
}
- ChapInfo getChapInfo(VolumeInfo volumeInfo, DataStore dataStore);
+ ChapInfo getChapInfo(DataObject dataObject, DataStore dataStore);
boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore);
@@ -81,7 +81,7 @@
VolumeEntity getVolumeEntity(long volumeId);
- AsyncCallFuture<VolumeApiResult> createManagedStorageAndVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId,
+ AsyncCallFuture<VolumeApiResult> createManagedStorageVolumeFromTemplateAsync(VolumeInfo volumeInfo, long destDataStoreId,
TemplateInfo srcTemplateInfo, long destHostId);
AsyncCallFuture<VolumeApiResult> createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId,
diff --git a/engine/components-api/pom.xml b/engine/components-api/pom.xml
index 10e1dd2..2e9cfe8 100644
--- a/engine/components-api/pom.xml
+++ b/engine/components-api/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/components-api/src/com/cloud/agent/AgentManager.java b/engine/components-api/src/com/cloud/agent/AgentManager.java
index e9e3249..244772d 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 @@
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 @@
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 @@
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 242f90c..843a634 100644
--- a/engine/components-api/src/com/cloud/agent/Listener.java
+++ b/engine/components-api/src/com/cloud/agent/Listener.java
@@ -64,6 +64,12 @@
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
* been registered for host events.
@@ -87,6 +93,18 @@
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
* from the agent. Returning true means you're expecting more
diff --git a/engine/components-api/src/com/cloud/capacity/CapacityManager.java b/engine/components-api/src/com/cloud/capacity/CapacityManager.java
index 51f7332..3db6e57 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 @@
"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<Boolean> StorageOperationsExcludeCluster =
+ new ConfigKey<Boolean>(
+ 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 0ed1d9e..ef8dddc 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<State, Event, Network> {
@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 aa6c0ce..129f6b1 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 @@
boolean storagePoolHasEnoughSpace(List<Volume> 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> 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 5987ac0..5b2d64a 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<Boolean> AllowPublicUserTemplates = new ConfigKey<Boolean>("Advanced", Boolean.class, AllowPublicUserTemplatesCK, "true",
"If false, users will not be able to create public templates.", true, ConfigKey.Scope.Account);
+ static final ConfigKey<Integer> TemplatePreloaderPoolSize = new ConfigKey<Integer>("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 d269112..de049b3 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 @@
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 @@
this.newSize = newSize;
this.newMinIops = newMinIops;
this.newMaxIops = newMaxIops;
+ this.newHypervisorSnapshotReserve = newHypervisorSnapshotReserve;
this.newServiceOfferingId = newServiceOfferingId;
this.shrinkOk = shrinkOk;
}
@@ -68,4 +69,6 @@
public boolean isShrinkOk() {
return shrinkOk;
}
+
+ public Integer getNewHypervisorSnapshotReserve() { return newHypervisorSnapshotReserve; }
}
diff --git a/engine/network/pom.xml b/engine/network/pom.xml
index 409fe2b..26ea63d 100644
--- a/engine/network/pom.xml
+++ b/engine/network/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/orchestration/pom.xml b/engine/orchestration/pom.xml
index e71bd0e..accb8d5 100755
--- a/engine/orchestration/pom.xml
+++ b/engine/orchestration/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java b/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java
index 0acac3c..d5ec900 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 @@
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 45a7dca..aa7068a 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 @@
@Inject
protected HostDao _hostDao = null;
@Inject
+ protected OutOfBandManagementDao outOfBandManagementDao;
+ @Inject
protected DataCenterDao _dcDao = null;
@Inject
protected HostPodDao _podDao = null;
@@ -538,6 +541,17 @@
}
}
+ @Override
+ public void notifyMonitorsOfNewlyAddedHost(long hostId) {
+ for (final Pair<Integer, Listener> 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 @@
return true;
}
+ @Override
+ public void notifyMonitorsOfHostAboutToBeRemoved(long hostId) {
+ for (final Pair<Integer, Listener> 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<Integer, Listener> 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 @@
}
@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 @@
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;
@@ -1618,6 +1660,10 @@
}
@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)) {
return;
@@ -1634,6 +1680,14 @@
}
@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 f35a4ef..9239adc 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 @@
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 @@
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 @@
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 28c60c1..96d4077 100644
--- a/engine/orchestration/src/com/cloud/agent/manager/SynchronousListener.java
+++ b/engine/orchestration/src/com/cloud/agent/manager/SynchronousListener.java
@@ -79,6 +79,18 @@
}
@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 2136f8e..9523b92 100644
--- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -1241,11 +1241,11 @@
}
}
-
- 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 @@
try {
final Commands cmds = new Commands(Command.OnError.Stop);
- cmds.addCommand(new RebootCommand(vm.getInstanceName()));
+ cmds.addCommand(new RebootCommand(vm.getInstanceName(), getExecuteInSequence(vm.getHypervisorType())));
_agentMgr.send(host.getId(), cmds);
final Answer rebootAnswer = cmds.getAnswer(RebootAnswer.class);
@@ -2642,7 +2642,7 @@
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);
}
}
@@ -2787,6 +2787,18 @@
}
@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)) {
return;
@@ -3686,7 +3698,7 @@
//
@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 2cf1635..66185c6 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 @@
_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 @@
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)) {
@@ -3089,6 +3092,14 @@
}
@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 8de6bd2..ca4ef4f 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 @@
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 @@
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 @@
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 d849eab..9bc22c4 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;
@@ -515,6 +516,14 @@
}
@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);
when(_serviceOfferingMock.isDynamic()).thenReturn(true);
diff --git a/engine/pom.xml b/engine/pom.xml
index 9295d53..287247c 100644
--- a/engine/pom.xml
+++ b/engine/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<build>
diff --git a/engine/schema/pom.xml b/engine/schema/pom.xml
index 70d0539..45e7178 100644
--- a/engine/schema/pom.xml
+++ b/engine/schema/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
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 67ed2a7..6916478 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 @@
<!--
DAOs with default configuration
-->
+ <bean id="roleDaoImpl" class="org.apache.cloudstack.acl.dao.RoleDaoImpl" />
+ <bean id="rolePermissionsDaoImpl" class="org.apache.cloudstack.acl.dao.RolePermissionsDaoImpl" />
<bean id="accountDaoImpl" class="com.cloud.user.dao.AccountDaoImpl" />
<bean id="accountDetailsDaoImpl" class="com.cloud.user.AccountDetailsDaoImpl" />
<bean id="accountJoinDaoImpl" class="com.cloud.api.query.dao.AccountJoinDaoImpl" />
@@ -345,6 +347,6 @@
<bean id="databaseIntegrityChecker" class="com.cloud.upgrade.DatabaseIntegrityChecker" />
<bean id="LBStickinessPolicyDetailsDaoImpl" class="org.apache.cloudstack.resourcedetail.dao.LBStickinessPolicyDetailsDaoImpl" />
<bean id="LBHealthCheckPolicyDetailsDaoImpl" class="org.apache.cloudstack.resourcedetail.dao.LBHealthCheckPolicyDetailsDaoImpl" />
-
+ <bean id="outOfBandManagementDaoImpl" class="org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDaoImpl" />
</beans>
diff --git a/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java b/engine/schema/src/com/cloud/capacity/dao/CapacityDao.java
index 50d6052..fcccd56 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<SummedCapacity> 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<Long> 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 bc992b0..1b1b856 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 @@
}
@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<Long> resourceIdList = new ArrayList<Long>();
+ 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 50c234c..06bc5a3 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 @@
List<ClusterVO> listClustersByDcId(long zoneId);
List<Long> 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 3459e51..0c5bd6f 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 @@
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 @@
@Override
public List<Long> listClustersWithDisabledPods(long zoneId) {
- GenericSearchBuilder<HostPodVO, Long> disabledPodIdSearch = _hostPodDao.createSearchBuilder(Long.class);
+ GenericSearchBuilder<HostPodVO, Long> 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 @@
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 ed7c494..1422e3f 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<DataCenterDetailVO, Long>, ResourceDetailsDao<DataCenterDetailVO> {
+ 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 8bc9eff..e36c8eb 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<DataCenterDetailVO> implements DataCenterDetailsDao, ScopedConfigStorage {
+ private final SearchBuilder<DataCenterDetailVO> 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 @@
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<DataCenterDetailVO> 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 bd48482..88a3547 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 @@
*/
List<HostVO> listAllUpAndEnabledNonHAHosts(Type type, Long clusterId, Long podId, long dcId, String haTag);
+ List<HostVO> findByDataCenterId(Long zoneId);
+
List<HostVO> findByPodId(Long podId);
List<HostVO> findByClusterId(Long clusterId);
List<HostVO> listByDataCenterId(long id);
+ List<HostVO> listByDataCenterIdAndHypervisorType(long zoneId, Hypervisor.HypervisorType hypervisorType);
+
List<Long> listAllHosts(long zoneId);
+ List<HostVO> listAllHostsByType(Host.Type type);
+
HostVO findByPublicIp(String publicIp);
+
+ List<HostVO> 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 8342f1f..46f8a4d 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;
@@ -422,6 +424,37 @@
}
@Override
+ public List<HostVO> listByDataCenterIdAndHypervisorType(long zoneId, Hypervisor.HypervisorType hypervisorType) {
+ SearchBuilder<ClusterVO> clusterSearch = _clusterDao.createSearchBuilder();
+
+ clusterSearch.and("allocationState", clusterSearch.entity().getAllocationState(), SearchCriteria.Op.EQ);
+ clusterSearch.and("hypervisorType", clusterSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ);
+
+ SearchBuilder<HostVO> 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<HostVO> 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<HostVO> sc = GuidSearch.create("guid", guid);
return findOneBy(sc);
@@ -1049,6 +1082,14 @@
}
@Override
+ public List<HostVO> findByDataCenterId(Long zoneId) {
+ SearchCriteria<HostVO> sc = DcSearch.create();
+ sc.setParameters("dc", zoneId);
+ sc.setParameters("type", Type.Routing);
+ return listBy(sc);
+ }
+
+ @Override
public List<HostVO> findByPodId(Long podId) {
SearchCriteria<HostVO> sc = PodSearch.create();
sc.setParameters("podId", podId);
@@ -1087,4 +1128,20 @@
sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, zoneId);
return customSearch(sc, null);
}
+
+ @Override
+ public List<HostVO> listAllHostsByType(Host.Type type) {
+ SearchCriteria<HostVO> sc = TypeSearch.create();
+ sc.setParameters("type", type);
+ sc.setParameters("resourceState", ResourceState.Enabled);
+
+ return listBy(sc);
+ }
+
+ @Override
+ public List<HostVO> listByType(Host.Type type) {
+ SearchCriteria<HostVO> 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 6a8ff56..b864a59 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 @@
@Override
public Map<String, String> findDetails(long hostId) {
SearchCriteria<DetailVO> sc = HostSearch.create();
+
sc.setParameters("hostId", hostId);
List<DetailVO> results = search(sc, null);
+
Map<String, String> details = new HashMap<String, String>(results.size());
+
for (DetailVO result : results) {
if ("password".equals(result.getName())) {
details.put(result.getName(), DBEncryptionUtil.decrypt(result.getValue()));
@@ -76,6 +79,7 @@
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 c49b28b..dda5c38 100644
--- a/engine/schema/src/com/cloud/storage/UploadVO.java
+++ b/engine/schema/src/com/cloud/storage/UploadVO.java
@@ -77,7 +77,7 @@
@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 4ba5088..fc4d9c1 100644
--- a/engine/schema/src/com/cloud/storage/VMTemplateHostVO.java
+++ b/engine/schema/src/com/cloud/storage/VMTemplateHostVO.java
@@ -84,7 +84,7 @@
@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 dd2b35a..d28c23b 100644
--- a/engine/schema/src/com/cloud/storage/VMTemplateVO.java
+++ b/engine/schema/src/com/cloud/storage/VMTemplateVO.java
@@ -63,7 +63,7 @@
@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 56a9a92..d086f2d 100644
--- a/engine/schema/src/com/cloud/storage/VolumeHostVO.java
+++ b/engine/schema/src/com/cloud/storage/VolumeHostVO.java
@@ -93,7 +93,7 @@
@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 770e673..93aad15 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 @@
}
@Override
- public VMTemplateStoragePoolVO findByPoolTemplate(long hostId, long templateId) {
+ public VMTemplateStoragePoolVO findByPoolTemplate(long poolId, long templateId) {
SearchCriteria<VMTemplateStoragePoolVO> 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 750f6f6..e260662 100644
--- a/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java
+++ b/engine/schema/src/com/cloud/upgrade/DatabaseUpgradeChecker.java
@@ -62,6 +62,8 @@
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.Upgrade490to4910;
import com.cloud.upgrade.dao.UpgradeSnapshot217to224;
import com.cloud.upgrade.dao.UpgradeSnapshot223to224;
import com.cloud.upgrade.dao.VersionDao;
@@ -114,193 +116,198 @@
public DatabaseUpgradeChecker() {
_dao = new VersionDaoImpl();
- _upgradeMap.put(CloudStackVersion.parse("2.1.7"), new DbUpgrade[]{new Upgrade217to218(), new Upgrade218to22(), new Upgrade221to222(),
- new UpgradeSnapshot217to224(), 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()});
+ _upgradeMap.put(CloudStackVersion.parse("2.1.7"), new DbUpgrade[] {new Upgrade217to218(), new Upgrade218to22(), new Upgrade221to222(),
+ new UpgradeSnapshot217to224(), 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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("2.1.8"), new DbUpgrade[]{new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(),
- new Upgrade222to224(), new Upgrade218to224DomainVlans(), 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()});
+ _upgradeMap.put(CloudStackVersion.parse("2.1.8"), new DbUpgrade[] {new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(),
+ new Upgrade222to224(), new Upgrade218to224DomainVlans(), 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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("2.1.9"), new DbUpgrade[]{new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(),
- new Upgrade222to224(), new Upgrade218to224DomainVlans(), 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()});
+ _upgradeMap.put(CloudStackVersion.parse("2.1.9"), new DbUpgrade[] {new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(),
+ new Upgrade222to224(), new Upgrade218to224DomainVlans(), 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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910() });
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("4.5.0"), new DbUpgrade[]{new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()});
+ _upgradeMap.put(CloudStackVersion.parse("4.5.0"), new DbUpgrade[] {new Upgrade450to451(), new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("4.5.1"), new DbUpgrade[]{new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()});
+ _upgradeMap.put(CloudStackVersion.parse("4.5.1"), new DbUpgrade[] {new Upgrade451to452(), new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("4.5.2"), new DbUpgrade[]{new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()});
+ _upgradeMap.put(CloudStackVersion.parse("4.5.2"), new DbUpgrade[] {new Upgrade452to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("4.5.3"), new DbUpgrade[]{new Upgrade453to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()});
+ _upgradeMap.put(CloudStackVersion.parse("4.5.3"), new DbUpgrade[] {new Upgrade453to460(), new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("4.6.0"), new DbUpgrade[]{new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()});
+ _upgradeMap.put(CloudStackVersion.parse("4.6.0"), new DbUpgrade[] {new Upgrade460to461(), new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("4.6.1"), new DbUpgrade[]{new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()});
+ _upgradeMap.put(CloudStackVersion.parse("4.6.1"), new DbUpgrade[] {new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("4.6.2"), new DbUpgrade[]{new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()});
+ _upgradeMap.put(CloudStackVersion.parse("4.6.2"), new DbUpgrade[] {new Upgrade461to470(), new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("4.7.0"), new DbUpgrade[]{new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481()});
+ _upgradeMap.put(CloudStackVersion.parse("4.7.0"), new DbUpgrade[] {new Upgrade470to471(), new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("4.7.1"), new DbUpgrade[]{new Upgrade471to480(), new Upgrade480to481()});
+ _upgradeMap.put(CloudStackVersion.parse("4.7.1"), new DbUpgrade[] {new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("4.7.2"), new DbUpgrade[]{new Upgrade471to480(), new Upgrade480to481()});
+ _upgradeMap.put(CloudStackVersion.parse("4.7.2"), new DbUpgrade[] {new Upgrade471to480(), new Upgrade480to481(), new Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("4.8.0"), new DbUpgrade[]{new Upgrade480to481()});
+ _upgradeMap.put(CloudStackVersion.parse("4.8.0"), new DbUpgrade[] {new Upgrade480to481(), new Upgrade481to490(), new Upgrade490to4910()});
+
+ _upgradeMap.put(CloudStackVersion.parse("4.8.1"), new DbUpgrade[] {new Upgrade481to490(), new Upgrade490to4910()});
+
+ _upgradeMap.put(CloudStackVersion.parse("4.8.2.0"), new DbUpgrade[] {new Upgrade481to490(), new Upgrade490to4910()});
+
+ _upgradeMap.put(CloudStackVersion.parse("4.9.0"), new DbUpgrade[] {new Upgrade490to4910()});
//CP Upgrades
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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(CloudStackVersion.parse("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(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
- _upgradeMap.put(CloudStackVersion.parse("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()});
+ _upgradeMap.put(CloudStackVersion.parse("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 Upgrade481to490(), new Upgrade490to4910()});
final List<CloudStackVersion> sortedVersions = newArrayList(_upgradeMap.keySet());
sort(sortedVersions);
availableVersions = ImmutableList.copyOf(sortedVersions);
-
}
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 e13c766..f9ec6e4 100644
--- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java
+++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java
@@ -706,11 +706,11 @@
String vc = "";
String dcName = "";
- try(PreparedStatement pstmt = conn.prepareStatement("select id from `cloud`.`data_center` where removed is NULL");) {
+ try (PreparedStatement pstmt = conn.prepareStatement("select id from `cloud`.`data_center` where removed is NULL");) {
try (ResultSet rs = pstmt.executeQuery();) {
while (rs.next()) {
zoneId = rs.getLong("id");
- try(PreparedStatement clustersQuery = conn.prepareStatement("select id, hypervisor_type from `cloud`.`cluster` where removed is NULL AND data_center_id=?");) {
+ try (PreparedStatement clustersQuery = conn.prepareStatement("select id, hypervisor_type from `cloud`.`cluster` where removed is NULL AND data_center_id=?");) {
clustersQuery.setLong(1, zoneId);
legacyZone = false;
ignoreZone = true;
@@ -719,53 +719,54 @@
// Legacy zone term is meant only for VMware
// Legacy zone is a zone with atleast 2 clusters & with multiple DCs or VCs
clusters = clustersQuery.executeQuery();
- }catch (SQLException e) {
- throw new CloudRuntimeException("persistLegacyZones:Exception:"+e.getMessage(), e);
- }
- if (!clusters.next()) {
- continue; // Ignore the zone without any clusters
- } else {
- dcOfPreviousCluster = null;
- dcOfCurrentCluster = null;
- do {
- clusterHypervisorType = clusters.getString("hypervisor_type");
- clusterId = clusters.getLong("id");
- if (clusterHypervisorType.equalsIgnoreCase("VMware")) {
- ignoreZone = false;
- try (PreparedStatement clusterDetailsQuery = conn.prepareStatement("select value from `cloud`.`cluster_details` where name='url' and cluster_id=?");) {
- clusterDetailsQuery.setLong(1, clusterId);
- try (ResultSet clusterDetails = clusterDetailsQuery.executeQuery();) {
- clusterDetails.next();
- url = clusterDetails.getString("value");
- tokens = url.split("/"); // url format - http://vcenter/dc/cluster
- vc = tokens[2];
- dcName = tokens[3];
- dcOfPreviousCluster = dcOfCurrentCluster;
- dcOfCurrentCluster = dcName + "@" + vc;
- if (!dcList.contains(dcOfCurrentCluster)) {
- dcList.add(dcOfCurrentCluster);
- }
- if (count > 0) {
- if (!dcOfPreviousCluster.equalsIgnoreCase(dcOfCurrentCluster)) {
- legacyZone = true;
- s_logger.debug("Marking the zone " + zoneId + " as legacy zone.");
+ if (!clusters.next()) {
+ continue; // Ignore the zone without any clusters
+ } else {
+ dcOfPreviousCluster = null;
+ dcOfCurrentCluster = null;
+ do {
+ clusterHypervisorType = clusters.getString("hypervisor_type");
+ clusterId = clusters.getLong("id");
+ if (clusterHypervisorType.equalsIgnoreCase("VMware")) {
+ ignoreZone = false;
+ try (PreparedStatement clusterDetailsQuery = conn
+ .prepareStatement("select value from `cloud`.`cluster_details` where name='url' and cluster_id=?");) {
+ clusterDetailsQuery.setLong(1, clusterId);
+ try (ResultSet clusterDetails = clusterDetailsQuery.executeQuery();) {
+ clusterDetails.next();
+ url = clusterDetails.getString("value");
+ tokens = url.split("/"); // url format - http://vcenter/dc/cluster
+ vc = tokens[2];
+ dcName = tokens[3];
+ dcOfPreviousCluster = dcOfCurrentCluster;
+ dcOfCurrentCluster = dcName + "@" + vc;
+ if (!dcList.contains(dcOfCurrentCluster)) {
+ dcList.add(dcOfCurrentCluster);
}
+ if (count > 0) {
+ if (!dcOfPreviousCluster.equalsIgnoreCase(dcOfCurrentCluster)) {
+ legacyZone = true;
+ s_logger.debug("Marking the zone " + zoneId + " as legacy zone.");
+ }
+ }
+ } catch (SQLException e) {
+ throw new CloudRuntimeException("Unable add zones to cloud.legacyzones table.", e);
}
} catch (SQLException e) {
throw new CloudRuntimeException("Unable add zones to cloud.legacyzones table.", e);
}
- } catch (SQLException e) {
- throw new CloudRuntimeException("Unable add zones to cloud.legacyzones table.", e);
+ } else {
+ s_logger.debug("Ignoring zone " + zoneId + " with hypervisor type " + clusterHypervisorType);
+ break;
}
- } else {
- s_logger.debug("Ignoring zone " + zoneId + " with hypervisor type " + clusterHypervisorType);
- break;
+ count++;
+ } while (clusters.next());
+ if (ignoreZone) {
+ continue; // Ignore the zone with hypervisors other than VMware
}
- count++;
- } while (clusters.next());
- if (ignoreZone) {
- continue; // Ignore the zone with hypervisors other than VMware
}
+ } catch (SQLException e) {
+ throw new CloudRuntimeException("persistLegacyZones:Exception:" + e.getMessage(), e);
}
if (legacyZone) {
listOfLegacyZones.add(zoneId);
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 0000000..1c6ce38
--- /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<String, String> 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/upgrade/dao/Upgrade490to4910.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade490to4910.java
new file mode 100644
index 0000000..01e4b13
--- /dev/null
+++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade490to4910.java
@@ -0,0 +1,64 @@
+// 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.exception.CloudRuntimeException;
+import com.cloud.utils.script.Script;
+
+import java.io.File;
+import java.sql.Connection;
+
+public class Upgrade490to4910 implements DbUpgrade {
+
+ @Override
+ public String[] getUpgradableVersionRange() {
+ return new String[] {"4.9.0", "4.9.1.0"};
+ }
+
+ @Override
+ public String getUpgradedVersion() {
+ return "4.9.1.0";
+ }
+
+ @Override
+ public boolean supportsRollingUpgrade() {
+ return false;
+ }
+
+ @Override
+ public File[] getPrepareScripts() {
+ String script = Script.findScript("", "db/schema-490to4910.sql");
+ if (script == null) {
+ throw new CloudRuntimeException("Unable to find db/schema-490to4910.sql");
+ }
+ return new File[] {new File(script)};
+ }
+
+ @Override
+ public void performDataMigration(Connection conn) {
+ }
+
+ @Override
+ public File[] getCleanupScripts() {
+ String script = Script.findScript("", "db/schema-490to4910-cleanup.sql");
+ if (script == null) {
+ throw new CloudRuntimeException("Unable to find db/schema-490to4910-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 9c9ab0b..39f57df 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 @@
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 @@
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 0f5a044..a504d2f 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 @@
@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 @@
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 @@
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 4c7ce8e..374c9cc 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 @@
List<AccountVO> findActiveAccountsForDomain(Long domain);
+ List<AccountVO> findAccountsByRole(Long roleId);
+
void markForCleanup(long accountId);
List<AccountVO> 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 bff6213..2789150 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<AccountVO, Long> 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<AccountVO> AllFieldsSearch;
@@ -53,6 +53,7 @@
protected final SearchBuilder<AccountVO> CleanupForRemovedAccountsSearch;
protected final SearchBuilder<AccountVO> CleanupForDisabledAccountsSearch;
protected final SearchBuilder<AccountVO> NonProjectAccountSearch;
+ protected final SearchBuilder<AccountVO> AccountByRoleSearch;
protected final GenericSearchBuilder<AccountVO, Long> AccountIdsSearch;
public AccountDaoImpl() {
@@ -96,6 +97,10 @@
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 @@
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<User, Account>(u, a);
}
@@ -259,6 +265,13 @@
}
@Override
+ public List<AccountVO> findAccountsByRole(Long roleId) {
+ SearchCriteria<AccountVO> sc = AccountByRoleSearch.create();
+ sc.setParameters("roleId", roleId);
+ return listBy(sc);
+ }
+
+ @Override
public void markForCleanup(long accountId) {
AccountVO account = findByIdIncludingRemoved(accountId);
if (!account.getNeedsCleanup()) {
diff --git a/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java b/engine/schema/src/com/cloud/vm/dao/DomainRouterDao.java
index d555e79..ef8829e 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 @@
List<DomainRouterVO> listRunningByDataCenter(long dcId);
List<DomainRouterVO> listStopped(long networkId);
+
+ List<DomainRouterVO> 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 271644f..85a8a93 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 @@
sc.setParameters("states", State.Stopped);
return listBy(sc);
}
+
+ @Override
+ public List<DomainRouterVO> listIncludingRemovedByVpcId(long vpcId) {
+ SearchCriteria<DomainRouterVO> 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 0000000..a81cebb
--- /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 0000000..f3404ab
--- /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/api/src/com/cloud/exception/MissingParameterValueException.java b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java
similarity index 69%
copy from api/src/com/cloud/exception/MissingParameterValueException.java
copy to engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java
index 4bcaa56..e53654d 100644
--- a/api/src/com/cloud/exception/MissingParameterValueException.java
+++ b/engine/schema/src/org/apache/cloudstack/acl/dao/RoleDao.java
@@ -14,13 +14,16 @@
// 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.acl.dao;
-public class MissingParameterValueException extends CloudRuntimeException {
+import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.acl.RoleVO;
- public MissingParameterValueException(String message) {
- super(message);
- }
-}
\ No newline at end of file
+import java.util.List;
+
+public interface RoleDao extends GenericDao<RoleVO, Long> {
+ List<RoleVO> findAllByName(String roleName);
+ List<RoleVO> 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 0000000..c7eb496
--- /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<RoleVO, Long> implements RoleDao {
+ private final SearchBuilder<RoleVO> RoleByNameSearch;
+ private final SearchBuilder<RoleVO> 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<RoleVO> findAllByName(final String roleName) {
+ SearchCriteria<RoleVO> sc = RoleByNameSearch.create();
+ sc.setParameters("roleName", "%" + roleName + "%");
+ return listBy(sc);
+ }
+
+ @Override
+ public List<RoleVO> findAllByRoleType(final RoleType type) {
+ SearchCriteria<RoleVO> 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 0000000..3754491
--- /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<RolePermissionVO, Long> {
+ /**
+ * 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<RolePermission> 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<RolePermissionVO> 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 0000000..8f6fa83
--- /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<RolePermissionVO, Long> implements RolePermissionsDao {
+ protected static final Logger LOGGER = Logger.getLogger(RolePermissionsDaoImpl.class);
+
+ private final SearchBuilder<RolePermissionVO> 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<RolePermissionVO> 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<RolePermissionVO> 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<RolePermission> newOrder) {
+ if (role == null || newOrder == null || newOrder.isEmpty()) {
+ return false;
+ }
+ return Transaction.execute(new TransactionCallback<Boolean>() {
+ @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<RolePermissionVO> currentOrder = findAllByRoleIdSorted(role.getId());
+ if (role.getId() < 1L || newOrder.size() != currentOrder.size()) {
+ throw new CloudRuntimeException(failMessage);
+ }
+ final Set<Long> newOrderSet = new HashSet<>();
+ for (final RolePermission permission : newOrder) {
+ if (permission == null) {
+ continue;
+ }
+ newOrderSet.add(permission.getId());
+ }
+ final Set<Long> 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<RolePermissionVO> 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<RolePermissionVO> findAllByRoleIdSorted(final Long roleId) {
+ final SearchCriteria<RolePermissionVO> 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<RolePermissionVO> 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 0000000..b5c357c
--- /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/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDao.java b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDao.java
new file mode 100644
index 0000000..5985b81
--- /dev/null
+++ b/engine/schema/src/org/apache/cloudstack/outofbandmanagement/dao/OutOfBandManagementDao.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.outofbandmanagement.dao;
+
+import com.cloud.utils.db.GenericDao;
+import com.cloud.utils.fsm.StateDao;
+import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement;
+import org.apache.cloudstack.outofbandmanagement.OutOfBandManagementVO;
+
+import java.util.List;
+
+public interface OutOfBandManagementDao extends GenericDao<OutOfBandManagementVO, Long>, StateDao<OutOfBandManagement.PowerState, OutOfBandManagement.PowerState.Event, OutOfBandManagement> {
+ OutOfBandManagement findByHost(long hostId);
+ List<OutOfBandManagementVO> 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 0000000..b914b6b
--- /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<OutOfBandManagementVO, Long> implements OutOfBandManagementDao {
+ private static final Logger LOG = Logger.getLogger(OutOfBandManagementDaoImpl.class);
+
+ private SearchBuilder<OutOfBandManagementVO> HostSearch;
+ private SearchBuilder<OutOfBandManagementVO> ManagementServerSearch;
+ private SearchBuilder<OutOfBandManagementVO> OutOfBandManagementOwnerSearch;
+ private SearchBuilder<OutOfBandManagementVO> 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<OutOfBandManagementVO> sc = HostSearch.create("hostId", hostId);
+ return findOneBy(sc);
+ }
+
+ @Override
+ public List<OutOfBandManagementVO> findAllByManagementServer(long serverId) {
+ SearchCriteria<OutOfBandManagementVO> 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<OutOfBandManagementVO> 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 2d1a3ed..2c70677 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 @@
@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 d265da1..32d1d79 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 @@
*/
List<StoragePoolVO> findPoolByName(String name);
+ List<StoragePoolVO> 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 fd617cc..c451e1d 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 @@
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();
@@ -129,6 +130,13 @@
}
@Override
+ public List<StoragePoolVO> findPoolsByProvider(String provider) {
+ SearchCriteria<StoragePoolVO> sc = AllFieldSearch.create();
+ sc.setParameters("storage_provider_name", provider);
+ return listBy(sc);
+ }
+
+ @Override
public StoragePoolVO findPoolByUUID(String uuid) {
SearchCriteria<StoragePoolVO> sc = AllFieldSearch.create();
sc.setParameters("uuid", uuid);
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 bb05300..024f056 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 @@
@Column(name = "install_path")
private String installPath;
- @Column(name = "url")
+ @Column(name = "url", length = 2048)
private String downloadUrl;
- @Column(name = "download_url")
+ @Column(name = "download_url", length = 2048)
private String extractUrl;
@Column(name = "download_url_created")
diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
index 91d4ef7..68baab2 100644
--- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
+++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/VolumeDataStoreVO.java
@@ -96,10 +96,10 @@
@Column(name = "install_path")
private String installPath;
- @Column(name = "url")
+ @Column(name = "url", length = 2048)
private String downloadUrl;
- @Column(name = "download_url")
+ @Column(name = "download_url", length = 2048)
private String extractUrl;
@Column(name = "download_url_created")
diff --git a/engine/schema/test/com/cloud/upgrade/DatabaseUpgradeCheckerTest.java b/engine/schema/test/com/cloud/upgrade/DatabaseUpgradeCheckerTest.java
index 1530251..b3a30d1 100644
--- a/engine/schema/test/com/cloud/upgrade/DatabaseUpgradeCheckerTest.java
+++ b/engine/schema/test/com/cloud/upgrade/DatabaseUpgradeCheckerTest.java
@@ -23,6 +23,7 @@
import com.cloud.upgrade.dao.Upgrade470to471;
import com.cloud.upgrade.dao.Upgrade471to480;
import com.cloud.upgrade.dao.Upgrade480to481;
+import com.cloud.upgrade.dao.Upgrade490to4910;
import org.apache.cloudstack.utils.CloudStackVersion;
import org.junit.Test;
@@ -47,40 +48,18 @@
final DbUpgrade[] upgrades = checker.calculateUpgradePath(dbVersion, currentVersion);
assertNotNull(upgrades);
- assertEquals(1, upgrades.length);
+ assertTrue(upgrades.length >= 1);
assertTrue(upgrades[0] instanceof Upgrade480to481);
}
@Test
- public void testCalculateUpgradePath480to4820() {
+ public void testCalculateUpgradePath490to4910() {
- final CloudStackVersion dbVersion = CloudStackVersion.parse("4.8.0");
+ final CloudStackVersion dbVersion = CloudStackVersion.parse("4.9.0");
assertNotNull(dbVersion);
- final CloudStackVersion currentVersion = CloudStackVersion.parse("4.8.2.0");
- assertNotNull(currentVersion);
-
- final DatabaseUpgradeChecker checker = new DatabaseUpgradeChecker();
- final DbUpgrade[] upgrades = checker.calculateUpgradePath(dbVersion, currentVersion);
-
- assertNotNull(upgrades);
- assertEquals(2, upgrades.length);
-
- assertTrue(upgrades[0] instanceof Upgrade480to481);
-
- assertTrue(Arrays.equals(new String[] { "4.8.1", currentVersion.toString()}, upgrades[1].getUpgradableVersionRange()));
- assertEquals(currentVersion.toString(), upgrades[1].getUpgradedVersion());
-
- }
-
- @Test
- public void testCalculateUpgradePath481to4820() {
-
- final CloudStackVersion dbVersion = CloudStackVersion.parse("4.8.1");
- assertNotNull(dbVersion);
-
- final CloudStackVersion currentVersion = CloudStackVersion.parse("4.8.2.0");
+ final CloudStackVersion currentVersion = CloudStackVersion.parse("4.9.1.0");
assertNotNull(currentVersion);
final DatabaseUpgradeChecker checker = new DatabaseUpgradeChecker();
@@ -88,8 +67,9 @@
assertNotNull(upgrades);
assertEquals(1, upgrades.length);
+ assertTrue(upgrades[0] instanceof Upgrade490to4910);
- assertTrue(Arrays.equals(new String[] { "4.8.1", currentVersion.toString()}, upgrades[0].getUpgradableVersionRange()));
+ assertTrue(Arrays.equals(new String[] { "4.9.0", currentVersion.toString()}, upgrades[0].getUpgradableVersionRange()));
assertEquals(currentVersion.toString(), upgrades[0].getUpgradedVersion());
}
@@ -107,7 +87,6 @@
final DbUpgrade[] upgrades = checker.calculateUpgradePath(dbVersion, currentVersion);
assertNotNull(upgrades);
- assertEquals(3, upgrades.length);
assertTrue(upgrades[0] instanceof Upgrade470to471);
assertTrue(upgrades[1] instanceof Upgrade471to480);
@@ -116,19 +95,18 @@
}
@Test
- public void testFindUpgradePath452to4820() {
+ public void testFindUpgradePath452to490() {
final CloudStackVersion dbVersion = CloudStackVersion.parse("4.5.2");
assertNotNull(dbVersion);
- final CloudStackVersion currentVersion = CloudStackVersion.parse("4.8.2.0");
+ final CloudStackVersion currentVersion = CloudStackVersion.parse("4.9.0");
assertNotNull(currentVersion);
final DatabaseUpgradeChecker checker = new DatabaseUpgradeChecker();
final DbUpgrade[] upgrades = checker.calculateUpgradePath(dbVersion, currentVersion);
assertNotNull(upgrades);
- assertEquals(7, upgrades.length);
assertTrue(upgrades[0] instanceof Upgrade452to460);
assertTrue(upgrades[1] instanceof Upgrade460to461);
diff --git a/engine/service/pom.xml b/engine/service/pom.xml
index 9108b84..74ef590 100644
--- a/engine/service/pom.xml
+++ b/engine/service/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-engine-service</artifactId>
<packaging>war</packaging>
@@ -61,17 +61,6 @@
<version>${project.version}</version>
</dependency>
<dependency>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-bundle-jaxrs</artifactId>
- <version>2.7.13</version>
- <exclusions>
- <exclusion>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-server</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
@@ -84,9 +73,9 @@
<finalName>engine</finalName>
<plugins>
<plugin>
- <groupId>org.mortbay.jetty</groupId>
+ <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
- <version>8.1.7.v20120910</version>
+ <version>${cs.jetty.version}</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webApp>
diff --git a/engine/storage/cache/pom.xml b/engine/storage/cache/pom.xml
index ff8b887..e98362f 100644
--- a/engine/storage/cache/pom.xml
+++ b/engine/storage/cache/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/engine/storage/datamotion/pom.xml b/engine/storage/datamotion/pom.xml
index dab11de..e26a750 100644
--- a/engine/storage/datamotion/pom.xml
+++ b/engine/storage/datamotion/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
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 24ecff5..3124666 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 @@
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 @@
// Note: destHost is currently only used if the copyObject method is invoked
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
Answer answer = null;
String errMsg = null;
try {
@@ -465,12 +455,6 @@
CopyCommandResult result = new CopyCommandResult(null, answer);
result.setResult(errMsg);
callback.complete(result);
- return null;
- }
-
- @Override
- public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
- return copyAsync(srcData, destData, null, callback);
}
@DB
@@ -569,11 +553,9 @@
}
@Override
- public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> 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 3c9334d..7a59ad0 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<String, String> 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 @@
}
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> 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 handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, TemplateInfo templateInfo, AsyncCompletionCallback<CopyCommandResult> callback) {
+ private boolean usingBackendSnapshotFor(SnapshotInfo snapshotInfo) {
+ String property = getProperty(snapshotInfo.getId(), "takeSnapshot");
+
+ return Boolean.parseBoolean(property);
+ }
+
+ private void handleCreateTemplateFromSnapshot(SnapshotInfo snapshotInfo, TemplateInfo templateInfo, AsyncCompletionCallback<CopyCommandResult> callback) {
try {
snapshotInfo.processEvent(Event.CopyingRequested);
}
@@ -182,57 +288,168 @@
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<String, String> 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());
- copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand);
- }
- catch (Exception ex) {
- throw new CloudRuntimeException(ex.getMessage());
+ String errMsg = null;
+
+ CopyCmdAnswer copyCmdAnswer = null;
+
+ try {
+ // 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<String, String> srcDetails = getSnapshotDetails(snapshotInfo);
+
+ copyCommand.setOptions(srcDetails);
+
+ copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand);
+ }
+ 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 && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) {
+ errMsg = copyCmdAnswer.getDetails();
+ }
+ else {
+ errMsg = "Unable to create template from snapshot";
+ }
+ }
+
+ 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);
+ }
+ }
+
+ CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer);
+
+ result.setResult(errMsg);
+
+ callback.complete(result);
}
finally {
- try {
- _volumeService.revokeAccess(snapshotInfo, hostVO, srcDataStore);
+ if (usingBackendSnapshot) {
+ deleteVolumeFromSnapshot(snapshotInfo);
}
- catch (Exception ex) {
- s_logger.debug(ex.getMessage(), ex);
+ }
+ }
+
+ /**
+ * 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<CopyCommandResult> 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<VolumeApiResult> 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 && 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 a volume from a template");
}
}
+ } catch (InterruptedException | ExecutionException ex) {
+ volumeInfo.getDataStore().getDriver().deleteAsync(volumeInfo.getDataStore(), volumeInfo, null);
- try {
- if (errMsg == null) {
- snapshotInfo.processEvent(Event.OperationSuccessed);
- }
- else {
- snapshotInfo.processEvent(Event.OperationFailed);
- }
- }
- catch (Exception ex) {
- s_logger.debug(ex.getMessage(), ex);
- }
+ throw new CloudRuntimeException("Create volume from template (ID = " + templateInfo.getId() + ") failed " + ex.getMessage());
}
CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer);
@@ -240,12 +457,40 @@
result.setResult(errMsg);
callback.complete(result);
-
- return null;
}
- private Void handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snapshotInfo, VolumeInfo volumeInfo, AsyncCompletionCallback<CopyCommandResult> callback) {
+ private void handleCreateVolumeFromSnapshotBothOnStorageSystem(SnapshotInfo snapshotInfo, VolumeInfo volumeInfo, AsyncCompletionCallback<CopyCommandResult> 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,72 +502,44 @@
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());
-
- CopyCmdAnswer copyCmdAnswer = null;
-
- try {
- _volumeService.grantAccess(snapshotInfo, hostVO, snapshotInfo.getDataStore());
- _volumeService.grantAccess(volumeInfo, hostVO, volumeInfo.getDataStore());
-
- Map<String, String> srcDetails = getSnapshotDetails(_storagePoolDao.findById(snapshotInfo.getDataStore().getId()), snapshotInfo);
-
- copyCommand.setOptions(srcDetails);
-
- Map<String, String> destDetails = getVolumeDetails(volumeInfo);
-
- copyCommand.setOptions2(destDetails);
-
- copyCmdAnswer = (CopyCmdAnswer)_agentMgr.send(hostVO.getId(), copyCommand);
- }
- catch (Exception ex) {
- throw new CloudRuntimeException(ex.getMessage());
- }
- 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);
- }
- }
-
- String errMsg = null;
-
- if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) {
- if (copyCmdAnswer != null && copyCmdAnswer.getDetails() != null && !copyCmdAnswer.getDetails().isEmpty()) {
- errMsg = copyCmdAnswer.getDetails();
+ if (useCloning) {
+ copyCmdAnswer = performResignature(volumeInfo, hostVO);
}
else {
- errMsg = "Unable to perform host-side operation";
+ // 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 = performCopyOfVdi(volumeInfo, snapshotInfo, hostVO);
}
+
+ 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'";
}
CopyCommandResult result = new CopyCommandResult(null, copyCmdAnswer);
@@ -330,26 +547,78 @@
result.setResult(errMsg);
callback.complete(result);
-
- return null;
}
- private Map<String, String> getSnapshotDetails(StoragePoolVO storagePoolVO, SnapshotInfo snapshotInfo) {
- Map<String, String> details = new HashMap<String, String>();
+ /**
+ * 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");
- details.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress());
- details.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort()));
+ try {
+ snapshotInfo.getDataStore().getDriver().createAsync(snapshotInfo.getDataStore(), snapshotInfo, null);
+ }
+ finally {
+ _snapshotDetailsDao.remove(snapshotDetails.getId());
+ }
- long snapshotId = snapshotInfo.getId();
+ CopyCmdAnswer copyCmdAnswer = performResignature(snapshotInfo, hostVO, keepGrantedAccess);
- details.put(DiskTO.IQN, getProperty(snapshotId, DiskTO.IQN));
+ if (copyCmdAnswer == null || !copyCmdAnswer.getResult()) {
+ if (copyCmdAnswer != null && !StringUtils.isEmpty(copyCmdAnswer.getDetails())) {
+ throw new CloudRuntimeException(copyCmdAnswer.getDetails());
+ }
+ else {
+ throw new CloudRuntimeException("Unable to create volume from snapshot");
+ }
+ }
+ }
- 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));
+ /**
+ * 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");
- return details;
+ try {
+ snapshotInfo.getDataStore().getDriver().createAsync(snapshotInfo.getDataStore(), snapshotInfo, null);
+ }
+ finally {
+ _snapshotDetailsDao.remove(snapshotDetails.getId());
+ }
+ }
+
+ private SnapshotDetailsVO handleSnapshotDetails(long csSnapshotId, String name, String value) {
+ _snapshotDetailsDao.removeDetail(csSnapshotId, name);
+
+ SnapshotDetailsVO snapshotDetails = new SnapshotDetailsVO(csSnapshotId, name, value, false);
+
+ return _snapshotDetailsDao.persist(snapshotDetails);
+ }
+
+ private boolean canStorageSystemCreateVolumeFromVolume(SnapshotInfo snapshotInfo) {
+ boolean supportsCloningVolumeFromVolume = false;
+
+ DataStore dataStore = dataStoreMgr.getDataStore(snapshotInfo.getDataStore().getId(), DataStoreRole.Primary);
+
+ Map<String, String> mapCapabilities = dataStore.getDriver().getCapabilities();
+
+ if (mapCapabilities != null) {
+ String value = mapCapabilities.get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString());
+
+ supportsCloningVolumeFromVolume = Boolean.valueOf(value);
+ }
+
+ return supportsCloningVolumeFromVolume;
}
private String getProperty(long snapshotId, String property) {
@@ -363,68 +632,209 @@
}
private Map<String, String> getVolumeDetails(VolumeInfo volumeInfo) {
- Map<String, String> sourceDetails = new HashMap<String, String>();
+ Map<String, String> volumeDetails = new HashMap<String, String>();
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<String, String> getSnapshotDetails(SnapshotInfo snapshotInfo) {
+ Map<String, String> snapshotDetails = new HashMap<String, String>();
- List<? extends Cluster> 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<HostVO> 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;
+ }
+
+ private HostVO getHost(Long zoneId, boolean computeClusterMustSupportResign) {
+ Preconditions.checkArgument(zoneId != null, "Zone ID cannot be null.");
+
+ List<HostVO> hosts = _hostDao.listByDataCenterIdAndHypervisorType(zoneId, HypervisorType.XenServer);
+
+ if (hosts == null) {
+ return null;
+ }
+
+ List<Long> 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(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
- return copyAsync(srcData, destData, null, callback);
- }
-
- @Override
- public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
CopyCommandResult result = new CopyCommandResult(null, null);
result.setResult("Unsupported operation requested for copying data.");
callback.complete(result);
+ }
- return null;
+ private Map<String, String> 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<String, String> 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<String, String> srcDetails = getSnapshotDetails(snapshotInfo);
+
+ copyCommand.setOptions(srcDetails);
+
+ Map<String, String> 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 8075f4d..9bc8abc 100644
--- a/engine/storage/image/pom.xml
+++ b/engine/storage/image/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
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 db517db..51be9d9 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 @@
<bean id="templateServiceImpl"
class="org.apache.cloudstack.storage.image.TemplateServiceImpl"
- depends-on="dataObjectManagerImpl, dataStoreManagerImpl, dataMotionServiceImpl, objectInDataStoreManagerImpl, defaultEndPointSelector, templateDataFactoryImpl" />
+ depends-on="dataObjectManagerImpl, dataStoreManagerImpl, dataMotionServiceImpl, objectInDataStoreManagerImpl, defaultEndPointSelector, templateDataFactoryImpl, imageStoreDetailsUtil" />
<bean id="templateDataFactoryImpl"
class="org.apache.cloudstack.storage.image.TemplateDataFactoryImpl" />
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 9ab3595..8dcc439 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 @@
ConfigurationDao _configDao;
@Inject
StorageCacheManager _cacheMgr;
+ @Inject
+ MessageBus _messageBus;
+ @Inject
+ ImageStoreDetailsUtil imageStoreDetailsUtil;
class TemplateOpContext<T> extends AsyncRpcContext<T> {
final TemplateObject template;
@@ -352,6 +363,16 @@
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 @@
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 @@
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<TemplateApiResult> context = new TemplateOpContext<>(null,(TemplateObject)tmpl, null);
+ AsyncCallbackDispatcher<TemplateServiceImpl, TemplateApiResult> 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 @@
}
}
+ protected Void createTemplateAsyncCallBack(AsyncCallbackDispatcher<TemplateServiceImpl, TemplateApiResult> callback,
+ TemplateOpContext<TemplateApiResult> 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<String, TemplateProp> 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 @@
return copyAsync(srcTemplate, srcTemplate, (DataStore)pool);
}
+ @Override
+ public AsyncCallFuture<TemplateApiResult> 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<TemplateApiResult> future = new AsyncCallFuture<>();
+ TemplateOpContext<TemplateApiResult> context = new TemplateOpContext<>(null, templateObject, future);
+ AsyncCallbackDispatcher<TemplateServiceImpl, CommandResult> 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<TemplateServiceImpl, CopyCommandResult> callback, TemplateOpContext<TemplateApiResult> 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 473959b..6e78f19 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 @@
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 @@
}
}
+ /**
+ * 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 @@
@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<String, String> 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 @@
}
@Override
- public Map getDetails() {
+ public Map<String, String> getDetails() {
return imageVO.getDetails();
}
diff --git a/engine/storage/integration-test/pom.xml b/engine/storage/integration-test/pom.xml
index 4484326..ed366ad 100644
--- a/engine/storage/integration-test/pom.xml
+++ b/engine/storage/integration-test/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
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 8963428..f732805 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 @@
}
@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 b34b697..0e4755e 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 @@
}
@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 1f1ba24..a86b321 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 @@
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 @@
}
@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 @@
}
@Override
- public void revertSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CommandResult> callback) {
- //To change body of implemented methods use File | Settings | File Templates.
+ public void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback<CommandResult> 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<CreateCmdResult> callback) {
- //To change body of implemented methods use File | Settings | File Templates.
}
@Override
@@ -119,22 +123,19 @@
@Override
public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback<CopyCommandResult> 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<CreateCmdResult> callback) {
- //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Map<String, String> 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 accfeb5..757d96c 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 @@
}
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
throw new UnsupportedOperationException();
}
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> 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<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> 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 b1524f3..43a2476 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 @@
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 f2038ef..59a48e8 100644
--- a/engine/storage/pom.xml
+++ b/engine/storage/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
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 8040d80..a45e4ee 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 @@
<property name="snapshotStrategies" value="#{snapshotStrategiesRegistry.registered}" />
<property name="vmSnapshotStrategies" value="#{vmSnapshotStrategiesRegistry.registered}" />
</bean>
+
+ <bean id="imageStoreDetailsUtil" class="com.cloud.storage.ImageStoreDetailsUtil" />
</beans>
diff --git a/engine/storage/snapshot/pom.xml b/engine/storage/snapshot/pom.xml
index 6d39b0c..5201b40 100644
--- a/engine/storage/snapshot/pom.xml
+++ b/engine/storage/snapshot/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
@@ -37,6 +37,11 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-engine-storage-volume</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
<build>
<plugins>
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 c6960eb..02691ff 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 @@
@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 @@
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 @@
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 @@
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 @@
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 @@
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<String, String> 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<String, String> 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 @@
sourceDetails = getSourceDetails(volumeInfo);
}
- HostVO hostVO = getHost(hostId, volumeVO);
+ HostVO hostVO = null;
+
+ if (hostId != null) {
+ hostVO = hostDao.findById(hostId);
+ }
+ else {
+ Optional<HostVO> 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<String, String> destDetails = getDestDetails(storagePoolVO, snapshotInfo);
@@ -248,23 +306,23 @@
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 @@
path,
false);
- _snapshotDetailsDao.persist(snapshotDetail);
+ snapshotDetailsDao.persist(snapshotDetail);
}
private Map<String, String> getSourceDetails(VolumeInfo volumeInfo) {
- Map<String, String> sourceDetails = new HashMap<String, String>();
+ Map<String, String> 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<String, String> getDestDetails(StoragePoolVO storagePoolVO, SnapshotInfo snapshotInfo) {
- Map<String, String> destDetails = new HashMap<String, String>();
+ Map<String, String> destDetails = new HashMap<>();
destDetails.put(DiskTO.STORAGE_HOST, storagePoolVO.getHostAddress());
destDetails.put(DiskTO.STORAGE_PORT, String.valueOf(storagePoolVO.getPort()));
@@ -338,7 +396,7 @@
}
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 @@
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<HostVO> 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();
-
- List<? extends Cluster> clusters = _mgr.searchForClusters(zoneId, new Long(0), Long.MAX_VALUE, HypervisorType.XenServer.toString());
-
- if (clusters == null) {
- throw new CloudRuntimeException("Unable to locate an applicable cluster");
+ if (optHostVO.isPresent()) {
+ return optHostVO.get();
}
+ throw new CloudRuntimeException("Unable to locate an applicable host");
+ }
+
+ private Optional<HostVO> getHost(long zoneId, boolean computeClusterMustSupportResign) {
+ List<? extends Cluster> clusters = mgr.searchForClusters(zoneId, 0L, Long.MAX_VALUE, HypervisorType.XenServer.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<HostVO> hosts = _hostDao.findByClusterId(cluster.getId());
+ List<HostVO> 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 @@
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<String, String> 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 edd194e..2544484 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 @@
VolumeDao volumeDao;
@Inject
SnapshotDataFactory snapshotDataFactory;
+ @Inject
+ private SnapshotDao _snapshotDao;
@Override
public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) {
@@ -263,6 +267,10 @@
//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 @@
@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 @@
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 a458b23..e8e9412 100644
--- a/engine/storage/snapshot/test/resources/db.properties
+++ b/engine/storage/snapshot/test/resources/db.properties
@@ -26,6 +26,7 @@
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.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.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 1f59cc6..3bad62e 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java
@@ -161,6 +161,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException {
// TODO Auto-generated method stub
@@ -173,6 +177,14 @@
}
@Override
+ public void processHostAboutToBeRemoved(long hostId) {
+ }
+
+ @Override
+ public void processHostRemoved(long hostId, long clusterId) {
+ }
+
+ @Override
public boolean isRecurring() {
// TODO Auto-generated method stub
return false;
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 73a8544..194f7bd 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 @@
Volume volume = _volumeDao.findById(dskCh.getVolumeId());
List<Volume> requestVolumes = new ArrayList<Volume>();
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 6e36514..98eeb6b 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 @@
this.imageStoreProviderMgr = imageDataStoreProviderMgr;
}
+ @Override
public List<DataStoreProvider> 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 df9c836..f1d9323 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 @@
@Column(name = "local_path")
String localDownloadPath;
- @Column(name = "url")
+ @Column(name = "url", length = 2048)
private String downloadUrl;
@Column(name = "format")
diff --git a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
index d38aaed..e414b6c 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
@@ -29,9 +29,6 @@
import javax.inject.Inject;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
-
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.EndPoint;
@@ -43,7 +40,10 @@
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.storage.LocalHostEndpoint;
import org.apache.cloudstack.storage.RemoteHostEndPoint;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+import com.cloud.capacity.CapacityManager;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
@@ -63,11 +63,13 @@
public class DefaultEndPointSelector implements EndPointSelector {
private static final Logger s_logger = Logger.getLogger(DefaultEndPointSelector.class);
@Inject
- HostDao hostDao;
- private final String findOneHostOnPrimaryStorage =
- "select h.id from host h, storage_pool_host_ref s where h.status = 'Up' and h.type = 'Routing' and h.resource_state = 'Enabled' and"
- + " h.id = s.host_id and s.pool_id = ? ";
- private String findOneHypervisorHostInScope = "select h.id from host h where h.status = 'Up' and h.hypervisor_type is not null ";
+ private HostDao hostDao;
+ private final String findOneHostOnPrimaryStorage = "select t.id from "
+ + "(select h.id, cd.value "
+ + "from host h join storage_pool_host_ref s on h.id = s.host_id "
+ + "join cluster c on c.id=h.cluster_id "
+ + "left join cluster_details cd on c.id=cd.cluster_id and cd.name='" + CapacityManager.StorageOperationsExcludeCluster.key() + "' "
+ + "where h.status = 'Up' and h.type = 'Routing' and h.resource_state = 'Enabled' and s.pool_id = ? ";
protected boolean moveBetweenPrimaryImage(DataStore srcStore, DataStore destStore) {
DataStoreRole srcRole = srcStore.getRole();
@@ -115,6 +117,7 @@
sbuilder.append(scope.getScopeId());
}
// TODO: order by rand() is slow if there are lot of hosts
+ sbuilder.append(") t where t.value<>'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 @@
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 @@
}
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 0068c2d..288fae4 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 @@
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 0000000..28d9d46
--- /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<String, String> 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 6ec13e4..c7ed521 100644
--- a/engine/storage/volume/pom.xml
+++ b/engine/storage/volume/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
@@ -25,6 +25,11 @@
<artifactId>cloud-engine-storage</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-engine-storage-image</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
<build>
<plugins>
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 f3c9e79..8196678 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 @@
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 obj) {
+ 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, 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 89af076..64533d5 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
@@ -55,6 +55,11 @@
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);
ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, pool);
@@ -109,4 +114,13 @@
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 a2fd656..05ec7d0 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 @@
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 @@
}
@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 @@
return null;
}
+ protected Void createManagedTemplateImageCallback(AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> callback, CreateVolumeContext<CreateCmdResult> context) {
+ CreateCmdResult result = callback.getResult();
+ VolumeApiResult res = new VolumeApiResult(null);
+
+ res.setResult(result.getResult());
+
+ AsyncCallFuture<VolumeApiResult> 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<VolumeServiceImpl, CopyCommandResult> callback, CreateBaseImageContext<VolumeApiResult> context) {
+ CopyCommandResult result = callback.getResult();
+ VolumeApiResult res = new VolumeApiResult(context.getVolume());
+
+ res.setResult(result.getResult());
+
+ AsyncCallFuture<VolumeApiResult> 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<VolumeServiceImpl, CopyCommandResult> callback, CreateBaseImageContext<VolumeApiResult> context) {
CopyCommandResult result = callback.getResult();
@@ -636,8 +699,10 @@
if (templatePoolRef == null) {
s_logger.warn("Reset Template State On Pool failed - unable to lock TemplatePoolRef " + templatePoolRefId);
} else {
+ templatePoolRef.setTemplateSize(0);
templatePoolRef.setDownloadState(VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED);
templatePoolRef.setState(ObjectInDataStoreStateMachine.State.Allocated);
+
_tmpltPoolDao.update(templatePoolRefId, templatePoolRef);
}
}finally {
@@ -653,50 +718,132 @@
return null;
}
- @Override
- public AsyncCallFuture<VolumeApiResult> 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<VolumeApiResult> 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<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
+ // 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<VolumeApiResult> createVolumeFuture = createVolumeAsync(volumeInfo, destPrimaryDataStore);
+ // create a cache volume on the back-end
- VolumeApiResult createVolumeResult = createVolumeFuture.get();
+ templateOnPrimary.processEvent(Event.CreateOnlyRequested);
- if (createVolumeResult.isFailed()) {
- throw new CloudRuntimeException("Creation of a volume failed: " + createVolumeResult.getResult());
+ CreateVolumeContext<CreateCmdResult> createContext = new CreateVolumeContext<>(null, templateOnPrimary, createTemplateFuture);
+ AsyncCallbackDispatcher<VolumeServiceImpl, CreateCmdResult> 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);
- // refresh the volume from the DB
- volumeInfo = volFactory.getVolume(volumeInfo.getId(), destPrimaryDataStore);
+ templateOnPrimary.processEvent(Event.OperationFailed);
- grantAccess(volumeInfo, destHost, destPrimaryDataStore);
+ throw new CloudRuntimeException(e.getMessage());
+ }
+ finally {
+ _tmpltPoolDao.releaseFromLockTable(templatePoolRefId);
+ }
- ManagedCreateBaseImageContext<CreateCmdResult> context = new ManagedCreateBaseImageContext<CreateCmdResult>(null, volumeInfo,
- destPrimaryDataStore, srcTemplateInfo, future);
- AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
- caller.setCallback(caller.getTarget().managedCopyBaseImageCallback(null, null)).setContext(context);
+ 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<VolumeApiResult> 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<CreateCmdResult> copyContext = new CreateBaseImageContext<>(
+ null, null, destPrimaryDataStore, srcTemplateInfo,
+ copyTemplateFuture, templateOnPrimary, templatePoolRefId
+ );
+
+ AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> 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<String, String> details = new HashMap<String, String>();
details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString());
details.put(PrimaryDataStore.STORAGE_HOST, destPrimaryDataStore.getHostAddress());
details.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(destPrimaryDataStore.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()));
+ 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(volumeInfo, destPrimaryDataStore);
+ ChapInfo chapInfo = getChapInfo(templateOnPrimary, destPrimaryDataStore);
if (chapInfo != null) {
details.put(PrimaryDataStore.CHAP_INITIATOR_USERNAME, chapInfo.getInitiatorUsername());
@@ -705,17 +852,142 @@
details.put(PrimaryDataStore.CHAP_TARGET_SECRET, chapInfo.getTargetSecret());
}
+ templateOnPrimary.processEvent(Event.CopyingRequested);
+
destPrimaryDataStore.setDetails(details);
- motionSrv.copyAsync(srcTemplateInfo, destTemplateInfo, destHost, caller);
+ 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 t) {
+ 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<VolumeApiResult> 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<VolumeApiResult> context =
+ new CreateVolumeFromBaseImageContext<>(null, volumeInfo, destPrimaryDataStore, templateOnPrimary, future, null);
+
+ AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> 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<VolumeApiResult> future) {
+ try {
+ // Create a volume on managed storage.
+
+ TemplateInfo destTemplateInfo = (TemplateInfo)primaryDataStore.create(srcTemplateInfo, false);
+
+ AsyncCallFuture<VolumeApiResult> createVolumeFuture = createVolumeAsync(volumeInfo, primaryDataStore);
+ VolumeApiResult createVolumeResult = createVolumeFuture.get();
+
+ if (createVolumeResult.isFailed()) {
+ throw new CloudRuntimeException("Creation of a volume failed: " + createVolumeResult.getResult());
+ }
+
+ // Refresh the volume info from the DB.
+ volumeInfo = volFactory.getVolume(volumeInfo.getId(), primaryDataStore);
+
+ ManagedCreateBaseImageContext<CreateCmdResult> context = new ManagedCreateBaseImageContext<CreateCmdResult>(null, volumeInfo,
+ primaryDataStore, srcTemplateInfo, future);
+ AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
+
+ caller.setCallback(caller.getTarget().managedCopyBaseImageCallback(null, null)).setContext(context);
+
+ Map<String, String> details = new HashMap<String, String>();
+
+ details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString());
+ 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, primaryDataStore);
+
+ 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());
+ }
+
+ primaryDataStore.setDetails(details);
+
+ 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<VolumeApiResult> expungeVolumeFuture = expungeVolumeAsync(volumeInfo);
@@ -735,10 +1007,112 @@
future.complete(result);
}
+ }
+
+ @Override
+ public AsyncCallFuture<VolumeApiResult> 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<VolumeApiResult> 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<? extends Cluster> 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<HostVO> 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<VolumeApiResult> createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template) {
@@ -1332,7 +1706,8 @@
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 175f68a..dfeecab 100644
--- a/framework/cluster/pom.xml
+++ b/framework/cluster/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/cluster/src/com/cloud/cluster/ClusterServiceServletHttpHandler.java b/framework/cluster/src/com/cloud/cluster/ClusterServiceServletHttpHandler.java
index 3a85302..e12e0fe 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 @@
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 @@
@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 @@
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 @@
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 @@
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 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 835ab99..b348941 100644
--- a/framework/config/pom.xml
+++ b/framework/config/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/db/pom.xml b/framework/db/pom.xml
index 11caff3..6dd48a1 100644
--- a/framework/db/pom.xml
+++ b/framework/db/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
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 0000000..06c8da5
--- /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<String> LOADED_DRIVERS;
+ private static final Map<String, String> DRIVERS;
+
+ static {
+ DRIVERS = new HashMap<String, String>();
+ 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<String>();
+ }
+
+
+ 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 29adbe2..f1b8d0d 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 @@
@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 @@
@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 864ee73..e6cb9cb 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 @@
LinkedHashMap<String, List<Attribute>> _ids;
HashMap<String, TableGenerator> _generators;
ArrayList<Attribute> _ecAttrs;
+ Field[] _mappedSuperclassFields;
public SqlGenerator(Class<?> clazz) {
_clazz = clazz;
@@ -91,6 +94,12 @@
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 @@
}
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 8f71e87..6a422d3 100644
--- a/framework/db/src/com/cloud/utils/db/TransactionLegacy.java
+++ b/framework/db/src/com/cloud/utils/db/TransactionLegacy.java
@@ -1034,6 +1034,7 @@
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"));
@@ -1082,10 +1083,12 @@
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);
@@ -1102,6 +1105,7 @@
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"));
@@ -1110,11 +1114,12 @@
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);
@@ -1130,6 +1135,7 @@
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"));
@@ -1137,9 +1143,11 @@
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 49fd68a..c7aeaad 100644
--- a/framework/db/test/db.properties
+++ b/framework/db/test/db.properties
@@ -29,6 +29,7 @@
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.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.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 18eec26..33c3d7b 100644
--- a/framework/events/pom.xml
+++ b/framework/events/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/ipc/pom.xml b/framework/ipc/pom.xml
index 2ab1dd3..ac043bc 100644
--- a/framework/ipc/pom.xml
+++ b/framework/ipc/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
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 b4c6d4a..0000000
--- 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<Void> 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 b1dbfc5..2c7c86f 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 void MethodThatWillCallAsyncMethod() {
String vol = new String();
-
- /* _ds.createVolume(vol,
- new AsyncCompletionCallback<String>() {
- @Override
- public void complete(String resultObject) {
- // TODO Auto-generated method stub
-
- }
- });*/
}
}
diff --git a/framework/jobs/pom.xml b/framework/jobs/pom.xml
index 0cfaf76..81a4a7d 100644
--- a/framework/jobs/pom.xml
+++ b/framework/jobs/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/JobCancellationException.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/JobCancellationException.java
deleted file mode 100644
index 23540e7..0000000
--- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/JobCancellationException.java
+++ /dev/null
@@ -1,46 +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.jobs;
-
-import java.util.concurrent.CancellationException;
-
-import com.cloud.utils.SerialVersionUID;
-
-/**
- * This exception is fired when the job has been cancelled
- *
- */
-public class JobCancellationException extends CancellationException {
-
- private static final long serialVersionUID = SerialVersionUID.AffinityConflictException;
-
- public enum Reason {
- RequestedByUser, RequestedByCaller, TimedOut;
- }
-
- Reason reason;
-
- public JobCancellationException(Reason reason) {
- super("The job was cancelled due to " + reason.toString());
- this.reason = reason;
- }
-
- public Reason getReason() {
- return reason;
- }
-
-}
diff --git a/framework/jobs/test/resources/db.properties b/framework/jobs/test/resources/db.properties
index 9d250ba..235de85 100644
--- a/framework/jobs/test/resources/db.properties
+++ b/framework/jobs/test/resources/db.properties
@@ -22,6 +22,7 @@
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.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.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 02b268b..2acd2cb 100644
--- a/framework/managed-context/pom.xml
+++ b/framework/managed-context/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-maven-standard</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../maven-standard/pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/pom.xml b/framework/pom.xml
index 9b379eb..1a0a257 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<build>
<defaultGoal>install</defaultGoal>
diff --git a/framework/quota/pom.xml b/framework/quota/pom.xml
index b08c713..ec95629 100644
--- a/framework/quota/pom.xml
+++ b/framework/quota/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java
index a57e0c2..b31af52 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 @@
private ConfigurationDao _configDao;
@Inject
private QuotaUsageDao _quotaUsage;
+ @Inject
+ private QuotaManager _quotaManager;
private EmailQuotaAlert _emailQuotaAlert;
private boolean _lockAccountEnforcement = false;
@@ -153,12 +154,13 @@
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 @@
public void sendQuotaAlert(List<String> 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 1cda3b2..7811bcb 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 b039e26..7f592f8 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 @@
_quotaBalanceDao.saveQuotaBalance(firstBalance);
} else {
QuotaBalanceVO lastRealBalanceEntry = _quotaBalanceDao.findLastBalanceEntry(account.getAccountId(), account.getDomainId(), endDate);
- aggrUsage = aggrUsage.add(lastRealBalanceEntry.getCreditBalance());
+ if (lastRealBalanceEntry != null){
+ aggrUsage = aggrUsage.add(lastRealBalanceEntry.getCreditBalance());
+ }
if (s_logger.isDebugEnabled()) {
s_logger.debug("Last balance entry " + lastRealBalanceEntry + " AggrUsage=" + aggrUsage);
}
@@ -358,10 +360,11 @@
BigDecimal rawusage;
// get service offering details
ServiceOfferingVO serviceoffering = _serviceOfferingDao.findServiceOffering(usageRecord.getVmInstanceId(), usageRecord.getOfferingId());
+ if (serviceoffering == null) return quotalist;
rawusage = new BigDecimal(usageRecord.getRawUsage());
QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.CPU_NUMBER, usageRecord.getEndDate());
- if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
+ if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0 && serviceoffering.getCpu() != null) {
BigDecimal cpu = new BigDecimal(serviceoffering.getCpu());
onehourcostpercpu = tariff.getCurrencyValue().multiply(aggregationRatio);
cpuquotausgage = rawusage.multiply(onehourcostpercpu).multiply(cpu);
@@ -371,7 +374,7 @@
quotalist.add(quota_usage);
}
tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.CPU_CLOCK_RATE, usageRecord.getEndDate());
- if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
+ if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0 && serviceoffering.getSpeed() != null) {
BigDecimal speed = new BigDecimal(serviceoffering.getSpeed() / 100.00);
onehourcostper100mhz = tariff.getCurrencyValue().multiply(aggregationRatio);
speedquotausage = rawusage.multiply(onehourcostper100mhz).multiply(speed);
@@ -381,7 +384,7 @@
quotalist.add(quota_usage);
}
tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.MEMORY, usageRecord.getEndDate());
- if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
+ if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0 && serviceoffering.getRamSize() != null) {
BigDecimal memory = new BigDecimal(serviceoffering.getRamSize());
onehourcostper1mb = tariff.getCurrencyValue().multiply(aggregationRatio);
memoryquotausage = rawusage.multiply(onehourcostper1mb).multiply(memory);
@@ -461,4 +464,9 @@
return quota_usage;
}
+ @Override
+ public boolean isLockable(AccountVO account) {
+ return (account.getType() == AccountVO.ACCOUNT_TYPE_NORMAL || account.getType() == AccountVO.ACCOUNT_TYPE_DOMAIN_ADMIN);
+ }
+
}
diff --git a/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java
index 682b2ef..30d2589 100644
--- a/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java
+++ b/framework/quota/src/org/apache/cloudstack/quota/QuotaStatementImpl.java
@@ -59,11 +59,11 @@
final public static int s_LAST_STATEMENT_SENT_DAYS = 6; //ideally should be less than 7 days
- public enum STATEMENT_PERIODS {
+ public enum QuotaStatementPeriods {
BIMONTHLY, MONTHLY, QUATERLY, HALFYEARLY, YEARLY
};
- private STATEMENT_PERIODS _period = STATEMENT_PERIODS.MONTHLY;
+ private QuotaStatementPeriods _period = QuotaStatementPeriods.MONTHLY;
public QuotaStatementImpl() {
super();
@@ -85,9 +85,9 @@
mergeConfigs(configs, params);
}
String period_str = configs.get(QuotaConfig.QuotaStatementPeriod.key());
- int period = period_str == null ? 1 : Integer.valueOf(period_str);
+ int period = period_str == null ? 1 : Integer.parseInt(period_str);
- STATEMENT_PERIODS _period = STATEMENT_PERIODS.values()[period];
+ QuotaStatementPeriods _period = QuotaStatementPeriods.values()[period];
return true;
}
@@ -122,15 +122,17 @@
Date lastStatementDate = quotaAccount.getLastStatementDate();
if (interval != null) {
AccountVO account = _accountDao.findById(quotaAccount.getId());
- if (lastStatementDate == null || getDifferenceDays(lastStatementDate, new Date()) >= 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");
+ if (account != null) {
+ if (lastStatementDate == null || getDifferenceDays(lastStatementDate, new Date()) >= 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 @@
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 aa650e1..d8ce7ac 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 @@
// 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 b454a14..509702a 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 @@
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 @@
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 @@
this.creditsId = creditsId;
}
+ public boolean isBalanceEntry(){
+ return creditsId==0;
+ }
+
public BigDecimal getCreditBalance() {
return creditBalance;
}
@@ -121,7 +125,7 @@
}
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 2d11edd..795a178 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 @@
@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<String, String> details;
+ Map<String, String> details = new HashMap<String, String>();
- // 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 @@
}
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 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 @@
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 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 792728f..c9f6dcd 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 @@
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 d1cc7ac..e2b5a0a 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 @@
//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 @@
//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 @@
//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 @@
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 @@
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 @@
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 @@
// 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 5d25f46..62989b6 100644
--- a/framework/rest/pom.xml
+++ b/framework/rest/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>cloud-framework-rest</artifactId>
@@ -33,32 +33,32 @@
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
- <version>2.6.3</version>
+ <version>${cs.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
- <version>2.6.3</version>
+ <version>${cs.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
- <version>2.6.3</version>
+ <version>${cs.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
- <version>2.6.3</version>
+ <version>${cs.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
- <version>2.6.3</version>
+ <version>${cs.jackson.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
- <artifactId>cxf-bundle-jaxrs</artifactId>
- <version>2.7.13</version>
+ <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+ <version>${cs.cxf.version}</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
diff --git a/framework/security/pom.xml b/framework/security/pom.xml
index 11f88db..90a0b3a 100644
--- a/framework/security/pom.xml
+++ b/framework/security/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/spring/lifecycle/pom.xml b/framework/spring/lifecycle/pom.xml
index 25ad863..09baf5e 100644
--- a/framework/spring/lifecycle/pom.xml
+++ b/framework/spring/lifecycle/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-maven-standard</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../../maven-standard/pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/framework/spring/module/pom.xml b/framework/spring/module/pom.xml
index 67ff11d..66e8365 100644
--- a/framework/spring/module/pom.xml
+++ b/framework/spring/module/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-maven-standard</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../../maven-standard/pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/maven-standard/pom.xml b/maven-standard/pom.xml
index 60d3db6..9334f0e 100644
--- a/maven-standard/pom.xml
+++ b/maven-standard/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<build>
diff --git a/packaging/README.md b/packaging/README.md
new file mode 100644
index 0000000..abfd420
--- /dev/null
+++ b/packaging/README.md
@@ -0,0 +1,39 @@
+# CloudStack RPM and DEB packaging
+This directory contains all the required scripts and tools needed to build RPM and DEB packages for Apache CloudStack.
+
+These scripts are also used by the CloudStack team to build packages for the official release of CloudStack.
+
+# Requirements
+The RPM and DEB packages have dependencies on versions of specific libraries. Due to these dependencies the following distributions and their versions are supported by the packages.
+
+* CentOS / RHEL: 6 and 7
+* Debian 7 (Wheezy) and 8 (Jessy) (untested!)
+* Ubuntu: 14.04 (Trusty) and 16.04 (Xenial)
+
+# Building
+Using the scripts in the *packaging* directory the RPM and DEB packages can be build.
+
+## DEB
+If you simply want to build packages go to the root directory of your CloudStack source code and run:
+
+``dpkg-buildpackage``
+
+This will build packages for the current distribution version you are running. If you run this on a Ubuntu 16.04 system the packages will be tailored for Ubuntu 16.04 and will not install on Ubuntu 14.04.
+
+### Building cross-distribution
+If you want to build packages for a different distribution run the *build-deb.sh* script. This will build packages with the current distribution as a suffix to the package names. E.g. *cloudstack-agent_4.9.0~xenial_all.deb*
+
+Using a Docker image you can build packages for a distribution you are not running.
+
+The following commands assume that the CloudStack source is present in **/tmp/cloudstack** on the system you are running these commands on.
+
+``docker run -ti -v /tmp:/src ubuntu:16.04 /bin/bash -c "apt-get update && apt-get install -y dpkg-dev python debhelper openjdk-8-jdk genisoimage python-mysql.connector maven lsb-release devscripts && /src/cloudstack/packaging/build-deb.sh"``
+
+``docker run -ti -v /tmp:/src ubuntu:14.04 /bin/bash -c "apt-get update && apt-get install -y dpkg-dev python debhelper openjdk-7-jdk genisoimage python-mysql.connector maven lsb-release devscripts && /src/cloudstack/packaging/build-deb.sh"``
+
+The commands above will generate Ubuntu 14.04 and 16.04 packages which you will find in */tmp* on your system after the build succeeds.
+
+## RPM
+The *package.sh* script can be used to build RPM packages for CloudStack. In the *packaging* script you can run the following command:
+
+``./package.sh --pack oss --distribution centos7``
diff --git a/packaging/build-deb.sh b/packaging/build-deb.sh
new file mode 100755
index 0000000..aa17dc5
--- /dev/null
+++ b/packaging/build-deb.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+#
+# This script builds Debian packages for CloudStack and does
+# so by altering the debian/changelog file and add the Ubuntu
+# version as a suffix, for example: 4.9.0~xenial
+#
+# To build packages for Ubuntu 14.04 run this script on a
+# 14.04 system. The same goes for Ubuntu 16.04
+#
+# The biggest difference between those two versions is the
+# sysvinit vs systemd and Java 7 vs Java 8
+#
+# These packages can be build using Docker for example:
+#
+# Assume that the cloudstack source is present in /tmp/cloudstack
+#
+# Ubuntu 16.04
+# docker run -ti -v /tmp:/src ubuntu:16.04 /bin/bash -c "apt-get update && apt-get install -y dpkg-dev python debhelper openjdk-8-jdk genisoimage python-mysql.connector maven lsb-release devscripts && /src/cloudstack/packaging/build-deb.sh"
+#
+# Ubuntu 14.04
+# docker run -ti -v /tmp:/src ubuntu:14.04 /bin/bash -c "apt-get update && apt-get install -y dpkg-dev python debhelper openjdk-7-jdk genisoimage python-mysql.connector maven lsb-release devscripts && /src/cloudstack/packaging/build-deb.sh"
+#
+
+cd `dirname $0`
+cd ..
+
+dpkg-checkbuilddeps
+
+VERSION=$(grep '^ <version>' pom.xml| cut -d'>' -f2 |cut -d'<' -f1)
+DISTCODE=$(lsb_release -sc)
+
+dch -b -v "${VERSION}~${DISTCODE}" -u low -m "Apache CloudStack Release ${VERSION}"
+
+dpkg-buildpackage -j2 -b -uc -us
diff --git a/packaging/centos63/cloud-agent.rc b/packaging/centos63/cloud-agent.rc
index 6cc6abc..aad9582 100755
--- a/packaging/centos63/cloud-agent.rc
+++ b/packaging/centos63/cloud-agent.rc
@@ -26,6 +26,7 @@
# set environment variables
+TMP=/usr/share/cloudstack-agent/tmp
SHORTNAME=$(basename $0 | sed -e 's/^[SK][0-9][0-9]//')
PIDFILE=/var/run/"$SHORTNAME".pid
LOCKFILE=/var/lock/subsys/"$SHORTNAME"
@@ -41,6 +42,9 @@
exit 1;
fi
+# create java tmp dir if not found
+mkdir -m 0755 -p "$TMP"
+
unset OPTIONS
[ -r /etc/sysconfig/"$SHORTNAME" ] && source /etc/sysconfig/"$SHORTNAME"
@@ -64,7 +68,7 @@
start() {
echo -n $"Starting $PROGNAME: "
if hostname --fqdn >/dev/null 2>&1 ; then
- $JSVC -Xms256m -Xmx2048m -cp "$CLASSPATH" -pidfile "$PIDFILE" \
+ $JSVC -Djava.io.tmpdir="$TMP" -Xms256m -Xmx2048m -cp "$CLASSPATH" -pidfile "$PIDFILE" \
-errfile $LOGDIR/cloudstack-agent.err -outfile $LOGDIR/cloudstack-agent.out $CLASS
RETVAL=$?
echo
diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec
index fd02157..9556236 100644
--- a/packaging/centos63/cloud.spec
+++ b/packaging/centos63/cloud.spec
@@ -50,7 +50,7 @@
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/chkconfig
Requires: /usr/bin/ssh-keygen
Requires: mkisofs
-Requires: MySQL-python
+Requires: mysql-connector-python
Requires: python-paramiko
Requires: ipmitool
Requires: %{name}-common = %{_ver}
@@ -96,6 +96,7 @@
%package common
Summary: Apache CloudStack common files and scripts
Requires: python
+Requires: python-argparse
Obsoletes: cloud-test < 4.1.0
Obsoletes: cloud-scripts < 4.1.0
Obsoletes: cloud-utils < 4.1.0
@@ -252,7 +253,6 @@
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
@@ -318,6 +318,7 @@
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
@@ -425,12 +426,23 @@
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
/sbin/chkconfig --level 345 cloudstack-management on > /dev/null 2>&1 || true
fi
+grep -s -q "db.cloud.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.cloud.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties"
+grep -s -q "db.usage.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.usage.driver=jdbc:mysql" db.properties
+grep -s -q "db.simulator.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.simulator.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties"
+
if [ ! -f %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/vhd-util ] ; then
echo Please download vhd-util from http://download.cloud.com.s3.amazonaws.com/tools/vhd-util and put it in
echo %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/
@@ -618,6 +630,7 @@
%{_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
@@ -641,7 +654,6 @@
%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 6a3101f..bdf6e22 100644
--- a/packaging/centos63/replace.properties
+++ b/packaging/centos63/replace.properties
@@ -21,6 +21,7 @@
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-agent.rc b/packaging/centos7/cloud-agent.rc
index 6cc6abc..aad9582 100755
--- a/packaging/centos7/cloud-agent.rc
+++ b/packaging/centos7/cloud-agent.rc
@@ -26,6 +26,7 @@
# set environment variables
+TMP=/usr/share/cloudstack-agent/tmp
SHORTNAME=$(basename $0 | sed -e 's/^[SK][0-9][0-9]//')
PIDFILE=/var/run/"$SHORTNAME".pid
LOCKFILE=/var/lock/subsys/"$SHORTNAME"
@@ -41,6 +42,9 @@
exit 1;
fi
+# create java tmp dir if not found
+mkdir -m 0755 -p "$TMP"
+
unset OPTIONS
[ -r /etc/sysconfig/"$SHORTNAME" ] && source /etc/sysconfig/"$SHORTNAME"
@@ -64,7 +68,7 @@
start() {
echo -n $"Starting $PROGNAME: "
if hostname --fqdn >/dev/null 2>&1 ; then
- $JSVC -Xms256m -Xmx2048m -cp "$CLASSPATH" -pidfile "$PIDFILE" \
+ $JSVC -Djava.io.tmpdir="$TMP" -Xms256m -Xmx2048m -cp "$CLASSPATH" -pidfile "$PIDFILE" \
-errfile $LOGDIR/cloudstack-agent.err -outfile $LOGDIR/cloudstack-agent.out $CLASS
RETVAL=$?
echo
diff --git a/packaging/centos7/cloud.spec b/packaging/centos7/cloud.spec
index 3917a05..7c093f9 100644
--- a/packaging/centos7/cloud.spec
+++ b/packaging/centos7/cloud.spec
@@ -50,7 +50,7 @@
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/chkconfig
Requires: /usr/bin/ssh-keygen
Requires: mkisofs
-Requires: MySQL-python
+Requires: mysql-connector-python
Requires: ipmitool
Requires: %{name}-common = %{_ver}
Requires: iptables-services
@@ -91,6 +91,7 @@
%package common
Summary: Apache CloudStack common files and scripts
Requires: python
+Requires: python-argparse
Group: System Environment/Libraries
%description common
The Apache CloudStack files shared between agent and management server
@@ -209,7 +210,7 @@
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/%{name}/mnt
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/%{name}/management
mkdir -p ${RPM_BUILD_ROOT}%{_initrddir}
-mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig
+mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/default
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/profile.d
mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d
@@ -220,7 +221,6 @@
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
@@ -285,11 +285,12 @@
install -D client/target/pythonlibs/jasypt-1.9.2.jar ${RPM_BUILD_ROOT}%{_datadir}/%{name}-common/lib/jasypt-1.9.2.jar
install -D packaging/centos7/cloud-ipallocator.rc ${RPM_BUILD_ROOT}%{_initrddir}/%{name}-ipallocator
-install -D packaging/centos7/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/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
+install -D packaging/systemd/cloudstack-management.service ${RPM_BUILD_ROOT}%{_unitdir}/%{name}-management.service
+install -D packaging/systemd/cloudstack-management.default ${RPM_BUILD_ROOT}%{_sysconfdir}/default/%{name}-management
+install -D server/target/conf/cloudstack-sudoers ${RPM_BUILD_ROOT}%{_sysconfdir}/sudoers.d/%{name}-management
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
@@ -308,6 +309,7 @@
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-agent/lib
mkdir -p ${RPM_BUILD_ROOT}%{_datadir}/%{name}-agent/plugins
install -D packaging/systemd/cloudstack-agent.service ${RPM_BUILD_ROOT}%{_unitdir}/%{name}-agent.service
+install -D packaging/systemd/cloudstack-agent.default ${RPM_BUILD_ROOT}%{_sysconfdir}/default/%{name}-agent
install -D agent/target/transformed/agent.properties ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/agent/agent.properties
install -D agent/target/transformed/environment.properties ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/agent/environment.properties
install -D agent/target/transformed/log4j-cloud.xml ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/agent/log4j-cloud.xml
@@ -328,6 +330,7 @@
install -D usage/target/transformed/log4j-cloud_usage.xml ${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}/usage/log4j-cloud.xml
cp usage/target/dependencies/* ${RPM_BUILD_ROOT}%{_datadir}/%{name}-usage/lib/
install -D packaging/systemd/cloudstack-usage.service ${RPM_BUILD_ROOT}%{_unitdir}/%{name}-usage.service
+install -D packaging/systemd/cloudstack-usage.default ${RPM_BUILD_ROOT}%{_sysconfdir}/default/%{name}-usage
mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}/usage/
# CLI
@@ -381,16 +384,31 @@
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
fi
+grep -s -q "db.cloud.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.cloud.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties"
+grep -s -q "db.usage.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.usage.driver=jdbc:mysql" db.properties
+grep -s -q "db.simulator.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties" || sed -i -e "\$adb.simulator.driver=jdbc:mysql" "%{_sysconfdir}/%{name}/management/db.properties"
+
if [ ! -f %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/vhd-util ] ; then
echo Please download vhd-util from http://download.cloud.com.s3.amazonaws.com/tools/vhd-util and put it in
echo %{_datadir}/cloudstack-common/scripts/vm/hypervisor/xenserver/
fi
+if [ -f %{_sysconfdir}/sysconfig/%{name}-management ] ; then
+ mv %{_sysconfdir}/sysconfig/%{name}-management %{_sysconfdir}/default/%{name}-management
+fi
+
%preun agent
/sbin/service cloudstack-agent stop || true
if [ "$1" == "0" ] ; then
@@ -470,7 +488,7 @@
%dir %attr(0770,root,cloud) %{_localstatedir}/cache/%{name}/management/work
%dir %attr(0770,root,cloud) %{_localstatedir}/cache/%{name}/management/temp
%dir %attr(0770,root,cloud) %{_localstatedir}/log/%{name}/management
-%config(noreplace) %{_sysconfdir}/sysconfig/%{name}-management
+%config(noreplace) %{_sysconfdir}/default/%{name}-management
%config(noreplace) %{_sysconfdir}/sudoers.d/%{name}-management
%config(noreplace) %{_sysconfdir}/security/limits.d/cloud
%config(noreplace) %attr(0640,root,cloud) %{_sysconfdir}/%{name}/management/db.properties
@@ -514,12 +532,14 @@
%{_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
%attr(0755,root,root) %{_bindir}/%{name}-agent-upgrade
%attr(0755,root,root) %{_bindir}/%{name}-ssh
%attr(0644,root,root) %{_unitdir}/%{name}-agent.service
+%config(noreplace) %{_sysconfdir}/default/%{name}-agent
%attr(0644,root,root) %{_sysconfdir}/profile.d/%{name}-agent-profile.sh
%attr(0644,root,root) %{_sysconfdir}/logrotate.d/%{name}-agent
%attr(0755,root,root) %{_datadir}/%{name}-common/scripts/network/cisco
@@ -537,7 +557,6 @@
%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/*
@@ -547,6 +566,7 @@
%files usage
%attr(0644,root,root) %{_unitdir}/%{name}-usage.service
+%config(noreplace) %{_sysconfdir}/default/%{name}-usage
%attr(0644,root,root) %{_datadir}/%{name}-usage/*.jar
%attr(0644,root,root) %{_datadir}/%{name}-usage/lib/*.jar
%dir %attr(0770,root,cloud) %{_localstatedir}/log/%{name}/usage
diff --git a/packaging/centos7/replace.properties b/packaging/centos7/replace.properties
index aec359e..0b0f2cc 100644
--- a/packaging/centos7/replace.properties
+++ b/packaging/centos7/replace.properties
@@ -21,6 +21,7 @@
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 282892b..e0baf61 100644
--- a/packaging/centos7/tomcat7/catalina.properties
+++ b/packaging/centos7/tomcat7/catalina.properties
@@ -44,7 +44,7 @@
# "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 36ade8c..6161f3a 100644
--- a/packaging/centos7/tomcat7/db.properties
+++ b/packaging/centos7/tomcat7/db.properties
@@ -25,6 +25,7 @@
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.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.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/init/cloud-agent b/packaging/debian/cloudstack-agent.init
similarity index 94%
rename from packaging/debian/init/cloud-agent
rename to packaging/debian/cloudstack-agent.init
index a3f2ae9..0cae5f5 100755
--- a/packaging/debian/init/cloud-agent
+++ b/packaging/debian/cloudstack-agent.init
@@ -33,6 +33,7 @@
. /lib/lsb/init-functions
+TMP=/usr/share/cloudstack-agent/tmp
SHORTNAME="cloudstack-agent"
PIDFILE=/var/run/"$SHORTNAME".pid
LOCKFILE=/var/lock/subsys/"$SHORTNAME"
@@ -45,6 +46,9 @@
unset OPTIONS
[ -r /etc/default/"$SHORTNAME" ] && source /etc/default/"$SHORTNAME"
+# create java tmp dir if not found
+mkdir -m 0755 -p "$TMP"
+
# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not defined in $DEFAULT)
JDK_DIRS="/usr/lib/jvm/java-7-openjdk-amd64 /usr/lib/jvm/java-7-openjdk-i386 /usr/lib/jvm/java-7-oracle /usr/lib/jvm/java-6-openjdk /usr/lib/jvm/java-6-openjdk-i386 /usr/lib/jvm/java-6-openjdk-amd64 /usr/lib/jvm/java-6-sun"
@@ -96,7 +100,7 @@
wait_for_network
- if start_daemon -p $PIDFILE $DAEMON -Xms256m -Xmx2048m -cp "$CLASSPATH" -Djna.nosys=true -pidfile "$PIDFILE" -errfile SYSLOG $CLASS
+ if start_daemon -p $PIDFILE $DAEMON -Djava.io.tmpdir="$TMP" -Xms256m -Xmx2048m -cp "$CLASSPATH" -Djna.nosys=true -pidfile "$PIDFILE" -errfile SYSLOG $CLASS
RETVAL=$?
then
rc=0
diff --git a/packaging/debian/init/cloud-usage b/packaging/debian/cloudstack-usage.init
similarity index 100%
rename from packaging/debian/init/cloud-usage
rename to packaging/debian/cloudstack-usage.init
diff --git a/packaging/debian/replace.properties b/packaging/debian/replace.properties
index 6d55a98..e1d28bb 100644
--- a/packaging/debian/replace.properties
+++ b/packaging/debian/replace.properties
@@ -21,6 +21,7 @@
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 93cf186..0a80991 100644
--- a/packaging/fedora20/cloud.spec
+++ b/packaging/fedora20/cloud.spec
@@ -50,7 +50,7 @@
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/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}%/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-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 @@
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 @@
%{_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 @@
%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 6a3101f..bdf6e22 100644
--- a/packaging/fedora20/replace.properties
+++ b/packaging/fedora20/replace.properties
@@ -21,6 +21,7 @@
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 e089b12..a749d13 100644
--- a/packaging/fedora21/cloud.spec
+++ b/packaging/fedora21/cloud.spec
@@ -50,7 +50,7 @@
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/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}%/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-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 @@
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 @@
%{_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 @@
%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 6a3101f..bdf6e22 100644
--- a/packaging/fedora21/replace.properties
+++ b/packaging/fedora21/replace.properties
@@ -21,6 +21,7 @@
MSLOG=vmops.log
APISERVERLOG=api.log
DBHOST=localhost
+DBDRIVER=jdbc:mysql
COMPONENTS-SPEC=components-premium.xml
REMOTEHOST=localhost
AGENTCLASSPATH=
diff --git a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup b/packaging/systemd/cloudstack-agent.default
old mode 100755
new mode 100644
similarity index 66%
copy from systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
copy to packaging/systemd/cloudstack-agent.default
index 9d254d3..41fa85b
--- a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
+++ b/packaging/systemd/cloudstack-agent.default
@@ -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,8 @@
# 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"
-
-[ "$output" != "" ] && logger -t cloud $output
-[ -z "$output" ] && logger -t cloud "No files removed"
-
-exit 0
+JAVA=/usr/bin/java
+JAVA_HEAP_INITIAL=256m
+JAVA_HEAP_MAX=2048m
+JAVA_CLASS=com.cloud.agent.AgentShell
+JAVA_TMPDIR=/usr/share/cloudstack-agent/tmp
diff --git a/packaging/systemd/cloudstack-agent.service b/packaging/systemd/cloudstack-agent.service
index 00411f1..9cde22d 100644
--- a/packaging/systemd/cloudstack-agent.service
+++ b/packaging/systemd/cloudstack-agent.service
@@ -23,14 +23,12 @@
[Service]
Type=simple
-Environment=JAVA_HOME=/usr/lib/jvm/jre
-Environment=JAVA_HEAP_INITIAL=256m
-Environment=JAVA_HEAP_MAX=2048m
-Environment=JAVA_CLASS=com.cloud.agent.AgentShell
+EnvironmentFile=-/etc/default/cloudstack-agent
ExecStart=/bin/sh -ec '\
export ACP=`ls /usr/share/cloudstack-agent/lib/*.jar /usr/share/cloudstack-agent/plugins/*.jar 2>/dev/null|tr "\\n" ":"`; \
export CLASSPATH="$ACP:/etc/cloudstack/agent:/usr/share/cloudstack-common/scripts"; \
- ${JAVA_HOME}/bin/java -Xms${JAVA_HEAP_INITIAL} -Xmx${JAVA_HEAP_MAX} -cp "$CLASSPATH" $JAVA_CLASS'
+ mkdir -m 0755 -p ${JAVA_TMPDIR}; \
+ ${JAVA} -Djava.io.tmpdir="${JAVA_TMPDIR}" -Xms${JAVA_HEAP_INITIAL} -Xmx${JAVA_HEAP_MAX} -cp "$CLASSPATH" $JAVA_CLASS'
Restart=always
RestartSec=10s
diff --git a/packaging/centos7/cloud-management.sysconfig b/packaging/systemd/cloudstack-management.default
similarity index 95%
rename from packaging/centos7/cloud-management.sysconfig
rename to packaging/systemd/cloudstack-management.default
index c262b11..6e5fcf9 100644
--- a/packaging/centos7/cloud-management.sysconfig
+++ b/packaging/systemd/cloudstack-management.default
@@ -45,5 +45,5 @@
# 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-management.service b/packaging/systemd/cloudstack-management.service
similarity index 95%
rename from packaging/centos7/cloud-management.service
rename to packaging/systemd/cloudstack-management.service
index db52dcf..c1ede4b 100644
--- a/packaging/centos7/cloud-management.service
+++ b/packaging/systemd/cloudstack-management.service
@@ -28,7 +28,7 @@
Type=simple
EnvironmentFile=/etc/tomcat/tomcat.conf
Environment="NAME=cloudstack-management"
-EnvironmentFile=-/etc/sysconfig/cloudstack-management
+EnvironmentFile=-/etc/default/cloudstack-management
ExecStart=/usr/libexec/tomcat/server start
ExecStop=/usr/libexec/tomcat/server stop
SuccessExitStatus=143
diff --git a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup b/packaging/systemd/cloudstack-usage.default
old mode 100755
new mode 100644
similarity index 66%
copy from systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
copy to packaging/systemd/cloudstack-usage.default
index 9d254d3..84de943
--- a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
+++ b/packaging/systemd/cloudstack-usage.default
@@ -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,8 @@
# 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"
-
-[ "$output" != "" ] && logger -t cloud $output
-[ -z "$output" ] && logger -t cloud "No files removed"
-
-exit 0
+JAVA=/usr/bin/java
+JAVA_HEAP_INITIAL=256m
+JAVA_HEAP_MAX=2048m
+JAVA_CLASS=com.cloud.usage.UsageServer
+JAVA_PID=$$
diff --git a/packaging/systemd/cloudstack-usage.service b/packaging/systemd/cloudstack-usage.service
index 9a1827d..424a455 100644
--- a/packaging/systemd/cloudstack-usage.service
+++ b/packaging/systemd/cloudstack-usage.service
@@ -23,14 +23,11 @@
[Service]
Type=simple
-Environment=JAVA_HOME=/usr/lib/jvm/jre
-Environment=JAVA_HEAP_INITIAL=256m
-Environment=JAVA_HEAP_MAX=2048m
-Environment=JAVA_CLASS=com.cloud.usage.UsageServer
+EnvironmentFile=-/etc/default/cloudstack-usage
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} -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 0000000..bb8008a
--- /dev/null
+++ b/plugins/acl/dynamic-role-based/pom.xml
@@ -0,0 +1,32 @@
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+ http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>cloud-plugin-acl-dynamic-role-based</artifactId>
+ <name>Apache CloudStack Plugin - ACL Dynamic Role Based</name>
+ <parent>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloudstack-plugins</artifactId>
+ <version>4.9.1.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+</project>
diff --git a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties
old mode 100755
new mode 100644
similarity index 66%
copy from systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
copy to plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties
index 9d254d3..dda9998
--- a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
+++ b/plugins/acl/dynamic-role-based/resources/META-INF/cloudstack/acl-dynamic-role-based/module.properties
@@ -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
@@ -16,12 +14,5 @@
# KIND, either express or implied. See the License for the
# 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"
-
-[ "$output" != "" ] && logger -t cloud $output
-[ -z "$output" ] && logger -t cloud "No files removed"
-
-exit 0
+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 0000000..9ffe465
--- /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 @@
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context-3.0.xsd"
+ >
+
+ <bean id="DynamicRoleBasedAPIAccessChecker" class="org.apache.cloudstack.acl.DynamicRoleBasedAPIAccessChecker" >
+ <property name="services" value="#{apiCommandsRegistry.registered}" />
+ </bean>
+</beans>
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 0000000..754d4cc
--- /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<PluggableService> services;
+ private Map<RoleType, Set<String>> annotationRoleBasedApisMap = new HashMap<>();
+
+ protected DynamicRoleBasedAPIAccessChecker() {
+ super();
+ for (RoleType roleType : RoleType.values()) {
+ annotationRoleBasedApisMap.put(roleType, new HashSet<String>());
+ }
+ }
+
+ 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<String> commands = annotationRoleBasedApisMap.get(roleType);
+ if (commands != null && !commands.contains(commandName)) {
+ commands.add(commandName);
+ }
+ }
+
+ @Override
+ public boolean configure(String name, Map<String, Object> 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<PluggableService> getServices() {
+ return services;
+ }
+
+ @Inject
+ public void setServices(List<PluggableService> 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 0000000..12ebbe5
--- /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.<RolePermission>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 2666447..bee50e7 100644
--- a/plugins/acl/static-role-based/pom.xml
+++ b/plugins/acl/static-role-based/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
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 9221ea4..fc78268 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<String> commandPropertyFiles = new HashSet<String>();
- Set<String> commandsPropertiesOverrides = new HashSet<String>();
- Map<RoleType, Set<String>> commandsPropertiesRoleBasedApisMap = new HashMap<RoleType, Set<String>>();
- Map<RoleType, Set<String>> annotationRoleBasedApisMap = new HashMap<RoleType, Set<String>>();
+ private Set<String> commandPropertyFiles = new HashSet<String>();
+ private Set<String> commandsPropertiesOverrides = new HashSet<String>();
+ private Map<RoleType, Set<String>> commandsPropertiesRoleBasedApisMap = new HashMap<RoleType, Set<String>>();
+ private Map<RoleType, Set<String>> annotationRoleBasedApisMap = new HashMap<RoleType, Set<String>>();
+ private List<PluggableService> services;
- List<PluggableService> _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<String>());
@@ -60,23 +62,31 @@
}
}
+ 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 @@
@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 @@
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<PluggableService> getServices() {
- return _services;
+ return services;
}
@Inject
public void setServices(List<PluggableService> services) {
- this._services = services;
+ this.services = services;
}
public Set<String> getCommandPropertyFiles() {
diff --git a/plugins/affinity-group-processors/explicit-dedication/pom.xml b/plugins/affinity-group-processors/explicit-dedication/pom.xml
index 9bf1efc..5ad9c32 100644
--- a/plugins/affinity-group-processors/explicit-dedication/pom.xml
+++ b/plugins/affinity-group-processors/explicit-dedication/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<build>
diff --git a/plugins/affinity-group-processors/host-anti-affinity/pom.xml b/plugins/affinity-group-processors/host-anti-affinity/pom.xml
index 57d4b04..74074fd 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 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<build>
diff --git a/plugins/alert-handlers/snmp-alerts/pom.xml b/plugins/alert-handlers/snmp-alerts/pom.xml
index f5c1e0c..c3e6278 100644
--- a/plugins/alert-handlers/snmp-alerts/pom.xml
+++ b/plugins/alert-handlers/snmp-alerts/pom.xml
@@ -22,7 +22,7 @@
<parent>
<artifactId>cloudstack-plugins</artifactId>
<groupId>org.apache.cloudstack</groupId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
diff --git a/plugins/alert-handlers/syslog-alerts/pom.xml b/plugins/alert-handlers/syslog-alerts/pom.xml
index 9e2da0e..0b06df1 100644
--- a/plugins/alert-handlers/syslog-alerts/pom.xml
+++ b/plugins/alert-handlers/syslog-alerts/pom.xml
@@ -22,7 +22,7 @@
<parent>
<artifactId>cloudstack-plugins</artifactId>
<groupId>org.apache.cloudstack</groupId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
diff --git a/plugins/api/discovery/pom.xml b/plugins/api/discovery/pom.xml
index bff3c4c..0a27f4e 100644
--- a/plugins/api/discovery/pom.xml
+++ b/plugins/api/discovery/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
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 be0d5d5..66d8c5d 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 dfe2f44..a8d9714 100644
--- a/plugins/api/rate-limit/pom.xml
+++ b/plugins/api/rate-limit/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<build>
diff --git a/plugins/api/solidfire-intg-test/pom.xml b/plugins/api/solidfire-intg-test/pom.xml
index 6b22ae3..9ef448f 100644
--- a/plugins/api/solidfire-intg-test/pom.xml
+++ b/plugins/api/solidfire-intg-test/pom.xml
@@ -19,11 +19,11 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-plugin-api-solidfire-intg-test</artifactId>
- <name>Apache CloudStack Plugin - API SolidFire</name>
+ <name>Apache CloudStack Plugin - API SolidFire Integration Testing</name>
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
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 1bab734..2fe875a 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"
>
- <bean id="apiSolidFireServiceImpl" class="org.apache.cloudstack.solidfire.ApiSolidFireServiceImpl"/>
+ <bean id="sfIntgTestUtil" class="org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil"/>
+ <bean id="solidFireIntegrationTestManagerImpl" class="org.apache.cloudstack.solidfire.SolidFireIntegrationTestManagerImpl"/>
+ <bean id="apiSolidFireIntegrationTestServiceImpl" class="org.apache.cloudstack.api.solidfire.ApiSolidFireIntegrationTestServiceImpl" />
</beans>
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 0000000..5ff178a
--- /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 f4c0076..9bb8481 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 @@
@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");
- ApiSolidFireAccountIdResponse response = _apiSolidFireService.getSolidFireAccountId(account.getId(), storagePool.getId());
+ long sfAccountId = manager.getSolidFireAccountId(csAccountUuid, storagePoolUuid);
+
+ 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 c432fb1..5c15e01 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 @@
@Override
public String getCommandName() {
- return s_name;
+ return NAME;
}
@Override
@@ -71,10 +67,11 @@
@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/admin/solidfire/GetSolidFireVolumeSizeCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeSizeCmd.java
new file mode 100644
index 0000000..d7c8acf
--- /dev/null
+++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetSolidFireVolumeSizeCmd.java
@@ -0,0 +1,70 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package 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.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 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;
+
+ @Inject private SolidFireIntegrationTestManager manager;
+ @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("'GetSolidFireVolumeSizeCmd.execute' method invoked");
+
+ long sfVolumeSize = manager.getSolidFireVolumeSize(volumeUuid);
+
+ ApiSolidFireVolumeSizeResponse response = new ApiSolidFireVolumeSizeResponse(sfVolumeSize);
+
+ response.setResponseName(getCommandName());
+ response.setObjectName("apisolidfirevolumesize");
+
+ this.setResponseObject(response);
+ }
+}
\ No newline at end of file
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 0000000..5b9ce37
--- /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<ApiVolumeSnapshotDetailsResponse> responses = util.getSnapshotDetails(snapshotUuid);
+
+ ListResponse<ApiVolumeSnapshotDetailsResponse> 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/admin/solidfire/GetVolumeiScsiNameCmd.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeiScsiNameCmd.java
new file mode 100644
index 0000000..dd6992c
--- /dev/null
+++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/admin/solidfire/GetVolumeiScsiNameCmd.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.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.ApiVolumeiScsiNameResponse;
+import org.apache.cloudstack.util.solidfire.SolidFireIntegrationTestUtil;
+
+@APICommand(name = "getVolumeiScsiName", responseObject = ApiVolumeiScsiNameResponse.class, description = "Get Volume's iSCSI Name",
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+
+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 SolidFireIntegrationTestUtil _util;
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return NAME;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return _util.getAccountIdForVolumeUuid(volumeUuid);
+ }
+
+ @Override
+ public void execute() {
+ LOGGER.info("'GetVolumeiScsiNameCmd.execute' method invoked");
+
+ String volume_iScsiName = _util.getVolume_iScsiName(volumeUuid);
+
+ ApiVolumeiScsiNameResponse response = new ApiVolumeiScsiNameResponse(volume_iScsiName);
+
+ response.setResponseName(getCommandName());
+ response.setObjectName("apivolumeiscsiname");
+
+ this.setResponseObject(response);
+ }
+}
\ 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/user/solidfire/GetSolidFireVolumeIscsiNameCmd.java
deleted file mode 100644
index 7afa301..0000000
--- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeIscsiNameCmd.java
+++ /dev/null
@@ -1,78 +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.command.user.solidfire;
-
-import com.cloud.storage.dao.VolumeDao;
-import com.cloud.storage.Volume;
-import com.cloud.user.Account;
-
-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.ApiSolidFireVolumeIscsiNameResponse;
-import org.apache.cloudstack.context.CallContext;
-import org.apache.cloudstack.solidfire.ApiSolidFireService;
-
-@APICommand(name = "getSolidFireVolumeIscsiName", responseObject = ApiSolidFireVolumeIscsiNameResponse.class, description = "Get SolidFire 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";
-
- @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;
-
- /////////////////////////////////////////////////////
- /////////////// API Implementation///////////////////
- /////////////////////////////////////////////////////
-
- @Override
- public String getCommandName() {
- return s_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
- }
-
- @Override
- public void execute() {
- Volume volume = _volumeDao.findByUuid(volumeUuid);
-
- ApiSolidFireVolumeIscsiNameResponse response = _apiSolidFireService.getSolidFireVolumeIscsiName(volume);
-
- response.setResponseName(getCommandName());
- response.setObjectName("apisolidfirevolumeiscsiname");
-
- this.setResponseObject(response);
- }
-}
\ No newline at end of file
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/user/solidfire/GetSolidFireVolumeSizeCmd.java
deleted file mode 100644
index 3a27a66..0000000
--- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/command/user/solidfire/GetSolidFireVolumeSizeCmd.java
+++ /dev/null
@@ -1,84 +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.command.user.solidfire;
-
-import com.cloud.storage.Volume;
-import com.cloud.user.Account;
-import com.cloud.storage.dao.VolumeDao;
-import com.cloud.storage.StoragePool;
-
-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.ApiSolidFireVolumeSizeResponse;
-import org.apache.cloudstack.context.CallContext;
-import org.apache.cloudstack.solidfire.ApiSolidFireService;
-import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
-
-@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";
-
- @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;
-
- /////////////////////////////////////////////////////
- /////////////// API Implementation///////////////////
- /////////////////////////////////////////////////////
-
- @Override
- public String getCommandName() {
- return s_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
- }
-
- @Override
- public void execute() {
- Volume volume = _volumeDao.findByUuid(volumeUuid);
- StoragePool storagePool = _storagePoolDao.findByUuid(storagePoolUuid);
-
- ApiSolidFireVolumeSizeResponse response = _apiSolidFireService.getSolidFireVolumeSize(volume, storagePool);
-
- response.setResponseName(getCommandName());
- response.setObjectName("apisolidfirevolumesize");
-
- this.setResponseObject(response);
- }
-}
\ No newline at end of file
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/ApiSolidFireVolumeIscsiNameResponse.java
deleted file mode 100644
index 517cba9..0000000
--- a/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/ApiSolidFireVolumeIscsiNameResponse.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.api.response;
-
-import com.cloud.serializer.Param;
-
-import com.google.gson.annotations.SerializedName;
-
-import org.apache.cloudstack.api.BaseResponse;
-
-public class ApiSolidFireVolumeIscsiNameResponse extends BaseResponse {
- @SerializedName("solidFireVolumeIscsiName")
- @Param(description = "SolidFire Volume Iscsi Name")
- private String solidFireVolumeIscsiName;
-
- public ApiSolidFireVolumeIscsiNameResponse(String sfVolumeIscsiName) {
- solidFireVolumeIscsiName = sfVolumeIscsiName;
- }
-
- public String getSolidFireVolumeIscsiName() {
- return solidFireVolumeIscsiName;
- }
-}
\ 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/ApiPathForVolumeResponse.java
similarity index 69%
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/ApiPathForVolumeResponse.java
index fa2b4b2..3e0f820 100644
--- a/api/src/org/apache/cloudstack/api/response/StatusResponse.java
+++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiPathForVolumeResponse.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.google.gson.annotations.SerializedName;
-
+import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
-public class StatusResponse extends BaseResponse {
- @SerializedName("status")
- private Boolean status;
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
- public Boolean getStatus() {
- return status;
- }
+public class ApiPathForVolumeResponse extends BaseResponse {
+ @SerializedName(ApiConstants.PATH)
+ @Param(description = "The path field for the volume")
+ private String path;
- public void setStatus(Boolean status) {
- this.status = status;
+ public ApiPathForVolumeResponse(String path) {
+ this.path = path;
}
}
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 ad77c74..a1c2a4c 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 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 8b63192..202a7e9 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 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 b320ada..d8a7d04 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 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 0000000..364ded8
--- /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 69%
copy from api/src/org/apache/cloudstack/api/response/StatusResponse.java
copy to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/response/solidfire/ApiVolumeiScsiNameResponse.java
index fa2b4b2..f43e533 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 class ApiVolumeiScsiNameResponse extends BaseResponse {
+ @SerializedName("volumeiScsiName")
+ @Param(description = "Volume iSCSI Name")
+ private String volumeiScsiName;
- public Boolean getStatus() {
- return status;
- }
-
- public void setStatus(Boolean status) {
- this.status = status;
+ public ApiVolumeiScsiNameResponse(String volumeiScsiName) {
+ this.volumeiScsiName = volumeiScsiName;
}
}
diff --git a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestService.java
similarity index 81%
copy from plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java
copy to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestService.java
index 4e1cc43..ff206d3 100644
--- a/plugins/network-elements/nuage-vsp/src/com/cloud/network/sync/NuageVspSync.java
+++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/api/solidfire/ApiSolidFireIntegrationTestService.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,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.solidfire;
-package com.cloud.network.sync;
+import com.cloud.utils.component.PluggableService;
-
-public interface NuageVspSync {
-
- public void syncWithNuageVsp(String nuageVspEntity);
+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 0000000..0458903
--- /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<Class<?>> getCommands() {
+ List<Class<?>> cmdList = new ArrayList<Class<?>>();
+
+ 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 92828d4..0000000
--- 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 fbda654..0000000
--- 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<String, Object> 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<Class<?>> getCommands() {
- List<Class<?>> cmdList = new ArrayList<Class<?>>();
-
- cmdList.add(GetSolidFireAccountIdCmd.class);
- cmdList.add(GetSolidFireVolumeSizeCmd.class);
- cmdList.add(GetSolidFireVolumeAccessGroupIdCmd.class);
- cmdList.add(GetSolidFireVolumeIscsiNameCmd.class);
-
- return cmdList;
- }
-}
diff --git a/api/src/com/cloud/exception/MissingParameterValueException.java b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java
similarity index 71%
copy from api/src/com/cloud/exception/MissingParameterValueException.java
copy to plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.java
index 4bcaa56..bdc1180 100644
--- a/api/src/com/cloud/exception/MissingParameterValueException.java
+++ b/plugins/api/solidfire-intg-test/src/org/apache/cloudstack/solidfire/SolidFireIntegrationTestManager.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;
+package org.apache.cloudstack.solidfire;
-import com.cloud.utils.exception.CloudRuntimeException;
-
-public class MissingParameterValueException extends CloudRuntimeException {
-
- public MissingParameterValueException(String message) {
- super(message);
- }
-}
\ No newline at end of file
+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 0000000..ff6e72c
--- /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 0000000..307e8c5
--- /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<ApiVolumeSnapshotDetailsResponse> getSnapshotDetails(String snapshotUuid) {
+ SnapshotVO snapshot = snapshotDao.findByUuid(snapshotUuid);
+
+ List<SnapshotDetailsVO> snapshotDetails = snapshotDetailsDao.listDetails(snapshot.getId());
+
+ List<ApiVolumeSnapshotDetailsResponse> 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 f4c639a..12f11f6 100644
--- a/plugins/database/mysql-ha/pom.xml
+++ b/plugins/database/mysql-ha/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/database/quota/pom.xml b/plugins/database/quota/pom.xml
index 08a6ff6..a09773d 100644
--- a/plugins/database/quota/pom.xml
+++ b/plugins/database/quota/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
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 1258445..f12733d 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 @@
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 @@
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 b4f2001..88466e0 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 void execute() {
Account caller = CallContext.current().getCallingAccount();
List<QuotaSummaryResponse> 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 6e7ab81..0f27697 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 @@
List<QuotaBalanceVO> 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<QuotaEmailTemplateResponse> 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 1b6f400..5748de5 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 @@
private AccountManager _accountMgr;
@Inject
private QuotaStatement _statement;
+ @Inject
+ private QuotaManager _quotaManager;
@Override
public QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO tariff) {
@@ -138,6 +141,7 @@
} 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 @@
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<QuotaBalanceVO> 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<QuotaBalanceVO>() {
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 @@
//check that there is at least one balance entry
for (Iterator<QuotaBalanceVO> 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 @@
}
@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 @@
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 @@
_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 0fd7101..3efc095 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 @@
}
@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 f4d16b7..1f22508 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 @@
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 @@
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 73ead4a..4a76052 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 @@
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 @@
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 ea0c414..c43e9d0 100644
--- a/plugins/dedicated-resources/pom.xml
+++ b/plugins/dedicated-resources/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/deployment-planners/implicit-dedication/pom.xml b/plugins/deployment-planners/implicit-dedication/pom.xml
index 1c3477e..c532a41 100644
--- a/plugins/deployment-planners/implicit-dedication/pom.xml
+++ b/plugins/deployment-planners/implicit-dedication/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/deployment-planners/user-concentrated-pod/pom.xml b/plugins/deployment-planners/user-concentrated-pod/pom.xml
index 0b87ea3..7df8050 100644
--- a/plugins/deployment-planners/user-concentrated-pod/pom.xml
+++ b/plugins/deployment-planners/user-concentrated-pod/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/deployment-planners/user-dispersing/pom.xml b/plugins/deployment-planners/user-dispersing/pom.xml
index 2d1e479..cf5c607 100644
--- a/plugins/deployment-planners/user-dispersing/pom.xml
+++ b/plugins/deployment-planners/user-dispersing/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/event-bus/inmemory/pom.xml b/plugins/event-bus/inmemory/pom.xml
index 1fcdc7e..a7e1a67 100644
--- a/plugins/event-bus/inmemory/pom.xml
+++ b/plugins/event-bus/inmemory/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/event-bus/kafka/pom.xml b/plugins/event-bus/kafka/pom.xml
index a7ac9a7..a8d0d42 100644
--- a/plugins/event-bus/kafka/pom.xml
+++ b/plugins/event-bus/kafka/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
@@ -36,7 +36,7 @@
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
- <version>0.8.2.0</version>
+ <version>0.9.0.1</version>
</dependency>
</dependencies>
<build>
diff --git a/plugins/event-bus/rabbitmq/pom.xml b/plugins/event-bus/rabbitmq/pom.xml
index 5ea5050..0eb80ac 100644
--- a/plugins/event-bus/rabbitmq/pom.xml
+++ b/plugins/event-bus/rabbitmq/pom.xml
@@ -24,14 +24,14 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
- <version>3.5.4</version>
+ <version>3.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
diff --git a/plugins/file-systems/netapp/pom.xml b/plugins/file-systems/netapp/pom.xml
index f31aa9a..ee0584b 100644
--- a/plugins/file-systems/netapp/pom.xml
+++ b/plugins/file-systems/netapp/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/ha-planners/skip-heurestics/pom.xml b/plugins/ha-planners/skip-heurestics/pom.xml
index 910862e..e2055bf 100644
--- a/plugins/ha-planners/skip-heurestics/pom.xml
+++ b/plugins/ha-planners/skip-heurestics/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/host-allocators/random/pom.xml b/plugins/host-allocators/random/pom.xml
index 7815ac6..619360e 100644
--- a/plugins/host-allocators/random/pom.xml
+++ b/plugins/host-allocators/random/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/hypervisors/baremetal/pom.xml b/plugins/hypervisors/baremetal/pom.xml
index ed1b0f2..56a0717 100755
--- a/plugins/hypervisors/baremetal/pom.xml
+++ b/plugins/hypervisors/baremetal/pom.xml
@@ -21,7 +21,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>cloud-plugin-hypervisor-baremetal</artifactId>
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 2451b56..aca7565 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 @@
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 b9e4858..b100929 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<SecurityGroupRule> generateRules(IpPortAndProto[] ipps) {
- List<SecurityGroupRule> rules = new ArrayList<SecurityGroupRule>(
- 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<String, Pair<Long, Long>> sync(String vmName, Long vmId, String agentIp) {
- HashMap<String, Pair<Long, Long>> states = new HashMap<String, Pair<Long, Long>>();
- 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<Long, Long>(vmId, -1L));
- return states;
- }
- Pair<Long, Long> p = new Pair<Long, Long>(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<SecurityGroupRule> generateRules(final List<IpPortAndProto> ipps) {
+ List<SecurityGroupRule> rules = new ArrayList<SecurityGroupRule>(
+ 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<String, Pair<Long, Long>> sync(String vmName, Long vmId, String agentIp) {
+ HashMap<String, Pair<Long, Long>> states = new HashMap<String, Pair<Long, Long>>();
+ 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<Long, Long>(vmId, -1L));
+ return states;
+ }
+ Pair<Long, Long> p = new Pair<Long, Long>(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 6ef2a0e..84401e7 100644
--- a/plugins/hypervisors/hyperv/pom.xml
+++ b/plugins/hypervisors/hyperv/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
@@ -42,11 +42,6 @@
<version>${project.version}</version>
</dependency>
<dependency>
- <groupId>org.mortbay.jetty</groupId>
- <artifactId>jetty</artifactId>
- <version>6.1.26</version>
- </dependency>
- <dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-utils</artifactId>
<version>${project.version}</version>
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 fd8db4a..fd54d43 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
@@ -107,6 +107,10 @@
}
@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
if (!(cmd instanceof StartupRoutingCommand)) {
@@ -177,6 +181,14 @@
}
@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 8a1c414..19c655b 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 @@
}
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
throw new UnsupportedOperationException();
}
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> 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<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+ public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost,
AsyncCompletionCallback<CopyCommandResult> callback) {
Answer answer = null;
String errMsg = null;
@@ -115,7 +106,6 @@
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 5e2c564..be8488e 100644
--- a/plugins/hypervisors/kvm/pom.xml
+++ b/plugins/hypervisors/kvm/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/hypervisors/kvm/src/com/cloud/ha/KVMInvestigator.java b/plugins/hypervisors/kvm/src/com/cloud/ha/KVMInvestigator.java
index 32388df..8337a7b 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 @@
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 @@
if (agent.getHypervisorType() != Hypervisor.HypervisorType.KVM && agent.getHypervisorType() != Hypervisor.HypervisorType.LXC) {
return null;
}
+
+ List<StoragePoolVO> 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 @@
List<HostVO> 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 883c8c9..2b9aa71
--- 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 @@
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 @@
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 @@
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;
}
@@ -1243,7 +1239,7 @@
command.add("-p", cmdLine.replaceAll(" ", "%"));
result = command.execute();
if (result != null) {
- s_logger.debug("passcmd failed:" + result);
+ s_logger.error("passcmd failed:" + result);
return false;
}
return true;
@@ -2626,7 +2622,14 @@
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 @@
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 @@
}
}
+ /**
+ * 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 4d13c1b..b5604d4 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 Answer execute(final RebootRouterCommand command, final LibvirtComputingResource libvirtComputingResource) {
final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
- final RebootCommand rebootCommand = new RebootCommand(command.getVmName());
+ final RebootCommand rebootCommand = new RebootCommand(command.getVmName(), true);
final Answer answer = wrapper.execute(rebootCommand, libvirtComputingResource);
final VirtualRoutingResource virtualRouterResource = libvirtComputingResource.getVirtRouterResource();
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSecurityGroupRulesCommandWrapper.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSecurityGroupRulesCommandWrapper.java
index f1a2e02..ef9fd89 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSecurityGroupRulesCommandWrapper.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtSecurityGroupRulesCommandWrapper.java
@@ -62,7 +62,7 @@
return new SecurityGroupRuleAnswer(command, false, "programming network rules failed");
} else {
s_logger.debug("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/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
index 749cbd8..29655d1 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
@@ -47,6 +47,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;
@@ -67,7 +69,10 @@
import com.ceph.rados.IoCTX;
import com.ceph.rados.Rados;
+import com.ceph.rados.exceptions.ErrorCode;
+import com.ceph.rados.exceptions.RadosException;
import com.ceph.rbd.Rbd;
+import com.ceph.rbd.RbdException;
import com.ceph.rbd.RbdImage;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
@@ -148,6 +153,13 @@
}
@Override
+ public ResignatureAnswer resignature(final ResignatureCommand cmd) {
+ s_logger.info("'ResignatureAnswer resignature(ResignatureCommand)' not currently used for KVMStorageProcessor");
+
+ return new ResignatureAnswer();
+ }
+
+ @Override
public Answer copyTemplateToPrimaryStorage(final CopyCommand cmd) {
final DataTO srcData = cmd.getSrcTO();
final DataTO destData = cmd.getDestTO();
@@ -1287,7 +1299,59 @@
@Override
public Answer deleteSnapshot(final DeleteCommand cmd) {
- return new Answer(cmd);
+ String snap_full_name = "";
+ try {
+ SnapshotObjectTO snapshotTO = (SnapshotObjectTO) cmd.getData();
+ PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO) snapshotTO.getDataStore();
+ VolumeObjectTO volume = snapshotTO.getVolume();
+ KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(), primaryStore.getUuid());
+ KVMPhysicalDisk disk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), volume.getPath());
+ String snapshotFullPath = snapshotTO.getPath();
+ String snapshotName = snapshotFullPath.substring(snapshotFullPath.lastIndexOf("/") + 1);
+ snap_full_name = disk.getName() + "@" + snapshotName;
+ if (primaryPool.getType() == StoragePoolType.RBD) {
+ Rados r = new Rados(primaryPool.getAuthUserName());
+ r.confSet("mon_host", primaryPool.getSourceHost() + ":" + primaryPool.getSourcePort());
+ r.confSet("key", primaryPool.getAuthSecret());
+ r.confSet("client_mount_timeout", "30");
+ r.connect();
+ s_logger.debug("Succesfully connected to Ceph cluster at " + r.confGet("mon_host"));
+ IoCTX io = r.ioCtxCreate(primaryPool.getSourceDir());
+ Rbd rbd = new Rbd(io);
+ RbdImage image = rbd.open(disk.getName());
+ try {
+ s_logger.info("Attempting to remove RBD snapshot " + snap_full_name);
+ if (image.snapIsProtected(snapshotName)) {
+ s_logger.debug("Unprotecting RBD snapshot " + snap_full_name);
+ image.snapUnprotect(snapshotName);
+ }
+ image.snapRemove(snapshotName);
+ s_logger.info("Snapshot " + snap_full_name + " successfully removed from " +
+ primaryPool.getType().toString() + " pool.");
+ } catch (RbdException e) {
+ s_logger.error("Failed to remove snapshot " + snap_full_name + ", with exception: " + e.toString() +
+ ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue()));
+ } finally {
+ rbd.close(image);
+ r.ioCtxDestroy(io);
+ }
+ } else {
+ s_logger.warn("Operation not implemented for storage pool type of " + primaryPool.getType().toString());
+ throw new InternalErrorException("Operation not implemented for storage pool type of " + primaryPool.getType().toString());
+ }
+ return new Answer(cmd, true, "Snapshot " + snap_full_name + " removed successfully.");
+ } catch (RadosException e) {
+ s_logger.error("Failed to remove snapshot " + snap_full_name + ", with exception: " + e.toString() +
+ ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue()));
+ return new Answer(cmd, false, "Failed to remove snapshot " + snap_full_name);
+ } catch (RbdException e) {
+ s_logger.error("Failed to remove snapshot " + snap_full_name + ", with exception: " + e.toString() +
+ ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue()));
+ return new Answer(cmd, false, "Failed to remove snapshot " + snap_full_name);
+ } catch (Exception e) {
+ s_logger.error("Failed to remove snapshot " + snap_full_name + ", with exception: " + e.toString());
+ return new Answer(cmd, false, "Failed to remove snapshot " + snap_full_name);
+ }
}
@Override
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
index d7bdab2..6e8ba30 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java
@@ -35,6 +35,7 @@
import com.ceph.rados.IoCTX;
import com.ceph.rados.Rados;
+import com.ceph.rados.exceptions.ErrorCode;
import com.ceph.rados.exceptions.RadosException;
import com.ceph.rbd.Rbd;
import com.ceph.rbd.RbdException;
@@ -863,26 +864,36 @@
RbdImage image = rbd.open(uuid);
s_logger.debug("Fetching list of snapshots of RBD image " + pool.getSourceDir() + "/" + uuid);
List<RbdSnapInfo> snaps = image.snapList();
- for (RbdSnapInfo snap : snaps) {
- if (image.snapIsProtected(snap.name)) {
- s_logger.debug("Unprotecting snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name);
- image.snapUnprotect(snap.name);
- } else {
- s_logger.debug("Snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name + " is not protected.");
+ try {
+ for (RbdSnapInfo snap : snaps) {
+ if (image.snapIsProtected(snap.name)) {
+ s_logger.debug("Unprotecting snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name);
+ image.snapUnprotect(snap.name);
+ } else {
+ s_logger.debug("Snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name + " is not protected.");
+ }
+ s_logger.debug("Removing snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name);
+ image.snapRemove(snap.name);
}
- s_logger.debug("Removing snapshot " + pool.getSourceDir() + "/" + uuid + "@" + snap.name);
- image.snapRemove(snap.name);
+ s_logger.info("Succesfully unprotected and removed any remaining snapshots (" + snaps.size() + ") of "
+ + pool.getSourceDir() + "/" + uuid + " Continuing to remove the RBD image");
+ } catch (RbdException e) {
+ s_logger.error("Failed to remove snapshot with exception: " + e.toString() +
+ ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue()));
+ throw new CloudRuntimeException(e.toString() + " - " + ErrorCode.getErrorMessage(e.getReturnValue()));
+ } finally {
+ s_logger.debug("Closing image and destroying context");
+ rbd.close(image);
+ r.ioCtxDestroy(io);
}
-
- rbd.close(image);
- r.ioCtxDestroy(io);
-
- s_logger.info("Succesfully unprotected and removed any remaining snapshots (" + snaps.size() + ") of "
- + pool.getSourceDir() + "/" + uuid + " Continuing to remove the RBD image");
} catch (RadosException e) {
- throw new CloudRuntimeException(e.toString());
+ s_logger.error("Failed to remove snapshot with exception: " + e.toString() +
+ ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue()));
+ throw new CloudRuntimeException(e.toString() + " - " + ErrorCode.getErrorMessage(e.getReturnValue()));
} catch (RbdException e) {
- throw new CloudRuntimeException(e.toString());
+ s_logger.error("Failed to remove snapshot with exception: " + e.toString() +
+ ", RBD error: " + ErrorCode.getErrorMessage(e.getReturnValue()));
+ throw new CloudRuntimeException(e.toString() + " - " + ErrorCode.getErrorMessage(e.getReturnValue()));
}
}
diff --git a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
index a10b477..488325e 100644
--- a/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
+++ b/plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java
@@ -39,6 +39,7 @@
import java.util.List;
import java.util.Random;
import java.util.UUID;
+import java.util.Vector;
import javax.naming.ConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -64,8 +65,10 @@
import org.libvirt.DomainInfo.DomainState;
import org.libvirt.DomainInterfaceStats;
import org.libvirt.LibvirtException;
+import org.libvirt.MemoryStatistic;
import org.libvirt.NodeInfo;
import org.libvirt.StorageVol;
+import org.libvirt.jna.virDomainMemoryStats;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
@@ -179,8 +182,8 @@
@Mock
private LibvirtComputingResource libvirtComputingResource;
- String _hyperVisorType = "kvm";
- Random _random = new Random();
+ String hyperVisorType = "kvm";
+ Random random = new Random();
/**
This test tests if the Agent can handle a vmSpec coming
@@ -191,10 +194,10 @@
*/
@Test
public void testCreateVMFromSpecLegacy() {
- final int id = _random.nextInt(65534);
+ final int id = random.nextInt(65534);
final String name = "test-instance-1";
- final int cpus = _random.nextInt(2) + 1;
+ final int cpus = random.nextInt(2) + 1;
final int speed = 1024;
final int minRam = 256 * 1024;
final int maxRam = 512 * 1024;
@@ -210,7 +213,7 @@
to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9");
final LibvirtVMDef vm = lcr.createVMFromSpec(to);
- vm.setHvsType(_hyperVisorType);
+ vm.setHvsType(hyperVisorType);
verifyVm(to, vm);
}
@@ -220,7 +223,7 @@
*/
@Test
public void testCreateVMFromSpecWithTopology6() {
- final int id = _random.nextInt(65534);
+ final int id = random.nextInt(65534);
final String name = "test-instance-1";
final int cpus = 12;
@@ -240,7 +243,7 @@
to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9");
final LibvirtVMDef vm = lcr.createVMFromSpec(to);
- vm.setHvsType(_hyperVisorType);
+ vm.setHvsType(hyperVisorType);
verifyVm(to, vm);
}
@@ -250,7 +253,7 @@
*/
@Test
public void testCreateVMFromSpecWithTopology4() {
- final int id = _random.nextInt(65534);
+ final int id = random.nextInt(65534);
final String name = "test-instance-1";
final int cpus = 8;
@@ -270,7 +273,7 @@
to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9");
final LibvirtVMDef vm = lcr.createVMFromSpec(to);
- vm.setHvsType(_hyperVisorType);
+ vm.setHvsType(hyperVisorType);
verifyVm(to, vm);
}
@@ -284,10 +287,10 @@
*/
@Test
public void testCreateVMFromSpec() {
- final int id = _random.nextInt(65534);
+ final int id = random.nextInt(65534);
final String name = "test-instance-1";
- final int cpus = _random.nextInt(2) + 1;
+ final int cpus = random.nextInt(2) + 1;
final int minSpeed = 1024;
final int maxSpeed = 2048;
final int minRam = 256 * 1024;
@@ -305,7 +308,7 @@
to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9");
final LibvirtVMDef vm = lcr.createVMFromSpec(to);
- vm.setHvsType(_hyperVisorType);
+ vm.setHvsType(hyperVisorType);
verifyVm(to, vm);
}
@@ -417,7 +420,10 @@
final Connect connect = Mockito.mock(Connect.class);
final Domain domain = Mockito.mock(Domain.class);
final DomainInfo domainInfo = new DomainInfo();
+ final MemoryStatistic[] domainMem = new MemoryStatistic[2];
+ domainMem[0] = Mockito.mock(MemoryStatistic.class);
Mockito.when(domain.getInfo()).thenReturn(domainInfo);
+ Mockito.when(domain.memoryStats(2)).thenReturn(domainMem);
Mockito.when(connect.domainLookupByName(VMNAME)).thenReturn(domain);
final NodeInfo nodeInfo = new NodeInfo();
nodeInfo.cpus = 8;
@@ -484,6 +490,10 @@
// 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 @@
}
}
- @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 @@
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 @@
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 @@
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 @@
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 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 @@
final Long seqNum = 1l;
final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)};
final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)};
+ final List<String> secIps = new Vector<String>();
+ final List<String> cidrs = new Vector<String>();
+ 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 @@
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 @@
final Long seqNum = 1l;
final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)};
final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)};
+ final List<String> secIps = new Vector<String>();
+ final List<String> cidrs = new Vector<String>();
+ 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 @@
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 @@
final Long seqNum = 1l;
final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)};
final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)};
+ final List<String> secIps = new Vector<String>();
- 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 @@
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 @@
}
}
}
-}
\ 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 f1d5d74..a2d37a1 100644
--- a/plugins/hypervisors/ovm/pom.xml
+++ b/plugins/hypervisors/ovm/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
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 0541b7e..648bf7f 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 @@
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 6dcf915..10e43ef 100644
--- a/plugins/hypervisors/ovm3/pom.xml
+++ b/plugins/hypervisors/ovm3/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
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 4743600..3f24527 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 @@
return null;
}
+ @Override
+ public void processHostAdded(long hostId) {
+ }
+
/* for reconnecting */
@Override
public void processConnect(Host host, StartupCommand cmd,
@@ -352,6 +356,14 @@
}
@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 0d60a2d..432474d 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 @@
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 @@
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<Boolean, Long> 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, Long>(Boolean.TRUE, Long.valueOf(ep.getId()));
- }
- }
- }
- }
return new Pair<Boolean, Long>(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 3c28f1f..7c89921 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 @@
* 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 86df00c..cb02a23 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 @@
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 e16d73f..bc9dab7 100644
--- a/plugins/hypervisors/simulator/pom.xml
+++ b/plugins/hypervisors/simulator/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>cloud-plugin-hypervisor-simulator</artifactId>
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 6602e1f..6eaf09c 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 @@
final HashMap<String, VmStatsEntry> vmStatsNameMap = new HashMap<String, VmStatsEntry>();
final List<String> 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 @@
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 751da9e..c77550e 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 @@
}
@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 76eb1c0..c942c8f 100644
--- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java
+++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorDiscoverer.java
@@ -246,6 +246,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException {
/*if(forRebalance)
@@ -274,6 +278,14 @@
}
@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 6e75244..e09a5a9 100644
--- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java
+++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorSecondaryDiscoverer.java
@@ -141,6 +141,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException {
}
@@ -156,6 +160,14 @@
}
@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 cae9261..9d86bc3 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;
@@ -67,6 +69,13 @@
}
@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();
template.setPath(UUID.randomUUID().toString());
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 4497448..14d75f8 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 @@
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 4090962..5e72bab 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 @@
}
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
throw new UnsupportedOperationException();
}
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
CopyCommandResult result = new CopyCommandResult("something", null);
callback.complete(result);
- return null;
- }
-
- @Override
- public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> 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 d8bccfe..3612bf5 100755
--- a/plugins/hypervisors/ucs/pom.xml
+++ b/plugins/hypervisors/ucs/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>cloud-plugin-hypervisor-ucs</artifactId>
diff --git a/plugins/hypervisors/vmware/pom.xml b/plugins/hypervisors/vmware/pom.xml
index 0bdc35f..8dc2ed5 100644
--- a/plugins/hypervisors/vmware/pom.xml
+++ b/plugins/hypervisors/vmware/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
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 72ee218..6559050 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 @@
String getSystemVMDefaultNicAdapterType();
- void prepareSecondaryStorageStore(String strStorageUrl);
+ void prepareSecondaryStorageStore(String strStorageUrl, Long storeId);
void setupResourceStartupParams(Map<String, Object> params);
@@ -48,7 +48,7 @@
String getManagementPortGroupName();
- String getSecondaryStorageStoreUrl(long dcId);
+ Pair<String, Long> 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 575801f..da83283 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 @@
private ManagementServerHostPeerDao _mshostPeerDao;
@Inject
private ClusterManager _clusterMgr;
+ @Inject
+ private ImageStoreDetailsUtil imageStoreDetailsUtil;
private String _mountParent;
private StorageLayer _storage;
@@ -439,12 +442,14 @@
}
@Override
- public String getSecondaryStorageStoreUrl(long dcId) {
+ public Pair<String, Long> 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 @@
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<String, Long>(secUrl, secId);
}
@Override
@@ -546,8 +552,9 @@
}
@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 @@
}
@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 @@
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 @@
}
}
- 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 @@
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");
@@ -832,6 +843,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) {
if (cmd instanceof StartupCommand) {
if (host.getHypervisorType() == HypervisorType.VMware) {
@@ -873,6 +888,14 @@
}
@Override
+ public void processHostAboutToBeRemoved(long hostId) {
+ }
+
+ @Override
+ public void processHostRemoved(long hostId, long clusterId) {
+ }
+
+ @Override
public boolean isRecurring() {
return false;
}
@@ -1234,4 +1257,5 @@
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 4109ff2..3158ad4 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 @@
_mountService = mountService;
}
+ public VmwareStorageManagerImpl(VmwareStorageMount mountService, Integer nfsVersion) {
+ assert (mountService != null);
+ _mountService = mountService;
+ _nfsVersion = nfsVersion;
+ }
+
public void configure(Map<String, Object> params) {
s_logger.info("Configure VmwareStorageManagerImpl");
@@ -156,7 +165,7 @@
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 @@
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 @@
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 @@
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 @@
Ternary<String, Long, Long> 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 @@
VmwareContext context = hostService.getServiceContext(cmd);
try {
- Ternary<String, Long, Long> result = createTemplateFromSnapshot(accountId, newTemplateId, uniqeName, secondaryStorageUrl, volumeId, backedUpSnapshotUuid);
+ Ternary<String, Long, Long> 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 @@
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 @@
}
}
- 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 @@
}
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 @@
// 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 Ternary<String, Long, Long> 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<String, Long, Long> 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 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 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 Pair<String, String> 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 @@
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<String, String>(volumeFolder, exportName);
} finally {
@@ -1025,12 +1038,12 @@
return datastoreVolumePath;
}
- private Pair<String, String> copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, long volumeId, DatastoreMO dsMo, String secStorageUrl, String exportName)
+ private Pair<String, String> 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<String, String>(volumeFolder, newVolume);
}
@@ -1171,7 +1184,8 @@
for (ManagedObjectReference taskMor : tasks) {
TaskInfo info = (TaskInfo)(context.getVimClient().getDynamicProperty(taskMor, "info"));
- if (info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("CreateSnapshot_Task")) {
+ if (info.getEntityName().equals(cmd.getVmName()) && StringUtils.isNotBlank(info.getName()) &&
+ info.getName().equalsIgnoreCase("CreateSnapshot_Task")) {
if (!(info.getState().equals(TaskInfoState.SUCCESS) || info.getState().equals(TaskInfoState.ERROR))) {
s_logger.debug("There is already a VM snapshot task running, wait for it");
context.getVimClient().waitForTask(taskMor);
@@ -1390,7 +1404,8 @@
for (ManagedObjectReference taskMor : tasks) {
TaskInfo info = (TaskInfo)(context.getVimClient().getDynamicProperty(taskMor, "info"));
- if (info.getEntityName().equals(cmd.getVmName()) && info.getName().equalsIgnoreCase("RevertToSnapshot_Task")) {
+ if (info.getEntityName().equals(cmd.getVmName()) && StringUtils.isNotBlank(info.getName()) &&
+ info.getName().equalsIgnoreCase("RevertToSnapshot_Task")) {
s_logger.debug("There is already a VM snapshot task running, wait for it");
context.getVimClient().waitForTask(taskMor);
}
@@ -1445,8 +1460,8 @@
}
}
- 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 dd07029..fd139e4 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 dd419f2..75ed342 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 @@
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 @@
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 @@
} 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);
@@ -518,6 +528,64 @@
}
/**
+ * Check if storage NFS version is already set or needs to be reconfigured.<br>
+ * If _storageNfsVersion is not null -> nothing to do, version already set.<br>
+ * 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.
*/
private void registerVm(String vmName, DatastoreMO dsMo) throws Exception{
@@ -932,7 +1000,7 @@
*/
// Fallback to E1000 if no specific nicAdapter is passed
VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.E1000;
- Map details = cmd.getDetails();
+ Map<String, String> details = cmd.getDetails();
if (details != null) {
nicDeviceType = VirtualEthernetCardType.valueOf((String) details.get("nicAdapter"));
}
@@ -1635,12 +1703,14 @@
// 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<String, Long> 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 @@
postDiskConfigBeforeStart(vmMo, vmSpec, sortedDisks, ideControllerKey, scsiControllerKey, iqnToPath, hyperHost, context);
+ postVideoCardMemoryConfigBeforeStart(vmMo, vmSpec);
+
//
// Power-on VM
//
@@ -1942,6 +2014,79 @@
}
}
+ /**
+ * 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 @@
prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false, cmd.getVirtualMachine().getType());
}
- String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId));
+ Pair<String, Long> 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 @@
}
// Ensure secondary storage mounted on target host
- String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId));
+ Pair<String, Long> 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 @@
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 @@
// 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 @@
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 @@
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<String, TemplateProp> tInfo = new HashMap<String, TemplateProp>();
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<Map<String, String>> 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 @@
}
}
- 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 @@
}
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<DynamicProperty> objProps = oc.getPropSet();
@@ -4870,6 +5044,9 @@
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 @@
} 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 @@
}
}
}
- 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 @@
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)) {
@@ -5354,17 +5539,8 @@
VmwareHypervisorHost hyperHost = getHyperHost(context, null);
VolumeTO vol = cmd.getVolume();
- ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, vol.getPoolUuid());
- if (morDs == null) {
- String msg = "Unable to find datastore based on volume mount point " + vol.getMountPoint();
- s_logger.error(msg);
- throw new Exception(msg);
- }
+ VirtualMachineMO vmMo = findVmOnDatacenter(context, hyperHost, vol);
- ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
- ClusterMO clusterMo = new ClusterMO(context, morCluster);
-
- VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(vol.getPath());
if (vmMo != null && vmMo.isTemplate()) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Destroy template volume " + vol.getPath());
@@ -5389,6 +5565,26 @@
}
}
+ /**
+ * Use data center to look for vm, instead of randomly picking up a cluster<br/>
+ * (in multiple cluster environments vm could not be found if wrong cluster was chosen)
+ * @param context vmware context
+ * @param hyperHost vmware hv host
+ * @param vol volume
+ * @return a virtualmachinemo if could be found on datacenter.
+ * @throws Exception if there is an error while finding vm
+ * @throws CloudRuntimeException if datacenter cannot be found
+ */
+ protected VirtualMachineMO findVmOnDatacenter(VmwareContext context, VmwareHypervisorHost hyperHost, VolumeTO vol) throws Exception {
+ DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter());
+ if (dcMo.getMor() == null) {
+ String msg = "Unable to find VMware DC";
+ s_logger.error(msg);
+ throw new CloudRuntimeException(msg);
+ }
+ return dcMo.findVm(vol.getPath());
+ }
+
private String getAbsoluteVmdkFile(VirtualDisk disk) {
String vmdkAbsFile = null;
VirtualDeviceBackingInfo backingInfo = disk.getBacking();
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 8e4a0d2..fd89cc7 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 @@
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 8a27799..9a8c37a 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 @@
* private Map<String, HostMO> _activeHosts = new HashMap<String, HostMO>();
*/
- 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 @@
}
@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 567f857..eb18e0b 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 @@
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 @@
this.resource = resource;
_shutdownWaitMs = shutdownWaitMs;
_gson = GsonHelper.getGsonLogger();
+ _nfsVersion = nfsVersion;
}
@Override
@@ -140,6 +146,13 @@
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 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 @@
if (managed) {
VirtualMachineMO vmMo = copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(),
- managedStoragePoolRootVolumeName, false);
+ managedStoragePoolRootVolumeName, false, _nfsVersion);
vmMo.unregisterVm();
@@ -334,7 +347,7 @@
}
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 @@
}
}
- private Pair<String, String> copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, String srcVolumePath, DatastoreMO dsMo, String secStorageUrl, long wait) throws Exception {
+ private Pair<String, String> 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 @@
}
String newVolume = VmwareHelper.getVCenterSafeUuid();
- restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, volumeFolder, volumeName, wait);
+ restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, volumeFolder, volumeName, wait, nfsVersion);
return new Pair<String, String>(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 @@
}
}
- Pair<String, String> result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000);
- deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl());
+ Pair<String, String> 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 @@
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<String, String>(destVolumePath, exportName);
} finally {
@@ -721,9 +734,9 @@
}
private Ternary<String, Long, Long> 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 @@
Ternary<String, Long, Long> 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 Ternary<String, Long, Long> 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 @@
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 @@
}
NfsTO nfsSvr = (NfsTO)imageStore;
- Ternary<String, Long, Long> result = createTemplateFromSnapshot(template.getPath(), uniqeName, nfsSvr.getUrl(), snapshot.getPath(), template.getId(), (long)cmd.getWait() * 1000);
+ Ternary<String, Long, Long> 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 @@
// return Pair<String(divice bus name), String[](disk chain)>
private Pair<String, String[]> 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 @@
// Ternary<String(backup uuid in secondary storage), String(device bus name), String[](original disk chain in the snapshot)>
private Ternary<String, String, String[]> 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<String, String[]> snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, installPath, backupUuid, workerVmName);
+ Pair<String, String[]> snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, installPath, backupUuid, workerVmName, nfsVersion);
return new Ternary<String, String, String[]>(backupUuid, snapshotInfo.first(), snapshotInfo.second());
}
@@ -1175,7 +1188,7 @@
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 @@
// 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 @@
return (int)(bytes / (1024L * 1024L));
}
- private void addRemoveInternetScsiTargetsToAllHosts(VmwareContext context, final boolean add, final List<HostInternetScsiHbaStaticTarget> lstTargets,
- List<Pair<ManagedObjectReference, String>> lstHosts) throws Exception {
- ExecutorService executorService = Executors.newFixedThreadPool(lstHosts.size());
+ public void handleTargetsForHost(boolean add, List<Map<String, String>> targets, HostMO host) throws Exception {
+ List<HostInternetScsiHbaStaticTarget> lstTargets = new ArrayList<HostInternetScsiHbaStaticTarget>();
+
+ for (Map<String, String> mapTarget : targets) {
+ HostInternetScsiHbaStaticTarget target = new HostInternetScsiHbaStaticTarget();
+
+ 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<HostMO> hosts = new ArrayList<>();
+
+ hosts.add(host);
+
+ addRemoveInternetScsiTargetsToAllHosts(add, lstTargets, hosts);
+ }
+
+ private void addRemoveInternetScsiTargetsToAllHosts(VmwareContext context, final boolean add, final List<HostInternetScsiHbaStaticTarget> targets,
+ List<Pair<ManagedObjectReference, String>> hostPairs) throws Exception {
+ List<HostMO> hosts = new ArrayList<>();
+
+ for (Pair<ManagedObjectReference, String> hostPair : hostPairs) {
+ HostMO host = new HostMO(context, hostPair.first());
+
+ hosts.add(host);
+ }
+
+ addRemoveInternetScsiTargetsToAllHosts(add, targets, hosts);
+ }
+
+ private void addRemoveInternetScsiTargetsToAllHosts(final boolean add, final List<HostInternetScsiHbaStaticTarget> targets,
+ List<HostMO> hosts) throws Exception {
+ ExecutorService executorService = Executors.newFixedThreadPool(hosts.size());
final List<Exception> exceptions = new ArrayList<Exception>();
- for (Pair<ManagedObjectReference, String> hostPair : lstHosts) {
- HostMO host = new HostMO(context, hostPair.first());
+ for (HostMO host : hosts) {
HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO();
boolean iScsiHbaConfigured = false;
@@ -1935,9 +2011,9 @@
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 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 @@
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 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 4312862..7252f51 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 @@
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 @@
//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 @@
} 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 @@
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 4b77aab..23b32a3 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 @@
}
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
throw new UnsupportedOperationException();
}
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> 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<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
Answer answer = null;
String errMsg = null;
try {
@@ -123,7 +113,6 @@
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<VolumeInfo, DataStore> 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 3b3dd47..fec2aba 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 @@
@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 @@
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 2e3d41c..a3e2daa 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,64 @@
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 static org.powermock.api.mockito.PowerMockito.whenNew;
+
+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.ManagedObjectReference;
+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.agent.api.to.VolumeTO;
+import com.cloud.hypervisor.vmware.mo.DatacenterMO;
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;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({CopyCommand.class, DatacenterMO.class, VmwareResource.class})
public class VmwareResourceTest {
+ private static final String VOLUME_PATH = "XXXXXXXXXXXX";
+
+ @Mock
+ VmwareStorageProcessor storageProcessor;
+ @Mock
+ VmwareStorageSubsystemCommandHandler storageHandler;
+
@Spy
+ @InjectMocks
VmwareResource _resource = new VmwareResource() {
@Override
@@ -50,6 +88,7 @@
public VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd) {
return hyperHost;
}
+
};
@Mock
@@ -64,12 +103,36 @@
VirtualMachineMO vmMo;
@Mock
VirtualMachineConfigSpec vmConfigSpec;
+ @Mock
+ VirtualMachineMO vmMo3dgpu;
+ @Mock
+ VirtualMachineTO vmSpec3dgpu;
+ @Mock
+ DataTO srcDataTO;
+ @Mock
+ NfsTO srcDataNfsTO;
+ @Mock
+ VolumeTO volume;
+ @Mock
+ ManagedObjectReference mor;
+ @Mock
+ DatacenterMO datacenter;
+
+ 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);
+ when(volume.getPath()).thenReturn(VOLUME_PATH);
}
//Test successful scaling up the vm
@@ -90,4 +153,92 @@
verify(_resource).execute(cmd);
}
+ @Test
+ public void testStartVm3dgpuEnabled() throws Exception{
+ Map<String, String> specDetails = new HashMap<String, String>();
+ 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);
+ }
+
+ @Test(expected=CloudRuntimeException.class)
+ public void testFindVmOnDatacenterNullHyperHostReference() throws Exception {
+ when(hyperHost.getMor()).thenReturn(null);
+ _resource.findVmOnDatacenter(context, hyperHost, volume);
+ }
+
+ @Test
+ public void testFindVmOnDatacenter() throws Exception {
+ when(hyperHost.getHyperHostDatacenter()).thenReturn(mor);
+ when(datacenter.getMor()).thenReturn(mor);
+ when(datacenter.findVm(VOLUME_PATH)).thenReturn(vmMo);
+ whenNew(DatacenterMO.class).withArguments(context, mor).thenReturn(datacenter);
+ VirtualMachineMO result = _resource.findVmOnDatacenter(context, hyperHost, volume);
+ assertEquals(vmMo, result);
+ }
}
diff --git a/plugins/hypervisors/xenserver/pom.xml b/plugins/hypervisors/xenserver/pom.xml
index 651ecfc..df15913 100644
--- a/plugins/hypervisors/xenserver/pom.xml
+++ b/plugins/hypervisors/xenserver/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/XenServerGuru.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/XenServerGuru.java
index e6ebe55..9bfcba2 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;
+ private GuestOSDao _guestOsDao;
@Inject
- GuestOSHypervisorDao _guestOsHypervisorDao;
+ private GuestOSHypervisorDao _guestOsHypervisorDao;
@Inject
- EndPointSelector endPointSelector;
+ private HostDao hostDao;
@Inject
- HostDao hostDao;
+ private VolumeDao _volumeDao;
@Inject
- VolumeDao _volumeDao;
+ private PrimaryDataStoreDao _storagePoolDao;
@Inject
- PrimaryDataStoreDao _storagePoolDao;
+ private VolumeDataFactory _volFactory;
@Inject
- VolumeDataFactory _volFactory;
- @Inject
- UserVmDao _userVmDao;
+ private UserVmDao _userVmDao;
- static final ConfigKey<Integer> MaxNumberOfVCPUSPerVM = new ConfigKey<Integer>("Advanced", Integer.class, "xen.vm.vcpu.max", "16",
+ private static final ConfigKey<Integer> MaxNumberOfVCPUSPerVM = new ConfigKey<Integer>("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;
@@ -130,11 +120,6 @@
}
@Override
- public Map<String, String> getClusterSettings(long vmId) {
- return null;
- }
-
- @Override
public List<Command> finalizeExpungeVolumes(VirtualMachine vm) {
List<Command> commands = new ArrayList<Command>();
@@ -189,15 +174,13 @@
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, Long>(Boolean.TRUE, new Long(ep.getId()));
+ return new Pair<Boolean, Long>(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 63c4485..4416c20 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 @@
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() {
}
@@ -543,6 +542,10 @@
}
@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)) {
return;
@@ -630,6 +633,14 @@
}
@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 7c8bca7..026d0c1 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 @@
}
}
+ 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 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<VM> templates = VM.getByNameLabel(conn, guestOsTypeName);
if (templates == null || templates.isEmpty()) {
throw new CloudRuntimeException("Cannot find template " + guestOsTypeName + " on XenServer host");
@@ -1337,7 +1345,7 @@
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 @@
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<Boolean, String> 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 @@
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 @@
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<String, String> deviceConfig = new HashMap<String, String>();
try {
@@ -2353,17 +2382,52 @@
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("<UUID>") != -1) {
pooluuid = result.substring(result.indexOf("<UUID>") + 6, result.indexOf("</UUID>")).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("<UUID>") != -1) {
+ pooluuid = result.substring(result.indexOf("<UUID>") + 6, result.indexOf("</UUID>")).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 @@
}
final Set<Host> 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 @@
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 @@
final HashMap<String, VmStatsEntry> vmResponseMap = new HashMap<String, VmStatsEntry>();
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 @@
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 @@
s_logger.debug("Vm cpu utilization " + vmStatsAnswer.getCPUUtilization());
}
}
+
return vmResponseMap;
}
@@ -3961,11 +4039,9 @@
}
}
- // the idea here is to see if the DiskTO in question is from managed storage
- // and
- // does not yet have an SR
- // if no SR, create it and create a VDI in it
- public VDI prepareManagedDisk(final Connection conn, final DiskTO disk, final String vmName) throws Exception {
+ // The idea here is to see if the DiskTO in question is from managed storage and does not yet have an SR.
+ // If no SR, create it and create a VDI in it.
+ public VDI prepareManagedDisk(final Connection conn, final DiskTO disk, final long vmId, final String vmName) throws Exception {
final Map<String, String> details = disk.getDetails();
if (details == null) {
@@ -3986,7 +4062,7 @@
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 @@
VDI vdi = getVDIbyUuid(conn, path, false);
final Long volumeSize = Long.parseLong(details.get(DiskTO.VOLUME_SIZE));
+ Set<VDI> 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 @@
s_logger.warn("Unable to resize volume", e);
}
}
+
+ // change the name-label in case of a cloned VDI
+ if (!Objects.equals(vdi.getNameLabel(conn), vdiNameLabel)) {
+ try {
+ vdi.setNameLabel(conn, vdiNameLabel);
+ } catch (final Exception e) {
+ s_logger.warn("Unable to rename volume", e);
+ }
+ }
}
return vdi;
@@ -5394,4 +5485,4 @@
}
-}
\ No newline at end of file
+}
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java
index 44fad93..ea7fe6f 100644
--- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XcpOssResource.java
@@ -17,16 +17,12 @@
package com.cloud.hypervisor.xenserver.resource;
-import javax.ejb.Local;
-
import org.apache.xmlrpc.XmlRpcException;
-import com.cloud.resource.ServerResource;
import com.xensource.xenapi.Connection;
import com.xensource.xenapi.Types.XenAPIException;
import com.xensource.xenapi.VM;
-@Local(value = ServerResource.class)
public class XcpOssResource extends CitrixResourceBase {
private static final long mem_32m = 33554432L;
@@ -37,18 +33,6 @@
}
@Override
- protected String getGuestOsType(final String stdType,
- final String platformEmulator, final boolean bootFromCD) {
- if (stdType.equalsIgnoreCase("Debian GNU/Linux 6(64-bit)")) {
- return "Debian Squeeze 6.0 (64-bit)";
- } else if (stdType.equalsIgnoreCase("CentOS 5.6 (64-bit)")) {
- return "CentOS 5 (64-bit)";
- } else {
- return super.getGuestOsType(stdType, platformEmulator, bootFromCD);
- }
- }
-
- @Override
protected void setMemory(final Connection conn, final VM vm, long minMemsize, final long maxMemsize) throws XmlRpcException, XenAPIException {
vm.setMemoryLimits(conn, mem_32m, maxMemsize, minMemsize, maxMemsize);
}
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
index 5c25bfd..bcf997f 100644
--- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
@@ -44,6 +44,8 @@
import org.apache.cloudstack.storage.command.ForgetObjectCmd;
import org.apache.cloudstack.storage.command.IntroduceObjectAnswer;
import org.apache.cloudstack.storage.command.IntroduceObjectCmd;
+import org.apache.cloudstack.storage.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.datastore.protocol.DataStoreProtocol;
@@ -160,6 +162,50 @@
}
@Override
+ public ResignatureAnswer resignature(final ResignatureCommand cmd) {
+ SR newSr = null;
+
+ final Connection conn = hypervisorResource.getConnection();
+
+ try {
+ final Map<String, String> 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<VDI> 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();
final DataTO data = disk.getData();
@@ -760,6 +806,9 @@
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) {
@@ -793,14 +842,11 @@
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<String, String> details = new HashMap<String, String>();
@@ -858,9 +904,11 @@
newVol.setUuid(uuidToReturn);
newVol.setPath(uuidToReturn);
+
if (physicalSize != null) {
newVol.setSize(physicalSize);
}
+
newVol.setFormat(ImageFormat.VHD);
return new CopyCmdAnswer(newVol);
@@ -872,6 +920,11 @@
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 e58bade..02c3197 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 @@
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 @@
final Set<VDI> 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 @@
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<String, String>();
@@ -291,9 +293,11 @@
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 @@
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 67d456f..4c7136e 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 @@
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 @@
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 966df43..236d8db 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 @@
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 0206939..b8e0f56 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<ResizeVolumeCommand, Answer, CitrixResourceBase> {
-
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<SR> srs = SR.getByNameLabel(conn, iScsiName);
+ Set<PBD> allPbds = new HashSet<>();
+
+ for (SR sr : srs) {
+ if (!CitrixResourceBase.SRType.LVMOISCSI.equals(sr.getType(conn))) {
+ continue;
+ }
+
+ Set<PBD> 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 0f8e6b5..b189ba0 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 @@
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 2411102..073f000 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 @@
}
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 36b8ad6..7de96b0 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 @@
}
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
throw new UnsupportedOperationException();
}
@Override
- public Void copyAsync(DataObject srcData, DataObject destData, AsyncCompletionCallback<CopyCommandResult> 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<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
Answer answer = null;
String errMsg = null;
try {
@@ -128,7 +118,6 @@
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<VolumeInfo, DataStore> 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 353b106..67fce92 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 testGetPathFilesListReturned(CitrixResourceBase citrixResourceBase) {
+ public void testGetPathFilesListReturned() {
String patch = citrixResourceBase.getPatchFilePath();
PowerMockito.mockStatic(Script.class);
@@ -49,4 +57,39 @@
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 b0c900c..9266bf9 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 @@
@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 ba3d91d..5b80a1d 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 @@
@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 def51cf..d2edbd4 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 960dd7f..dccdb28 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 @@
@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 300f95d..4cc9470 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 34deeb8..d5eba2af 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 640ca06..9998c2f 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{
- private Xenserver625Resource xenServer625Resource = new Xenserver625Resource();
+@RunWith(PowerMockRunner.class)
+public class XenServer625ResourceTest extends CitrixResourceBaseTest {
+
+ @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 148b22d..5195025 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 @@
@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 ca58f35..66ae2ec 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 @@
@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 @@
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<String> secIps = new Vector<String>();
+
+ 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 3285cf7..4957234 100644
--- a/plugins/network-elements/bigswitch/pom.xml
+++ b/plugins/network-elements/bigswitch/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<build>
diff --git a/plugins/network-elements/brocade-vcs/pom.xml b/plugins/network-elements/brocade-vcs/pom.xml
index be7fac0..7c2d648 100644
--- a/plugins/network-elements/brocade-vcs/pom.xml
+++ b/plugins/network-elements/brocade-vcs/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
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 dc111fd..eb03515 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 @@
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 @@
if (createInterfaceVlan(vlanId)) {
- PortProfile portProfile = createPortProfile(vlanId, networkId);
+ final PortProfile portProfile = createPortProfile(vlanId, networkId);
if (portProfile != null) {
return activatePortProfile(portProfile);
@@ -129,9 +128,9 @@
* 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 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 @@
* 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 @@
* - 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 @@
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 @@
* 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 @@
*/
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 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 @@
* 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 @@
* 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 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 @@
protected <T> 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 @@
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 @@
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 @@
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 @@
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("<show-vcs></show-vcs>", 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 @@
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 @@
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 @@
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 @@
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 4223d4c..e84b7ca 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 @@
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 ac17d29..d8ebf22 100644
--- a/plugins/network-elements/cisco-vnmc/pom.xml
+++ b/plugins/network-elements/cisco-vnmc/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/network-elements/dns-notifier/pom.xml b/plugins/network-elements/dns-notifier/pom.xml
index 1c0a52a..1ee71e9 100644
--- a/plugins/network-elements/dns-notifier/pom.xml
+++ b/plugins/network-elements/dns-notifier/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>cloud-plugin-example-dns-notifier</artifactId>
diff --git a/plugins/network-elements/elastic-loadbalancer/pom.xml b/plugins/network-elements/elastic-loadbalancer/pom.xml
index 2c284a9..9b64709 100644
--- a/plugins/network-elements/elastic-loadbalancer/pom.xml
+++ b/plugins/network-elements/elastic-loadbalancer/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/network-elements/f5/pom.xml b/plugins/network-elements/f5/pom.xml
index f3e4ca5..656c7a5 100644
--- a/plugins/network-elements/f5/pom.xml
+++ b/plugins/network-elements/f5/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/network-elements/globodns/pom.xml b/plugins/network-elements/globodns/pom.xml
index 2a9e2f4..d94189b 100644
--- a/plugins/network-elements/globodns/pom.xml
+++ b/plugins/network-elements/globodns/pom.xml
@@ -24,14 +24,14 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>com.globo.globodns</groupId>
<artifactId>globodns-client</artifactId>
- <version>0.0.15</version>
+ <version>0.0.20</version>
</dependency>
</dependencies>
</project>
diff --git a/plugins/network-elements/globodns/test/resources/db.properties b/plugins/network-elements/globodns/test/resources/db.properties
index 6ebe10a..6e38a4a 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.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.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.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 7e9fc26..ee43331 100644
--- a/plugins/network-elements/internal-loadbalancer/pom.xml
+++ b/plugins/network-elements/internal-loadbalancer/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<build>
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 1e0b294..f3ebeb0 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 @@
@Override
public boolean applyLBRules(Network network, List<LoadBalancingRule> rules) throws ResourceUnavailableException {
//1) Get Internal LB VMs to destroy
- Set<Ip> vmsToDestroy = getVmsToDestroy(rules);
+ Set<Ip> vmsToDestroy = getVmsToDestroy(network, rules);
//2) Get rules to apply
Map<Ip, List<LoadBalancingRule>> 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<? extends VirtualRouter> 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<? extends VirtualRouter> internalLbVms;
+ for (Ip sourceIp : vmsToDestroy) {
+ //2.1 Destroy internal lb vm
+ List<? extends VirtualRouter> 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<Ip,List<LoadBalancingRule>> entry : rulesToApply.entrySet()) {
+ Ip sourceIp = entry.getKey();
+ //2.2 Start Internal LB vm per IP address
+ List<? extends VirtualRouter> 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 @@
return rulesToApply;
}
- protected Set<Ip> getVmsToDestroy(List<LoadBalancingRule> rules) {
+ protected Set<Ip> getVmsToDestroy(Network network, List<LoadBalancingRule> rules) {
//1) Group rules by the source ip address as NetworkManager always passes the entire network lb config to the element
- Map<Ip, List<LoadBalancingRule>> groupedRules = groupBySourceIp(rules);
-
+ Set<Ip> lbPublicIps = new HashSet<Ip>();
Set<Ip> vmsToDestroy = new HashSet<Ip>();
- 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<LoadBalancingRule> 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 4e7373d..81c5e2a 100644
--- a/plugins/network-elements/juniper-contrail/pom.xml
+++ b/plugins/network-elements/juniper-contrail/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<repositories>
@@ -120,7 +120,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
- <version>1.9.5</version>
+ <version>1.10.19</version>
</dependency>
</dependencies>
<build>
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 b5da604..e56766a 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 @@
}
@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<String, String> 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<String, String> details, String accountUUID, String userUUID, User.Source source) {
// TODO Auto-generated method stub
return null;
@@ -392,8 +392,8 @@
}
@Override
- public Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map<String, String> 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<String, String> 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 9d250ba..235de85 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.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.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.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 b0b2599..e019eb1 100644
--- a/plugins/network-elements/juniper-srx/pom.xml
+++ b/plugins/network-elements/juniper-srx/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/network-elements/midonet/pom.xml b/plugins/network-elements/midonet/pom.xml
index 9b867e5..bfd1a11 100644
--- a/plugins/network-elements/midonet/pom.xml
+++ b/plugins/network-elements/midonet/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<repositories>
diff --git a/plugins/network-elements/netscaler/pom.xml b/plugins/network-elements/netscaler/pom.xml
index 2a30087..fca5657 100644
--- a/plugins/network-elements/netscaler/pom.xml
+++ b/plugins/network-elements/netscaler/pom.xml
@@ -23,19 +23,19 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>com.citrix.netscaler.nitro</groupId>
<artifactId>nitro</artifactId>
- <version>10.1</version>
+ <version>${cs.nitro.version}</version>
</dependency>
<dependency>
<groupId>com.citrix.netscaler.nitro</groupId>
<artifactId>sdx_nitro</artifactId>
- <version>10.1</version>
+ <version>${cs.nitro.version}</version>
</dependency>
</dependencies>
</project>
diff --git a/plugins/network-elements/nicira-nvp/pom.xml b/plugins/network-elements/nicira-nvp/pom.xml
index c8673ef..8152b3b 100644
--- a/plugins/network-elements/nicira-nvp/pom.xml
+++ b/plugins/network-elements/nicira-nvp/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
@@ -34,7 +34,7 @@
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-utils</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
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 79546a6..34518ce 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 48f3903..058da45 100644
--- a/plugins/network-elements/nuage-vsp/pom.xml
+++ b/plugins/network-elements/nuage-vsp/pom.xml
@@ -25,14 +25,20 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
+ <repositories>
+ <repository>
+ <id>nuage-vsp</id>
+ <url>http://cs.mv.nuagenetworks.net/releases/</url>
+ </repository>
+ </repositories>
<dependencies>
<dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- <version>${cs.commons-lang3.version}</version>
+ <groupId>net.nuage.vsp</groupId>
+ <artifactId>nuage-vsp-acs-client</artifactId>
+ <version>3.2.8.0</version>
</dependency>
</dependencies>
<build>
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 c579789..c447c44 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 @@
<property name="name" value="NuageVspElement" />
</bean>
<bean id="NuageVspManager" class="com.cloud.network.manager.NuageVspManagerImpl" />
- <bean id="NuageVspSync" class="com.cloud.network.sync.NuageVspSyncImpl" />
+ <bean id="NuageVspEntityBuilder" class="com.cloud.util.NuageVspEntityBuilder" />
</beans>
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 979dcd3..0000000
--- 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 6e03dab..0000000
--- 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 7b1d40b..50cace6 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<Map<String, Object>> _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<VspAclRule> _aclRules;
private final boolean _networkReset;
- private final String _domainTemplateName;
- private ApplyAclRuleVspCommand(boolean networkAcl, String networkUuid, String networkDomainUuid, String vpcOrSubnetUuid, String networkName, boolean isL2Network,
- List<Map<String, Object>> aclRules, long networkId, boolean egressDefaultPolicy, Boolean acsIngressAcl, boolean networkReset, String domainTemplateName) {
+ public ApplyAclRuleVspCommand(VspAclRule.ACLType aclType, VspNetwork network, List<VspAclRule> 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<Map<String, Object>> getAclRules() {
+ public List<VspAclRule> 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<ApplyAclRuleVspCommand> {
- private boolean _networkAcl;
- private String _networkUuid;
- private String _networkDomainUuid;
- private String _vpcOrSubnetUuid;
- private String _networkName;
- private boolean _isL2Network;
- private List<Map<String, Object>> _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<Map<String, Object>> 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 @@
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 @@
@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 cc4e930..500f091 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<Map<String, Object>> _staticNatDetails;
+ private final VspNetwork _network;
+ private final List<VspStaticNat> _staticNatDetails;
- private ApplyStaticNatVspCommand(String networkDomainUuid, String networkUuid, String vpcOrSubnetUuid, boolean isL3Network, boolean isVpc,
- List<Map<String, Object>> staticNatDetails) {
+ public ApplyStaticNatVspCommand(VspNetwork network, List<VspStaticNat> 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<Map<String, Object>> getStaticNatDetails() {
+ public List<VspStaticNat> getStaticNatDetails() {
return _staticNatDetails;
}
- public static class Builder implements CmdBuilder<ApplyStaticNatVspCommand> {
- private String _networkDomainUuid;
- private String _networkUuid;
- private String _vpcOrSubnetUuid;
- private boolean _isL3Network;
- private boolean _isVpc;
- private List<Map<String, Object>> _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<Map<String, Object>> 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 @@
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 @@
@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 c1de6b9..2145f60 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<String> _dnsServers;
- private final List<Map<String, Object>> _ingressFirewallRules;
- private final List<Map<String, Object>> _egressFirewallRules;
- private final List<String> _acsFipUuid;
- private final boolean _egressDefaultPolicy;
+ private final List<VspAclRule> _ingressFirewallRules;
+ private final List<VspAclRule> _egressFirewallRules;
+ private final List<String> _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<String> dnsServers, List<Map<String, Object>> ingressFirewallRules,
- List<Map<String, Object>> egressFirewallRules, List<String> acsFipUuid, boolean egressDefaultPolicy) {
+ public ImplementVspCommand(VspNetwork network, List<String> dnsServers, List<VspAclRule> ingressFirewallRules,
+ List<VspAclRule> egressFirewallRules, List<String> 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<String> getDnsServers() {
return _dnsServers;
}
- public List<Map<String, Object>> getIngressFirewallRules() {
+ public List<VspAclRule> getIngressFirewallRules() {
return _ingressFirewallRules;
}
- public List<Map<String, Object>> getEgressFirewallRules() {
+ public List<VspAclRule> getEgressFirewallRules() {
return _egressFirewallRules;
}
- public List<String> getAcsFipUuid() {
- return _acsFipUuid;
- }
-
- public boolean isEgressDefaultPolicy() {
- return _egressDefaultPolicy;
- }
-
- public static class Builder implements CmdBuilder<ImplementVspCommand> {
- 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<String> _dnsServers;
- private List<Map<String, Object>> _ingressFirewallRules;
- private List<Map<String, Object>> _egressFirewallRules;
- private List<String> _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<String> dnsServers) {
- this._dnsServers = dnsServers;
- return this;
- }
-
- public Builder ingressFirewallRules(List<Map<String, Object>> ingressFirewallRules) {
- this._ingressFirewallRules = ingressFirewallRules;
- return this;
- }
-
- public Builder egressFirewallRules(List<Map<String, Object>> egressFirewallRules) {
- this._egressFirewallRules = egressFirewallRules;
- return this;
- }
-
- public Builder acsFipUuid(List<String> 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<String> getFloatingIpUuids() {
+ return _floatingIpUuids;
}
@Override
@@ -248,27 +76,14 @@
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 (_floatingIpUuids != null ? !_floatingIpUuids.equals(that._floatingIpUuids) : that._floatingIpUuids != null)
+ return false;
if (_ingressFirewallRules != null ? !_ingressFirewallRules.equals(that._ingressFirewallRules) : that._ingressFirewallRules != 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 (_network != null ? !_network.equals(that._network) : that._network != null) return false;
return true;
}
@@ -276,22 +91,11 @@
@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 4c41e51..6ad4ec6 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<String> _domainRouterUuids;
- private ShutDownVpcVspCommand(String domainUuid, String vpcUuid, String domainTemplateName) {
+ public ShutDownVpcVspCommand(String domainUuid, String vpcUuid, String domainTemplateName, List<String> domainRouterUuids) {
super();
this._domainUuid = domainUuid;
this._vpcUuid = vpcUuid;
this._domainTemplateName = domainTemplateName;
+ this._domainRouterUuids = domainRouterUuids;
}
public String getDomainUuid() {
@@ -47,30 +50,8 @@
return _domainTemplateName;
}
- public static class Builder implements CmdBuilder<ShutDownVpcVspCommand> {
- 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<String> getDomainRouterUuids() {
+ return _domainRouterUuids;
}
@Override
@@ -86,6 +67,8 @@
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 @@
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 421fa4c..10dffcc 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<DeallocateVmVspCommand> {
- 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 @@
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 @@
@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 575e57d..bb35756 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<String> _dnsServers;
- private final List<String> _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<String[]> _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<String> dnsServers, List<String> gatewaySystemIds, String networkUuid,
- boolean isL3Network, boolean isVpc, boolean isSharedNetwork, String vpcName, String vpcUuid, boolean defaultEgressPolicy, List<String[]> ipAddressRange,
- String domainTemplateName) {
+ public ImplementNetworkVspCommand(VspNetwork network, List<String> 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<String> getDnsServers() {
return _dnsServers;
}
- public List<String> 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<String[]> getIpAddressRange() {
- return _ipAddressRange;
- }
-
- public String getDomainTemplateName() {
- return _domainTemplateName;
- }
-
- public static class Builder implements CmdBuilder<ImplementNetworkVspCommand> {
- 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<String> _dnsServers;
- private List<String> _gatewaySystemIds;
- private String _networkUuid;
- private boolean _isL3Network;
- private boolean _isVpc;
- private boolean _isSharedNetwork;
- private String _vpcName;
- private String _vpcUuid;
- private boolean _defaultEgressPolicy;
- private List<String[]> _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<String> dnsServers) {
- this._dnsServers = dnsServers;
- return this;
- }
-
- public Builder gatewaySystemIds(List<String> 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<String[]> 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 @@
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 @@
@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 abcd0f2..299b9a6 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<ReserveVmInterfaceVspCommand> {
- 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 @@
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 @@
@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 4a01fdc..b3f8f8e 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<TrashNetworkVspCommand> {
- 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 @@
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 @@
@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/manager/GetApiDefaultsAnswer.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsAnswer.java
new file mode 100644
index 0000000..c02eef1
--- /dev/null
+++ b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/manager/GetApiDefaultsAnswer.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 com.cloud.agent.api.manager;
+
+import com.cloud.agent.api.Answer;
+import net.nuage.vsp.acs.client.api.model.VspApiDefaults;
+
+public class GetApiDefaultsAnswer extends Answer {
+
+ private VspApiDefaults _apiDefaults;
+
+ public GetApiDefaultsAnswer(GetApiDefaultsCommand cmd, VspApiDefaults defaults) {
+ super(cmd);
+ this._apiDefaults = defaults;
+ }
+
+ public GetApiDefaultsAnswer(GetApiDefaultsCommand cmd, Exception e) {
+ super(cmd, e);
+ }
+
+ public VspApiDefaults getApiDefaults() {
+ return _apiDefaults;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof GetApiDefaultsAnswer)) return false;
+ if (!super.equals(o)) return false;
+
+ GetApiDefaultsAnswer that = (GetApiDefaultsAnswer) o;
+
+ if (_apiDefaults != null ? !_apiDefaults.equals(that._apiDefaults) : that._apiDefaults != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = super.hashCode();
+ 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 2ffbe04..3fca16a 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 f748e1c..0000000
--- 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<String, Object> 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 7ae474f..90a30a4 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 @@
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 @@
@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/agent/api/sync/SyncVspCommand.java b/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncVspCommand.java
deleted file mode 100644
index cfcfb87..0000000
--- a/plugins/network-elements/nuage-vsp/src/com/cloud/agent/api/sync/SyncVspCommand.java
+++ /dev/null
@@ -1,62 +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.sync;
-
-import com.cloud.agent.api.Command;
-
-public class SyncVspCommand extends Command {
-
- private final String _nuageVspEntity;
-
- public SyncVspCommand(String nuageVspEntity) {
- super();
- this._nuageVspEntity = nuageVspEntity;
- }
-
- @Override
- public boolean executeInSequence() {
- return false;
- }
-
- public String getNuageVspEntity() {
- return _nuageVspEntity;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof SyncVspCommand)) return false;
- if (!super.equals(o)) return false;
-
- SyncVspCommand that = (SyncVspCommand) o;
-
- if (_nuageVspEntity != null ? !_nuageVspEntity.equals(that._nuageVspEntity) : that._nuageVspEntity != null)
- return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = super.hashCode();
- result = 31 * result + (_nuageVspEntity != null ? _nuageVspEntity.hashCode() : 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 7590901..62a15ea 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 @@
@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 @@
this.apiVersion = apiVersion;
}
- public int getApiRetryCount() {
+ public Integer getApiRetryCount() {
return apiRetryCount;
}
@@ -125,7 +129,7 @@
this.apiRetryCount = apiRetryCount;
}
- public long getApiRetryInterval() {
+ public Long getApiRetryInterval() {
return apiRetryInterval;
}
@@ -158,7 +162,7 @@
@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 971f9c9..05a17d6 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 @@
@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 559b30d..0000000
--- 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<NuageVspDeviceVO> 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 2d08e12..d9f80e7 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 @@
@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 d235b2b..4197bd6 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 @@
@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 2372890..7abcdfb 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 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 136a465..346e288 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 @@
@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 @@
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 cb0d698..1f36ae0 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 @@
@Inject
NetworkDao _networkDao;
@Inject
- protected DomainDao _domainDao;
+ DomainDao _domainDao;
@Inject
- protected DataCenterDao _dcDao;
+ DataCenterDao _dcDao;
@Inject
IPAddressDao _ipAddressDao;
@Inject
@@ -135,6 +146,8 @@
@Inject
VpcDao _vpcDao;
@Inject
+ VpcOfferingServiceMapDao _vpcOfferingSrvcDao;
+ @Inject
NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao;
@Inject
AgentManager _agentMgr;
@@ -152,6 +165,12 @@
PhysicalNetworkDao _physicalNetworkDao;
@Inject
NetworkACLItemDao _networkACLItemDao;
+ @Inject
+ NuageVspEntityBuilder _nuageVspEntityBuilder;
+ @Inject
+ VpcDetailsDao _vpcDetailsDao;
+ @Inject
+ DomainRouterDao _routerDao;
@Override
public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress, Set<Service> service) throws ResourceUnavailableException {
@@ -237,53 +256,21 @@
return false;
}
- boolean egressDefaultPolicy = offering.getEgressDefaultPolicy();
- Domain networkDomain = _domainDao.findById(network.getDomainId());
- boolean isFirewallServiceSupported = _networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Service.Firewall);
+
+ VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false);
List<String> 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<Map<String, Object>> ingressFirewallRules = getFirewallRulesToApply(network.getId(), FirewallRule.TrafficType.Ingress, egressDefaultPolicy);
- List<Map<String, Object>> egressFirewallRules = getFirewallRulesToApply(network.getId(), FirewallRule.TrafficType.Egress, egressDefaultPolicy);
+ List<VspAclRule> ingressFirewallRules = getFirewallRulesToApply(network, FirewallRule.TrafficType.Ingress);
+ List<VspAclRule> egressFirewallRules = getFirewallRulesToApply(network, FirewallRule.TrafficType.Egress);
List<IPAddressVO> ips = _ipAddressDao.listStaticNatPublicIps(network.getId());
- List<String> acsFipUuid = new ArrayList<String>();
+ List<String> floatingIpUuids = new ArrayList<String>();
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 @@
private boolean applyACLRulesForVpc(Network network, NetworkOffering offering) throws ResourceUnavailableException {
List<NetworkACLItemVO> 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<Map<String, Object>> getFirewallRulesToApply(long networkId, FirewallRule.TrafficType trafficType, final boolean egressDefaultPolicy) {
- List<FirewallRuleVO> firewallRulesToApply = _firewallRulesDao.listByNetworkPurposeTrafficType(networkId, FirewallRule.Purpose.Firewall, trafficType);
+ private List<VspAclRule> getFirewallRulesToApply(final Network network, FirewallRule.TrafficType trafficType) {
+ List<FirewallRuleVO> firewallRulesToApply = _firewallRulesDao.listByNetworkPurposeTrafficType(network.getId(), FirewallRule.Purpose.Firewall, trafficType);
+ List<VspAclRule> 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<FirewallRuleVO, Map<String, Object>>() {
- @Override
- public Map<String, Object> apply(FirewallRuleVO firewallRuleVO) {
- return getACLRuleDetails(firewallRuleVO, egressDefaultPolicy);
- }
- });
+ return vspAclRulesToApply;
}
@Override
@@ -426,6 +411,16 @@
}
}
+ 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 @@
@Override
public boolean applyStaticNats(Network config, List<? extends StaticNat> 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<Map<String, Object>> sourceNatDetails = new ArrayList<Map<String, Object>>();
+ List<VspStaticNat> vspStaticNatDetails = new ArrayList<VspStaticNat>();
for (StaticNat staticNat : rules) {
- Map<String, Object> sourceNatDetail = new HashMap<String, Object>();
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 @@
}
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<? extends InternalIdentity> rules, boolean isNetworkAcl, Boolean isAcsIngressAcl, boolean networkReset)
+ protected boolean applyACLRules(final Network network, List<? extends InternalIdentity> 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<Map<String, Object>> aclRules = new ArrayList<Map<String, Object>>();
- for (InternalIdentity acl : rules) {
- aclRules.add(getACLRuleDetails(acl, egressDefaultPolicy));
- }
+ VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network, false);
+ List<VspAclRule> vspAclRules = Lists.transform(rules, new Function<InternalIdentity, VspAclRule>() {
+ @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 @@
}
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<VpcOfferingServiceMapVO> vpcOfferingServices = _vpcOfferingSrvcDao.listByVpcOffId(vpc.getVpcOfferingId());
+ Map<Network.Service, Set<Network.Provider>> 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<DomainRouterVO> routers = _routerDao.listByVpcId(vpc.getId());
+ if (CollectionUtils.isEmpty(routers)) {
+ routers = _routerDao.listIncludingRemovedByVpcId(vpc.getId());
+ }
+
+ List<String> domainRouterUuids = Lists.transform(routers, new Function<DomainRouterVO, String>() {
+ @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 @@
}
return nuageVspHost;
}
-
- protected boolean isL3Network(Long offeringId) {
- return _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offeringId, Service.SourceNat)
- || _ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offeringId, Service.StaticNat);
- }
-
- private Map<String, Object> getACLRuleDetails(Object aclRule, boolean egressDefaultPolicy) {
- Map<String, Object> aclDetails = new HashMap<String, Object>();
- 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 5f69a21..a6c17e3 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 @@
AgentManager _agentMgr;
@Inject
NuageVspManager _nuageVspManager;
+ @Inject
+ ConfigurationManager _configMgr;
+ @Inject
+ NuageVspEntityBuilder _nuageVspEntityBuilder;
+ @Inject
+ NetworkDetailsDao _networkDetailsDao;
+ @Inject
+ VpcDetailsDao _vpcDetailsDao;
public NuageVspGuestNetworkGuru() {
super();
@@ -145,33 +148,6 @@
throw new IllegalStateException("Network " + networkId + " is not in expected state Implementing, but is in state " + network.getState());
}
- long dcId = dest.getDataCenter().getId();
- //Get physical network id
- Long physicalNetworkId = network.getPhysicalNetworkId();
- //Physical network id can be null in Guest Network in Basic zone, so locate the physical network
- 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());
- if (network.getGateway() != null) {
- implemented.setGateway(network.getGateway());
- }
- if (network.getCidr() != null) {
- implemented.setCidr(network.getCidr());
- }
- List<String[]> ipAddressRanges = new ArrayList<String[]>();
- String virtualRouterIp = getVirtualRouterIP(network, ipAddressRanges);
- String networkUuid = implemented.getUuid();
- String tenantId = context.getDomain().getName() + "-" + context.getAccount().getAccountId();
- String broadcastUriStr = networkUuid + "/" + virtualRouterIp;
- 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) {
@@ -180,52 +156,37 @@
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();
+ long dcId = dest.getDataCenter().getId();
+ //Get physical network id
+ Long physicalNetworkId = network.getPhysicalNetworkId();
+ //Physical network id can be null in Guest Network in Basic zone, so locate the physical network
+ if (physicalNetworkId == null) {
+ physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType());
}
- if (isSharedNetwork) {
- List<VlanVO> 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);
- }
+ 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());
+ }
+
+ VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(implemented, true);
+ String tenantId = context.getDomain().getName() + "-" + context.getAccount().getAccountId();
+ String broadcastUriStr = implemented.getUuid() + "/" + vspNetwork.getVirtualRouterIp();
+ implemented.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr));
+ implemented.setBroadcastDomainType(Networks.BroadcastDomainType.Vsp);
HostVO nuageVspHost = getNuageVspHost(physicalNetworkId);
List<String> dnsServers = _nuageVspManager.getDnsDetails(network);
- List<String> 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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
return super.trash(network, offering);
}
- private String getVirtualRouterIP(Network network, Collection<String[]> 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<Long> allIPsInCidr = NetUtils.getAllIpsFromCidr(subnet, cidrSize, new HashSet<Long>());
- 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<Long> 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<NuageVspDeviceVO> 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 0aae22c..4861fb2 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 @@
static final String nuageVPCOfferingDisplayText = "Nuage VSP VPC Offering";
+ static final String nuageDomainTemplateDetailName = "domainTemplateName";
+
static final ConfigKey<Boolean> NuageVspConfigDns = new ConfigKey<Boolean>(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 ce2a363..04b1ccc 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 @@
private static final Logger s_logger = Logger.getLogger(NuageVspManagerImpl.class);
- private static final int ONE_MINUTE_MULTIPLIER = 60 * 1000;
-
- private static final Set<Network.Provider> NUAGE_VSP_PROVIDERS;
- private static final Map<Network.Service, Set<Network.Provider>> NUAGE_VSP_VPC_SERVICE_MAP;
+ public static final Map<Network.Service, Set<Network.Provider>> 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 @@
@Inject
NuageVspDao _nuageVspDao;
@Inject
- NuageVspSync _nuageVspSync;
- @Inject
DataCenterDao _dataCenterDao;
@Inject
ConfigurationDao _configDao;
@@ -188,27 +183,32 @@
NetworkOfferingDao _networkOfferingDao;
@Inject
NetworkOfferingServiceMapDao _networkOfferingServiceMapDao;
-
- private ScheduledExecutorService scheduler;
+ @Inject
+ NuageVspEntityBuilder _nuageVspEntityBuilder;
@Inject
MessageBus _messageBus;
static {
- NUAGE_VSP_PROVIDERS = ImmutableSet.of(Network.Provider.NuageVsp);
+ Set<Network.Provider> nuageVspProviders = ImmutableSet.of(Network.Provider.NuageVsp);
+ Set<Network.Provider> userDataProviders = ImmutableSet.of(Network.Provider.VPCVirtualRouter);
+ Set<Network.Provider> lbProviders = ImmutableSet.of(Network.Provider.InternalLbVm);
NUAGE_VSP_VPC_SERVICE_MAP = ImmutableMap.<Network.Service, Set<Network.Provider>>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<Class<?>> getCommands() {
return Lists.<Class<?>>newArrayList(AddNuageVspDeviceCmd.class, DeleteNuageVspDeviceCmd.class, ListNuageVspDevicesCmd.class,
- IssueNuageVspResourceRequestCmd.class, UpdateNuageVspDeviceCmd.class);
+ UpdateNuageVspDeviceCmd.class);
}
@Override
@@ -238,21 +238,21 @@
}
try {
- NuageVspPluginClientLoader clientLoader = NuageVspPluginClientLoader.getClientLoader(null, null, 1, 1, null);
+ NuageVspPluginClientLoader clientLoader = NuageVspPluginClientLoader.getClientLoader(null, null, null, null, 1, 1, null);
- Map<String, Object> 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 @@
_hostDetailsDao.persist(detail);
ConfigurationVO cmsIdConfig = _configDao.findByName("nuagevsp.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());
-
- detail = new DetailVO(host.getId(), "nuagevspcmsid", answer.getNuageVspCmsId());
- _hostDetailsDao.persist(detail);
-
- resourceConfiguration.nuageVspCmsId(answer.getNuageVspCmsId());
- resource.configure(cmd.getHostName(), Maps.<String, Object>newHashMap(resourceConfiguration.build()));
-
- auditDomainsOnVsp((HostVO) host, true, false);
+ NuageVspDeviceVO matchingNuageVspDevice = findMatchingNuageVspDevice(nuageVspDevice);
+ String cmsId;
+ if (matchingNuageVspDevice != null) {
+ cmsId = findNuageVspCmsIdForDevice(matchingNuageVspDevice.getId(), cmsIdConfig);
} else {
- throw new CloudRuntimeException("Failed to register CMS ID");
+ 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());
+ registerNewNuageVspDevice(cmsIdConfig, nuageVspDevice.getId() + ":" + cmsId);
+
+ detail = new DetailVO(host.getId(), "nuagevspcmsid", cmsId);
+ _hostDetailsDao.persist(detail);
+
+ resourceConfiguration.nuageVspCmsId(cmsId);
+ resource.configure(cmd.getHostName(), Maps.<String, Object>newHashMap(resourceConfiguration.build()));
+
+ if (matchingNuageVspDevice == null) {
+ auditDomainsOnVsp((HostVO) host, true, false);
+ }
+
return nuageVspDevice;
} catch (ConfigurationException e) {
s_logger.error("Failed to configure Nuage VSD resource " + cmd.getHostName(), e);
@@ -368,13 +379,13 @@
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 @@
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 @@
}
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 @@
}
}
+ 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);
+ if (matchingNuageVspDevice == null) {
+ if (!auditDomainsOnVsp(host, false, true)) {
+ 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 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);
- }
- _configDao.update("nuagevsp.cms.id", newValue);
- } else {
- 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 @@
return true;
}
+ private NuageVspDeviceVO findMatchingNuageVspDevice(NuageVspDeviceVO nuageVspDevice) {
+ List<NuageVspDeviceVO> 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<NuageVspDeviceVO> listNuageVspDevices(ListNuageVspDevicesCmd cmd) {
Long physicalNetworkId = cmd.getPhysicalNetworkId();
@@ -545,6 +580,8 @@
}
private void auditHost(HostVO host) {
+ if (host == null) return;
+
_hostDao.loadDetails(host);
boolean validateDomains = true;
@@ -579,7 +616,8 @@
_hostDao.loadDetails(host);
List<DomainVO> 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 @@
List<NuageVspDeviceVO> 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 @@
List<NuageVspDeviceVO> 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);
}
}
@@ -730,6 +770,11 @@
}
@Override
+ public void processHostAdded(long hostId) {
+
+ }
+
+ @Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException {
}
@@ -740,6 +785,16 @@
}
@Override
+ public void processHostAboutToBeRemoved(long hostId) {
+
+ }
+
+ @Override
+ public void processHostRemoved(long hostId, long clusterId) {
+
+ }
+
+ @Override
public boolean isRecurring() {
return false;
}
@@ -770,7 +825,7 @@
defaultNuageVspSharedSGNetworkOffering.setState(NetworkOffering.State.Enabled);
defaultNuageVspSharedSGNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNuageVspSharedSGNetworkOffering);
- Map<Network.Service, Network.Provider> defaultNuageVspSharedSGNetworkOfferingProviders = new HashMap<>();
+ Map<Network.Service, Network.Provider> defaultNuageVspSharedSGNetworkOfferingProviders = new HashMap<Network.Service, Network.Provider>();
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 @@
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<Network.Service, Set<Network.Provider>> svcProviderMap = Maps.newHashMap(NUAGE_VSP_VPC_SERVICE_MAP);
- Set<Network.Provider> 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 @@
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 @@
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<Network.Service, Set<Network.Provider>> svcProviderMap) {
+ Transaction.execute(new TransactionCallback<VpcOffering>() {
+ @Override
+ public VpcOffering doInTransaction(TransactionStatus status) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug(String.format("Updating vpc offering %s", offering));
+ }
+
+ List<VpcOfferingServiceMapVO> currentVpcOfferingServices = _vpcOffSvcMapDao.listByVpcOffId(offering.getId());
+ Map<Network.Service, Set<Network.Provider>> 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 8e14237..bdcb481 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 @@
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 @@
protected NuageVspApiClient _nuageVspApiClient;
protected NuageVspGuruClient _nuageVspGuruClient;
protected NuageVspElementClient _nuageVspElementClient;
- protected NuageVspSyncClient _nuageVspSyncClient;
protected NuageVspManagerClient _nuageVspManagerClient;
protected boolean _isNuageVspClientLoaded;
@@ -190,7 +186,8 @@
_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 @@
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 @@
_nuageVspApiClient.login();
}
- protected <A extends NuageVspApiClient, B extends NuageVspElementClient, C extends NuageVspSyncClient, D extends NuageVspGuruClient> 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 <A extends NuageVspApiClient, B extends NuageVspElementClient, C extends NuageVspGuruClient> 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 @@
@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 @@
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 @@
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 @@
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 @@
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(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(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(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(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(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(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(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(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(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(GetClientDefaultsCommand cmd) {
+ private Answer executeRequest(GetApiDefaultsCommand cmd) {
try {
isNuageVspManagerLoaded();
- Map<String, Object> 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 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 9180c17..0000000
--- 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<NuageVspDeviceVO> 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 0000000..8757ad0
--- /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<Pair<String, String>> 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<Pair<String, String>> getIpAddressRanges(NetworkOfferingVO networkOffering, Network network) {
+ List<Pair<String, String>> ipAddressRanges = Lists.newArrayList();
+ if (networkOffering.getGuestType() == Network.GuestType.Shared) {
+ List<VlanVO> 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<Long> allIPsInCidr = NetUtils.getAllIpsFromCidr(subnet, cidrSize, new HashSet<Long>());
+ 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<Long> 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<Pair<String, String>> ipAddressRanges) throws InsufficientVirtualNetworkCapacityException {
+ Pair<String, String> lowestIpAddressRange = null;
+ if (ipAddressRanges.size() == 1) {
+ lowestIpAddressRange = Iterables.getOnlyElement(ipAddressRanges);
+ } else {
+ for (Pair<String, String> 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 2300289..fedf048 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 57935b9..72ce290 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 NuageVspManagerClient getNuageVspManagerClient() {
return _nuageVspManagerClient;
}
-
- public NuageVspSyncClient getNuageVspSyncClient() {
- return _nuageVspSyncClient;
- }
}
diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspApiClient.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspApiClient.java
deleted file mode 100644
index d80daf9..0000000
--- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspApiClient.java
+++ /dev/null
@@ -1,32 +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.concurrent.ExecutionException;
-
-public interface NuageVspApiClient {
-
- void login() throws ExecutionException;
-
- void setNuageVspHost(String restRelativePath, String[] cmsUserInfo, int noofRetry, int retryInterval, String nuageVspCmsId);
-
- String executeRestApi(String method, String resource, String resourceId, String childResource, Object entityDetails, String resourceFilter, String proxyUserUuid,
- String proxyUserDomainuuid) throws ExecutionException;
-}
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 acd4256..0000000
--- 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<String> dnsServers, List<Map<String, Object>> ingressFirewallRules,
- List<Map<String, Object>> egressFirewallRules, List<String> acsFipUuid, boolean egressDefaultPolicy) throws ExecutionException;
-
- void applyStaticNats(String networkDomainUuid, String networkUuid, String vpcOrSubnetUuid, boolean isL3Network, boolean isVpc,
- List<Map<String, Object>> staticNatDetails) throws ExecutionException;
-
- void applyAclRules(boolean isNetworkAcl, String networkUuid, String networkDomainUuid, String vpcOrSubnetUuid, String networkName, boolean isL2Network,
- List<Map<String, Object>> rules, long networkId, boolean egressDefaultPolicy, Boolean isAcsIngressAcl, boolean networkReset, String domainTemplateName) throws ExecutionException;
-
- void shutdownVpc(String domainUuid, String vpcUuid, String domainTemplateName) throws ExecutionException;
-
- <C extends NuageVspApiClient> 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 2b3a63a..0000000
--- 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<String> dnsServers, List<String> gatewaySystemIds, boolean isL3Network, boolean isVpc, boolean isSharedNetwork,
- String networkUuid, String vpcName, String vpcUuid, boolean defaultEgressPolicy, Collection<String[]> 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 f134111..0000000
--- 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<Boolean, String> auditNuageVspCmsId(String nuageVspCmsId, boolean auditOnly) throws ExecutionException;
-
- String registerNuageVspCmsId() throws ExecutionException;
-
- boolean unregisterNuageVspCmsId(String nuageVspCmsId) throws ExecutionException;
-
- boolean isSupportedApiVersion(String version);
-
- Map<String, Object> getClientDefaults() throws ExecutionException;
-
- boolean syncDomainWithNuageVsp(String domainUuid, String domainName, String domainPath, boolean add, boolean remove) throws ExecutionException;
-
- <C extends NuageVspApiClient> void setNuageVspApiClient(NuageVspApiClient nuageVspApiClient);
-}
diff --git a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspSyncClient.java b/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspSyncClient.java
deleted file mode 100644
index 951ee5a..0000000
--- a/plugins/network-elements/nuage-vsp/src/net/nuage/vsp/acs/client/NuageVspSyncClient.java
+++ /dev/null
@@ -1,29 +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.concurrent.ExecutionException;
-
-public interface NuageVspSyncClient {
-
- void syncWithNuageVsp(String nuageVspEntity) throws ExecutionException;
-
- void setNuageVspApiClient(NuageVspApiClient nuageVspApiClient);
-}
\ No newline at end of file
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 0000000..845a8be
--- /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<Pair<String, String>>())
+ .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<String>())
+ .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 817ab7a..2a0b07a 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 @@
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 @@
.addEqualityGroup(supportedApiVersionCommand, otherSupportedApiVersionCommand)
.addEqualityGroup(syncDomainCommand, otherSyncDomainCommand)
.addEqualityGroup(syncNuageVspCmsIdCommand, otherSyncNuageVspCmsIdCommand)
- .addEqualityGroup(syncVspCommand, otherSyncVspCommand)
.addEqualityGroup(pingNuageVspCommand, otherPingNuageVspCommand)
- .addEqualityGroup(vspResourceCommand, otherVspResourceCommand)
.testEquals();
}
- private <T extends CmdBuilder> 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> T fillObject(Class<T> 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 bbdf764..85cbb36 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 {
+public class NuageVspElementTest extends NuageTest {
- 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);
+ private NuageVspElement _nuageVspElement = new NuageVspElement();
- org.mockito.stubbing.Answer<Object> genericAnswer = new org.mockito.stubbing.Answer<Object>() {
- public Object answer(InvocationOnMock invocation) {
- return null;
- }
- };
+ 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;
+ public void setUp() throws Exception {
+ super.setUp();
- // 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");
+ _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;
- element.configure("NuageVspTestElement", Collections.<String, Object> emptyMap());
+ _nuageVspElement.configure("NuageVspTestElement", Collections.<String, Object>emptyMap());
}
@Test
@@ -142,28 +132,34 @@
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 @@
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 @@
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 @@
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<FirewallRuleVO>());
- when(firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Egress)).thenReturn(new ArrayList<FirewallRuleVO>());
- when(ipAddressDao.listStaticNatPublicIps(NETWORK_ID)).thenReturn(new ArrayList<IPAddressVO>());
- when(nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList<String>());
+ when(_firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Ingress)).thenReturn(new ArrayList<FirewallRuleVO>());
+ when(_firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Egress)).thenReturn(new ArrayList<FirewallRuleVO>());
+ when(_ipAddressDao.listStaticNatPublicIps(NETWORK_ID)).thenReturn(new ArrayList<IPAddressVO>());
+ when(_nuageVspManager.getDnsDetails(network)).thenReturn(new ArrayList<String>());
- assertTrue(element.implement(network, offering, deployDest, context));
+ assertTrue(_nuageVspElement.implement(network, offering, deployDest, context));
}
@Test
@@ -218,14 +214,14 @@
services.add(Service.SourceNat);
services.add(Service.Connectivity);
services.add(Service.Firewall);
- assertTrue(element.verifyServicesCombination(services));
+ assertTrue(_nuageVspElement.verifyServicesCombination(services));
services = new HashSet<Service>();
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 @@
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<StaticNat>()));
+ when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer);
+ assertTrue(_nuageVspElement.applyStaticNats(network, new ArrayList<StaticNat>()));
}
@Test
@@ -271,21 +266,21 @@
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<FirewallRule>()));
+ when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer);
+ assertTrue(_nuageVspElement.applyFWRules(network, new ArrayList<FirewallRule>()));
}
@Test
@@ -300,20 +295,20 @@
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<NetworkACLItem>()));
+ when(_agentManager.easySend(eq(NETWORK_ID), (Command)any())).thenReturn(answer);
+ assertTrue(_nuageVspElement.applyNetworkACLs(network, new ArrayList<NetworkACLItem>()));
}
@Test
@@ -323,10 +318,11 @@
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 @@
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 18c088f..f101e1e 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 @@
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.<NuageVspDeviceVO> emptyList());
+ when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Collections.<NuageVspDeviceVO>emptyList());
final NetworkOffering offering = mock(NetworkOffering.class);
when(offering.getId()).thenReturn(NETWORK_ID);
@@ -218,19 +235,19 @@
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.<NuageVspDeviceVO> emptyList());
+ when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(Collections.<NuageVspDeviceVO>emptyList());
final NetworkOffering offering = mock(NetworkOffering.class);
when(offering.getId()).thenReturn(NETWORK_ID);
@@ -241,7 +258,7 @@
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 @@
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 @@
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 @@
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 @@
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<String>());
- when(nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList<String>());
+ 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<String>());
+ when(_nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList<String>());
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 @@
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 @@
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 @@
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<String>());
- when(nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList<String>());
+ 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<String>());
+ when(_nuageVspManager.getGatewaySystemIds()).thenReturn(new ArrayList<String>());
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 a29e3d7..ec16a97 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();
+ public void setUp() throws Exception {
+ super.setUp();
- 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;
+ _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 @@
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<NetworkVO>());
+ when(_networkDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(new ArrayList<NetworkVO>());
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 @@
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<NuageVspDeviceVO>());
+ when(_physicalNetworkDao.findById(NETWORK_ID)).thenReturn(phyNtwkVO);
+ when(_nuageVspDao.listByPhysicalNetwork(NETWORK_ID)).thenReturn(new ArrayList<NuageVspDeviceVO>());
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 770e13f..66d2632 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<String, Object> _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<String, Object> _hostDetails;
org.mockito.stubbing.Answer<Object> genericAnswer = new org.mockito.stubbing.Answer<Object>() {
public Object answer(InvocationOnMock invocation) {
@@ -66,6 +71,8 @@
@Before
public void setUp() throws Exception {
+ super.setUp();
+
_resource = new NuageVspResource() {
@Override
@@ -74,8 +81,6 @@
_nuageVspApiClient = _mockNuageVspApiClient;
_nuageVspElementClient = _mockNuageVspElementClient;
_nuageVspGuruClient = _mockNuageVspGuruClient;
- _nuageVspSyncClient = _mockNuageVspSyncClient;
-
}
protected void isNuageVspApiLoaded() throws ConfigurationException {
@@ -87,9 +92,6 @@
protected void isNuageVspElementLoaded() throws ConfigurationException {
}
- protected void isNuageVspSyncLoaded() throws ConfigurationException {
- }
-
protected void login() throws ConfigurationException {
}
@@ -148,15 +150,10 @@
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<String>()).gatewaySystemIds(new ArrayList<String>())
- .networkUuid("networkUuid").isL3Network(true).isVpc(true).isSharedNetwork(true).vpcName("vpcName").vpcUuid("vpcUuid").defaultEgressPolicy(true)
- .ipAddressRange(new ArrayList<String[]>()).domainTemplateName("domainTemplateName");
- doAnswer(genericAnswer).when(_mockNuageVspGuruClient).implement("networkDomainName", "networkDomainPath", "networkDomainUuid", "networkAccountName",
- "networkAccountUuid", "networkName", "networkCidr", "networkGateway", 0L, new ArrayList<String>(), new ArrayList<String>(), true, true, true, "networkUuid",
- "vpcName", "vpcUuid", true, new ArrayList<String[]>(), "domainTemplateName");
- com.cloud.agent.api.Answer implNtwkAns = _resource.executeRequest(cmdBuilder.build());
+ VspNetwork vspNetwork = buildVspNetwork();
+ ImplementNetworkVspCommand cmd = new ImplementNetworkVspCommand(vspNetwork, new ArrayList<String>());
+ doAnswer(genericAnswer).when(_mockNuageVspGuruClient).implement(vspNetwork, new ArrayList<String>());
+ com.cloud.agent.api.Answer implNtwkAns = _resource.executeRequest(cmd);
assertTrue(implNtwkAns.getResult());
}
@@ -164,16 +161,13 @@
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 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 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 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<Map<String, Object>>());
- doAnswer(genericAnswer).when(_mockNuageVspElementClient).applyStaticNats("networkDomainUuid", "networkUuid", "vpcOrSubnetUuid", true, true, new ArrayList<Map<String, Object>>());
- Answer applyNatAns = _resource.executeRequest(cmdBuilder.build());
+ VspNetwork vspNetwork = buildVspNetwork();
+ List<VspStaticNat> 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 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<Map<String, Object>>()).networkId(100)
- .egressDefaultPolicy(false).acsIngressAcl(true).networkReset(true).domainTemplateName("domainTemplateName");
- doAnswer(genericAnswer).when(_mockNuageVspElementClient).applyAclRules(true, "networkUuid", "networkDomainUuid", "vpcOrSubnetUuid", "networkName", true,
- new ArrayList<Map<String, Object>>(), 100, false, true, true, "domainTemplateName");
- Answer applyAclAns = _resource.executeRequest(cmdBuilder.build());
+ VspNetwork vspNetwork = buildVspNetwork();
+ List<VspAclRule> 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 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.<String>newArrayList());
+ doAnswer(genericAnswer).when(_mockNuageVspElementClient).shutdownVpc("domainUuid", "vpcUuid", "domainTemplateName", Lists.<String>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 23430d4..0000000
--- 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 0000000..1ddc106
--- /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<Pair<String, String>> 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 11158ee..cdd6d91 100644
--- a/plugins/network-elements/opendaylight/pom.xml
+++ b/plugins/network-elements/opendaylight/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
diff --git a/plugins/network-elements/ovs/pom.xml b/plugins/network-elements/ovs/pom.xml
index 3600bfb..0cb4d26 100644
--- a/plugins/network-elements/ovs/pom.xml
+++ b/plugins/network-elements/ovs/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/network-elements/palo-alto/pom.xml b/plugins/network-elements/palo-alto/pom.xml
index 4d29aab..3bef276 100644
--- a/plugins/network-elements/palo-alto/pom.xml
+++ b/plugins/network-elements/palo-alto/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/network-elements/stratosphere-ssp/pom.xml b/plugins/network-elements/stratosphere-ssp/pom.xml
index 4193cc3..96ae366 100644
--- a/plugins/network-elements/stratosphere-ssp/pom.xml
+++ b/plugins/network-elements/stratosphere-ssp/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/network-elements/vxlan/pom.xml b/plugins/network-elements/vxlan/pom.xml
index a179af8..c725ae3 100644
--- a/plugins/network-elements/vxlan/pom.xml
+++ b/plugins/network-elements/vxlan/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/outofbandmanagement-drivers/ipmitool/pom.xml b/plugins/outofbandmanagement-drivers/ipmitool/pom.xml
new file mode 100644
index 0000000..4b2e29a
--- /dev/null
+++ b/plugins/outofbandmanagement-drivers/ipmitool/pom.xml
@@ -0,0 +1,41 @@
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>cloud-plugin-outofbandmanagement-driver-ipmitool</artifactId>
+ <name>Apache CloudStack Plugin - Power Management Driver ipmitool</name>
+ <parent>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloudstack-plugins</artifactId>
+ <version>4.9.1.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup b/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/module.properties
old mode 100755
new mode 100644
similarity index 66%
copy from systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
copy to plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/module.properties
index 9d254d3..f6499d7
--- a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
+++ b/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/module.properties
@@ -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
@@ -16,12 +14,5 @@
# KIND, either express or implied. See the License for the
# 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"
-
-[ "$output" != "" ] && logger -t cloud $output
-[ -z "$output" ] && logger -t cloud "No files removed"
-
-exit 0
+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 0000000..49baa90d
--- /dev/null
+++ b/plugins/outofbandmanagement-drivers/ipmitool/resources/META-INF/cloudstack/ipmitool/spring-ipmitool-context.xml
@@ -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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context-3.0.xsd"
+ >
+
+ <bean id="ipmitoolOutOfBandManagementDriver" class="org.apache.cloudstack.outofbandmanagement.driver.ipmitool.IpmitoolOutOfBandManagementDriver">
+ <property name="name" value="IPMITOOL" />
+ </bean>
+
+</beans>
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 0000000..bad3cb6
--- /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<String> IpmiToolPath = new ConfigKey<String>("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<String> IpmiToolInterface = new ConfigKey<String>("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<String> IpmiToolRetries = new ConfigKey<String>("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<OutOfBandManagement.Option, String> 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<String> 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<String> 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<String> 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 0000000..f5896b2
--- /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<String> getIpmiToolCommandArgs(final String ipmiToolPath, final String ipmiInterface, final String retries,
+ final ImmutableMap<OutOfBandManagement.Option, String> options, String... commands) {
+
+ final ImmutableList.Builder<String> ipmiToolCommands = ImmutableList.<String>builder()
+ .add(ipmiToolPath)
+ .add("-I")
+ .add(ipmiInterface)
+ .add("-R")
+ .add(retries)
+ .add("-v");
+
+ if (options != null) {
+ for (ImmutableMap.Entry<OutOfBandManagement.Option, String> 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<String> commands) {
+ return executeCommands(commands, ProcessRunner.DEFAULT_MAX_TIMEOUT);
+ }
+
+ public OutOfBandManagementDriverResponse executeCommands(final List<String> commands, final Duration timeOut) {
+ final ProcessResult result = RUNNER.executeCommands(commands, timeOut);
+ if (LOG.isTraceEnabled()) {
+ List<String> cleanedCommands = new ArrayList<String>();
+ 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 0000000..26115f7
--- /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<String> 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<OutOfBandManagement.Option, String> argMap = new ImmutableMap.Builder<>();
+ argMap.put(OutOfBandManagement.Option.DRIVER, "ipmitool");
+ argMap.put(OutOfBandManagement.Option.ADDRESS, "127.0.0.1");
+ List<String> 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 effe6ee..b9c2e3b 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<build>
@@ -50,6 +50,7 @@
<module>api/solidfire-intg-test</module>
<module>api/discovery</module>
<module>acl/static-role-based</module>
+ <module>acl/dynamic-role-based</module>
<module>affinity-group-processors/host-anti-affinity</module>
<module>affinity-group-processors/explicit-dedication</module>
<module>deployment-planners/user-concentrated-pod</module>
@@ -74,11 +75,13 @@
<module>network-elements/palo-alto</module>
<module>network-elements/netscaler</module>
<module>network-elements/nicira-nvp</module>
+ <module>network-elements/nuage-vsp</module>
<module>network-elements/bigswitch</module>
<module>network-elements/brocade-vcs</module>
<module>network-elements/midonet</module>
<module>network-elements/stratosphere-ssp</module>
<module>network-elements/opendaylight</module>
+ <module>outofbandmanagement-drivers/ipmitool</module>
<module>storage-allocators/random</module>
<module>user-authenticators/ldap</module>
<module>user-authenticators/md5</module>
@@ -169,17 +172,6 @@
</modules>
</profile>
<profile>
- <id>nuagevsp</id>
- <activation>
- <property>
- <name>noredist</name>
- </property>
- </activation>
- <modules>
- <module>network-elements/nuage-vsp</module>
- </modules>
- </profile>
- <profile>
<id>vmware</id>
<activation>
<property>
diff --git a/plugins/storage-allocators/random/pom.xml b/plugins/storage-allocators/random/pom.xml
index 204ca4e..af013736 100644
--- a/plugins/storage-allocators/random/pom.xml
+++ b/plugins/storage-allocators/random/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/image/default/pom.xml b/plugins/storage/image/default/pom.xml
index b87f7dc..63a4561 100644
--- a/plugins/storage/image/default/pom.xml
+++ b/plugins/storage/image/default/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
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 05222c8..b8b5226 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 @@
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 d5aefb0..a2ddf84 100644
--- a/plugins/storage/image/s3/pom.xml
+++ b/plugins/storage/image/s3/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/image/sample/pom.xml b/plugins/storage/image/sample/pom.xml
index 65fbab7..2b73b11 100644
--- a/plugins/storage/image/sample/pom.xml
+++ b/plugins/storage/image/sample/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/image/swift/pom.xml b/plugins/storage/image/swift/pom.xml
index 616f582..7140310 100644
--- a/plugins/storage/image/swift/pom.xml
+++ b/plugins/storage/image/swift/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/plugins/storage/volume/cloudbyte/pom.xml b/plugins/storage/volume/cloudbyte/pom.xml
index 2d6f607..882615f 100755
--- a/plugins/storage/volume/cloudbyte/pom.xml
+++ b/plugins/storage/volume/cloudbyte/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
@@ -54,7 +54,7 @@
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-bundle</artifactId>
- <version>1.18.3</version>
+ <version>1.19.1</version>
</dependency>
</dependencies>
<build>
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 b7ae4d4..74fbde5 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 @@
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 @@
}
@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 @@
}
@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 c2624ea..b40e60e 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
@@ -77,6 +77,11 @@
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 @@
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 01fecce..bf6d890 100644
--- a/plugins/storage/volume/default/pom.xml
+++ b/plugins/storage/volume/default/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
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 e92e8f6..b5aee54 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 @@
}
@Override
- public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
+ public ChapInfo getChapInfo(DataObject dataObject) {
return null;
}
@@ -169,8 +169,13 @@
}
@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 a4d9714..edd7f89 100644
--- a/plugins/storage/volume/nexenta/pom.xml
+++ b/plugins/storage/volume/nexenta/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
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 7524703..c6ae3ed 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 @@
}
@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 @@
}
@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 9503252..5fe7599 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);
- public boolean hostConnect(long hostId, long poolId) {
+ @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 3c5e41a..8262162 100644
--- a/plugins/storage/volume/sample/pom.xml
+++ b/plugins/storage/volume/sample/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
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 0a4cfd6..343b08a 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 @@
}
@Override
- public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
+ public ChapInfo getChapInfo(DataObject dataObject) {
return null;
}
@@ -98,16 +97,18 @@
}
@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;
}
private class CreateVolumeContext<T> extends AsyncRpcContext<T> {
- private final DataObject volume;
-
public CreateVolumeContext(AsyncCompletionCallback<T> 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 fb0dbcb..694dd66 100644
--- a/plugins/storage/volume/solidfire/pom.xml
+++ b/plugins/storage/volume/solidfire/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
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 61e199c..af969e1 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;
-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;
+import com.google.common.base.Preconditions;
- @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;
+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 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<String, String> getCapabilities() {
- Map<String, String> mapCapabilities = new HashMap<String, String>();
+ Map<String, String> 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 @@
}
@Override
- public ChapInfo getChapInfo(VolumeInfo volumeInfo) {
+ public ChapInfo getChapInfo(DataObject dataObject) {
return null;
}
@@ -129,45 +149,52 @@
@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<HostVO> hosts = _hostDao.findByClusterId(clusterId);
+ List<HostVO> 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 @@
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<HostVO> 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 @@
}
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 @@
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 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 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,28 +311,54 @@
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<String, String> mapAttributes;
- Long minIops = volumeInfo.getMinIops();
- Long maxIops = volumeInfo.getMaxIops();
+ if (dataObject.getType() == DataObjectType.VOLUME) {
+ VolumeInfo volumeInfo = (VolumeInfo)dataObject;
+ minIops = volumeInfo.getMinIops();
+ maxIops = volumeInfo.getMaxIops();
+ volumeSize = getDataObjectSizeIncludingHypervisorSnapshotReserve(volumeInfo, storagePoolDao.findById(storagePoolId));
+ volumeName = volumeInfo.getName();
+
+ 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());
+ }
+
+ final Iops iops = getIops(minIops, maxIops, storagePoolId);
+
+ 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);
- iops = new Iops(getDefaultMinIops(storagePoolId), defaultMaxIops, getDefaultBurstIops(storagePoolId, defaultMaxIops));
- } else {
- iops = new Iops(volumeInfo.getMinIops(), volumeInfo.getMaxIops(), getDefaultBurstIops(storagePoolId, volumeInfo.getMaxIops()));
+ return new Iops(getDefaultMinIops(storagePoolId), defaultMaxIops, getDefaultBurstIops(storagePoolId, defaultMaxIops));
}
- long volumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(volumeInfo, _storagePoolDao.findById(storagePoolId));
-
- long sfVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, SolidFireUtil.getSolidFireVolumeName(volumeInfo.getName()), sfAccountId, volumeSize, true,
- NumberFormat.getInstance().format(volumeInfo.getSize()), iops.getMinIops(), iops.getMaxIops(), iops.getBurstIops());
-
- return SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
+ return new Iops(minIops, maxIops, getDefaultBurstIops(storagePoolId, maxIops));
}
@Override
@@ -300,7 +369,7 @@
private long getUsedBytes(StoragePool storagePool, long volumeIdToIgnore) {
long usedSpace = 0;
- List<VolumeVO> lstVolumes = _volumeDao.findByPoolId(storagePool.getId(), null);
+ List<VolumeVO> lstVolumes = volumeDao.findByPoolId(storagePool.getId(), null);
if (lstVolumes != null) {
for (VolumeVO volume : lstVolumes) {
@@ -308,7 +377,7 @@
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 @@
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 @@
}
}
- List<SnapshotVO> lstSnapshots = _snapshotDao.listAll();
+ List<SnapshotVO> 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 @@
}
}
+ List<VMTemplateStoragePoolVO> lstTemplatePoolRefs = tmpltPoolDao.listByPoolId(storagePool.getId());
+
+ if (lstTemplatePoolRefs != null) {
+ for (VMTemplateStoragePoolVO templatePoolRef : lstTemplatePoolRefs) {
+ usedSpace += templatePoolRef.getTemplateSize();
+ }
+ }
+
return usedSpace;
}
@@ -362,7 +443,7 @@
public long getUsedIops(StoragePool storagePool) {
long usedIops = 0;
- List<VolumeVO> volumes = _volumeDao.findByPoolId(storagePool.getId(), null);
+ List<VolumeVO> volumes = volumeDao.findByPoolId(storagePool.getId(), null);
if (volumes != null) {
for (VolumeVO volume : volumes) {
@@ -374,12 +455,25 @@
}
@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 @@
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<VMTemplateStoragePoolVO> 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 @@
long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
- SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId);
+ deleteSolidFireVolume(sfConnection, volumeInfo.getId(), sfVolumeId);
}
@Override
@@ -441,114 +558,234 @@
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";
- long storagePoolId = dataStore.getId();
-
- SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
-
- AccountDetailVO accountDetail = SolidFireUtil.getAccountDetail(volumeInfo.getAccountId(), storagePoolId, _accountDetailsDao);
-
- 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);
-
- if (sfAccount == null) {
- sfAccount = createSolidFireAccount(sfConnection, sfAccountName);
- }
-
- SolidFireUtil.updateCsDbWithSolidFireAccountInfo(account.getId(), sfAccount, storagePoolId, _accountDetailsDao);
-
- accountDetail = SolidFireUtil.getAccountDetail(volumeInfo.getAccountId(), storagePoolId, _accountDetailsDao);
+ LOGGER.error(errMsg);
}
+ }
+ catch (Exception ex) {
+ errMsg = ex.getMessage();
- long sfAccountId = Long.parseLong(accountDetail.getValue());
+ LOGGER.error(errMsg);
- SolidFireUtil.SolidFireVolume sfVolume = createSolidFireVolume(sfConnection, volumeInfo, sfAccountId);
-
- 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(dataStore.getId());
-
- 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);
- } else {
- errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync";
+ if (callback == null) {
+ throw ex;
+ }
}
- // path = iqn
- // size is pulled from DataObject instance, if errMsg is null
- CreateCmdResult result = new CreateCmdResult(iqn, new Answer(null, errMsg == null, errMsg));
+ 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));
- result.setResult(errMsg);
+ result.setResult(errMsg);
- callback.complete(result);
+ callback.complete(result);
+ }
+ }
+
+ private long getCreateSolidFireAccountId(SolidFireUtil.SolidFireConnection sfConnection, long csAccountId, long storagePoolId) {
+ AccountDetailVO accountDetail = SolidFireUtil.getAccountDetail(csAccountId, 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);
+
+ if (sfAccount == null) {
+ sfAccount = createSolidFireAccount(sfConnection, sfAccountName);
+ }
+
+ SolidFireUtil.updateCsDbWithSolidFireAccountInfo(account.getId(), sfAccount, storagePoolId, accountDetailsDao);
+
+ accountDetail = SolidFireUtil.getAccountDetail(csAccountId, storagePoolId, accountDetailsDao);
+ }
+
+ return Long.parseLong(accountDetail.getValue());
+ }
+
+ private void handleSnapshotDetails(long csSnapshotId, String name, String value) {
+ snapshotDetailsDao.removeDetail(csSnapshotId, name);
+
+ SnapshotDetailsVO snapshotDetails = new SnapshotDetailsVO(csSnapshotId, name, value, false);
+
+ snapshotDetailsDao.persist(snapshotDetails);
+ }
+
+ private void addTempVolumeId(long csSnapshotId, String tempVolumeId) {
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID);
+
+ if (snapshotDetails == null || snapshotDetails.getValue() == null) {
+ throw new CloudRuntimeException("'addTempVolumeId' should not be invoked unless " + SolidFireUtil.VOLUME_ID + " exists.");
+ }
+
+ String originalVolumeId = snapshotDetails.getValue();
+
+ handleSnapshotDetails(csSnapshotId, SolidFireUtil.TEMP_VOLUME_ID, originalVolumeId);
+ handleSnapshotDetails(csSnapshotId, SolidFireUtil.VOLUME_ID, tempVolumeId);
+ }
+
+ 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.");
+ }
+
+ String originalVolumeId = snapshotDetails.getValue();
+
+ handleSnapshotDetails(csSnapshotId, SolidFireUtil.VOLUME_ID, originalVolumeId);
+
+ snapshotDetailsDao.remove(snapshotDetails.getId());
+ }
+
+ private long getCsIdForCloning(long volumeId, String cloneOf) {
+ VolumeDetailVO volumeDetail = volumeDetailsDao.findDetail(volumeId, cloneOf);
+
+ if (volumeDetail != null && volumeDetail.getValue() != null) {
+ return new Long(volumeDetail.getValue());
+ }
+
+ return Long.MIN_VALUE;
+ }
+
+ private boolean shouldTakeSnapshot(long snapshotId) {
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(snapshotId, "takeSnapshot");
+
+ if (snapshotDetails != null && snapshotDetails.getValue() != null) {
+ return new Boolean(snapshotDetails.getValue());
+ }
+
+ return false;
+ }
+
+ private SolidFireUtil.SolidFireVolume createClone(SolidFireUtil.SolidFireConnection sfConnection, long dataObjectId, VolumeInfo volumeInfo, long sfAccountId,
+ long storagePoolId, DataObjectType dataObjectType) {
+ String sfNewVolumeName = volumeInfo.getName();
+
+ long sfVolumeId = Long.MIN_VALUE;
+ long sfSnapshotId = Long.MIN_VALUE;
+
+ if (dataObjectType == DataObjectType.SNAPSHOT) {
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(dataObjectId, SolidFireUtil.SNAPSHOT_ID);
+
+ if (snapshotDetails != null && snapshotDetails.getValue() != null) {
+ sfSnapshotId = Long.parseLong(snapshotDetails.getValue());
+ }
+
+ snapshotDetails = snapshotDetailsDao.findDetail(dataObjectId, SolidFireUtil.VOLUME_ID);
+
+ sfVolumeId = Long.parseLong(snapshotDetails.getValue());
+ } else if (dataObjectType == DataObjectType.TEMPLATE) {
+ // get the cached template on this storage
+ VMTemplateStoragePoolVO templatePoolRef = tmpltPoolDao.findByPoolTemplate(storagePoolId, dataObjectId);
+
+ if (templatePoolRef != null) {
+ sfVolumeId = Long.parseLong(templatePoolRef.getLocalDownloadPath());
+ }
+ }
+
+ 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);
+ }
+
+ private Map<String, String> getVolumeAttributes(VolumeInfo volumeInfo) {
+ Map<String, String> mapAttributes = new HashMap<>();
+
+ mapAttributes.put(SolidFireUtil.CloudStackVolumeId, String.valueOf(volumeInfo.getId()));
+ mapAttributes.put(SolidFireUtil.CloudStackVolumeSize, NumberFormat.getInstance().format(volumeInfo.getSize()));
+
+ return mapAttributes;
+ }
+
+ private Map<String, String> getSnapshotAttributes(SnapshotInfo snapshotInfo) {
+ Map<String, String> mapAttributes = new HashMap<>();
+
+ mapAttributes.put(SolidFireUtil.CloudStackSnapshotId, String.valueOf(snapshotInfo.getId()));
+ mapAttributes.put(SolidFireUtil.CloudStackSnapshotSize, NumberFormat.getInstance().format(snapshotInfo.getSize()));
+
+ return mapAttributes;
+ }
+
+ private Map<String, String> getTemplateAttributes(TemplateInfo templateInfo) {
+ Map<String, String> 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) {
- VolumeDetailVO volumeDetailVo = _volumeDetailsDao.findDetail(volumeId, SolidFireUtil.VOLUME_SIZE);
+ volumeDetailsDao.removeDetail(volumeId, SolidFireUtil.VOLUME_SIZE);
- if (volumeDetailVo == null || volumeDetailVo.getValue() == null) {
- volumeDetailVo = new VolumeDetailVO(volumeId, SolidFireUtil.VOLUME_SIZE, String.valueOf(sfVolumeSize), false);
+ VolumeDetailVO volumeDetailVo = new VolumeDetailVO(volumeId, SolidFireUtil.VOLUME_SIZE, String.valueOf(sfVolumeSize), false);
- _volumeDetailsDao.persist(volumeDetailVo);
- }
+ volumeDetailsDao.persist(volumeDetailVo);
}
@Override
public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CommandResult> callback) {
String errMsg = null;
- if (dataObject.getType() == DataObjectType.VOLUME) {
- try {
- VolumeInfo volumeInfo = (VolumeInfo)dataObject;
- long volumeId = volumeInfo.getId();
-
- long storagePoolId = dataStore.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);
+ 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";
}
- catch (Exception ex) {
- s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to delete SolidFire volume", ex);
+ }
+ catch (Exception ex) {
+ errMsg = ex.getMessage();
- errMsg = ex.getMessage();
- }
- } 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";
+ LOGGER.error(errMsg);
}
CommandResult result = new CommandResult();
@@ -574,49 +811,67 @@
try {
VolumeInfo volumeInfo = snapshotInfo.getBaseVolume();
- VolumeVO volumeVO = _volumeDao.findById(volumeInfo.getId());
+ VolumeVO volumeVO = volumeDao.findById(volumeInfo.getId());
long sfVolumeId = Long.parseLong(volumeVO.getFolder());
long storagePoolId = volumeVO.getPoolId();
- SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
- StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
long capacityBytes = storagePool.getCapacityBytes();
- // getUsedBytes(StoragePool) will not include the bytes of the proposed new volume because
- // updateSnapshotDetails(long, long, long, long, String) has not yet been called for this new volume
+ // getUsedBytes(StoragePool) will not include the bytes of the proposed new volume or snapshot because
+ // updateSnapshotDetails has not yet been called for this new volume or snapshot
long usedBytes = getUsedBytes(storagePool);
long sfVolumeSize = sfVolume.getTotalSize();
usedBytes += sfVolumeSize;
- // For creating a volume, we need to check to make sure a sufficient amount of space remains in the primary storage.
- // For the purpose of "charging" these bytes against storage_pool.capacityBytes, we take the full size of the SolidFire volume.
+ // For creating a volume or a snapshot, we need to check to make sure a sufficient amount of space remains in the primary storage.
+ // For the purpose of "charging" these bytes against storage_pool.capacity_bytes, we take the full size of the SolidFire volume
+ // that is serving as the volume the snapshot is of (either a new SolidFire volume or a SolidFire snapshot).
if (usedBytes > 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();
-
- long sfNewVolumeId = SolidFireUtil.createSolidFireVolume(sfConnection, volumeName, sfVolume.getAccountId(), sfVolumeSize,
- sfVolume.isEnable512e(), NumberFormat.getInstance().format(volumeInfo.getSize()), sfVolume.getMinIops(), 50000, 75000);
-
- // 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);
-
- SolidFireUtil.SolidFireVolume sfNewVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfNewVolumeId);
-
- updateSnapshotDetails(snapshotInfo.getId(), sfNewVolumeId, storagePoolId, sfVolumeSize, sfNewVolume.getIqn());
-
SnapshotObjectTO snapshotObjectTo = (SnapshotObjectTO)snapshotInfo.getTO();
- snapshotObjectTo.setPath(String.valueOf(sfNewVolumeId));
+ if (shouldTakeSnapshot(snapshotInfo.getId())) {
+ // We are supposed to take a SolidFire snapshot to serve as the back-end for our CloudStack volume snapshot.
+
+ String sfNewSnapshotName = volumeInfo.getName() + "-" + snapshotInfo.getUuid();
+
+ long sfNewSnapshotId = SolidFireUtil.createSolidFireSnapshot(sfConnection, sfVolumeId, sfNewSnapshotName, getSnapshotAttributes(snapshotInfo));
+
+ updateSnapshotDetails(snapshotInfo.getId(), sfVolumeId, sfNewSnapshotId, storagePoolId, sfVolumeSize);
+
+ 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());
+
+ 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 @@
result.setResult(null);
}
catch (Exception ex) {
- s_logger.debug(SolidFireUtil.LOG_PREFIX + "Failed to take CloudStack snapshot: " + snapshotInfo.getId(), ex);
+ LOGGER.debug(SolidFireUtil.LOG_PREFIX + "Failed to take CloudStack snapshot: " + snapshotInfo.getId(), ex);
result = new CreateCmdResult(null, new CreateObjectAnswer(ex.toString()));
@@ -635,73 +890,297 @@
callback.complete(result);
}
- private void updateSnapshotDetails(long csSnapshotId, long sfNewVolumeId, long storagePoolId, long sfNewVolumeSize, String sfNewVolumeIqn) {
+ private void updateSnapshotDetails(long csSnapshotId, long sfVolumeId, long sfNewSnapshotId, long storagePoolId, long sfNewVolumeSize) {
SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
SolidFireUtil.VOLUME_ID,
- String.valueOf(sfNewVolumeId),
+ String.valueOf(sfVolumeId),
false);
- _snapshotDetailsDao.persist(snapshotDetail);
+ snapshotDetailsDao.persist(snapshotDetail);
+
+ snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
+ SolidFireUtil.SNAPSHOT_ID,
+ String.valueOf(sfNewSnapshotId),
+ false);
+
+ snapshotDetailsDao.persist(snapshotDetail);
snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
SolidFireUtil.STORAGE_POOL_ID,
String.valueOf(storagePoolId),
false);
- _snapshotDetailsDao.persist(snapshotDetail);
+ snapshotDetailsDao.persist(snapshotDetail);
snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
SolidFireUtil.VOLUME_SIZE,
String.valueOf(sfNewVolumeSize),
false);
- _snapshotDetailsDao.persist(snapshotDetail);
+ snapshotDetailsDao.persist(snapshotDetail);
+ }
+
+ private void updateSnapshotDetails(long csSnapshotId, long sfNewVolumeId, long storagePoolId, long sfNewVolumeSize, String sfNewVolumeIqn) {
+ SnapshotDetailsVO snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
+ SolidFireUtil.VOLUME_ID,
+ String.valueOf(sfNewVolumeId),
+ false);
+
+ snapshotDetailsDao.persist(snapshotDetail);
+
+ snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
+ SolidFireUtil.STORAGE_POOL_ID,
+ String.valueOf(storagePoolId),
+ false);
+
+ snapshotDetailsDao.persist(snapshotDetail);
+
+ snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
+ SolidFireUtil.VOLUME_SIZE,
+ String.valueOf(sfNewVolumeSize),
+ false);
+
+ snapshotDetailsDao.persist(snapshotDetail);
snapshotDetail = new SnapshotDetailsVO(csSnapshotId,
DiskTO.IQN,
sfNewVolumeIqn,
false);
- _snapshotDetailsDao.persist(snapshotDetail);
+ snapshotDetailsDao.persist(snapshotDetail);
}
- // return null for no error message
- private String deleteSnapshot(SnapshotInfo snapshotInfo, long storagePoolId) {
- String errMsg = null;
+ private String createVolume(VolumeInfo volumeInfo, long storagePoolId) {
+ verifySufficientBytesForStoragePool(volumeInfo, storagePoolId);
+ verifySufficientIopsForStoragePool(volumeInfo.getMinIops() != null ? volumeInfo.getMinIops() : getDefaultMinIops(storagePoolId), storagePoolId);
- long snapshotId = snapshotInfo.getId();
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
+
+ long sfAccountId = getCreateSolidFireAccountId(sfConnection, volumeInfo.getAccountId(), storagePoolId);
+
+ long csSnapshotId = getCsIdForCloning(volumeInfo.getId(), "cloneOfSnapshot");
+ long csTemplateId = getCsIdForCloning(volumeInfo.getId(), "cloneOfTemplate");
+
+ SolidFireUtil.SolidFireVolume sfVolume;
+
+ if (csSnapshotId > 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);
+
+ 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(snapshotId, SolidFireUtil.VOLUME_ID);
+ SnapshotDetailsVO snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.SNAPSHOT_ID);
- long volumeId = Long.parseLong(snapshotDetails.getValue());
+ if (snapshotDetails != null && snapshotDetails.getValue() != null) {
+ // A SolidFire snapshot is being used to support the CloudStack volume snapshot.
- SolidFireUtil.deleteSolidFireVolume(sfConnection, volumeId);
+ long sfSnapshotId = Long.parseLong(snapshotDetails.getValue());
- _snapshotDetailsDao.removeDetails(snapshotId);
+ deleteSolidFireSnapshot(sfConnection, csSnapshotId, sfSnapshotId);
+ }
+ else {
+ // A SolidFire volume is being used to support the CloudStack volume snapshot.
- StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolId);
+ snapshotDetails = snapshotDetailsDao.findDetail(csSnapshotId, SolidFireUtil.VOLUME_ID);
+
+ long sfVolumeId = Long.parseLong(snapshotDetails.getValue());
+
+ SolidFireUtil.deleteSolidFireVolume(sfConnection, sfVolumeId);
+ }
+
+ snapshotDetailsDao.removeDetails(csSnapshotId);
+
+ 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<CommandResult> callback) {
+ public void revertSnapshot(SnapshotInfo snapshotOnImageStore, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback<CommandResult> callback) {
throw new UnsupportedOperationException("Reverting not supported. Create a template or volume based on the snapshot instead.");
}
@@ -717,26 +1196,49 @@
long sfVolumeId = Long.parseLong(volumeInfo.getFolder());
ResizeVolumePayload payload = (ResizeVolumePayload)volumeInfo.getpayload();
- SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, _storagePoolDetailsDao);
+ SolidFireUtil.SolidFireConnection sfConnection = SolidFireUtil.getSolidFireConnection(storagePoolId, storagePoolDetailsDao);
SolidFireUtil.SolidFireVolume sfVolume = SolidFireUtil.getSolidFireVolume(sfConnection, sfVolumeId);
verifySufficientIopsForStoragePool(storagePoolId, volumeInfo.getId(), payload.newMinIops);
+ verifySufficientBytesForStoragePool(storagePoolId, volumeInfo.getId(), payload.newSize, payload.newHypervisorSnapshotReserve);
- SolidFireUtil.modifySolidFireVolume(sfConnection, sfVolumeId, sfVolume.getTotalSize(), NumberFormat.getInstance().format(payload.newSize),
+ long sfNewVolumeSize = sfVolume.getTotalSize();
+
+ Integer hsr = volumeInfo.getHypervisorSnapshotReserve();
+
+ if (payload.newSize != null || payload.newHypervisorSnapshotReserve != null) {
+ if (payload.newHypervisorSnapshotReserve != null) {
+ if (hsr != null) {
+ if (payload.newHypervisorSnapshotReserve > hsr) {
+ hsr = payload.newHypervisorSnapshotReserve;
+ }
+ }
+ else {
+ hsr = payload.newHypervisorSnapshotReserve;
+ }
+ }
+
+ sfNewVolumeSize = getVolumeSizeIncludingHypervisorSnapshotReserve(payload.newSize, hsr);
+ }
+
+ Map<String, String> mapAttributes = new HashMap<>();
+
+ 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 @@
callback.complete(result);
}
+ private void verifySufficientBytesForStoragePool(long requestedBytes, long storagePoolId) {
+ StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId);
+
+ long capacityBytes = storagePool.getCapacityBytes();
+ long usedBytes = getUsedBytes(storagePool);
+
+ usedBytes += requestedBytes;
+
+ if (usedBytes > 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);
+ }
+ }
- if (usedIops + diffInMinIops > capacityIops) {
- throw new CloudRuntimeException("Insufficient number of IOPS available in this storage pool");
+ private void deleteSolidFireVolume(SolidFireUtil.SolidFireConnection sfConnection, long csVolumeId, long sfVolumeId) {
+ List<SnapshotVO> 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 (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<SnapshotVO> lstSnapshots = getNonDestroyedSnapshots(snapshot.getVolumeId());
+
+ List<SnapshotVO> 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<SnapshotVO> getNonDestroyedSnapshots(long csVolumeId) {
+ List<SnapshotVO> lstSnapshots = snapshotDao.listByVolumeId(csVolumeId);
+
+ if (lstSnapshots == null) {
+ lstSnapshots = new ArrayList<>();
+ }
+
+ List<SnapshotVO> 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 4b38f22..c47411e 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
@Override
public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
- dataStoreHelper.attachZone(dataStore);
+ _dataStoreHelper.attachZone(dataStore);
List<HostVO> xenServerHosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.XenServer, scope.getScopeId());
List<HostVO> vmWareServerHosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByHypervisor(HypervisorType.VMware, scope.getScopeId());
@@ -220,23 +225,25 @@
@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<SnapshotVO> lstSnapshots = _snapshotDao.listAll();
if (lstSnapshots != null) {
@@ -244,13 +251,39 @@
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<VMTemplateStoragePoolVO> 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 @@
@Override
public void updateStoragePool(StoragePool storagePool, Map<String, String> 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 @@
@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 7cb6900..6921e4f 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 @@
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 @@
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 @@
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 @@
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);
- // 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
+ 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;
+
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<HostVO> hosts = _hostDao.findByClusterId(clusterId);
- ClusterVO cluster = _clusterDao.findById(clusterId);
SolidFireUtil.placeVolumeInVolumeAccessGroup(sfConnection, sfVolume.getId(), dataStore.getId(), cluster.getUuid(), hosts, _clusterDetailsDao);
@@ -275,6 +286,10 @@
throw new CloudRuntimeException(ex.getMessage());
}
+ finally {
+ lock.unlock();
+ lock.releaseRef();
+ }
return dataStore;
}
@@ -546,7 +561,25 @@
}
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 @@
String vagId = clusterDetail != null ? clusterDetail.getValue() : null;
if (vagId != null) {
- List<HostVO> 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 d8e4ec6..082e1a3 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,33 +94,13 @@
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);
}
-
- 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 (" + storagePool.getId() + ")");
+ else if (host.getHypervisorType().equals(HypervisorType.KVM)) {
+ handleKVM(hostId, storagePoolId);
}
- if (!answer.getResult()) {
- String msg = "Unable to attach storage pool " + storagePoolId + " to host " + hostId;
-
- _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, storagePool.getDataCenterId(), storagePool.getPodId(), msg, msg);
-
- throw new CloudRuntimeException("Unable to establish a connection from agent to storage pool " + storagePool.getId() + " due to " + answer.getDetails() +
- " (" + storagePool.getId() + ")");
- }
-
- 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;
}
@@ -105,4 +114,171 @@
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<String> 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<StoragePoolVO> storagePools = _storagePoolDao.findPoolsByProvider(SolidFireUtil.PROVIDER_NAME);
+
+ if (storagePools != null && storagePools.size() > 0) {
+ List<Map<String, String>> targets = new ArrayList<>();
+
+ for (StoragePoolVO storagePool : storagePools) {
+ List<Map<String, String>> 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<String> getStoragePaths(long clusterId, long storagePoolId) {
+ List<String> storagePaths = new ArrayList<>();
+
+ // If you do not pass in null for the second parameter, you only get back applicable ROOT disks.
+ List<VolumeVO> 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<Map<String, String>> getTargets(long clusterId, long storagePoolId) {
+ List<Map<String, String>> 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<VolumeVO> 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<String, String> 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) {
+ throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command (" + storagePool.getId() + ")");
+ }
+
+ if (!answer.getResult()) {
+ 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);
+
+ throw new CloudRuntimeException("Unable to establish a connection from agent to storage pool " + storagePool.getId() + " due to " + answer.getDetails() +
+ " (" + storagePool.getId() + ")");
+ }
+
+ assert (answer instanceof ModifyStoragePoolAnswer) : "ModifyStoragePoolAnswer expected ; Pool = " + storagePool.getId() + " Host = " + hostId;
+
+ s_logger.info("Connection established between storage pool " + storagePool + " and host + " + hostId);
+ }
}
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 9881d1d..f88041a 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 hostAdded(long hostId) {
+ HostVO host = hostDao.findById(hostId);
+
+ SolidFireUtil.hostAddedToOrRemovedFromCluster(hostId, host.getClusterId(), true, SolidFireUtil.SHARED_PROVIDER_NAME,
+ clusterDao, clusterDetailsDao, storagePoolDao, storagePoolDetailsDao, hostDao);
+
+ handleVMware(hostId, true);
+
+ return true;
+ }
@Override
public boolean hostConnect(long hostId, long storagePoolId) {
+ StoragePool storagePool = (StoragePool) dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
+ ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool);
+
+ ModifyStoragePoolAnswer answer = sendModifyStoragePoolCommand(cmd, storagePool, hostId);
+
StoragePoolHostVO storagePoolHost = storagePoolHostDao.findByPoolHost(storagePoolId, hostId);
- if (storagePoolHost == null) {
- storagePoolHost = new StoragePoolHostVO(storagePoolId, hostId, "");
+ if (storagePoolHost != null) {
+ storagePoolHost.setLocalPath(answer.getPoolInfo().getLocalPath().replaceAll("//", "/"));
+ } else {
+ storagePoolHost = new StoragePoolHostVO(storagePoolId, hostId, answer.getPoolInfo().getLocalPath().replaceAll("//", "/"));
storagePoolHostDao.persist(storagePoolHost);
}
- StoragePool storagePool = (StoragePool)dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
- ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, storagePool);
- Answer answer = agentMgr.easySend(hostId, cmd);
+ StoragePoolVO storagePoolVO = storagePoolDao.findById(storagePoolId);
- if (answer == null) {
- throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command for storage pool: " + storagePool.getId());
- }
+ storagePoolVO.setCapacityBytes(answer.getPoolInfo().getCapacityBytes());
+ storagePoolVO.setUsedBytes(answer.getPoolInfo().getCapacityBytes() - answer.getPoolInfo().getAvailableBytes());
- if (!answer.getResult()) {
- String msg = "Unable to attach storage pool " + storagePoolId + " 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;
-
- s_logger.info("Connection established between storage pool " + storagePool + " and host + " + hostId);
+ storagePoolDao.update(storagePoolId, storagePoolVO);
return true;
}
@@ -89,4 +113,107 @@
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<StoragePoolVO> storagePools = storagePoolDao.findPoolsByProvider(SolidFireUtil.SHARED_PROVIDER_NAME);
+
+ if (storagePools != null && storagePools.size() > 0) {
+ List<Map<String, String>> 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<String, String> 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 9c486db..a9c1227 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 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 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 @@
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 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 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<StoragePoolVO> storagePools = storagePoolDao.findPoolsByProvider(storageProvider);
+
+ if (storagePools != null && storagePools.size() > 0) {
+ List<SolidFireUtil.SolidFireConnection> sfConnections = new ArrayList<SolidFireUtil.SolidFireConnection>();
+
+ 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<HostVO> 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<HostVO> hosts, ClusterDetailsDao clusterDetailsDao) {
if (hosts == null || hosts.isEmpty()) {
@@ -264,8 +367,7 @@
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 @@
return true;
}
- public static String[] getNewHostIqns(String[] currentIqns, String[] newIqns) {
- List<String> lstIqns = new ArrayList<String>();
+ public static String[] getNewHostIqns(String[] iqns, String[] iqnsToAddOrRemove, boolean add) {
+ if (add) {
+ return getNewHostIqnsAdd(iqns, iqnsToAddOrRemove);
+ }
- if (currentIqns != null) {
- for (String currentIqn : currentIqns) {
- lstIqns.add(currentIqn);
+ return getNewHostIqnsRemove(iqns, iqnsToAddOrRemove);
+ }
+
+ private static String[] getNewHostIqnsAdd(String[] iqns, String[] iqnsToAdd) {
+ List<String> lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList<String>();
+
+ 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<String> lstIqns = iqns != null ? new ArrayList<>(Arrays.asList(iqns)) : new ArrayList<String>();
+
+ if (iqnsToRemove != null) {
+ for (String iqnToRemove : iqnsToRemove) {
+ lstIqns.remove(iqnToRemove);
}
}
@@ -457,13 +573,44 @@
}
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<String, String> mapAttributes, long minIops, long maxIops, long burstIops)
{
- final Gson gson = new GsonBuilder().create();
+ JsonObject volumeToCreate = new JsonObject();
- 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);
+ 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);
+
+ if (mapAttributes != null && mapAttributes.size() > 0) {
+ JsonObject attributes = new JsonObject();
+
+ params.add("attributes", attributes);
+
+ Iterator<Map.Entry<String, String>> itr = mapAttributes.entrySet().iterator();
+
+ while (itr.hasNext()) {
+ Map.Entry<String, String> pair = itr.next();
+
+ attributes.addProperty(pair.getKey(), pair.getValue());
+ }
+ }
+
+ final Gson gson = new GsonBuilder().create();
String strVolumeToCreateJson = gson.toJson(volumeToCreate);
@@ -476,14 +623,46 @@
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<String, String> 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<Map.Entry<String, String>> itr = mapAttributes.entrySet().iterator();
+
+ while (itr.hasNext()) {
+ Map.Entry<String, String> pair = itr.next();
+
+ attributes.addProperty(pair.getKey(), pair.getValue());
+ }
+ }
+
+ final Gson gson = new GsonBuilder().create();
String strVolumeToModifyJson = gson.toJson(volumeToModify);
@@ -582,7 +761,7 @@
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 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;
- SnapshotToCreate snapshotToCreate = new SnapshotToCreate(lVolumeId, snapshotName);
+ 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<String, String> mapAttributes) {
+ JsonObject snapshotToCreate = new JsonObject();
+
+ snapshotToCreate.addProperty("method", "CreateSnapshot");
+
+ JsonObject params = new JsonObject();
+
+ snapshotToCreate.add("params", params);
+
+ params.addProperty("volumeID", lVolumeId);
+ params.addProperty("name", snapshotName);
+
+ if (mapAttributes != null && mapAttributes.size() > 0) {
+ JsonObject attributes = new JsonObject();
+
+ params.add("attributes", attributes);
+
+ Iterator<Map.Entry<String, String>> itr = mapAttributes.entrySet().iterator();
+
+ while (itr.hasNext()) {
+ Map.Entry<String, String> pair = itr.next();
+
+ attributes.addProperty(pair.getKey(), pair.getValue());
+ }
+ }
+
+ final Gson gson = new GsonBuilder().create();
String strSnapshotToCreateJson = gson.toJson(snapshotToCreate);
@@ -711,6 +931,38 @@
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 @@
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<String, String> mapAttributes) {
+ JsonObject cloneToCreate = new JsonObject();
- CloneToCreate cloneToCreate = new CloneToCreate(lVolumeId, lSnapshotId, cloneName);
+ 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);
+
+ Iterator<Map.Entry<String, String>> itr = mapAttributes.entrySet().iterator();
+
+ while (itr.hasNext()) {
+ Map.Entry<String, String> pair = itr.next();
+
+ attributes.addProperty(pair.getKey(), pair.getValue());
+ }
+ }
+
+ final Gson gson = new GsonBuilder().create();
String strCloneToCreateJson = gson.toJson(cloneToCreate);
@@ -749,7 +1031,33 @@
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)
@@ -1030,189 +1338,6 @@
}
@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
{
private final String method = "ListActiveVolumes";
@@ -1302,21 +1427,20 @@
}
@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;
}
}
}
@@ -1361,28 +1485,6 @@
}
@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
{
private final String method = "AddAccount";
@@ -1575,6 +1677,28 @@
}
}
+ @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 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 Result result;
private static final class Result {
- private long cloneID;
+ private long volumeID;
+ private long asyncHandle;
}
}
@@ -1681,6 +1819,15 @@
}
}
+ 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 5665b5d..9e6c1c7 100644
--- a/plugins/user-authenticators/ldap/pom.xml
+++ b/plugins/user-authenticators/ldap/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
@@ -96,13 +96,15 @@
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
- <version>0.7-groovy-2.0</version>
+ <version>1.0-groovy-2.4</version>
+ <scope>test</scope>
</dependency>
<!-- Optional dependencies for using Spock -->
<dependency> <!-- enables mocking of classes (in addition to interfaces) -->
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
- </dependency>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
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 1968f85..d845857 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 @@
@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 @@
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 @@
}
}
+ 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 @@
@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 63549f1..9fdd700 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 @@
@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<String, String> details;
@@ -112,7 +116,7 @@
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 @@
@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<LdapUser> users;
try {
if (StringUtils.isNotBlank(groupName)) {
@@ -161,6 +167,14 @@
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 ae3e706..477e80f 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 @@
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 5683b50..add39c5 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 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/src/org/apache/cloudstack/ldap/NoSuchLdapUserException.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/NoSuchLdapUserException.java
deleted file mode 100644
index d9bf13f..0000000
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/NoSuchLdapUserException.java
+++ /dev/null
@@ -1,31 +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.ldap;
-
-public class NoSuchLdapUserException extends Exception {
- private static final long serialVersionUID = 6782938919658010900L;
- private final String username;
-
- public NoSuchLdapUserException(final String username) {
- super("No such user: " + username);
- this.username = username;
- }
-
- public String getUsername() {
- return username;
- }
-}
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 514caeb..434151a 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 @@
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 dbdf646..0000000
--- 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 227b11a..a25eebe 100644
--- a/plugins/user-authenticators/md5/pom.xml
+++ b/plugins/user-authenticators/md5/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/user-authenticators/pbkdf2/pom.xml b/plugins/user-authenticators/pbkdf2/pom.xml
index ed3b163..67dfe5f 100644
--- a/plugins/user-authenticators/pbkdf2/pom.xml
+++ b/plugins/user-authenticators/pbkdf2/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/user-authenticators/plain-text/pom.xml b/plugins/user-authenticators/plain-text/pom.xml
index 70483df..1e4810d 100644
--- a/plugins/user-authenticators/plain-text/pom.xml
+++ b/plugins/user-authenticators/plain-text/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/plugins/user-authenticators/saml2/pom.xml b/plugins/user-authenticators/saml2/pom.xml
index 03ddc9e..e129967 100644
--- a/plugins/user-authenticators/saml2/pom.xml
+++ b/plugins/user-authenticators/saml2/pom.xml
@@ -23,16 +23,11 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
- <groupId>org.springframework.security.extensions</groupId>
- <artifactId>spring-security-saml2-core</artifactId>
- <version>1.0.0.RELEASE</version>
- </dependency>
- <dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
<version>${cs.opensaml.version}</version>
@@ -52,5 +47,11 @@
<artifactId>cloud-framework-config</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.11.0</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/plugins/user-authenticators/sha256salted/pom.xml b/plugins/user-authenticators/sha256salted/pom.xml
index df034c0..a403f73 100644
--- a/plugins/user-authenticators/sha256salted/pom.xml
+++ b/plugins/user-authenticators/sha256salted/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
</project>
diff --git a/pom.xml b/pom.xml
index bc5f151..326f363 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,7 +30,7 @@
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Apache CloudStack</name>
<description>Apache CloudStack is an IaaS (“Infrastructure as a Service”) cloud orchestration platform.</description>
@@ -51,10 +51,6 @@
</repository>
</repositories>
- <prerequisites>
- <maven>3.0.4</maven>
- </prerequisites>
-
<properties>
<cs.jdk.version>1.7</cs.jdk.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -62,7 +58,7 @@
<cs.log4j.version>1.2.17</cs.log4j.version>
<cs.log4j.extras.version>1.2.17</cs.log4j.extras.version>
- <cs.cglib.version>3.1</cs.cglib.version>
+ <cs.cglib.version>3.2.1</cs.cglib.version>
<cs.dbcp.version>1.4</cs.dbcp.version>
<cs.pool.version>1.6</cs.pool.version>
<cs.codec.version>1.10</cs.codec.version>
@@ -72,26 +68,26 @@
<cs.discovery.version>0.5</cs.discovery.version>
<cs.ejb.version>3.0</cs.ejb.version>
<!-- do not forget to also upgrade hamcrest library with junit -->
- <cs.junit.version>4.11</cs.junit.version>
+ <cs.junit.version>4.12</cs.junit.version>
<cs.hamcrest.version>1.3</cs.hamcrest.version>
<cs.junit.dataprovider.version>1.10.0</cs.junit.dataprovider.version>
<cs.bcprov.version>1.46</cs.bcprov.version>
- <cs.jsch.version>0.1.51</cs.jsch.version>
- <cs.jpa.version>2.1.0</cs.jpa.version>
+ <cs.jsch.version>0.1.53</cs.jsch.version>
+ <cs.jpa.version>2.1.1</cs.jpa.version>
<cs.jasypt.version>1.9.2</cs.jasypt.version>
- <cs.trilead.version>1.0.0-build217</cs.trilead.version>
- <cs.ehcache.version>2.6.9</cs.ehcache.version>
+ <cs.trilead.version>1.0.0-build220</cs.trilead.version>
+ <cs.ehcache.version>2.6.11</cs.ehcache.version>
<cs.gson.version>1.7.2</cs.gson.version>
<cs.guava-testlib.version>18.0</cs.guava-testlib.version>
- <cs.guava.version>18.0</cs.guava.version>
+ <cs.guava.version>19.0</cs.guava.version>
<cs.xapi.version>6.2.0-3.1</cs.xapi.version>
- <cs.httpclient.version>4.5</cs.httpclient.version>
- <cs.httpcore.version>4.4</cs.httpcore.version>
+ <cs.httpclient.version>4.5.2</cs.httpclient.version>
+ <cs.httpcore.version>4.4.4</cs.httpcore.version>
<cs.commons-httpclient.version>3.1</cs.commons-httpclient.version>
<cs.mysql.version>5.1.34</cs.mysql.version>
- <cs.xstream.version>1.4.7</cs.xstream.version>
+ <cs.xstream.version>1.4.9</cs.xstream.version>
<cs.xmlrpc.version>3.1.3</cs.xmlrpc.version>
- <cs.mail.version>1.4.7</cs.mail.version>
+ <cs.mail.version>1.5.0-b01</cs.mail.version>
<cs.axis.version>1.4</cs.axis.version>
<cs.axis2.version>1.5.6</cs.axis2.version>
<cs.rampart.version>1.5.1</cs.rampart.version>
@@ -99,32 +95,42 @@
<cs.neethi.version>2.0.4</cs.neethi.version>
<cs.servlet.version>2.5</cs.servlet.version>
<cs.jstl.version>1.2</cs.jstl.version>
+ <cs.jstl-api.version>1.2.1</cs.jstl-api.version>
<cs.selenium.server.version>1.0-20081010.060147</cs.selenium.server.version>
<cs.vmware.api.version>6.0</cs.vmware.api.version>
- <org.springframework.version>3.2.12.RELEASE</org.springframework.version>
- <cs.mockito.version>1.9.5</cs.mockito.version>
- <cs.powermock.version>1.5.3</cs.powermock.version>
- <cs.aws.sdk.version>1.10.34</cs.aws.sdk.version>
- <cs.jackson.version>2.6.3</cs.jackson.version>
+ <org.springframework.version>3.2.16.RELEASE</org.springframework.version>
+ <cs.mockito.version>1.10.19</cs.mockito.version>
+ <cs.powermock.version>1.6.4</cs.powermock.version>
+ <cs.aws.sdk.version>1.10.64</cs.aws.sdk.version>
+ <cs.jackson.version>2.7.1</cs.jackson.version>
<cs.lang.version>2.6</cs.lang.version>
<cs.commons-lang3.version>3.4</cs.commons-lang3.version>
<cs.commons-io.version>2.4</cs.commons-io.version>
- <cs.commons-validator.version>1.4.0</cs.commons-validator.version>
- <cs.reflections.version>0.9.9</cs.reflections.version>
- <cs.java-ipv6.version>0.15</cs.java-ipv6.version>
+ <cs.commons-fileupload.version>1.3.1</cs.commons-fileupload.version>
+ <cs.commons-collections.version>3.2.2</cs.commons-collections.version>
+ <cs.commons-validator.version>1.5.0</cs.commons-validator.version>
+ <cs.reflections.version>0.9.10</cs.reflections.version>
+ <cs.java-ipv6.version>0.16</cs.java-ipv6.version>
<cs.replace.properties>build/replace.properties</cs.replace.properties>
<cs.libvirt-java.version>0.5.1</cs.libvirt-java.version>
<cs.rados-java.version>0.2.0</cs.rados-java.version>
<cs.target.dir>target</cs.target.dir>
<cs.daemon.version>1.0.15</cs.daemon.version>
<cs.jna.version>4.0.0</cs.jna.version>
- <cs.checkstyle.version>2.11</cs.checkstyle.version>
- <cs.mycila.license.version>2.7</cs.mycila.license.version>
- <cs.findbugs.version>3.0.1</cs.findbugs.version>
- <cs.javadoc.version>2.10.1</cs.javadoc.version>
- <cs.opensaml.version>2.6.1</cs.opensaml.version>
+ <cs.checkstyle.version>2.17</cs.checkstyle.version>
+ <cs.mycila.license.version>2.11</cs.mycila.license.version>
+ <cs.findbugs.version>3.0.3</cs.findbugs.version>
+ <cs.javadoc.version>2.10.3</cs.javadoc.version>
+ <cs.opensaml.version>2.6.4</cs.opensaml.version>
<cs.xml-apis.version>1.4.01</cs.xml-apis.version>
<cs.joda-time.version>2.8.1</cs.joda-time.version>
+ <cs.batik.version>1.8</cs.batik.version>
+ <cs.servicemix.version>2.3.4_1</cs.servicemix.version>
+ <cs.jetty.version>9.2.15.v20160210</cs.jetty.version>
+ <cs.cxf.version>3.1.4</cs.cxf.version>
+ <cs.groovy.version>2.4.6</cs.groovy.version>
+ <cs.apache-jsp.version>9.2.15.v20160210</cs.apache-jsp.version>
+ <cs.nitro.version>10.1</cs.nitro.version>
</properties>
<distributionManagement>
@@ -217,6 +223,41 @@
<dependencyManagement>
<dependencies>
<dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>apache-jsp</artifactId>
+ <version>${cs.apache-jsp.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-all</artifactId>
+ <version>${cs.groovy.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ <version>${cs.bcprov.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.xmlgraphics</groupId>
+ <artifactId>batik-css</artifactId>
+ <version>${cs.batik.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.xmlgraphics</groupId>
+ <artifactId>batik-ext</artifactId>
+ <version>${cs.batik.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.xmlgraphics</groupId>
+ <artifactId>batik-util</artifactId>
+ <version>${cs.batik.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>${cs.commons-collections.version}</version>
+ </dependency>
+ <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${cs.mysql.version}</version>
@@ -254,26 +295,26 @@
<version>${cs.ehcache.version}</version>
</dependency>
<dependency>
- <groupId>commons-pool</groupId>
- <artifactId>commons-pool</artifactId>
- <version>${cs.pool.version}</version>
- </dependency>
- <dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${cs.codec.version}</version>
</dependency>
<dependency>
+ <groupId>commons-fileupload</groupId>
+ <artifactId>commons-fileupload</artifactId>
+ <version>${cs.commons-fileupload.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-pool</groupId>
+ <artifactId>commons-pool</artifactId>
+ <version>${cs.pool.version}</version>
+ </dependency>
+ <dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>${cs.commons-validator.version}</version>
</dependency>
<dependency>
- <groupId>org.bouncycastle</groupId>
- <artifactId>bcprov-jdk16</artifactId>
- <version>${cs.bcprov.version}</version>
- </dependency>
- <dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>${cs.jsch.version}</version>
@@ -333,7 +374,7 @@
<dependency>
<groupId>org.owasp.esapi</groupId>
<artifactId>esapi</artifactId>
- <version>2.1.0</version>
+ <version>2.1.0.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
@@ -398,17 +439,17 @@
<dependency>
<groupId>org.apache.servicemix.bundles</groupId>
<artifactId>org.apache.servicemix.bundles.snmp4j</artifactId>
- <version>2.3.1_1</version>
+ <version>${cs.servicemix.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
- <version>1.8.4</version>
+ <version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
- <version>1.8.4</version>
+ <version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.apache.axis</groupId>
@@ -433,12 +474,12 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
- <version>1.7.7</version>
+ <version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
- <version>1.7.7</version>
+ <version>1.7.21</version>
</dependency>
</dependencies>
</dependencyManagement>
@@ -770,6 +811,8 @@
<exclude>CONTRIBUTING.md</exclude>
<exclude>tools/docker/Dockerfile</exclude>
<exclude>tools/docker/supervisord.conf</exclude>
+ <exclude>.java-version</exclude>
+ <exclude>.python-version</exclude>
<exclude>.idea/</exclude>
<exclude>**/*.log</exclude>
<exclude>**/*.patch</exclude>
@@ -796,6 +839,8 @@
<exclude>**/*.json</exclude>
<exclude>build/build.number</exclude>
<exclude>services/console-proxy/server/js/jquery.js</exclude>
+ <exclude>debian/cloudstack-usage.dirs</exclude>
+ <exclude>debian/cloudstack-agent.dirs</exclude>
<exclude>debian/compat</exclude>
<exclude>debian/control</exclude>
<exclude>debian/dirs</exclude>
@@ -856,16 +901,14 @@
<exclude>ui/lib/qunit/qunit.js</exclude>
<exclude>ui/lib/reset.css</exclude>
<exclude>ui/lib/require.js</exclude>
+ <exclude>utils/testsmallfileinactive</exclude>
<exclude>systemvm/conf/agent.properties</exclude>
<exclude>systemvm/conf/environment.properties</exclude>
<exclude>systemvm/js/jquery.js</exclude>
<exclude>systemvm/patches/debian/systemvm.vmx</exclude>
<exclude>systemvm/patches/debian/config/root/.ssh/authorized_keys</exclude>
<exclude>systemvm/patches/debian/config/etc/apache2/httpd.conf</exclude>
- <exclude>systemvm/patches/debian/config/etc/apache2/ports.conf</exclude>
- <exclude>systemvm/patches/debian/config/etc/apache2/sites-available/default</exclude>
- <exclude>systemvm/patches/debian/config/etc/apache2/sites-available/default-ssl</exclude>
- <exclude>systemvm/patches/debian/config/etc/apache2/vhostexample.conf</exclude>
+ <exclude>systemvm/patches/debian/config/etc/apache2/vhost.template</exclude>
<exclude>systemvm/patches/debian/config/etc/dnsmasq.conf.tmpl</exclude>
<exclude>systemvm/patches/debian/config/etc/vpcdnsmasq.conf</exclude>
<exclude>systemvm/patches/debian/config/etc/ssh/sshd_config</exclude>
@@ -895,6 +938,7 @@
<exclude>**/.checkstyle</exclude>
<exclude>scripts/installer/windows/acs_license.rtf</exclude>
<exclude>**/*.md</exclude>
+ <exclude>test/integration/component/test_host_ha.sh</exclude>
</excludes>
</configuration>
</plugin>
diff --git a/python/lib/cloudutils/db.py b/python/lib/cloudutils/db.py
index 8fe3195..f2ce6f9 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 @@
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 @@
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 7812fff..dce85a0 100644
--- a/python/lib/cloudutils/serviceConfigServer.py
+++ b/python/lib/cloudutils/serviceConfigServer.py
@@ -120,7 +120,6 @@
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 78b1c4e..38cf8c7 100644
--- a/quickcloud/pom.xml
+++ b/quickcloud/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-maven-standard</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../maven-standard/pom.xml</relativePath>
</parent>
</project>
diff --git a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup b/requirements.txt
old mode 100755
new mode 100644
similarity index 66%
copy from systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
copy to requirements.txt
index 9d254d3..f5c7666
--- 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 3c9121d..f5aec48 100644
--- a/scripts/installer/windows/client.wxs
+++ b/scripts/installer/windows/client.wxs
@@ -595,9 +595,6 @@
<Component Id="cmp71D36BFB6B214FAAD323C31A1CE3BC19" Guid="{EF4C61E1-F77E-4E4D-80EA-131511E0804E}">
<File Id="fil44B623C422B90349A635A113C5F4D417" KeyPath="yes" Source="!(wix.SourceClient)\WEB-INF\classes\cloudmanagementserver.keystore" />
</Component>
- <Component Id="cmp19EB0E73466EB36D5AA02AB4CE8164B0" Guid="{D3EDCF5B-8A0F-444B-AE64-6C3EEE5F25F0}">
- <File Id="filAB20DD6954DD207821DD0311C1F48FAA" KeyPath="yes" Source="!(wix.SourceClient)\WEB-INF\classes\commands.properties" />
- </Component>
<Component Id="cmp68E096BB729948107692341D8202CC5A" Guid="{0D5D3AF3-0BC0-48EE-ABA3-AF07535169BF}">
<File Id="fil3E9BCB1A8CB8F8415FE3E71B65A94878" KeyPath="yes" Source="!(wix.SourceClient)\WEB-INF\classes\context.xml" />
</Component>
@@ -1058,7 +1055,7 @@
<File Id="fil47212822DDAFFCD71C79615CF4583BAF" KeyPath="yes" Source="!(wix.SourceClient)\WEB-INF\classes\scripts\vm\hypervisor\kvm\kvmheartbeat.sh" />
</Component>
<Component Id="cmpF2BBDD336FEC0B34B3C744ACF1E4B959" Guid="{56D8ECF7-49F8-4B26-A8F4-662252C0A647}">
- <File Id="filD809C7F728AC5D1BD36E7DB403BFA141" KeyPath="yes" Source="!(wix.SourceClient)\WEB-INF\classes\scripts\vm\hypervisor\kvm\patchviasocket.pl" />
+ <File Id="filD809C7F728AC5D1BD36E7DB403BFA141" KeyPath="yes" Source="!(wix.SourceClient)\WEB-INF\classes\scripts\vm\hypervisor\kvm\patchviasocket.py" />
</Component>
<Component Id="cmp2F4D4D81563D153E86B0A652A83D363A" Guid="{7BFC7637-E33D-4BC4-8B25-3CDEA601110C}">
<File Id="fil349420D6088A01C9F63E27634623F5BE" KeyPath="yes" Source="!(wix.SourceClient)\WEB-INF\classes\scripts\vm\hypervisor\kvm\setup_agent.sh" />
diff --git a/scripts/util/migrate-dynamicroles.py b/scripts/util/migrate-dynamicroles.py
new file mode 100755
index 0000000..cbb83f9
--- /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 == '\r\n' or line.startswith('#'):
+ continue
+ name, value = line.split('=')
+ apiMap[name.strip()] = value.strip().split(';')[-1]
+
+ # 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 7bcd245..0000000
--- 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 = <FILE>;
-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 0000000..c971d5d
--- /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 0000000..6b411d3
--- /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 915a8af..8283256 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 @@
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:
@@ -475,6 +493,7 @@
if vm_ip is not None:
execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -m set ! --set " + vmipsetName + " src -j DROP")
execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -m set --set " + vmipsetName + " src -p udp --dport 53 -j RETURN ")
+ execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -m set --set " + vmipsetName + " src -p tcp --dport 53 -j RETURN ")
execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-in " + vif + " -m set --set " + vmipsetName + " src -j " + vmchain_egress)
execute("iptables -A " + vmchain_default + " -m physdev --physdev-is-bridged --physdev-out " + vif + " -j " + vmchain)
execute("iptables -A " + vmchain + " -j DROP")
@@ -1029,6 +1048,14 @@
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/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup b/server/conf/cloudstack-catalina.logrotate
old mode 100755
new mode 100644
similarity index 66%
copy from systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
copy to server/conf/cloudstack-catalina.logrotate
index 9d254d3..498f690
--- a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
+++ b/server/conf/cloudstack-catalina.logrotate
@@ -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
@@ -7,9 +5,9 @@
# 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
@@ -17,11 +15,12 @@
# 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"
-[ "$output" != "" ] && logger -t cloud $output
-[ -z "$output" ] && logger -t cloud "No files removed"
-
-exit 0
+/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 427acd5..22c434d 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
@@ -72,6 +72,12 @@
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
+ <version>${cs.jstl.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet.jsp.jstl</groupId>
+ <artifactId>javax.servlet.jsp.jstl-api</artifactId>
+ <version>${cs.jstl-api.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
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 e39d918..b25c1c3 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}" />
</bean>
+ <bean id="roleManagerImpl" class="org.apache.cloudstack.acl.RoleManagerImpl" />
+
<bean id="accountManagerImpl" class="com.cloud.user.AccountManagerImpl">
<property name="userAuthenticators"
value="#{userAuthenticatorsRegistry.registered}" />
@@ -140,6 +142,10 @@
<bean id="oCFS2ManagerImpl" class="com.cloud.storage.OCFS2ManagerImpl" />
+ <bean id="outOfBandManagementServiceImpl" class="org.apache.cloudstack.outofbandmanagement.OutOfBandManagementServiceImpl">
+ <property name="outOfBandManagementDrivers" value="#{outOfBandManagementDriversRegistry.registered}" />
+ </bean>
+
<bean id="projectManagerImpl" class="com.cloud.projects.ProjectManagerImpl" />
<bean id="queryManagerImpl" class="com.cloud.api.query.QueryManagerImpl" />
diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java
index 9b9802a..e18d231 100644
--- a/server/src/com/cloud/alert/AlertManagerImpl.java
+++ b/server/src/com/cloud/alert/AlertManagerImpl.java
@@ -758,7 +758,8 @@
(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 1c55c67..d6b529f 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 @@
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 @@
@Inject
private NetworkACLDao networkACLDao;
@Inject
+ private RoleService roleService;
+ @Inject
private AccountService accountService;
@Inject
private ConfigurationManager configMgr;
@@ -768,6 +773,7 @@
// 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, 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 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 1708fa7..19db96a 100644
--- a/server/src/com/cloud/api/ApiResponseGsonHelper.java
+++ b/server/src/com/cloud/api/ApiResponseGsonHelper.java
@@ -68,7 +68,7 @@
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 1c25644..6a7f0ab 100644
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -191,8 +191,10 @@
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.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.Pod;
import com.cloud.dc.StorageNetworkIpRange;
@@ -200,6 +202,7 @@
import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.VlanVO;
import com.cloud.domain.Domain;
+import com.cloud.domain.DomainVO;
import com.cloud.event.Event;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
@@ -342,6 +345,8 @@
private SnapshotDataStoreDao _snapshotStoreDao;
@Inject
private PrimaryDataStoreDao _storagePoolDao;
+ @Inject
+ private ClusterDetailsDao _clusterDetailsDao;
@Override
public UserResponse createUserResponse(User user) {
@@ -549,6 +554,10 @@
UserVm vm = ApiDBUtils.findUserVmById(vmSnapshot.getVmId());
if (vm != null) {
vmSnapshotResponse.setVirtualMachineid(vm.getUuid());
+ DataCenterVO datacenter = ApiDBUtils.findZoneById(vm.getDataCenterId());
+ if (datacenter != null) {
+ vmSnapshotResponse.setZoneId(datacenter.getUuid());
+ }
}
if (vmSnapshot.getParent() != null) {
VMSnapshot vmSnapshotParent = ApiDBUtils.getVMSnapshotById(vmSnapshot.getParent());
@@ -562,6 +571,16 @@
vmSnapshotResponse.setProjectId(project.getUuid());
vmSnapshotResponse.setProjectName(project.getName());
}
+ Account account = ApiDBUtils.findAccountById(vmSnapshot.getAccountId());
+ if (account != null) {
+ vmSnapshotResponse.setAccountName(account.getAccountName());
+ }
+ DomainVO domain = ApiDBUtils.findDomainById(vmSnapshot.getDomainId());
+ if (domain != null) {
+ vmSnapshotResponse.setDomainId(domain.getUuid());
+ vmSnapshotResponse.setDomainName(domain.getName());
+ }
+
vmSnapshotResponse.setCurrent(vmSnapshot.getCurrent());
vmSnapshotResponse.setType(vmSnapshot.getType().toString());
vmSnapshotResponse.setObjectName("vmsnapshot");
@@ -1053,6 +1072,7 @@
String memoryOvercommitRatio = ApiDBUtils.findClusterDetails(cluster.getId(), "memoryOvercommitRatio");
clusterResponse.setCpuOvercommitRatio(cpuOvercommitRatio);
clusterResponse.setMemoryOvercommitRatio(memoryOvercommitRatio);
+ clusterResponse.setResourceDetails(_clusterDetailsDao.findDetails(cluster.getId()));
if (showCapacities != null && showCapacities) {
List<SummedCapacity> capacities = ApiDBUtils.getCapacityByClusterPodZone(null, null, cluster.getId());
@@ -1388,7 +1408,7 @@
@Override
public List<TemplateResponse> createTemplateResponses(ResponseView view, VirtualMachineTemplate result, Long zoneId, boolean readyOnly) {
List<TemplateJoinVO> 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 689ae9c..0651d16 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;
- List<PluggableService> _pluggableServices;
- List<APIChecker> _apiAccessCheckers;
+ private List<PluggableService> pluggableServices;
+
+ private List<APIChecker> 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 @@
private static ExecutorService s_executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new NamedThreadFactory(
"ApiServer"));
@Inject
- MessageBus _messageBus;
-
- public ApiServer() {
- }
+ private MessageBus messageBus;
@Override
public boolean configure(final String name, final Map<String, Object> 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 @@
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<Map<String, String>>(){}.getType();
+ Map<String, String> 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 @@
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<String, String> configs = _configDao.getConfiguration("management-server", new HashMap<String, String>());
+ Map<String, String> configs = configDao.getConfiguration("management-server", new HashMap<String, String>());
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 @@
@Override
public boolean start() {
Integer apiPort = null; // api port, null by default
- final SearchCriteria<ConfigurationVO> sc = _configDao.createSearchCriteria();
+ final SearchCriteria<ConfigurationVO> sc = configDao.createSearchCriteria();
sc.addAnd("name", SearchCriteria.Op.EQ, Config.IntegrationAPIPort.key());
- final List<ConfigurationVO> values = _configDao.search(sc, null);
+ final List<ConfigurationVO> 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 @@
}
}
- final Map<String, String> configs = _configDao.getConfiguration();
+ final Map<String, String> 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<Class<?>> cmdClasses = new HashSet<Class<?>>();
- 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 @@
}
- 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 @@
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 @@
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<String, String> paramMap = new HashMap<String, String>();
@@ -562,7 +565,7 @@
} 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 @@
} 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 @@
} 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 @@
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 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 @@
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 @@
// 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 @@
List<? extends AsyncJob> 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 @@
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 @@
txn.close();
User user = null;
// verify there is a user with this api key
- final Pair<User, Account> userAcctPair = _accountMgr.findUserByApiKey(apiKey);
+ final Pair<User, Account> 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 @@
@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 @@
final Map<String, Object[]> 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 @@
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 @@
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 @@
@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 @@
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 @@
// 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 @@
_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 @@
return responseText;
}
- public List<PluggableService> getPluggableServices() {
- return _pluggableServices;
- }
-
@Inject
public void setPluggableServices(final List<PluggableService> pluggableServices) {
- _pluggableServices = pluggableServices;
- }
-
- public List<APIChecker> getApiAccessCheckers() {
- return _apiAccessCheckers;
+ this.pluggableServices = pluggableServices;
}
@Inject
public void setApiAccessCheckers(final List<APIChecker> 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 51827da..6c83698 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 @@
"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 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 @@
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 @@
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 @@
}
}
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 @@
}
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 @@
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 @@
}
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 @@
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 @@
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 099c0c9..feefaab 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 @@
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<Object, AccessType> entitiesToAccess = new HashMap<Object, AccessType>();
@@ -112,6 +163,7 @@
// 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 @@
for (final Class<?> entity : entities) {
CallContext.current().putContextParameter(entity, internalId);
}
+ validateNaturalNumber(internalId, annotation.name());
return internalId;
}
}
@@ -452,6 +505,7 @@
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 166af4b..9246edd 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<String, Class<?>> s_apiNameCmdClassMap = new HashMap<String, Class<?>>();
private static LinkedHashMap<Object, String> s_allApiCommands = new LinkedHashMap<Object, String>();
- private static LinkedHashMap<Object, String> s_domainAdminApiCommands = new LinkedHashMap<Object, String>();
- private static LinkedHashMap<Object, String> s_regularUserApiCommands = new LinkedHashMap<Object, String>();
private static TreeMap<Object, String> s_allApiCommandsSorted = new TreeMap<Object, String>();
- private static TreeMap<Object, String> s_domainAdminApiCommandsSorted = new TreeMap<Object, String>();
- private static TreeMap<Object, String> s_regularUserApiCommandsSorted = new TreeMap<Object, String>();
- private static String s_dirName = "";
private static final List<String> AsyncResponses = setAsyncResponses();
private static List<String> setAsyncResponses() {
@@ -123,71 +116,22 @@
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<String> argsList = Arrays.asList(args);
Iterator<String> 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<String, Class<?>> 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 @@
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");
+ ObjectOutputStream rootAdmin = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + "apiSummary.xml"), "commands");
+ ObjectOutputStream rootAdminSorted = xs.createObjectOutputStream(new FileWriter(rootAdminDirName + "/" + "apiSummarySorted.xml"), "commands");
- // Write commands in the order they are represented in commands.properties.in file
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 @@
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 0000000..c7b3222
--- /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<Z>
+ * @param ids ids list, class type List<T>
+ */
+ protected <Z,T> void setIdsListToSearchCriteria(SearchCriteria<Z> sc, List<T> ids){
+ if (ids != null && !ids.isEmpty()) {
+ sc.setParameters("idIN", ids.toArray());
+ }
+ }
+
+ /***
+ * Mutually exclusive parameters id and ids for API calls.<br/>
+ * 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<T>
+ * @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 <T> List<T> getIdsListFromCmd(T id, List<T> ids){
+ List<T> 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<T>();
+ 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 0e3f3f2..95f260d 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 @@
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 @@
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 @@
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 @@
Long zoneId = cmd.getZoneId();
Long podId = cmd.getPodId();
+ List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
+
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(
cmd.getDomainId(), cmd.isRecursive(), null);
_accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts,
@@ -1754,6 +1767,7 @@
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 @@
sc.setParameters("display", display);
}
+ setIdsListToSearchCriteria(sc, ids);
+
sc.setParameters("systemUse", 1);
if (tags != null && !tags.isEmpty()) {
@@ -3077,14 +3093,15 @@
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<List<TemplateJoinVO>, 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<Account> permittedAccounts, Account caller, ListProjectResourcesCriteria listProjectResourcesCriteria,
- Map<String, String> tags, boolean showRemovedTmpl) {
+ Map<String, String> tags, boolean showRemovedTmpl, List<Long> ids) {
// check if zone is configured, if not, just return empty list
List<HypervisorType> hypers = null;
@@ -3104,6 +3121,9 @@
SearchBuilder<TemplateJoinVO> 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<TemplateJoinVO> sc = sb.create();
// verify templateId parameter and specially handle it
@@ -3149,6 +3169,8 @@
// 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 @@
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 be3f5b4..6aecb81 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 @@
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 0000000..e6760d8
--- /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<T extends BaseViewWithTagInformationVO, Z extends BaseResponseWithTagInformation> extends GenericDaoBase<T, Long> {
+
+ /**
+ * 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 970c2b2..6c15a8b 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 @@
@Inject
private ConfigurationDao _configDao;
@Inject
- private HostDao hostDao;
+ private HostDetailsDao hostDetailsDao;
+ @Inject
+ private OutOfBandManagementDao outOfBandManagementDao;
private final SearchBuilder<HostJoinVO> hostSearch;
@@ -189,11 +190,7 @@
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<String, String> 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 @@
}
}
+ 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 5444eca..38120af 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<TemplateJoinVO, Long> implements TemplateJoinDao {
+public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<TemplateJoinVO, TemplateResponse> implements TemplateJoinDao {
public static final Logger s_logger = Logger.getLogger(TemplateJoinDaoImpl.class);
@@ -188,10 +187,7 @@
// 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 @@
// 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 7983065..106cd25 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<UserVmJoinVO, Long> implements UserVmJoinDao {
+public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJoinVO, UserVmResponse> implements UserVmJoinDao {
public static final Logger s_logger = Logger.getLogger(UserVmJoinDaoImpl.class);
@Inject
@@ -202,20 +198,16 @@
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 @@
// 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 @@
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 6d8a8ab..73e0c6d 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<VolumeJoinVO, Long> implements VolumeJoinDao {
+public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation<VolumeJoinVO, VolumeResponse> implements VolumeJoinDao {
public static final Logger s_logger = Logger.getLogger(VolumeJoinDaoImpl.class);
@Inject
@@ -81,14 +79,18 @@
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 @@
}
}
- 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 @@
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 @@
// 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 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 8d642ed..f251abc 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 @@
@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 @@
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 0000000..ec2947a
--- /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 48ac531..dcd058f 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 @@
@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 @@
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 99f61c3..6d9f038 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 @@
@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 2c1ff47..6758552 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 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 834a9ce..43a9c3b 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 @@
@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;
@@ -260,11 +223,6 @@
}
@Override
- public long getId() {
- return id;
- }
-
- @Override
public String getUuid() {
return uuid;
}
@@ -343,46 +301,6 @@
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 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 0e66ca0..e6b1ace 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 @@
@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 @@
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 54a48fb..7ff557c 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 @@
@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;
@@ -405,11 +375,6 @@
}
@Override
- public long getId() {
- return id;
- }
-
- @Override
public String getUuid() {
return uuid;
}
@@ -776,46 +741,6 @@
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 @@
@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 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 d9c482c..77785b1 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 @@
@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;
@@ -296,11 +259,6 @@
}
@Override
- public long getId() {
- return id;
- }
-
- @Override
public String getUuid() {
return uuid;
}
@@ -563,46 +521,6 @@
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 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 59426e6..2b9717d 100644
--- a/server/src/com/cloud/api/response/ApiResponseSerializer.java
+++ b/server/src/com/cloud/api/response/ApiResponseSerializer.java
@@ -251,7 +251,7 @@
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 55ed917..d0ae3e9 100644
--- a/server/src/com/cloud/capacity/CapacityManagerImpl.java
+++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java
@@ -549,28 +549,35 @@
return getUsedBytes(pool);
}
else {
- // Get size for all the non-destroyed volumes
+ // Get size for all the non-destroyed volumes.
Pair<Long, Long> 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<VMTemplateStoragePoolVO> templatePoolVOs;
- templatePoolVOs = _templatePoolDao.listByPoolId(pool.getId());
+ boolean tmpInstalled = false;
+ // Iterate through all templates on this storage pool.
+ List<VMTemplateStoragePoolVO> 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;
}
@@ -982,6 +989,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException {
// TODO Auto-generated method stub
@@ -994,6 +1005,14 @@
}
@Override
+ public void processHostAboutToBeRemoved(long hostId) {
+ }
+
+ @Override
+ public void processHostRemoved(long hostId, long clusterId) {
+ }
+
+ @Override
public boolean isRecurring() {
// TODO Auto-generated method stub
return false;
@@ -1082,6 +1101,6 @@
@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 d8a3e6a..453960d 100644
--- a/server/src/com/cloud/capacity/ComputeCapacityListener.java
+++ b/server/src/com/cloud/capacity/ComputeCapacityListener.java
@@ -56,6 +56,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host server, StartupCommand startup, boolean forRebalance) throws ConnectionException {
if (!(startup instanceof StartupRoutingCommand)) {
return;
@@ -69,6 +73,14 @@
}
@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 f83cbd3..e2d5a5d 100644
--- a/server/src/com/cloud/capacity/StorageCapacityListener.java
+++ b/server/src/com/cloud/capacity/StorageCapacityListener.java
@@ -59,6 +59,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host server, StartupCommand startup, boolean forRebalance) throws ConnectionException {
if (!(startup instanceof StartupStorageCommand)) {
@@ -82,6 +86,14 @@
}
@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 b473f7e..70afd8a 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 <a href="https://cwiki.apache.org/confluence/display/CLOUDSTACK/QuickCloud">QuickCloud</a>.
+ */
public class AgentBasedStandaloneConsoleProxyManager extends AgentBasedConsoleProxyManager {
private static final Logger s_logger = Logger.getLogger(AgentBasedStandaloneConsoleProxyManager.class);
@@ -58,26 +61,30 @@
}
}
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 2c1bbd6..77c9d5a 100644
--- a/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java
+++ b/server/src/com/cloud/consoleproxy/ConsoleProxyListener.java
@@ -64,6 +64,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) {
_proxyMgr.onAgentConnect(host, cmd);
@@ -79,6 +83,14 @@
}
@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 f3766c3..1817ade 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,6 +667,78 @@
return null;
}
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * 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.");
+ }
+
+ if (dc.isSecurityGroupEnabled()) {
+ List<NetworkVO> 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<NetworkVO> 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 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<NetworkVO> 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<String, Object> createProxyInstance(long dataCenterId, VMTemplateVO template) throws ConcurrentOperationException {
long id = _consoleProxyDao.getNextInSequence(Long.class, "id");
@@ -675,26 +748,7 @@
DataCenterDeployment plan = new DataCenterDeployment(dataCenterId);
- NetworkVO defaultNetwork = null;
- if (dc.getNetworkType() == NetworkType.Advanced && dc.isSecurityGroupEnabled()) {
- List<NetworkVO> 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<NetworkVO> 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<? extends NetworkOffering> offerings =
_networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemControlNetwork, NetworkOffering.SystemManagementNetwork);
@@ -1127,7 +1181,7 @@
}
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 f5d2af9..ef0ad19 100644
--- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
+++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java
@@ -900,6 +900,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException {
if (!(cmd instanceof StartupRoutingCommand)) {
return;
@@ -921,6 +925,14 @@
}
@Override
+ public void processHostAboutToBeRemoved(long hostId) {
+ }
+
+ @Override
+ public void processHostRemoved(long hostId, long clusterId) {
+ }
+
+ @Override
public boolean isRecurring() {
// TODO Auto-generated method stub
return false;
@@ -1222,7 +1234,8 @@
requestVolumes = new ArrayList<Volume>();
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 ac7dbd1..53d79f7 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 @@
"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 4bdb2bc..2aa9b04 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 @@
@Inject
HostDao _hostDao = null;
@Inject
+ private HostDetailsDao hostDetailsDao;
+ @Inject
HostPodDao _podDao = null;
@Inject
DataCenterDetailsDao _zoneDetailsDao = null;
@@ -319,6 +323,25 @@
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 fb14dc4..e48c1f5 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 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 48be8f2..13a1a64 100644
--- a/server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java
+++ b/server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java
@@ -86,6 +86,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) {
}
@@ -96,6 +100,14 @@
}
@Override
+ public void processHostAboutToBeRemoved(long hostId) {
+ }
+
+ @Override
+ public void processHostRemoved(long hostId, long clusterId) {
+ }
+
+ @Override
public boolean isRecurring() {
// TODO Auto-generated method stub
return false;
diff --git a/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java b/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java
index 59b398f..200b279 100644
--- a/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java
+++ b/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java
@@ -340,6 +340,15 @@
@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 @@
}
}
- 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 d4da5fa..e65adb6 100644
--- a/server/src/com/cloud/network/IpAddressManagerImpl.java
+++ b/server/src/com/cloud/network/IpAddressManagerImpl.java
@@ -401,7 +401,7 @@
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 a0356ca..b7adecd 100644
--- a/server/src/com/cloud/network/NetworkUsageManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkUsageManagerImpl.java
@@ -484,6 +484,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) {
if (cmd instanceof StartupTrafficMonitorCommand) {
long agentId = agent.getId();
@@ -499,6 +503,14 @@
}
@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 1eeb3a3..e263c54 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;
}
@@ -68,6 +66,18 @@
}
@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) {
if (((StartupRoutingCommand)cmd).getHypervisorType() == HypervisorType.KVM || ((StartupRoutingCommand)cmd).getHypervisorType() == HypervisorType.XenServer ||
diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
index f7947d5..3332393 100644
--- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
+++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
@@ -251,159 +251,98 @@
Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualMachine> {
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 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;
+ @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<String> _guestOSNeedGatewayOnNonDefaultNetwork = new HashSet<String>();
+ private final Set<String> _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<Long> _vrUpdateQueue = null;
+ private BlockingQueue<Long> _vrUpdateQueue;
@Override
public VirtualRouter destroyRouter(final long routerId, final Account caller, final Long callerUserId) throws ResourceUnavailableException, ConcurrentOperationException {
@@ -586,10 +525,7 @@
}
}
- 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 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");
@@ -2365,6 +2298,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(final Host host, final StartupCommand cmd, final boolean forRebalance) throws ConnectionException {
final List<DomainRouterVO> routers = _routerDao.listIsolatedByHostId(host.getId());
for (DomainRouterVO router : routers) {
@@ -2399,6 +2336,14 @@
}
@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 af963b1..32186cc 100644
--- a/server/src/com/cloud/network/security/SecurityGroupListener.java
+++ b/server/src/com/cloud/network/security/SecurityGroupListener.java
@@ -81,7 +81,7 @@
@Override
public boolean processAnswers(long agentId, long seq, Answer[] answers) {
List<Long> affectedVms = new ArrayList<Long>();
- int commandNum = 0;
+
for (Answer ans : answers) {
if (ans instanceof SecurityGroupRuleAnswer) {
SecurityGroupRuleAnswer ruleAnswer = (SecurityGroupRuleAnswer)ans;
@@ -106,7 +106,7 @@
}
}
}
- commandNum++;
+
if (_workTracker != null)
_workTracker.processAnswers(agentId, seq, answers);
}
@@ -152,6 +152,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) {
if (s_logger.isInfoEnabled())
s_logger.info("Received a host startup notification");
@@ -189,6 +193,14 @@
}
@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) {
_workTracker.processTimeout(agentId, seq);
diff --git a/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java b/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java
index 64204fe..64bbb75 100644
--- a/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java
+++ b/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java
@@ -182,8 +182,6 @@
List<String> 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 @@
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 18fbfe2..706f4c4 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 @@
svcProviderMap.put(Service.NetworkACL, defaultProviders);
}
- svcProviderMap.put(Service.Gateway, defaultProviders);
-
if (serviceProviders != null) {
for (final Entry<String, List<String>> serviceEntry : serviceProviders.entrySet()) {
final Network.Service service = Network.Service.getService(serviceEntry.getKey());
@@ -425,6 +424,12 @@
}
}
+ // add gateway provider (if sourceNat provider is enabled)
+ final Set<Provider> 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 ee66506..a8dd225 100644
--- a/server/src/com/cloud/projects/ProjectManagerImpl.java
+++ b/server/src/com/cloud/projects/ProjectManagerImpl.java
@@ -211,7 +211,7 @@
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 359bccf..2bb1596 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 @@
_hostTagsDao.persist(host.getId(), hostTags);
}
hosts.add(host);
+
+ _agentMgr.notifyMonitorsOfNewlyAddedHost(host.getId());
+
return hosts;
}
}
@@ -843,10 +847,13 @@
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 @@
}
});
+ if (clusterId != null) {
+ _agentMgr.notifyMonitorsOfRemovedHost(host.getId(), clusterId);
+ }
+
return true;
}
@@ -1168,7 +1179,8 @@
// 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);
}
@@ -1350,6 +1362,11 @@
}
@Override
+ public DataCenter getZone(Long zoneId) {
+ return _dcDao.findById(zoneId);
+ }
+
+ @Override
public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
_defaultSystemVMHypervisor = HypervisorType.getType(_configDao.getValue(Config.SystemVMDefaultHypervisor.toString()));
_gson = GsonHelper.getGson();
@@ -1570,17 +1587,35 @@
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<String, String> details, List<String> 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 @@
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 @@
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<HostVO> 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 @@
}
}
+ // find out if the host we want to connect to is new (so we can send an event)
+ boolean newHost = getNewHost(cmds) == null;
+
host = createHostVO(cmds, resource, details, hostTags, ResourceStateAdapter.Event.CREATE_HOST_VO_FOR_DIRECT_CONNECT);
+
if (host != null) {
- created = _agentMgr.handleDirectConnectAgent(host, cmds, resource, forRebalance);
+ created = _agentMgr.handleDirectConnectAgent(host, cmds, resource, forRebalance, newHost);
/* reload myself from database */
host = _hostDao.findById(host.getId());
}
@@ -1866,12 +1969,19 @@
}
host = null;
+ boolean newHost = false;
+
final GlobalLock addHostLock = GlobalLock.getInternLock("AddHostLock");
+
try {
if (addHostLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) {
// to safely determine first host in cluster in multi-MS scenario
try {
+ // find out if the host we want to connect to is new (so we can send an event)
+ newHost = getNewHost(cmds) == null;
+
host = createHostVO(cmds, resource, details, hostTags, ResourceStateAdapter.Event.CREATE_HOST_VO_FOR_DIRECT_CONNECT);
+
if (host != null) {
// if first host in cluster no need to defer agent creation
deferAgentCreation = !isFirstHostInCluster(host);
@@ -1886,7 +1996,7 @@
if (host != null) {
if (!deferAgentCreation) { // if first host in cluster then
- created = _agentMgr.handleDirectConnectAgent(host, cmds, resource, forRebalance);
+ created = _agentMgr.handleDirectConnectAgent(host, cmds, resource, forRebalance, newHost);
host = _hostDao.findById(host.getId()); // reload
} else {
host = _hostDao.findById(host.getId()); // reload
@@ -2112,11 +2222,13 @@
/* TODO: move to listener */
_haMgr.cancelScheduledMigrations(host);
+
+ boolean vms_migrating = false;
final List<VMInstanceVO> 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 @@
_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 16e4ff0..13f98a2 100644
--- a/server/src/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/com/cloud/server/ConfigurationServerImpl.java
@@ -449,7 +449,7 @@
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 @@
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 e4ae8e1..60b44d7 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 @@
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 ee9e41d..b5d67c7 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,11 +34,15 @@
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.commons.lang.StringUtils;
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;
@@ -91,6 +96,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;
@@ -152,6 +158,8 @@
@Inject
private HostDao _hostDao;
@Inject
+ private OutOfBandManagementDao outOfBandManagementDao;
+ @Inject
private UserVmDao _userVmDao;
@Inject
private VolumeDao _volsDao;
@@ -168,6 +176,8 @@
@Inject
private ResourceManager _resourceMgr;
@Inject
+ private OutOfBandManagementService outOfBandManagementService;
+ @Inject
private ConfigurationDao _configDao;
@Inject
private EndPointSelector _epSelector;
@@ -199,6 +209,8 @@
private ServiceOfferingDao _serviceOfferingDao;
@Inject
private HostGpuGroupsDao _hostGpuGroupsDao;
+ @Inject
+ private ImageStoreDetailsUtil imageStoreDetailsUtil;
private ConcurrentHashMap<Long, HostStats> _hostStats = new ConcurrentHashMap<Long, HostStats>();
private final ConcurrentHashMap<Long, VmStats> _VmStats = new ConcurrentHashMap<Long, VmStats>();
@@ -207,6 +219,7 @@
private ConcurrentHashMap<Long, StorageStats> _storagePoolStats = new ConcurrentHashMap<Long, StorageStats>();
long hostStatsInterval = -1L;
+ long hostOutOfBandManagementStatsInterval = -1L;
long hostAndVmStatsInterval = -1L;
long storageStatsInterval = -1L;
long volumeStatsInterval = -1L;
@@ -250,8 +263,9 @@
}
private void init(Map<String, String> 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);
@@ -299,6 +313,10 @@
_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);
}
@@ -417,6 +435,36 @@
}
}
+ class HostOutOfBandManagementStatsCollector extends ManagedContextRunnable {
+ @Override
+ protected void runInContext() {
+ try {
+ s_logger.debug("HostOutOfBandManagementStatsCollector is running...");
+ List<OutOfBandManagementVO> 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() {
@@ -469,6 +517,9 @@
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);
}
@@ -489,6 +540,10 @@
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());
+
}
}
@@ -722,7 +777,8 @@
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());
@@ -769,6 +825,7 @@
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 0000000..7107650
--- /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.<br/>
+ * 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 <br/>
+ * {@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<String, String> 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.<br/>
+ * 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 <br/>
+ * {@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 1478910..2d9f544 100755
--- a/server/src/com/cloud/storage/ImageStoreUploadMonitorImpl.java
+++ b/server/src/com/cloud/storage/ImageStoreUploadMonitorImpl.java
@@ -115,7 +115,7 @@
public boolean configure(String name, Map<String, Object> 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;
}
@@ -153,6 +153,14 @@
}
@Override
+ public void processHostAboutToBeRemoved(long hostId) {
+ }
+
+ @Override
+ public void processHostRemoved(long hostId, long clusterId) {
+ }
+
+ @Override
public boolean isRecurring() {
return false;
}
@@ -168,6 +176,10 @@
}
@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 a66515e..941e505 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() {
@@ -72,6 +64,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
@DB
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException {
if (!(cmd instanceof StartupStorageCommand)) {
@@ -103,6 +99,14 @@
}
@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 7a927b2..9e4c3ec 100644
--- a/server/src/com/cloud/storage/ResizeVolumePayload.java
+++ b/server/src/com/cloud/storage/ResizeVolumePayload.java
@@ -21,16 +21,21 @@
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 97a4db6..c0dda25 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 @@
_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 @@
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 @@
@Override
public boolean storagePoolHasEnoughSpace(List<Volume> volumes, StoragePool pool) {
+ return storagePoolHasEnoughSpace(volumes, pool, null);
+ }
+
+ @Override
+ public boolean storagePoolHasEnoughSpace(List<Volume> volumes, StoragePool pool, Long clusterId) {
if (volumes == null || volumes.isEmpty()) {
return false;
}
@@ -1712,10 +1718,11 @@
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 @@
// 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 @@
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 @@
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 @@
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 9243503..77ecc2a 100644
--- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
@@ -841,6 +841,7 @@
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 @@
// 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 @@
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 @@
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 @@
volume.setSize(newSize);
volume.setMinIops(newMinIops);
volume.setMaxIops(newMaxIops);
+ volume.setHypervisorSnapshotReserve(newHypervisorSnapshotReserve);
if (newDiskOffering != null) {
volume.setDiskOfferingId(cmd.getNewDiskOfferingId());
@@ -1040,13 +1042,13 @@
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<Volume> 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 @@
}
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 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 @@
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 @@
}
}
- 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<VolumeApiResult> 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 @@
_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<VolumeApiResult> 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 @@
return new VmJobVolumeOutcome(workJob, volumeId);
}
- public Outcome<Volume> 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<Volume> 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 @@
// 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 @@
@ReflectionUse
private Pair<JobInfo.Status, String> 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, String>(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 814ce3c..51f9d42 100644
--- a/server/src/com/cloud/storage/download/DownloadListener.java
+++ b/server/src/com/cloud/storage/download/DownloadListener.java
@@ -270,9 +270,7 @@
}
@Override
- public boolean processDisconnect(long agentId, com.cloud.host.Status state) {
- setDisconnected();
- return true;
+ public void processHostAdded(long hostId) {
}
@Override
@@ -310,6 +308,20 @@
}
}
+ @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 286d994..0b14918 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 @@
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 @@
}
@Override
- public synchronized boolean processDisconnect(long agentId, Status state) {
- return true;
+ public void processHostAdded(long hostId) {
+ List<DataStoreProvider> 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
@@ -114,6 +136,55 @@
}
@Override
+ public synchronized boolean processDisconnect(long agentId, Status state) {
+ return true;
+ }
+
+ @Override
+ public void processHostAboutToBeRemoved(long hostId) {
+ List<DataStoreProvider> 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<DataStoreProvider> 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 fe15d30..eeef434 100644
--- a/server/src/com/cloud/storage/listener/StorageSyncListener.java
+++ b/server/src/com/cloud/storage/listener/StorageSyncListener.java
@@ -51,6 +51,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) {
}
@@ -61,6 +65,14 @@
}
@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 43613e7..b78a548 100644
--- a/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java
+++ b/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java
@@ -66,6 +66,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) {
if ((cmd instanceof StartupStorageCommand)) {
StartupStorageCommand scmd = (StartupStorageCommand)cmd;
@@ -92,6 +96,14 @@
}
@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 bee2cf5..9a363be 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;
@@ -513,6 +514,8 @@
}
}
+ List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
+
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null);
_accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first();
@@ -527,6 +530,7 @@
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);
@@ -566,6 +570,8 @@
sc.setParameters("dataCenterId", zoneId);
}
+ setIdsListToSearchCriteria(sc, ids);
+
if (name != null) {
sc.setParameters("name", "%" + name + "%");
}
@@ -1009,9 +1015,14 @@
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) {
@@ -1026,6 +1037,30 @@
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<String, String> 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<String, Object> params) throws ConfigurationException {
diff --git a/server/src/com/cloud/storage/upload/UploadListener.java b/server/src/com/cloud/storage/upload/UploadListener.java
index f6ad815..838676e 100644
--- a/server/src/com/cloud/storage/upload/UploadListener.java
+++ b/server/src/com/cloud/storage/upload/UploadListener.java
@@ -113,8 +113,6 @@
private DataStore sserver;
- private boolean uploadActive = true;
-
private UploadDao uploadDao;
private final UploadMonitorImpl uploadMonitor;
@@ -251,6 +249,10 @@
}
@Override
+ public void processHostAdded(long hostId) {
+ }
+
+ @Override
public void processConnect(Host agent, StartupCommand cmd, boolean forRebalance) {
if (!(cmd instanceof StartupStorageCommand)) {
return;
@@ -270,7 +272,6 @@
}
public void setUploadInactive(Status reason) {
- uploadActive = false;
uploadMonitor.handleUploadEvent(accountId, typeName, type, uploadId, reason, eventId);
}
@@ -295,6 +296,14 @@
}
@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 e614142..c03db35 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 @@
private UserVmJoinDao _userVmJoinDao;
@Inject
private SnapshotDataStoreDao _snapshotStoreDao;
-
+ @Inject
+ private ImageStoreDao _imgStoreDao;
@Inject
MessageBus _messageBus;
@@ -276,6 +280,7 @@
@Inject
private EndPointSelector selector;
+
private TemplateAdapter getAdapter(HypervisorType type) {
TemplateAdapter adapter = null;
if (type == HypervisorType.BareMetal) {
@@ -689,7 +694,9 @@
}
try {
+ templateStoragePoolRef.setTemplateSize(0);
templateStoragePoolRef.setDownloadState(VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED);
+
_tmpltPoolDao.update(templateStoragePoolRefId, templateStoragePoolRef);
} finally {
_tmpltPoolDao.releaseFromLockTable(templateStoragePoolRefId);
@@ -873,41 +880,55 @@
@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<TemplateApiResult> 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 @@
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 @@
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 @@
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<ImageStoreVO> stores = _imgStoreDao.findRegionImageStores();
+ if (!CollectionUtils.isEmpty(stores)) {
+ privateTemplate.setCrossZones(true);
+ }
+
privateTemplate.setSourceTemplateId(sourceTemplateId);
VMTemplateVO template = _tmpltDao.persist(privateTemplate);
@@ -1975,7 +2007,7 @@
@Override
public ConfigKey<?>[] getConfigKeys() {
- return new ConfigKey<?>[] {AllowPublicUserTemplates};
+ return new ConfigKey<?>[] {AllowPublicUserTemplates, TemplatePreloaderPoolSize};
}
public List<TemplateAdapter> getTemplateAdapters() {
diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java
index 7b9e093..9789a22 100644
--- a/server/src/com/cloud/user/AccountManager.java
+++ b/server/src/com/cloud/user/AccountManager.java
@@ -50,7 +50,7 @@
Long checkAccessAndSpecifyAuthority(Account caller, Long zoneId);
- Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map<String, String> details, String uuid);
+ Account createAccount(String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map<String, String> 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 0cbbefd..c601e10 100644
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -1004,9 +1004,9 @@
@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<String, String> details, String accountUUID, final String userUUID) {
+ String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map<String, String> 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);
}
@@ -1021,7 +1021,7 @@
@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<String, String> details,
+ final String timezone, String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map<String, String> details,
String accountUUID, final String userUUID, final User.Source source) {
if (accountName == null) {
@@ -1075,7 +1075,7 @@
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
@@ -1879,27 +1879,10 @@
@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
@@ -1926,7 +1909,7 @@
@Override
@DB
- public AccountVO createAccount(final String accountName, final short accountType, final Long domainId, final String networkDomain, final Map<String, String> details,
+ public AccountVO createAccount(final String accountName, final short accountType, final Long roleId, final Long domainId, final String networkDomain, final Map<String, String> details,
final String uuid) {
// Validate domain
Domain domain = _domainMgr.getDomain(domainId);
@@ -1939,7 +1922,7 @@
}
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
@@ -1971,7 +1954,7 @@
return Transaction.execute(new TransactionCallback<AccountVO>() {
@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 71f9b67..13dcd90 100644
--- a/server/src/com/cloud/user/DomainManagerImpl.java
+++ b/server/src/com/cloud/user/DomainManagerImpl.java
@@ -328,6 +328,7 @@
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 fe0e98c..411fd9b 100644
--- a/server/src/com/cloud/vm/UserVmManager.java
+++ b/server/src/com/cloud/vm/UserVmManager.java
@@ -103,7 +103,7 @@
void collectVmDiskStatistics(UserVmVO userVm);
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<Long> 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 cc007d9..dd7e817 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;
@@ -2044,6 +2046,9 @@
return false;
}
try {
+
+ releaseNetworkResourcesOnExpunge(vm.getId());
+
List<VolumeVO> rootVol = _volsDao.findByInstanceAndType(vm.getId(), Volume.Type.ROOT);
// expunge the vm
_itMgr.advanceExpunge(vm.getUuid());
@@ -2084,6 +2089,23 @@
}
}
+ /**
+ * Release network resources, it was done on vm stop previously.
+ * @param id vm id
+ * @throws ConcurrentOperationException
+ * @throws ResourceUnavailableException
+ */
+ private void releaseNetworkResourcesOnExpunge(long id) throws ConcurrentOperationException, ResourceUnavailableException {
+ final VMInstanceVO vmInstance = _vmDao.findById(id);
+ if (vmInstance != null){
+ final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vmInstance);
+ _networkMgr.release(profile, false);
+ }
+ else {
+ s_logger.error("Couldn't find vm with id = " + id + ", unable to release network resources");
+ }
+ }
+
private boolean cleanupVmResources(long vmId) {
boolean success = true;
// Remove vm from security groups
@@ -2289,6 +2311,7 @@
String hostName = cmd.getHostName();
Map<String,String> details = cmd.getDetails();
Account caller = CallContext.current().getCallingAccount();
+ List<Long> securityGroupIdList = getSecurityGroupIdList(cmd);
// Input validation and permission checks
UserVmVO vmInstance = _vmDao.findById(id);
@@ -2339,7 +2362,7 @@
}
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 +2412,11 @@
@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<Long> 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 +2475,44 @@
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 +2554,34 @@
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));
-
- 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);
- }
+ userDataApplied |= applyUserData(template.getHypervisorType(), vm, nic);
}
+ return userDataApplied;
+ }
- return true;
+ 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);
+
+ 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 false;
}
@Override
@@ -4270,8 +4342,172 @@
@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<Long> 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<Long> securityGroupIds = new ArrayList<Long>();
+ 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<String,String> 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 c113e3c..bb1536d 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();
@@ -163,7 +163,7 @@
}
@Override
- public List<VMSnapshotVO> listVMSnapshots(ListVMSnapshotCmd cmd) {
+ public Pair<List<? extends VMSnapshot>, Integer> listVMSnapshots(ListVMSnapshotCmd cmd) {
Account caller = getCaller();
List<Long> permittedAccounts = new ArrayList<Long>();
@@ -176,6 +176,8 @@
String name = cmd.getVmSnapshotName();
String accountName = cmd.getAccountName();
+ List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
+
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(
cmd.getDomainId(), cmd.isRecursive(), null);
_accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, listAll,
@@ -193,6 +195,7 @@
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 @@
sc.setParameters("vm_id", vmId);
}
+ setIdsListToSearchCriteria(sc, ids);
+
if (domainId != null) {
sc.setParameters("domain_id", domainId);
}
@@ -238,7 +243,8 @@
sc.setParameters("id", id);
}
- return _vmSnapshotDao.search(sc, searchFilter);
+ Pair<List<VMSnapshotVO>,Integer> searchAndCount = _vmSnapshotDao.searchAndCount(sc, searchFilter);
+ return new Pair<List<? extends VMSnapshot>, Integer>(searchAndCount.first(), searchAndCount.second());
}
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 0000000..7363b13
--- /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<RoleVO>() {
+ @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<? extends Account> 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<? extends Account> accounts = accountDao.findAccountsByRole(role.getId());
+ if (accounts == null || accounts.size() == 0) {
+ return Transaction.execute(new TransactionCallback<Boolean>() {
+ @Override
+ public Boolean doInTransaction(TransactionStatus status) {
+ List<? extends RolePermission> 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<RolePermissionVO>() {
+ @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<RolePermission> 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<Role> findRolesByName(final String name) {
+ List<? extends Role> roles = null;
+ if (!Strings.isNullOrEmpty(name)) {
+ roles = roleDao.findAllByName(name);
+ }
+ return ListUtils.toListOfInterface(roles);
+ }
+
+ @Override
+ public List<Role> findRolesByType(final RoleType roleType) {
+ List<? extends Role> roles = null;
+ if (roleType != null) {
+ roles = roleDao.findAllByRoleType(roleType);
+ }
+ return ListUtils.toListOfInterface(roles);
+ }
+
+ @Override
+ public List<Role> listRoles() {
+ List<? extends Role> roles = roleDao.listAll();
+ return ListUtils.toListOfInterface(roles);
+ }
+
+ @Override
+ public List<RolePermission> findAllPermissionsBy(final Long roleId) {
+ List<? extends RolePermission> 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<Class<?>> getCommands() {
+ final List<Class<?>> 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 2b88737..0869b22 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 @@
boolean agentResults = true;
for (final DomainRouterVO router : routers) {
- if (router.getState() != State.Running) {
+ if(router.getState() == State.Stopped || router.getState() == State.Stopping){
+ s_logger.info("The router " + router.getInstanceName()+ " is in the " + router.getState() + " state. So not applying the VPN rules. Will be applied once the router gets restarted.");
+ continue;
+ }
+ else if (router.getState() != State.Running) {
s_logger.warn("Failed to add/remove VPN users: router not in running state");
throw new ResourceUnavailableException("Unable to assign ip addresses, domR is not in right state " + router.getState(), DataCenter.class,
network.getDataCenterId());
diff --git a/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementBackgroundTask.java b/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementBackgroundTask.java
new file mode 100644
index 0000000..38e139e
--- /dev/null
+++ b/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementBackgroundTask.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 org.apache.cloudstack.outofbandmanagement;
+
+import com.cloud.host.Host;
+import org.apache.log4j.Logger;
+
+public class OutOfBandManagementBackgroundTask implements Runnable {
+ public static final Logger LOG = Logger.getLogger(OutOfBandManagementBackgroundTask.class);
+
+ final private OutOfBandManagementService service;
+ final private Host host;
+ final private OutOfBandManagement.PowerOperation powerOperation;
+
+ public OutOfBandManagementBackgroundTask(OutOfBandManagementService service, Host host, OutOfBandManagement.PowerOperation powerOperation) {
+ this.service = service;
+ this.host = host;
+ this.powerOperation = powerOperation;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[OOBM Task] Power operation:%s on Host:%d(%s)", powerOperation, host.getId(), host.getName());
+ }
+
+ @Override
+ public void run() {
+ try {
+ service.executeOutOfBandManagementPowerOperation(host, powerOperation, null);
+ } catch (Exception e) {
+ LOG.warn(String.format("Out-of-band management background task operation=%s for host id=%d failed with: %s",
+ powerOperation.name(), host.getId(), e.getMessage()));
+ }
+ }
+}
diff --git a/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceImpl.java b/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceImpl.java
new file mode 100644
index 0000000..ca65ef7
--- /dev/null
+++ b/server/src/org/apache/cloudstack/outofbandmanagement/OutOfBandManagementServiceImpl.java
@@ -0,0 +1,540 @@
+// 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.alert.AlertManager;
+import com.cloud.dc.ClusterDetailsDao;
+import com.cloud.dc.ClusterDetailsVO;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenterDetailVO;
+import com.cloud.dc.dao.DataCenterDetailsDao;
+import com.cloud.domain.Domain;
+import com.cloud.event.ActionEvent;
+import com.cloud.event.ActionEventUtils;
+import com.cloud.event.EventTypes;
+import com.cloud.host.Host;
+import com.cloud.host.dao.HostDao;
+import com.cloud.org.Cluster;
+import com.cloud.utils.component.Manager;
+import com.cloud.utils.component.ManagerBase;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
+import com.cloud.utils.db.TransactionStatus;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.fsm.NoTransitionException;
+import com.google.common.base.Strings;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.collect.ImmutableMap;
+import org.apache.cloudstack.api.response.OutOfBandManagementResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.Configurable;
+import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao;
+import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverChangePasswordCommand;
+import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverPowerCommand;
+import org.apache.cloudstack.outofbandmanagement.driver.OutOfBandManagementDriverResponse;
+import org.apache.cloudstack.utils.identity.ManagementServerNode;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class OutOfBandManagementServiceImpl extends ManagerBase implements OutOfBandManagementService, Manager, Configurable {
+ public static final Logger LOG = Logger.getLogger(OutOfBandManagementServiceImpl.class);
+
+ @Inject
+ private ClusterDetailsDao clusterDetailsDao;
+ @Inject
+ private DataCenterDetailsDao dataCenterDetailsDao;
+ @Inject
+ private OutOfBandManagementDao outOfBandManagementDao;
+ @Inject
+ private HostDao hostDao;
+ @Inject
+ private AlertManager alertMgr;
+
+ private String name;
+ private long serviceId;
+
+ private List<OutOfBandManagementDriver> outOfBandManagementDrivers = new ArrayList<>();
+ private final Map<String, OutOfBandManagementDriver> outOfBandManagementDriversMap = new HashMap<String, OutOfBandManagementDriver>();
+
+ private static final String OOBM_ENABLED_DETAIL = "outOfBandManagementEnabled";
+
+ private static Cache<Long, Long> 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<OutOfBandManagement.Option, String> 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<OutOfBandManagement.Option, String> getOptions(final OutOfBandManagement outOfBandManagementConfig) {
+ final ImmutableMap.Builder<OutOfBandManagement.Option, String> 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<? extends Host> 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<OutOfBandManagement.Option, String> 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<OutOfBandManagement.Option, String> 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()));
+ }
+
+ final OutOfBandManagement outOfBandManagementConfig = outOfBandManagementDao.findByHost(host.getId());
+ final ImmutableMap<OutOfBandManagement.Option, String> 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 changePasswordCmd = new OutOfBandManagementDriverChangePasswordCommand(options, ActionTimeout.valueIn(host.getClusterId()), newPassword);
+
+ final boolean changePasswordResult = Transaction.execute(new TransactionCallback<Boolean>() {
+ @Override
+ public Boolean doInTransaction(TransactionStatus status) {
+ final OutOfBandManagement updatedOutOfBandManagementConfig = outOfBandManagementDao.findByHost(host.getId());
+ updatedOutOfBandManagementConfig.setPassword(newPassword);
+ boolean result = outOfBandManagementDao.update(updatedOutOfBandManagementConfig.getId(), (OutOfBandManagementVO) updatedOutOfBandManagementConfig);
+
+ if (!result) {
+ throw new CloudRuntimeException(String.format("Failed to change out-of-band management password for host (%s) in the database.", host.getUuid()));
+ }
+
+ final OutOfBandManagementDriverResponse driverResponse;
+ try {
+ driverResponse = driver.execute(changePasswordCmd);
+ } catch (Exception e) {
+ LOG.error("Out-of-band management change password failed due to driver error: " + e.getMessage());
+ throw new CloudRuntimeException(String.format("Failed to change out-of-band management password for host (%s) due to driver error: %s", host.getUuid(), e.getMessage()));
+ }
+
+ 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()));
+ }
+
+ return result && driverResponse.isSuccess();
+ }
+ });
+
+ final OutOfBandManagementResponse response = new OutOfBandManagementResponse();
+ response.setSuccess(changePasswordResult );
+ response.setId(host.getUuid());
+ return response;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public long getId() {
+ return serviceId;
+ }
+
+ @Override
+ public boolean configure(final String name, final Map<String, Object> 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<Runnable>(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<OutOfBandManagementDriver> getOutOfBandManagementDrivers() {
+ return outOfBandManagementDrivers;
+ }
+
+ public void setOutOfBandManagementDrivers(List<OutOfBandManagementDriver> 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 2d04a7e..19f80b9 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 @@
}
public List<DomainRouterVO> deployVirtualRouter() throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
-
findOrDeployVirtualRouter();
-
return nwHelper.startRouters(this);
}
+ private boolean isRouterDeployed() throws ResourceUnavailableException {
+ boolean isDeployed = true;
+ checkPreconditions();
+ final List<DeployDestination> 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();
+ 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<DeployDestination> destinations = findDestinations();
-
- for (final DeployDestination destination : destinations) {
- dest = destination;
- generateDeploymentPlan();
- executeDeployment();
+ // dest has pod=null, for Basic Zone findOrDeployVRs for all Pods
+ final List<DeployDestination> destinations = findDestinations();
+ for (final DeployDestination destination : destinations) {
+ dest = destination;
+ generateDeploymentPlan();
+ executeDeployment();
+ }
+ } finally {
+ unlock();
}
- } finally {
- unlock();
}
}
@@ -378,7 +395,7 @@
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 a0a6004..e7cdf41 100644
--- a/server/test/com/cloud/api/ApiServletTest.java
+++ b/server/test/com/cloud/api/ApiServletTest.java
@@ -89,7 +89,7 @@
@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 @@
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 @@
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 @@
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 @@
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 0000000..a4d9261
--- /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<String> sc;
+
+ private static Long id1 = 1L;
+ private static Long id2 = 2L;
+
+ private List<Long> idsList;
+ private List<Long> idsEmptyList;
+ private List<Long> expectedListId;
+ private List<Long> 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<Long> result = mgr.getIdsListFromCmd(id1, idsEmptyList);
+ assertEquals(expectedListId, result);
+ }
+
+ @Test
+ public void testGetIdsListProvideList(){
+ List<Long> result = mgr.getIdsListFromCmd(null, idsList);
+ assertEquals(expectedListIds, result);
+ }
+
+ @Test(expected=InvalidParameterValueException.class)
+ public void testGetIdsListBothNotNull(){
+ mgr.getIdsListFromCmd(id1, idsList);
+ }
+
+ @Test
+ public void testGetIdsListBothNull(){
+ List<Long> result = mgr.getIdsListFromCmd(null, null);
+ assertNull(result);
+ }
+
+ @Test
+ public void testGetIdsEmptyListIdNull(){
+ List<Long> 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 0000000..c7c65f8
--- /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<T extends BaseViewWithTagInformationVO,
+ Z extends BaseResponseWithTagInformation> {
+
+ 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<T, Z> 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 0000000..d194e32
--- /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<TemplateJoinVO, TemplateResponse> {
+
+ @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 0000000..669143e
--- /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<UserVmJoinVO, UserVmResponse> {
+
+ @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 0000000..b0b0ad2
--- /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<VolumeJoinVO, VolumeResponse> {
+
+ @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 fd12d23..76a3f42 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 @@
@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 @@
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 f60044e..898dff2 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 @@
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 046bdb6..dbc31ba 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 @@
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<HostVO>());
+ Mockito.when(_hostDao.listByType(Host.Type.ExternalLoadBalancer)).thenReturn(new ArrayList<HostVO>());
+ 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 86de140..6e6d66f 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 @@
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 0000000..4b3ce40
--- /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<String, String> imgStoreDetails = new HashMap<String, String>();
+ 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<String, String> imgStoreDetails = new HashMap<String, String>();
+ 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<String, String> imgStoreDetails = new HashMap<String, String>();
+ 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/storage/listener/StoragePoolMonitorTest.java b/server/test/com/cloud/storage/listener/StoragePoolMonitorTest.java
index 06733f4..0200966 100644
--- a/server/test/com/cloud/storage/listener/StoragePoolMonitorTest.java
+++ b/server/test/com/cloud/storage/listener/StoragePoolMonitorTest.java
@@ -46,7 +46,7 @@
storageManager = Mockito.mock(StorageManagerImpl.class);
poolDao = Mockito.mock(PrimaryDataStoreDao.class);
- storagePoolMonitor = new StoragePoolMonitor(storageManager, poolDao);
+ storagePoolMonitor = new StoragePoolMonitor(storageManager, poolDao, null);
host = new HostVO("some-uuid");
pool = new StoragePoolVO();
pool.setScope(ScopeType.CLUSTER);
diff --git a/server/test/com/cloud/template/TemplateManagerImplTest.java b/server/test/com/cloud/template/TemplateManagerImplTest.java
index ed4ec52..6e16938 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 @@
@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 @@
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<ImageStoreVO> 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<VMTemplateVO>() {
+ @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)},
@@ -524,6 +604,11 @@
}
@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 3971fd6..fd85167 100644
--- a/server/test/com/cloud/user/MockAccountManagerImpl.java
+++ b/server/test/com/cloud/user/MockAccountManagerImpl.java
@@ -328,13 +328,13 @@
@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<String, String> details, String accountUUID, String userUUID) {
+ short accountType, Long roleId, Long domainId, String networkDomain, Map<String, String> 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<String, String> details, String accountUUID, String userUUID, User.Source source) {
// TODO Auto-generated method stub
return null;
@@ -366,7 +366,7 @@
}
@Override
- public Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map<String, String> details, String uuid) {
+ public Account createAccount(String accountName, short accountType, Long roleId, Long domainId, String networkDomain, Map<String, String> 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 637a309..9df3f68 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;
@@ -930,6 +934,54 @@
}
@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);
_userVmMgr.persistDeviceBusInfo(_vmMock, 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 0000000..69f03ff
--- /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<OutOfBandManagement.Option, String> buildRandomOptionsMap() {
+ ImmutableMap.Builder<OutOfBandManagement.Option, String> 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<OutOfBandManagement.Option, String> optionsEmpty = oobmService.getOptions(configEmpty);
+ Assert.assertEquals(optionsEmpty.size(), 0);
+
+ OutOfBandManagement config = new OutOfBandManagementVO(123L);
+ config.setAddress("localhost");
+ config.setDriver("ipmitool");
+ config.setPort(1234);
+ ImmutableMap<OutOfBandManagement.Option, String> 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 1570a2e..eff16c1 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 @@
} 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();
@@ -525,6 +525,36 @@
}
@Test
+ public void testDeployVirtualRouterSkip() throws ConcurrentOperationException,
+ InsufficientCapacityException, ResourceUnavailableException {
+
+ // Prepare
+ final List<DeployDestination> 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
deployment.routers = new ArrayList<>(); // Empty list
diff --git a/server/test/resources/db.properties b/server/test/resources/db.properties
index 45baf4c..e9355a3 100644
--- a/server/test/resources/db.properties
+++ b/server/test/resources/db.properties
@@ -26,6 +26,7 @@
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.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.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 0524b8f..ba34df3 100755
--- a/services/console-proxy-rdp/rdpconsole/pom.xml
+++ b/services/console-proxy-rdp/rdpconsole/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-services</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
@@ -71,12 +71,13 @@
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
- <version>8.0.15</version>
+ <version>8.0.30</version>
</dependency>
<!-- Another implementation of SSL protocol. Does not work with broken MS RDP SSL too. -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
+ <version>1.46</version>
</dependency>
</dependencies>
</project>
diff --git a/services/console-proxy/plugin/pom.xml b/services/console-proxy/plugin/pom.xml
index 54fb3c3..a3eb494 100644
--- a/services/console-proxy/plugin/pom.xml
+++ b/services/console-proxy/plugin/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-service-console-proxy</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
</project>
diff --git a/services/console-proxy/pom.xml b/services/console-proxy/pom.xml
index f36fc1c..05527c7 100644
--- a/services/console-proxy/pom.xml
+++ b/services/console-proxy/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-services</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<build>
diff --git a/services/console-proxy/server/pom.xml b/services/console-proxy/server/pom.xml
index 2b9b532..9f27aab 100644
--- a/services/console-proxy/server/pom.xml
+++ b/services/console-proxy/server/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-service-console-proxy</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/services/iam/plugin/pom.xml b/services/iam/plugin/pom.xml
index 1575b50..5a85887 100644
--- a/services/iam/plugin/pom.xml
+++ b/services/iam/plugin/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-service-iam</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
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 634ce0a..3072b77 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 @@
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 faa577c..a672d63 100644
--- a/services/iam/plugin/test/resources/db.properties
+++ b/services/iam/plugin/test/resources/db.properties
@@ -27,6 +27,7 @@
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.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.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 9f80d9a..f005780 100644
--- a/services/iam/server/pom.xml
+++ b/services/iam/server/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-service-iam</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
diff --git a/services/iam/server/test/resources/db.properties b/services/iam/server/test/resources/db.properties
index faa577c..a672d63 100644
--- a/services/iam/server/test/resources/db.properties
+++ b/services/iam/server/test/resources/db.properties
@@ -27,6 +27,7 @@
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.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.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 887b05a..fc22385 100644
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<build>
diff --git a/services/secondary-storage/controller/pom.xml b/services/secondary-storage/controller/pom.xml
index 253b36d..04a5d7e 100644
--- a/services/secondary-storage/controller/pom.xml
+++ b/services/secondary-storage/controller/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-service-secondary-storage</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
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 4891b71..79c1de1 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 @@
TemplateDataStoreDao _tmplStoreDao;
@Inject
VolumeDataStoreDao _volumeStoreDao;
+ @Inject
+ private ImageStoreDetailsUtil imageStoreDetailsUtil;
private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL;
private int _secStorageVmMtuSize;
@@ -310,6 +314,9 @@
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 @@
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<NetworkVO> 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<NetworkVO> 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<NetworkVO> 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<String, Object> createSecStorageVmInstance(long dataCenterId, SecondaryStorageVm.Role role) {
DataStore secStore = _dataStoreMgr.getImageStore(dataCenterId);
if (secStore == null) {
@@ -531,26 +608,7 @@
DataCenterDeployment plan = new DataCenterDeployment(dataCenterId);
DataCenter dc = _dcDao.findById(plan.getDataCenterId());
- NetworkVO defaultNetwork = null;
- if (dc.getNetworkType() == NetworkType.Advanced && dc.isSecurityGroupEnabled()) {
- List<NetworkVO> 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<NetworkVO> 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<? extends NetworkOffering> offerings = null;
if (_sNwMgr.isStorageIpRangeAvailable(dataCenterId)) {
@@ -983,7 +1041,7 @@
}
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 @@
@Override
public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) {
-
SecondaryStorageVmVO vm = _secStorageVmDao.findById(profile.getId());
Map<String, String> details = _vmDetailsDao.listDetailsKeyPairs(vm.getId());
vm.setDetails(details);
@@ -1131,6 +1188,8 @@
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 void setSecondaryStorageVmAllocators(List<SecondaryStorageVmAllocator> 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 0000000..c42f2b1
--- /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 c116e60..86a8ba8 100644
--- a/services/secondary-storage/pom.xml
+++ b/services/secondary-storage/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-services</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modules>
diff --git a/services/secondary-storage/server/pom.xml b/services/secondary-storage/server/pom.xml
index 5f30600..522ce12 100644
--- a/services/secondary-storage/server/pom.xml
+++ b/services/secondary-storage/server/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-service-secondary-storage</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
@@ -54,7 +54,7 @@
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
- <version>4.0.25.Final</version>
+ <version>4.0.33.Final</version>
<scope>compile</scope>
</dependency>
</dependencies>
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 9393ee2..c02fe8a 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 @@
}
@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 @@
}
@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 bdfe7e8..c6f6ba8 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 @@
}
@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 f512da0..420842f 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 @@
private String _storageIp;
private String _storageNetmask;
private String _storageGateway;
+ private Integer _nfsVersion;
private final List<String> nfsIps = new ArrayList<String>();
protected String _parent = "/mnt/SecStorage";
final private String _tmpltpp = "template.properties";
@@ -224,6 +229,26 @@
_inSystemVM = inSystemVM;
}
+ /**
+ * Retrieve converted "nfsVersion" value from params
+ * @param params
+ * @return nfsVersion value if exists, null in other case
+ */
+ public static Integer retrieveNfsVersionFromParams(Map<String, Object> 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 @@
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 @@
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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
if (store instanceof NfsTO) {
NfsTO nfs = (NfsTO)store;
String secUrl = nfs.getUrl();
- String root = getRootDir(secUrl);
+ String root = getRootDir(secUrl, cmd.getNfsVersion());
Map<String, TemplateProp> templateInfos = _dlMgr.gatherTemplateInfo(root);
return new ListTemplateAnswer(secUrl, templateInfos);
} else if (store instanceof SwiftTO) {
@@ -1674,7 +1691,7 @@
}
DataStoreTO store = cmd.getDataStore();
if (store instanceof NfsTO) {
- String root = getRootDir(cmd.getSecUrl());
+ String root = getRootDir(cmd.getSecUrl(), _nfsVersion);
Map<Long, TemplateProp> templateInfos = _dlMgr.gatherVolumeInfo(root);
return new ListVolumeAnswer(cmd.getSecUrl(), templateInfos);
} else if (store instanceof S3TO) {
@@ -1809,7 +1826,7 @@
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 @@
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 @@
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 @@
}
@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 @@
startAdditionalServices();
_params.put("install.numthreads", "50");
_params.put("secondary.storage.vm", "true");
+ _nfsVersion = retrieveNfsVersionFromParams(params);
}
try {
@@ -2386,15 +2404,17 @@
* @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 @@
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 @@
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 @@
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 @@
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 @@
//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 @@
}
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 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 4d3f048..d7e0c7e 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 9cf37e5..40a1e1c 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 @@
StorageLayer _storage;
public Map<String, Processor> _processors;
+ private Integer _nfsVersion;
+
public class Completion implements DownloadCompleteCallback {
private final String jobId;
@@ -708,7 +711,7 @@
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 @@
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 58a02d5..513e60b 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 @@
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 0472a7c..80e4064 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 @@
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 0000000..57601fb
--- /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 b79af7f..5db5ac6 100644
--- a/setup/db/db/schema-471to480.sql
+++ b/setup/db/db/schema-471to480.sql
@@ -27,3 +27,4 @@
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 0000000..0ab02d8
--- /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 0000000..bd1dd82
--- /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/db/schema-490to4910-cleanup.sql b/setup/db/db/schema-490to4910-cleanup.sql
new file mode 100644
index 0000000..71638f1
--- /dev/null
+++ b/setup/db/db/schema-490to4910-cleanup.sql
@@ -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.
+
+--;
+-- Schema cleanup from 4.9.0 to 4.9.1;
+--;
+
diff --git a/setup/db/db/schema-490to4910.sql b/setup/db/db/schema-490to4910.sql
new file mode 100644
index 0000000..4ac7bf2
--- /dev/null
+++ b/setup/db/db/schema-490to4910.sql
@@ -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.
+
+--;
+-- Schema upgrade from 4.9.0 to 4.9.1;
+--;
+
+-- Fix default user role description
+UPDATE `cloud`.`roles` SET `description`='Default user role' WHERE `id`=4 AND `role_type`='User' AND `description`='Default Root Admin role';
+
+-- Fix mysql engine to innodb
+ALTER TABLE cloud.load_balancer_cert_map ENGINE=INNODB;
+ALTER TABLE cloud.monitoring_services ENGINE=INNODB;
+ALTER TABLE cloud.nic_ip_alias ENGINE=INNODB;
+ALTER TABLE cloud.sslcerts ENGINE=INNODB;
+ALTER TABLE cloud.op_lock ENGINE=INNODB;
+ALTER TABLE cloud.op_nwgrp_work ENGINE=INNODB;
+ALTER TABLE cloud_usage.quota_account ENGINE=INNODB;
+
+-- Add Ubuntu 16.04 LTS as support guest os
+INSERT IGNORE INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (255, UUID(), 10, 'Ubuntu 16.04 (32-bit)', utc_timestamp());
+INSERT IGNORE INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (256, UUID(), 10, 'Ubuntu 16.04 (64-bit)', utc_timestamp());
+-- Ubuntu 16.04 VMware guest os mapping
+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', 'ubuntuGuest', 255, utc_timestamp(), 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', 'ubuntuGuest', 255, utc_timestamp(), 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', 'ubuntuGuest', 255, utc_timestamp(), 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', 'ubuntu64Guest', 256, utc_timestamp(), 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', 'ubuntu64Guest', 256, utc_timestamp(), 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', 'ubuntu64Guest', 256, utc_timestamp(), 0);
+-- Ubuntu 16.04 KVM guest os mapping
+INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'KVM', 'default', 'Ubuntu 16.04', 255, utc_timestamp(), 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(),'KVM', 'default', 'Ubuntu 16.04', 256, utc_timestamp(), 0);
+-- Ubuntu 16.04 LXC guest os mapping
+INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'LXC', 'default', 'Ubuntu 16.04', 255, utc_timestamp(), 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(),'LXC', 'default', 'Ubuntu 16.04', 256, utc_timestamp(), 0);
+-- Ubuntu 16.04 XenServer guest os mapping
+INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '6.5.0', 'Ubuntu Trusty Tahr 14.04', 255, utc_timestamp(), 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(),'Xenserver', '6.5.0', 'Ubuntu Trusty Tahr 14.04', 256, utc_timestamp(), 0);
diff --git a/setup/db/server-setup.sql b/setup/db/server-setup.sql
index b7f5c3f..df2c924 100644
--- a/setup/db/server-setup.sql
+++ b/setup/db/server-setup.sql
@@ -25,4 +25,5 @@
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 bb8878f..178f29a 100755
--- a/setup/db/server-setup.xml
+++ b/setup/db/server-setup.xml
@@ -239,6 +239,13 @@
<value>qatest-vmops.com</value>
</configuration>
<!--
+ Enable Dynamic RBAC by default for fresh installations
+ -->
+ <configuration>
+ <name>dynamic.apichecker.enabled</name>
+ <value>true</value>
+ </configuration>
+ <!--
The instance.name parameter is tacked to the end of the names of the VMs you create.
So, for example, with the TEST value as it ships by default, your VMs would be named:
i-X-Y-TEST, where X is the account ID and Y is the serially incrementing VM ID.
diff --git a/setup/db/templates.simulator.sql b/setup/db/templates.simulator.sql
index 25e91bd..ac09c05 100755
--- a/setup/db/templates.simulator.sql
+++ b/setup/db/templates.simulator.sql
@@ -19,4 +19,6 @@
INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, state)
VALUES (100, UUID(), 'simulator-domR', 'SystemVM Template (simulator)', 0, now(), 'SYSTEM', 0, 64, 1, 'http://nfs1.lab.vmops.com/templates/routing/debian/latest/systemvm.vhd.bz2', '', 0, 'SystemVM Template (simulator)', 'VHD', 15, 0, 1, 'Simulator','Active');
INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type,state)
- VALUES (111, UUID(), 'simulator-Centos', 'CentOS 5.3(64-bit) no GUI (Simulator)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://nfs1.lab.vmops.com/templates/centos53-x86_64/latest/f59f18fb-ae94-4f97-afd2-f84755767aca.vhd.bz2', '', 0, 'CentOS 5.3(64-bit) no GUI (Simulator)', 'VHD', 11, 1, 1, 'Simulator','Active');
+ VALUES (111, UUID(), 'simulator-Centos', 'CentOS 5.6 (64-bit) no GUI (Simulator)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://nfs1.lab.vmops.com/templates/centos53-x86_64/latest/f59f18fb-ae94-4f97-afd2-f84755767aca.vhd.bz2', '', 0, 'CentOS 5.6 (64-bit) no GUI (Simulator)', 'VHD', 142, 1, 1, 'Simulator','Active');
+
+INSERT INTO `cloud`.`template_store_ref` VALUES (1,1,111,NOW(),NOW(),NULL,100,0,'Image',0,'DOWNLOADED',NULL,NULL,'template/tmpl/1/111/','http://fake.cloud/111.vhd.bz2','Ready',0,0,0,0,NULL,NULL,NULL);
diff --git a/setup/dev/advanced.cfg b/setup/dev/advanced.cfg
index 8109bb1..48241fa 100644
--- a/setup/dev/advanced.cfg
+++ b/setup/dev/advanced.cfg
@@ -154,7 +154,7 @@
},
{
"name": "storage.cleanup.interval",
- "value": "300"
+ "value": "60"
},
{
"name": "vm.op.wait.interval",
@@ -162,7 +162,7 @@
},
{
"name": "default.page.size",
- "value": "10000"
+ "value": "500"
},
{
"name": "network.gc.interval",
@@ -178,7 +178,7 @@
},
{
"name": "account.cleanup.interval",
- "value": "600"
+ "value": "60"
},
{
"name": "guest.domain.suffix",
@@ -215,6 +215,18 @@
{
"name": "enable.dynamic.scale.vm",
"value": "true"
+ },
+ {
+ "name": "ping.interval",
+ "value": "10"
+ },
+ {
+ "name": "ping.timeout",
+ "value": "1.5"
+ },
+ {
+ "name": "outofbandmanagement.sync.interval",
+ "value": "1000"
}
],
"mgtSvr": [
diff --git a/systemvm/js/ajaxviewer.js b/systemvm/js/ajaxviewer.js
index f5df103..09fb41a 100644
--- a/systemvm/js/ajaxviewer.js
+++ b/systemvm/js/ajaxviewer.js
@@ -649,6 +649,7 @@
this.sendingEventInProgress = false;
ajaxViewer.installMouseHook();
ajaxViewer.installKeyboardHook();
+ ajaxViewer.panel.parent().focus();
$(window).bind("resize", function() {
ajaxViewer.onWindowResize();
@@ -1259,6 +1260,7 @@
case 38 : // UP
case 39 : // RIGHT
case 40 : // DOWN
+ case 47 : // FORWARD SLASH // Added to stop Firefox's quick search from opening
return false;
}
diff --git a/systemvm/patches/debian/config/etc/apache2/httpd.conf b/systemvm/patches/debian/config/etc/apache2/httpd.conf
index 56366f2..b7db254 100644
--- a/systemvm/patches/debian/config/etc/apache2/httpd.conf
+++ b/systemvm/patches/debian/config/etc/apache2/httpd.conf
@@ -1,3 +1 @@
-SSLProtocol all -SSLv2 -SSLv3
-SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
-SSLHonorCipherOrder on
+# Empty
diff --git a/systemvm/patches/debian/config/etc/apache2/ports.conf b/systemvm/patches/debian/config/etc/apache2/ports.conf
deleted file mode 100644
index 369cb29..0000000
--- a/systemvm/patches/debian/config/etc/apache2/ports.conf
+++ /dev/null
@@ -1,23 +0,0 @@
-# If you just change the port or add more ports here, you will likely also
-# have to change the VirtualHost statement in
-# /etc/apache2/sites-enabled/000-default
-# This is also true if you have upgraded from before 2.2.9-3 (i.e. from
-# Debian etch). See /usr/share/doc/apache2.2-common/NEWS.Debian.gz and
-# README.Debian.gz
-
-NameVirtualHost 10.1.1.1:80
-Listen 10.1.1.1:80
-
-<IfModule mod_ssl.c>
- # If you add NameVirtualHost *:443 here, you will also have to change
- # the VirtualHost statement in /etc/apache2/sites-available/default-ssl
- # to <VirtualHost *:443>
- # Server Name Indication for SSL named virtual hosts is currently not
- # supported by MSIE on Windows XP.
- Listen 10.1.1.1:443
-</IfModule>
-
-<IfModule mod_gnutls.c>
- Listen 10.1.1.1:443
-</IfModule>
-
diff --git a/systemvm/patches/debian/config/etc/apache2/sites-available/default b/systemvm/patches/debian/config/etc/apache2/sites-available/default
deleted file mode 100644
index ae009b7..0000000
--- a/systemvm/patches/debian/config/etc/apache2/sites-available/default
+++ /dev/null
@@ -1,41 +0,0 @@
-<VirtualHost 10.1.1.1:80>
- ServerAdmin webmaster@localhost
-
- DocumentRoot /var/www/html
- <Directory />
- Options FollowSymLinks
- AllowOverride None
- </Directory>
- <Directory /var/www/html>
- Options Indexes FollowSymLinks MultiViews
- AllowOverride All
- Order allow,deny
- allow from all
- </Directory>
-
- ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
- <Directory "/usr/lib/cgi-bin">
- AllowOverride None
- Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
- Order allow,deny
- Allow from all
- </Directory>
-
- ErrorLog ${APACHE_LOG_DIR}/error.log
-
- # Possible values include: debug, info, notice, warn, error, crit,
- # alert, emerg.
- LogLevel warn
-
- CustomLog ${APACHE_LOG_DIR}/access.log combined
-
- Alias /doc/ "/usr/share/doc/"
- <Directory "/usr/share/doc/">
- Options Indexes MultiViews FollowSymLinks
- AllowOverride None
- Order deny,allow
- Deny from all
- Allow from 127.0.0.0/255.0.0.0 ::1/128
- </Directory>
-
-</VirtualHost>
diff --git a/systemvm/patches/debian/config/etc/apache2/sites-available/default-ssl b/systemvm/patches/debian/config/etc/apache2/sites-available/default-ssl
deleted file mode 100644
index a2c21d7..0000000
--- a/systemvm/patches/debian/config/etc/apache2/sites-available/default-ssl
+++ /dev/null
@@ -1,175 +0,0 @@
-<IfModule mod_ssl.c>
-<VirtualHost 10.1.1.1:443>
- ServerAdmin webmaster@localhost
-
- DocumentRoot /var/www/html
- <Directory />
- Options FollowSymLinks
- AllowOverride None
- </Directory>
- <Directory /var/www/html>
- Options Indexes FollowSymLinks MultiViews
- AllowOverride all
- Order allow,deny
- allow from all
- </Directory>
-
- ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
- <Directory "/usr/lib/cgi-bin">
- AllowOverride None
- Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
- Order allow,deny
- Allow from all
- </Directory>
-
- ErrorLog ${APACHE_LOG_DIR}/error.log
-
- # Possible values include: debug, info, notice, warn, error, crit,
- # alert, emerg.
- LogLevel warn
-
- CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined
-
- Alias /doc/ "/usr/share/doc/"
- <Directory "/usr/share/doc/">
- Options Indexes MultiViews FollowSymLinks
- AllowOverride None
- Order deny,allow
- Deny from all
- Allow from 127.0.0.0/255.0.0.0 ::1/128
- </Directory>
-
- # SSL Engine Switch:
- # Enable/Disable SSL for this virtual host.
- SSLEngine on
- SSLProtocol all -SSLv2 -SSLv3
- SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
- SSLHonorCipherOrder on
-
- # A self-signed (snakeoil) certificate can be created by installing
- # the ssl-cert package. See
- # /usr/share/doc/apache2.2-common/README.Debian.gz for more info.
- # If both key and certificate are stored in the same file, only the
- # SSLCertificateFile directive is needed.
- SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
- SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
-
- # Server Certificate Chain:
- # Point SSLCertificateChainFile at a file containing the
- # concatenation of PEM encoded CA certificates which form the
- # certificate chain for the server certificate. Alternatively
- # the referenced file can be the same as SSLCertificateFile
- # when the CA certificates are directly appended to the server
- # certificate for convinience.
- #SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt
-
- # Certificate Authority (CA):
- # Set the CA certificate verification path where to find CA
- # certificates for client authentication or alternatively one
- # huge file containing all of them (file must be PEM encoded)
- # Note: Inside SSLCACertificatePath you need hash symlinks
- # to point to the certificate files. Use the provided
- # Makefile to update the hash symlinks after changes.
- #SSLCACertificatePath /etc/ssl/certs/
- #SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt
-
- # Certificate Revocation Lists (CRL):
- # Set the CA revocation path where to find CA CRLs for client
- # authentication or alternatively one huge file containing all
- # of them (file must be PEM encoded)
- # Note: Inside SSLCARevocationPath you need hash symlinks
- # to point to the certificate files. Use the provided
- # Makefile to update the hash symlinks after changes.
- #SSLCARevocationPath /etc/apache2/ssl.crl/
- #SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl
-
- # Client Authentication (Type):
- # Client certificate verification type and depth. Types are
- # none, optional, require and optional_no_ca. Depth is a
- # number which specifies how deeply to verify the certificate
- # issuer chain before deciding the certificate is not valid.
- #SSLVerifyClient require
- #SSLVerifyDepth 10
-
- # Access Control:
- # With SSLRequire you can do per-directory access control based
- # on arbitrary complex boolean expressions containing server
- # variable checks and other lookup directives. The syntax is a
- # mixture between C and Perl. See the mod_ssl documentation
- # for more details.
- #<Location />
- #SSLRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \
- # and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \
- # and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \
- # and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \
- # and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \
- # or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/
- #</Location>
-
- # SSL Engine Options:
- # Set various options for the SSL engine.
- # o FakeBasicAuth:
- # Translate the client X.509 into a Basic Authorisation. This means that
- # the standard Auth/DBMAuth methods can be used for access control. The
- # user name is the `one line' version of the client's X.509 certificate.
- # Note that no password is obtained from the user. Every entry in the user
- # file needs this password: `xxj31ZMTZzkVA'.
- # o ExportCertData:
- # This exports two additional environment variables: SSL_CLIENT_CERT and
- # SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
- # server (always existing) and the client (only existing when client
- # authentication is used). This can be used to import the certificates
- # into CGI scripts.
- # o StdEnvVars:
- # This exports the standard SSL/TLS related `SSL_*' environment variables.
- # Per default this exportation is switched off for performance reasons,
- # because the extraction step is an expensive operation and is usually
- # useless for serving static content. So one usually enables the
- # exportation for CGI and SSI requests only.
- # o StrictRequire:
- # This denies access when "SSLRequireSSL" or "SSLRequire" applied even
- # under a "Satisfy any" situation, i.e. when it applies access is denied
- # and no other module can change it.
- # o OptRenegotiate:
- # This enables optimized SSL connection renegotiation handling when SSL
- # directives are used in per-directory context.
- #SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
- <FilesMatch "\.(cgi|shtml|phtml|php)$">
- SSLOptions +StdEnvVars
- </FilesMatch>
- <Directory /usr/lib/cgi-bin>
- SSLOptions +StdEnvVars
- </Directory>
-
- # SSL Protocol Adjustments:
- # The safe and default but still SSL/TLS standard compliant shutdown
- # approach is that mod_ssl sends the close notify alert but doesn't wait for
- # the close notify alert from client. When you need a different shutdown
- # approach you can use one of the following variables:
- # o ssl-unclean-shutdown:
- # This forces an unclean shutdown when the connection is closed, i.e. no
- # SSL close notify alert is send or allowed to received. This violates
- # the SSL/TLS standard but is needed for some brain-dead browsers. Use
- # this when you receive I/O errors because of the standard approach where
- # mod_ssl sends the close notify alert.
- # o ssl-accurate-shutdown:
- # This forces an accurate shutdown when the connection is closed, i.e. a
- # SSL close notify alert is send and mod_ssl waits for the close notify
- # alert of the client. This is 100% SSL/TLS standard compliant, but in
- # practice often causes hanging connections with brain-dead browsers. Use
- # this only for browsers where you know that their SSL implementation
- # works correctly.
- # Notice: Most problems of broken clients are also related to the HTTP
- # keep-alive facility, so you usually additionally want to disable
- # keep-alive for those clients, too. Use variable "nokeepalive" for this.
- # Similarly, one has to force some clients to use HTTP/1.0 to workaround
- # their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
- # "force-response-1.0" for this.
- BrowserMatch "MSIE [2-6]" \
- nokeepalive ssl-unclean-shutdown \
- downgrade-1.0 force-response-1.0
- # MSIE 7 and newer should be able to use keepalive
- BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
-
-</VirtualHost>
-</IfModule>
diff --git a/systemvm/patches/debian/config/etc/apache2/vhostexample.conf b/systemvm/patches/debian/config/etc/apache2/vhost.template
similarity index 90%
rename from systemvm/patches/debian/config/etc/apache2/vhostexample.conf
rename to systemvm/patches/debian/config/etc/apache2/vhost.template
index 70cb7dc..043a286 100644
--- a/systemvm/patches/debian/config/etc/apache2/vhostexample.conf
+++ b/systemvm/patches/debian/config/etc/apache2/vhost.template
@@ -83,10 +83,15 @@
Allow from 127.0.0.0/255.0.0.0 ::1/128
</Directory>
+ # Include CORS configuration **IF SET**
+ Include /etc/apache2/[cC][oO][rR][sS].conf
+
# SSL Engine Switch:
# Enable/Disable SSL for this virtual host.
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
+ SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
+ SSLHonorCipherOrder on
# A self-signed (snakeoil) certificate can be created by installing
# the ssl-cert package. See
@@ -223,6 +228,7 @@
# README.Debian.gz
Listen 10.1.1.1:80
+NameVirtualHost 10.1.1.1:80
<IfModule mod_ssl.c>
# If you add NameVirtualHost *:443 here, you will also have to change
diff --git a/systemvm/patches/debian/config/etc/init.d/cloud-early-config b/systemvm/patches/debian/config/etc/init.d/cloud-early-config
index 5d45661..cd42bb0 100755
--- a/systemvm/patches/debian/config/etc/init.d/cloud-early-config
+++ b/systemvm/patches/debian/config/etc/init.d/cloud-early-config
@@ -342,6 +342,7 @@
EOF
mv /usr/local/cloud/systemvm/conf/temp.xml /usr/local/cloud/systemvm/conf/log4j-cloud.xml
}
+
setup_interface() {
local intfnum=$1
local ip=$2
@@ -801,38 +802,33 @@
setup_vpc_apache2() {
log_it "Setting up apache web server for VPC"
chkconfig apache2 off
- rm -f /etc/apache2/conf.d/vhost*.conf
- [ -f /etc/apache2/sites-available/default ] && echo "" >/etc/apache2/sites-available/default
- [ -f /etc/apache2/sites-available/default-ssl ] && echo "">/etc/apache2/sites-available/default-ssl
- [ -f /etc/apache2/ports.conf ] && echo "">/etc/apache2/ports.conf
- [ -f /etc/apache2/ports.conf ] && echo "">/etc/apache2/ports.conf
- [ -f /etc/apache2/ports.conf ] && echo "">/etc/apache2/ports.conf
- [ -f /etc/apache2/conf.d/security ] && sed -i -e "s/^ServerTokens .*/ServerTokens Prod/g" /etc/apache2/conf.d/security
- [ -f /etc/apache2/conf.d/security ] && sed -i -e "s/^ServerSignature .*/ServerSignature Off/g" /etc/apache2/conf.d/security
-
- # Disable listing of http://SSVM-IP/icons folder for security issue. see article http://www.i-lateral.com/tutorials/disabling-the-icons-folder-on-an-ubuntu-web-server/
- [ -f /etc/apache2/mods-available/alias.conf ] && sed -i s/"Options Indexes MultiViews"/"Options -Indexes MultiViews"/ /etc/apache2/mods-available/alias.conf
-
- echo "Options -Indexes" > /var/www/html/.htaccess
+ clean_ipalias_config
+ setup_apache2_common
}
clean_ipalias_config() {
-rm -f /etc/apache2/conf.d/ports.*.meta-data.conf
-rm -f /etc/apache2/sites-available/ipAlias*
-rm -f /etc/apache2/sites-enabled/ipAlias*
-rm -rf /etc/failure_config
+ # Old
+ rm -f /etc/apache2/conf.d/ports.*.meta-data.conf
+ rm -f /etc/apache2/sites-available/ipAlias*
+ rm -f /etc/apache2/sites-enabled/ipAlias*
+ rm -f /etc/apache2/conf.d/vhost*.conf
+ rm -f /etc/apache2/ports.conf
+ rm -f /etc/apache2/vhostexample.conf
+ rm -f /etc/apache2/sites-available/default
+ rm -f /etc/apache2/sites-available/default-ssl
+ rm -f /etc/apache2/sites-enabled/default
+ rm -f /etc/apache2/sites-enabled/default-ssl
+
+ # New
+ rm -f /etc/apache2/sites-enabled/vhost-*.conf
+ rm -f /etc/apache2/sites-enabled/000-default
+
+ rm -rf /etc/failure_config
}
-setup_apache2() {
- clean_ipalias_config
- log_it "Setting up apache web server"
- local ip=$1
- [ -f /etc/apache2/sites-available/default ] && sed -i -e "s/<VirtualHost.*>/<VirtualHost $ip:80>/" /etc/apache2/sites-available/default
- [ -f /etc/apache2/sites-available/default-ssl ] && sed -i -e "s/<VirtualHost.*>/<VirtualHost $ip:443>/" /etc/apache2/sites-available/default-ssl
- [ -f /etc/apache2/ports.conf ] && sed -i -e "s/Listen .*:80/Listen $ip:80/g" /etc/apache2/ports.conf
- [ -f /etc/apache2/ports.conf ] && sed -i -e "s/Listen .*:443/Listen $ip:443/g" /etc/apache2/ports.conf
- [ -f /etc/apache2/ports.conf ] && sed -i -e "s/NameVirtualHost .*:80/NameVirtualHost $ip:80/g" /etc/apache2/ports.conf
+setup_apache2_common() {
+ sed -i 's/^Include ports.conf.*/# CS: Done by Python CsApp config\n#Include ports.conf/g' /etc/apache2/apache2.conf
[ -f /etc/apache2/conf.d/security ] && sed -i -e "s/^ServerTokens .*/ServerTokens Prod/g" /etc/apache2/conf.d/security
[ -f /etc/apache2/conf.d/security ] && sed -i -e "s/^ServerSignature .*/ServerSignature Off/g" /etc/apache2/conf.d/security
@@ -842,72 +838,18 @@
echo "Options -Indexes" > /var/www/html/.htaccess
}
-setup_redundant_router() {
- rrouter_bin_path="/ramdisk/rrouter"
- rrouter_log="/ramdisk/rrouter/keepalived.log"
- rrouter_bin_path_str="\/ramdisk\/rrouter"
- rrouter_log_str="\/ramdisk\/rrouter\/keepalived.log"
- mkdir -p /ramdisk
- mount tmpfs /ramdisk -t tmpfs
- mkdir -p /ramdisk/rrouter
- ip route delete default
- cp /root/redundant_router/keepalived.conf.templ /etc/keepalived/keepalived.conf
- cp /root/redundant_router/conntrackd.conf.templ /etc/conntrackd/conntrackd.conf
- cp /root/redundant_router/enable_pubip.sh.templ $rrouter_bin_path/enable_pubip.sh
- cp /root/redundant_router/master.sh.templ $rrouter_bin_path/master.sh
- cp /root/redundant_router/backup.sh.templ $rrouter_bin_path/backup.sh
- cp /root/redundant_router/fault.sh.templ $rrouter_bin_path/fault.sh
- cp /root/redundant_router/primary-backup.sh.templ $rrouter_bin_path/primary-backup.sh
- cp /root/redundant_router/heartbeat.sh.templ $rrouter_bin_path/heartbeat.sh
- cp /root/redundant_router/check_heartbeat.sh.templ $rrouter_bin_path/check_heartbeat.sh
- cp /root/redundant_router/arping_gateways.sh.templ $rrouter_bin_path/arping_gateways.sh
- cp /root/redundant_router/check_bumpup.sh $rrouter_bin_path/
- cp /root/redundant_router/disable_pubip.sh $rrouter_bin_path/
- cp /root/redundant_router/checkrouter.sh.templ /opt/cloud/bin/checkrouter.sh
- cp /root/redundant_router/services.sh $rrouter_bin_path/
- sed -i "s/\[ROUTER_ID\]/$NAME/g" /etc/keepalived/keepalived.conf
- sed -i "s/\[ROUTER_IP\]/$GUEST_GW\/$GUEST_CIDR_SIZE/g" /etc/keepalived/keepalived.conf
- sed -i "s/\[BOARDCAST\]/$GUEST_BRD/g" /etc/keepalived/keepalived.conf
- sed -i "s/\[PRIORITY\]/$ROUTER_PR/g" /etc/keepalived/keepalived.conf
- sed -i "s/\[RROUTER_BIN_PATH\]/$rrouter_bin_path_str/g" /etc/keepalived/keepalived.conf
- sed -i "s/\[DELTA\]/2/g" /etc/keepalived/keepalived.conf
- sed -i "s/\[LINK_IF\]/eth0/g" /etc/conntrackd/conntrackd.conf
- sed -i "s/\[LINK_IP\]/$ETH0_IP/g" /etc/conntrackd/conntrackd.conf
- sed -i "s/\[IGNORE_IP1\]/$GUEST_GW/g" /etc/conntrackd/conntrackd.conf
- sed -i "s/\[IGNORE_IP2\]/$ETH0_IP/g" /etc/conntrackd/conntrackd.conf
- sed -i "s/\[IGNORE_IP3\]/$ETH1_IP/g" /etc/conntrackd/conntrackd.conf
- sed -i "s/\[ETH2IP\]/$ETH2_IP/g" $rrouter_bin_path/enable_pubip.sh
- sed -i "s/\[ETH2MASK\]/$ETH2_MASK/g" $rrouter_bin_path/enable_pubip.sh
- sed -i "s/\[GATEWAY\]/$GW/g" $rrouter_bin_path/enable_pubip.sh
- sed -i "s/\[GATEWAY\]/$GW/g" $rrouter_bin_path/master.sh
+setup_apache2() {
+ log_it "Setting up apache web server"
+ clean_ipalias_config
+ setup_apache2_common
+ local ip=$1
- sed -i "s/\[RROUTER_BIN_PATH\]/$rrouter_bin_path_str/g" $rrouter_bin_path/master.sh
- sed -i "s/\[RROUTER_BIN_PATH\]/$rrouter_bin_path_str/g" $rrouter_bin_path/backup.sh
- sed -i "s/\[RROUTER_BIN_PATH\]/$rrouter_bin_path_str/g" $rrouter_bin_path/fault.sh
- sed -i "s/\[RROUTER_BIN_PATH\]/$rrouter_bin_path_str/g" $rrouter_bin_path/heartbeat.sh
- sed -i "s/\[RROUTER_BIN_PATH\]/$rrouter_bin_path_str/g" $rrouter_bin_path/check_heartbeat.sh
- sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" $rrouter_bin_path/master.sh
- sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" $rrouter_bin_path/backup.sh
- sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" $rrouter_bin_path/fault.sh
- sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" $rrouter_bin_path/primary-backup.sh
- sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" $rrouter_bin_path/check_heartbeat.sh
- sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" $rrouter_bin_path/arping_gateways.sh
- sed -i "s/\[RROUTER_LOG\]/$rrouter_log_str/g" /opt/cloud/bin/checkrouter.sh
-
- if [ $ADVERT_INT ]
- then
- sed -i "s/advert_int 1/advert_int $ADVERT_INT/g" /etc/keepalived/keepalived.conf
- fi
-
- chmod a+x $rrouter_bin_path/*.sh
-
- sed -i "s/--exec\ \$DAEMON;/--exec\ \$DAEMON\ --\ --vrrp;/g" /etc/init.d/keepalived
- crontab -l|grep "check_heartbeat.sh"
- if [ $? -ne 0 ]
- then
- (crontab -l; echo -e "SHELL=/bin/bash\nPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n*/1 * * * * $rrouter_bin_path/check_heartbeat.sh 2>&1 > /dev/null") | crontab
- fi
- load_modules
+ # Deprecated, functionality moved to Cs Python code
+ # [ -f /etc/apache2/sites-available/default ] && sed -i -e "s/<VirtualHost.*>/<VirtualHost $ip:80>/" /etc/apache2/sites-available/default
+ # [ -f /etc/apache2/sites-available/default-ssl ] && sed -i -e "s/<VirtualHost.*>/<VirtualHost $ip:443>/" /etc/apache2/sites-available/default-ssl
+ # [ -f /etc/apache2/ports.conf ] && sed -i -e "s/Listen .*:80/Listen $ip:80/g" /etc/apache2/ports.conf
+ # [ -f /etc/apache2/ports.conf ] && sed -i -e "s/Listen .*:443/Listen $ip:443/g" /etc/apache2/ports.conf
+ # [ -f /etc/apache2/ports.conf ] && sed -i -e "s/NameVirtualHost .*:80/NameVirtualHost $ip:80/g" /etc/apache2/ports.conf
}
setup_aesni() {
@@ -1207,33 +1149,27 @@
fi
setup_apache2 $ETH2_IP
+ # Deprecated, should move to Cs Python all of it
+ sed -e "s/<VirtualHost .*:80>/<VirtualHost $ETH2_IP:80>/" \
+ -e "s/<VirtualHost .*:443>/<VirtualHost $ETH2_IP:443>/" \
+ -e "s/Listen .*:80/Listen $ETH2_IP:80/g" \
+ -e "s/Listen .*:443/Listen $ETH2_IP:443/g" \
+ -e "s/NameVirtualHost .*:80/NameVirtualHost $ETH2_IP:80/g" /etc/apache2/vhost.template > /etc/apache2/sites-enabled/vhost-${ETH2_IP}.conf
+
log_it "setting up apache2 for post upload of volume/template"
a2enmod proxy
a2enmod proxy_http
a2enmod headers
- SSL_FILE="/etc/apache2/sites-available/default-ssl"
- PATTERN="RewriteRule ^\/upload\/(.*)"
- CORS_PATTERN="Header set Access-Control-Allow-Origin"
- if [ -f $SSL_FILE ]; then
- if grep -q "$PATTERN" $SSL_FILE ; then
- log_it "rewrite rules already exist in file $SSL_FILE"
- else
- log_it "adding rewrite rules to file: $SSL_FILE"
- sed -i -e "s/<\/VirtualHost>/RewriteEngine On \n&/" $SSL_FILE
- sed -i -e "s/<\/VirtualHost>/RewriteCond %{HTTPS} =on \n&/" $SSL_FILE
- sed -i -e "s/<\/VirtualHost>/RewriteCond %{REQUEST_METHOD} =POST \n&/" $SSL_FILE
- sed -i -e "s/<\/VirtualHost>/RewriteRule ^\/upload\/(.*) http:\/\/127.0.0.1:8210\/upload?uuid=\$1 [P,L] \n&/" $SSL_FILE
- fi
- if grep -q "$CORS_PATTERN" $SSL_FILE ; then
- log_it "cors rules already exist in file $SSL_FILE"
- else
- log_it "adding cors rules to file: $SSL_FILE"
- sed -i -e "s/<\/VirtualHost>/Header always set Access-Control-Allow-Origin \"*\" \n&/" $SSL_FILE
- sed -i -e "s/<\/VirtualHost>/Header always set Access-Control-Allow-Methods \"POST, OPTIONS\" \n&/" $SSL_FILE
- sed -i -e "s/<\/VirtualHost>/Header always set Access-Control-Allow-Headers \"x-requested-with, Content-Type, origin, authorization, accept, client-security-token, x-signature, x-metadata, x-expires\" \n&/" $SSL_FILE
- fi
- fi
+ cat >/etc/apache2/cors.conf <<CORS
+RewriteEngine On
+RewriteCond %{HTTPS} =on
+RewriteCond %{REQUEST_METHOD} =POST
+RewriteRule ^/upload/(.*) http://127.0.0.1:8210/upload?uuid=\$1 [P,L]
+Header always set Access-Control-Allow-Origin "*"
+Header always set Access-Control-Allow-Methods "POST, OPTIONS"
+Header always set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token, x-signature, x-metadata, x-expires"
+CORS
service apache2 restart
diff --git a/systemvm/patches/debian/config/etc/logrotate.d/cloud b/systemvm/patches/debian/config/etc/logrotate.d/cloud
index 420fce2..3fedd5e 100644
--- a/systemvm/patches/debian/config/etc/logrotate.d/cloud
+++ b/systemvm/patches/debian/config/etc/logrotate.d/cloud
@@ -5,9 +5,9 @@
# 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
@@ -16,7 +16,6 @@
# under the License.
/var/log/cloud.log {
rotate 4
- daily
size 10M
missingok
notifempty
diff --git a/systemvm/patches/debian/config/etc/logrotate.d/conntrackd b/systemvm/patches/debian/config/etc/logrotate.d/conntrackd
index 0229cd7..1c37c4c 100644
--- a/systemvm/patches/debian/config/etc/logrotate.d/conntrackd
+++ b/systemvm/patches/debian/config/etc/logrotate.d/conntrackd
@@ -1,5 +1,4 @@
/var/log/conntrackd-stats.log {
- daily
size 10M
rotate 2
missingok
diff --git a/systemvm/patches/debian/config/etc/logrotate.d/dnsmasq b/systemvm/patches/debian/config/etc/logrotate.d/dnsmasq
index 2f91785..99815d8 100644
--- a/systemvm/patches/debian/config/etc/logrotate.d/dnsmasq
+++ b/systemvm/patches/debian/config/etc/logrotate.d/dnsmasq
@@ -1,5 +1,4 @@
/var/log/dnsmasq.log {
- daily
size 10M
missingok
rotate 5
diff --git a/systemvm/patches/debian/config/etc/logrotate.d/haproxy b/systemvm/patches/debian/config/etc/logrotate.d/haproxy
index 858fe2a..28da41c 100644
--- a/systemvm/patches/debian/config/etc/logrotate.d/haproxy
+++ b/systemvm/patches/debian/config/etc/logrotate.d/haproxy
@@ -1,10 +1,9 @@
/var/log/haproxy.log {
- daily
rotate 5
missingok
notifempty
size 10M
- postrotate
+ postrotate
/bin/kill -HUP `cat /var/run/rsyslog.pid 2> /dev/null` 2> /dev/null || true
endscript
}
diff --git a/systemvm/patches/debian/config/etc/logrotate.d/ppp b/systemvm/patches/debian/config/etc/logrotate.d/ppp
index 2004e77..624b4ae 100644
--- a/systemvm/patches/debian/config/etc/logrotate.d/ppp
+++ b/systemvm/patches/debian/config/etc/logrotate.d/ppp
@@ -1,5 +1,4 @@
/var/log/ppp-connect-errors {
- daily
size 10M
rotate 5
missingok
diff --git a/systemvm/patches/debian/config/etc/logrotate.d/rsyslog b/systemvm/patches/debian/config/etc/logrotate.d/rsyslog
index 5803c43d..5a104b3 100644
--- a/systemvm/patches/debian/config/etc/logrotate.d/rsyslog
+++ b/systemvm/patches/debian/config/etc/logrotate.d/rsyslog
@@ -1,7 +1,6 @@
/var/log/syslog
{
rotate 7
- daily
size 50M
missingok
notifempty
@@ -26,7 +25,6 @@
/var/log/messages
{
rotate 10
- daily
size 50M
missingok
notifempty
diff --git a/systemvm/patches/debian/config/etc/rc.local b/systemvm/patches/debian/config/etc/rc.local
index 18e7cd1..3b19218 100755
--- a/systemvm/patches/debian/config/etc/rc.local
+++ b/systemvm/patches/debian/config/etc/rc.local
@@ -42,7 +42,10 @@
echo 1000000 > /proc/sys/net/nf_conntrack_max
fi
-python /opt/cloud/bin/baremetal-vr.py &
+if [ "$router" != "" ]
+then
+ python /opt/cloud/bin/baremetal-vr.py &
+fi
date > /var/cache/cloud/boot_up_done
logger -t cloud "Boot up process done"
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/configure.py b/systemvm/patches/debian/config/opt/cloud/bin/configure.py
index 40242ee..3c01574 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/configure.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/configure.py
@@ -46,9 +46,9 @@
class CsPassword(CsDataBag):
-
+
TOKEN_FILE="/tmp/passwdsrvrtoken"
-
+
def process(self):
for item in self.dbag:
if item == "id":
@@ -99,7 +99,7 @@
self.rule['allowed'] = True
self.rule['action'] = "ACCEPT"
-
+
if self.rule['type'] == 'all' and not obj['source_cidr_list']:
self.rule['cidr'] = ['0.0.0.0/0']
else:
@@ -145,41 +145,40 @@
logging.debug("Current ACL IP direction is ==> %s", self.direction)
if self.direction == 'egress':
self.fw.append(["filter", "", " -A FW_OUTBOUND -j FW_EGRESS_RULES"])
- if rule['protocol'] == "icmp":
- self.fw.append(["filter", "front",
- " -A FW_EGRESS_RULES" +
- " -s %s " % cidr +
- " -p %s " % rule['protocol'] +
- " -m %s " % rule['protocol'] +
- " --icmp-type %s -j %s" % (icmp_type, self.rule['action'])])
- else:
- fwr = " -I FW_EGRESS_RULES"
- #In case we have a default rule (accept all or drop all), we have to evaluate the action again.
- if rule['type'] == 'all' and not rule['source_cidr_list']:
- fwr = " -A FW_EGRESS_RULES"
- # For default egress ALLOW or DENY, the logic is inverted.
- # Having default_egress_policy == True, means that the default rule should have ACCEPT,
- # otherwise DROP. The rule should be appended, not inserted.
- if self.rule['default_egress_policy']:
- self.rule['action'] = "ACCEPT"
- else:
- self.rule['action'] = "DROP"
+
+ fwr = " -I FW_EGRESS_RULES"
+ # In case we have a default rule (accept all or drop all), we have to evaluate the action again.
+ if rule['type'] == 'all' and not rule['source_cidr_list']:
+ fwr = " -A FW_EGRESS_RULES"
+ # For default egress ALLOW or DENY, the logic is inverted.
+ # Having default_egress_policy == True, means that the default rule should have ACCEPT,
+ # otherwise DROP. The rule should be appended, not inserted.
+ if self.rule['default_egress_policy']:
+ self.rule['action'] = "ACCEPT"
else:
- # For other rules added, if default_egress_policy == True, following rules should be DROP,
- # otherwise ACCEPT
- if self.rule['default_egress_policy']:
- self.rule['action'] = "DROP"
- else:
- self.rule['action'] = "ACCEPT"
+ self.rule['action'] = "DROP"
+ else:
+ # For other rules added, if default_egress_policy == True, following rules should be DROP,
+ # otherwise ACCEPT
+ if self.rule['default_egress_policy']:
+ self.rule['action'] = "DROP"
+ else:
+ self.rule['action'] = "ACCEPT"
- if rule['protocol'] != "all":
- fwr += " -s %s " % cidr + \
- " -p %s " % rule['protocol'] + \
- " -m %s " % rule['protocol'] + \
- " --dport %s" % rnge
+ if rule['protocol'] == "icmp":
+ fwr += " -s %s " % cidr + \
+ " -p %s " % rule['protocol'] + \
+ " -m %s " % rule['protocol'] + \
+ " --icmp-type %s" % icmp_type
+ elif rule['protocol'] != "all":
+ fwr += " -s %s " % cidr + \
+ " -p %s " % rule['protocol'] + \
+ " -m %s " % rule['protocol'] + \
+ " --dport %s" % rnge
+ elif rule['protocol'] == "all":
+ fwr += " -s %s " % cidr
- self.fw.append(["filter", "", "%s -j %s" % (fwr, rule['action'])])
-
+ self.fw.append(["filter", "", "%s -j %s" % (fwr, rule['action'])])
logging.debug("EGRESS rule configured for protocol ==> %s, action ==> %s", rule['protocol'], rule['action'])
class AclDevice():
@@ -263,6 +262,12 @@
rstr = rstr.replace(" ", " ").lstrip()
self.fw.append([self.table, self.count, rstr])
+ def flushAllowAllEgressRules(self):
+ logging.debug("Flush allow 'all' egress firewall rule")
+ # Ensure that FW_EGRESS_RULES chain exists
+ CsHelper.execute("iptables-save | grep '^:FW_EGRESS_RULES' || iptables -t filter -N FW_EGRESS_RULES")
+ CsHelper.execute("iptables-save | grep '^-A FW_EGRESS_RULES -j ACCEPT$' | sed 's/^-A/iptables -t filter -D/g' | bash")
+
def process(self):
for item in self.dbag:
if item == "id":
@@ -313,6 +318,9 @@
# base64 decode userdata
if folder == "userdata" or folder == "user-data":
if data is not None:
+ # need to pad data if it is not valid base 64
+ if len(data) % 4 != 0:
+ data += (4-(len(data) % 4)) * "="
data = base64.b64decode(data)
fh = open(dest, "w")
@@ -615,6 +623,7 @@
#Enable remote access vpn
if vpnconfig['create']:
logging.debug("Enabling remote access vpn on "+ public_ip)
+ CsHelper.start_if_stopped("ipsec")
self.configure_l2tpIpsec(public_ip, self.dbag[public_ip])
logging.debug("Remote accessvpn data bag %s", self.dbag)
self.remoteaccessvpn_iptables(public_ip, self.dbag[public_ip])
@@ -907,104 +916,107 @@
logging.basicConfig(filename=config.get_logger(),
level=config.get_level(),
format=config.get_format())
+ try:
+ # Load stored ip adresses from disk to CsConfig()
+ config.set_address()
- # Load stored ip adresses from disk to CsConfig()
- config.set_address()
+ logging.debug("Configuring ip addresses")
+ config.address().compare()
+ config.address().process()
- logging.debug("Configuring ip addresses")
- config.address().compare()
- config.address().process()
+ if process_file in ["cmd_line.json", "guest_network.json"]:
+ logging.debug("Configuring Guest Network")
+ iptables_change = True
- if process_file in ["cmd_line.json", "guest_network.json"]:
- logging.debug("Configuring Guest Network")
- iptables_change = True
+ if process_file in ["cmd_line.json", "vm_password.json"]:
+ logging.debug("Configuring vmpassword")
+ password = CsPassword("vmpassword", config)
+ password.process()
- if process_file in ["cmd_line.json", "vm_password.json"]:
- logging.debug("Configuring vmpassword")
- password = CsPassword("vmpassword", config)
- password.process()
+ if process_file in ["cmd_line.json", "vm_metadata.json"]:
+ logging.debug("Configuring vmdata")
+ metadata = CsVmMetadata('vmdata', config)
+ metadata.process()
- if process_file in ["cmd_line.json", "vm_metadata.json"]:
- logging.debug("Configuring vmdata")
- metadata = CsVmMetadata('vmdata', config)
- metadata.process()
+ if process_file in ["cmd_line.json", "network_acl.json"]:
+ logging.debug("Configuring networkacl")
+ iptables_change = True
- if process_file in ["cmd_line.json", "network_acl.json"]:
- logging.debug("Configuring networkacl")
- iptables_change = True
+ if process_file in ["cmd_line.json", "firewall_rules.json"]:
+ logging.debug("Configuring firewall rules")
+ iptables_change = True
- if process_file in ["cmd_line.json", "firewall_rules.json"]:
- logging.debug("Configuring firewall rules")
- iptables_change = True
+ if process_file in ["cmd_line.json", "forwarding_rules.json", "staticnat_rules.json"]:
+ logging.debug("Configuring PF rules")
+ iptables_change = True
- if process_file in ["cmd_line.json", "forwarding_rules.json", "staticnat_rules.json"]:
- logging.debug("Configuring PF rules")
- iptables_change = True
+ if process_file in ["cmd_line.json", "site_2_site_vpn.json"]:
+ logging.debug("Configuring s2s vpn")
+ iptables_change = True
- if process_file in ["cmd_line.json", "site_2_site_vpn.json"]:
- logging.debug("Configuring s2s vpn")
- iptables_change = True
+ if process_file in ["cmd_line.json", "remote_access_vpn.json"]:
+ logging.debug("Configuring remote access vpn")
+ iptables_change = True
- if process_file in ["cmd_line.json", "remote_access_vpn.json"]:
- logging.debug("Configuring remote access vpn")
- iptables_change = True
+ if process_file in ["cmd_line.json", "vpn_user_list.json"]:
+ logging.debug("Configuring vpn users list")
+ vpnuser = CsVpnUser("vpnuserlist", config)
+ vpnuser.process()
- if process_file in ["cmd_line.json", "vpn_user_list.json"]:
- logging.debug("Configuring vpn users list")
- vpnuser = CsVpnUser("vpnuserlist", config)
- vpnuser.process()
+ if process_file in ["cmd_line.json", "vm_dhcp_entry.json", "dhcp.json"]:
+ logging.debug("Configuring dhcp entry")
+ dhcp = CsDhcp("dhcpentry", config)
+ dhcp.process()
- if process_file in ["cmd_line.json", "vm_dhcp_entry.json", "dhcp.json"]:
- logging.debug("Configuring dhcp entry")
- dhcp = CsDhcp("dhcpentry", config)
- dhcp.process()
+ if process_file in ["cmd_line.json", "load_balancer.json"]:
+ logging.debug("Configuring load balancer")
+ iptables_change = True
- if process_file in ["cmd_line.json", "load_balancer.json"]:
- logging.debug("Configuring load balancer")
- iptables_change = True
+ if process_file in ["cmd_line.json", "monitor_service.json"]:
+ logging.debug("Configuring monitor service")
+ mon = CsMonitor("monitorservice", config)
+ mon.process()
- if process_file in ["cmd_line.json", "monitor_service.json"]:
- logging.debug("Configuring monitor service")
- mon = CsMonitor("monitorservice", config)
- mon.process()
+ # If iptable rules have changed, apply them.
+ if iptables_change:
+ acls = CsAcl('networkacl', config)
+ acls.process()
- # If iptable rules have changed, apply them.
- if iptables_change:
- acls = CsAcl('networkacl', config)
- acls.process()
+ acls = CsAcl('firewallrules', config)
+ acls.flushAllowAllEgressRules()
+ acls.process()
- acls = CsAcl('firewallrules', config)
- acls.process()
+ fwd = CsForwardingRules("forwardingrules", config)
+ fwd.process()
- fwd = CsForwardingRules("forwardingrules", config)
- fwd.process()
+ vpns = CsSite2SiteVpn("site2sitevpn", config)
+ vpns.process()
- vpns = CsSite2SiteVpn("site2sitevpn", config)
- vpns.process()
+ rvpn = CsRemoteAccessVpn("remoteaccessvpn", config)
+ rvpn.process()
- rvpn = CsRemoteAccessVpn("remoteaccessvpn", config)
- rvpn.process()
+ lb = CsLoadBalancer("loadbalancer", config)
+ lb.process()
- lb = CsLoadBalancer("loadbalancer", config)
- lb.process()
+ logging.debug("Configuring iptables rules")
+ nf = CsNetfilters()
+ nf.compare(config.get_fw())
- logging.debug("Configuring iptables rules")
- nf = CsNetfilters()
- nf.compare(config.get_fw())
+ logging.debug("Configuring iptables rules done ...saving rules")
- logging.debug("Configuring iptables rules done ...saving rules")
+ # Save iptables configuration - will be loaded on reboot by the iptables-restore that is configured on /etc/rc.local
+ CsHelper.save_iptables("iptables-save", "/etc/iptables/router_rules.v4")
+ CsHelper.save_iptables("ip6tables-save", "/etc/iptables/router_rules.v6")
- # Save iptables configuration - will be loaded on reboot by the iptables-restore that is configured on /etc/rc.local
- CsHelper.save_iptables("iptables-save", "/etc/iptables/router_rules.v4")
- CsHelper.save_iptables("ip6tables-save", "/etc/iptables/router_rules.v6")
+ red = CsRedundant(config)
+ red.set()
- red = CsRedundant(config)
- red.set()
-
- if process_file in ["cmd_line.json", "static_routes.json"]:
- logging.debug("Configuring static routes")
- static_routes = CsStaticRoutes("staticroutes", config)
- static_routes.process()
+ if process_file in ["cmd_line.json", "static_routes.json"]:
+ logging.debug("Configuring static routes")
+ static_routes = CsStaticRoutes("staticroutes", config)
+ static_routes.process()
+ except Exception:
+ logging.exception("Exception while configuring router")
if __name__ == "__main__":
main(sys.argv)
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py
index e4c5d1f..075fddb 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py
@@ -15,15 +15,13 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-from CsDatabag import CsDataBag, CsCmdLine
-from CsApp import CsApache, CsDnsmasq, CsPasswdSvc
-import CsHelper
import logging
from netaddr import IPAddress, IPNetwork
-import CsHelper
-
import subprocess
import time
+import CsHelper
+from CsDatabag import CsDataBag
+from CsApp import CsApache, CsDnsmasq, CsPasswdSvc
from CsRoute import CsRoute
from CsRule import CsRule
@@ -198,7 +196,7 @@
return self.get_attr("add")
def to_str(self):
- pprint(self.address)
+ return self.address
class CsDevice:
@@ -293,9 +291,10 @@
interfaces = [CsInterface(address, self.config)]
CsHelper.reconfigure_interfaces(self.cl, interfaces)
-
self.set_mark()
- self.arpPing()
+
+ if 'gateway' in self.address:
+ self.arpPing()
CsRpsrfs(self.dev).enable()
self.post_config_change("add")
@@ -360,6 +359,10 @@
"-m state --state RELATED,ESTABLISHED " +
"-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff"])
+ self.fw.append(["mangle", "front",
+ "-A POSTROUTING " +
+ "-p udp -m udp --dport 68 -j CHECKSUM --checksum-fill"])
+
if self.get_type() in ["public"]:
self.fw.append(["mangle", "front",
"-A PREROUTING " +
@@ -376,9 +379,6 @@
"-A VPN_%s -m state --state RELATED,ESTABLISHED -j ACCEPT" % self.address['public_ip']])
self.fw.append(["mangle", "",
"-A VPN_%s -j RETURN" % self.address['public_ip']])
- self.fw.append(["mangle", "front",
- "-A POSTROUTING " +
- "-p udp -m udp --dport 68 -j CHECKSUM --checksum-fill"])
self.fw.append(["nat", "",
"-A POSTROUTING -o eth2 -j SNAT --to-source %s" % self.address['public_ip']])
self.fw.append(["mangle", "",
@@ -395,12 +395,13 @@
self.fw.append(["filter", "", "-A INPUT -i lo -j ACCEPT"])
if self.get_type() in ["guest"]:
+ guestNetworkCidr = self.address['network']
self.fw.append(
["filter", "", "-A INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % self.dev])
self.fw.append(
- ["filter", "", "-A INPUT -i %s -p udp -m udp --dport 53 -j ACCEPT" % self.dev])
+ ["filter", "", "-A INPUT -i %s -p udp -m udp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
- ["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 53 -j ACCEPT" % self.dev])
+ ["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 80 -m state --state NEW -j ACCEPT" % self.dev])
self.fw.append(
@@ -433,23 +434,32 @@
self.fw.append(["mangle", "front", "-A PREROUTING " +
"-m state --state RELATED,ESTABLISHED " +
"-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff"])
+
+ self.fw.append(["filter", "", "-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT"])
+
if self.get_type() in ["guest"]:
+ guestNetworkCidr = self.address['network']
self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" %
- (self.address['network'], self.dev, self.dev)])
+ (guestNetworkCidr, self.dev, self.dev)])
self.fw.append(
["filter", "front", "-A ACL_INBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev])
self.fw.append(
["filter", "front", "-A ACL_INBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev])
self.fw.append(
+ ["filter", "", "-A ACL_INBOUND_%s -j DROP" % self.dev])
+
+ self.fw.append(
["mangle", "front", "-A ACL_OUTBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev])
self.fw.append(
["mangle", "front", "-A ACL_OUTBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev])
self.fw.append(
["filter", "", "-A INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % self.dev])
self.fw.append(
- ["filter", "", "-A INPUT -i %s -p udp -m udp --dport 53 -j ACCEPT" % self.dev])
+ ["mangle", "front", "-A POSTROUTING " + "-p udp -m udp --dport 68 -j CHECKSUM --checksum-fill"])
self.fw.append(
- ["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 53 -j ACCEPT" % self.dev])
+ ["filter", "", "-A INPUT -i %s -p udp -m udp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)])
+ self.fw.append(
+ ["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 80 -m state --state NEW -j ACCEPT" % self.dev])
@@ -457,18 +467,16 @@
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 8080 -m state --state NEW -j ACCEPT" % self.dev])
self.fw.append(["mangle", "",
"-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" %
- (self.dev, self.address[
- 'network'], self.address['gateway'], self.dev)
- ])
+ (self.dev, guestNetworkCidr, self.address['gateway'], self.dev)])
+
+ self.fw.append(["", "front", "-A NETWORK_STATS_%s -i %s -d %s" %
+ ("eth1", "eth1", guestNetworkCidr)])
self.fw.append(["", "front", "-A NETWORK_STATS_%s -o %s -s %s" %
- ("eth1", "eth1", self.address['network'])])
- self.fw.append(["", "front", "-A NETWORK_STATS_%s -o %s -d %s" %
- ("eth1", "eth1", self.address['network'])])
+ ("eth1", "eth1", guestNetworkCidr)])
+
self.fw.append(["nat", "front",
"-A POSTROUTING -s %s -o %s -j SNAT --to-source %s" %
- (self.address['network'], self.dev,
- self.address['public_ip'])
- ])
+ (guestNetworkCidr, self.dev, self.address['public_ip'])])
if self.get_type() in ["public"]:
self.fw.append(["", "front",
@@ -497,7 +505,10 @@
self.fw.append(["filter", "", "-A INPUT -d 225.0.0.50/32 -j ACCEPT"])
self.fw.append(["filter", "", "-A INPUT -p icmp -j ACCEPT"])
+ self.fw.append(["filter", "", "-A INPUT -i lo -j ACCEPT"])
+
self.fw.append(["filter", "", "-A INPUT -i eth0 -p tcp -m tcp --dport 3922 -m state --state NEW,ESTABLISHED -j ACCEPT"])
+ self.fw.append(["filter", "", "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT"])
self.fw.append(["filter", "", "-P INPUT DROP"])
self.fw.append(["filter", "", "-P FORWARD DROP"])
@@ -514,16 +525,19 @@
self.fw_vpcrouter()
# On deletion nw_type will no longer be known
- if self.get_type() in ["guest"] and self.config.is_vpc():
+ if self.get_type() in ('guest'):
+ if self.config.is_vpc() or self.config.is_router():
+ CsDevice(self.dev, self.config).configure_rp()
+ logging.error(
+ "Not able to setup source-nat for a regular router yet")
- CsDevice(self.dev, self.config).configure_rp()
+ if self.config.has_dns() or self.config.is_dhcp():
+ dns = CsDnsmasq(self)
+ dns.add_firewall_rules()
- logging.error(
- "Not able to setup source-nat for a regular router yet")
- dns = CsDnsmasq(self)
- dns.add_firewall_rules()
- app = CsApache(self)
- app.setup()
+ if self.config.has_metadata():
+ app = CsApache(self)
+ app.setup()
cmdline = self.config.cmdline()
# If redundant then this is dealt with by the master backup functions
@@ -534,7 +548,7 @@
if self.address["source_nat"]:
vpccidr = cmdline.get_vpccidr()
self.fw.append(
- ["filter", "", "-A FORWARD -s %s ! -d %s -j ACCEPT" % (vpccidr, vpccidr)])
+ ["filter", 3, "-A FORWARD -s %s ! -d %s -j ACCEPT" % (vpccidr, vpccidr)])
self.fw.append(
["nat", "", "-A POSTROUTING -j SNAT -o %s --to-source %s" % (self.dev, self.address['public_ip'])])
@@ -685,3 +699,4 @@
if count < 2:
logging.debug("Single CPU machine")
return count
+
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsApp.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsApp.py
index a0b4c6e..9762e04 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsApp.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsApp.py
@@ -28,35 +28,42 @@
self.ip = ip.get_ip_address()
self.type = ip.get_type()
self.fw = ip.fw
+ self.config = ip.config
class CsApache(CsApp):
""" Set up Apache """
def remove(self):
- file = "/etc/apache2/conf.d/vhost%s.conf" % self.dev
+ file = "/etc/apache2/sites-enabled/vhost-%s.conf" % self.dev
if os.path.isfile(file):
os.remove(file)
CsHelper.service("apache2", "restart")
def setup(self):
- CsHelper.copy_if_needed("/etc/apache2/vhostexample.conf",
- "/etc/apache2/conf.d/vhost%s.conf" % self.dev)
+ CsHelper.copy_if_needed("/etc/apache2/vhost.template",
+ "/etc/apache2/sites-enabled/vhost-%s.conf" % self.ip)
- file = CsFile("/etc/apache2/conf.d/vhost%s.conf" % (self.dev))
- file.search("<VirtualHost.*:80>", "\t<VirtualHost %s:80>" % (self.ip))
+ file = CsFile("/etc/apache2/sites-enabled/vhost-%s.conf" % (self.ip))
file.search("<VirtualHost.*:80>", "\t<VirtualHost %s:80>" % (self.ip))
file.search("<VirtualHost.*:443>", "\t<VirtualHost %s:443>" % (self.ip))
file.search("Listen .*:80", "Listen %s:80" % (self.ip))
file.search("Listen .*:443", "Listen %s:443" % (self.ip))
- file.search("ServerName.*", "\tServerName vhost%s.cloudinternal.com" % (self.dev))
+ file.search("NameVirtualHost .*:80", "NameVirtualHost %s:80" % (self.ip))
+ file.search("ServerName.*", "\tServerName %s.%s" % (self.config.cl.get_type(), self.config.get_domain()))
if file.is_changed():
file.commit()
CsHelper.service("apache2", "restart")
- self.fw.append(["", "front",
- "-A INPUT -i %s -d %s/32 -p tcp -m tcp -m state --state NEW --dport 80 -j ACCEPT" % (self.dev, self.ip)
- ])
+ self.fw.append([
+ "", "front",
+ "-A INPUT -i %s -d %s/32 -p tcp -m tcp -m state --state NEW --dport 80 -j ACCEPT" % (self.dev, self.ip)
+ ])
+
+ self.fw.append([
+ "", "front",
+ "-A INPUT -i %s -d %s/32 -p tcp -m tcp -m state --state NEW --dport 443 -j ACCEPT" % (self.dev, self.ip)
+ ])
class CsPasswdSvc():
@@ -94,10 +101,13 @@
"-A INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % self.dev
])
- self.fw.append(["", "front",
- "-A INPUT -i %s -d %s/32 -p udp -m udp --dport 53 -j ACCEPT" % (self.dev, self.ip)
- ])
+ if self.config.has_dns():
+ self.fw.append([
+ "", "front",
+ "-A INPUT -i %s -d %s/32 -p udp -m udp --dport 53 -j ACCEPT" % (self.dev, self.ip)
+ ])
- self.fw.append(["", "front",
- "-A INPUT -i %s -d %s/32 -p tcp -m tcp --dport 53 -j ACCEPT" % (self.dev, self.ip)
- ])
+ self.fw.append([
+ "", "front",
+ "-A INPUT -i %s -d %s/32 -p tcp -m tcp --dport 53 -j ACCEPT" % (self.dev, self.ip)
+ ])
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsConfig.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsConfig.py
index a35a545..e3b9009 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsConfig.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsConfig.py
@@ -58,25 +58,38 @@
return self.__LOG_LEVEL
def is_vpc(self):
- return self.cl.get_type() == "vpcrouter"
+ return self.cl.get_type() == 'vpcrouter'
def is_router(self):
- return self.cl.get_type() == "router"
+ return self.cl.get_type() == 'router'
+
+ def is_dhcp(self):
+ return self.cl.get_type() == 'dhcpsrvr'
+
+ def has_dns(self):
+ return not self.use_extdns()
+
+ def has_metadata(self):
+ return any((self.is_vpc(), self.is_router(), self.is_dhcp()))
def get_domain(self):
return self.cl.get_domain()
+ def use_extdns(self):
+ return self.cmdline().idata().get('useextdns', 'false') == 'true'
+
def get_dns(self):
+ conf = self.cmdline().idata()
dns = []
- if not self.cl.get_use_ext_dns():
- if not self.is_vpc() and self.cl.is_redundant():
+ if not self.use_extdns():
+ if not self.is_vpc() and self.cl.is_redundant() and self.cl.get_guest_gw():
dns.append(self.cl.get_guest_gw())
else:
dns.append(self.address().get_guest_ip())
- names = ["dns1", "dns2"]
- for name in names:
- if name in self.cmdline().idata():
- dns.append(self.cmdline().idata()[name])
+
+ for name in ('dns1', 'dns2'):
+ if name in conf:
+ dns.append(conf[name])
return dns
def get_format(self):
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py
index 3f102e6..d97c04b 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py
@@ -17,6 +17,7 @@
import CsHelper
import logging
from netaddr import *
+from random import randint
from CsGuestNetwork import CsGuestNetwork
from cs.CsDatabag import CsDataBag
from cs.CsFile import CsFile
@@ -44,7 +45,7 @@
continue
self.add(self.dbag[item])
self.write_hosts()
-
+
if self.cloud.is_changed():
self.delete_leases()
@@ -59,23 +60,24 @@
def configure_server(self):
# self.conf.addeq("dhcp-hostsfile=%s" % DHCP_HOSTS)
+ idx = 0
for i in self.devinfo:
if not i['dnsmasq']:
continue
device = i['dev']
ip = i['ip'].split('/')[0]
- sline = "dhcp-range=interface:%s,set:interface" % (device)
- line = "dhcp-range=interface:%s,set:interface-%s,%s,static" % (device, device, ip)
+ sline = "dhcp-range=interface:%s,set:interface-%s-%s" % (device, device, idx)
+ line = "dhcp-range=interface:%s,set:interface-%s-%s,%s,static" % (device, device, idx, ip)
self.conf.search(sline, line)
gn = CsGuestNetwork(device, self.config)
- sline = "dhcp-option=tag:interface-%s,15" % device
- line = "dhcp-option=tag:interface-%s,15,%s" % (device, gn.get_domain())
+ sline = "dhcp-option=tag:interface-%s-%s,15" % (device, idx)
+ line = "dhcp-option=tag:interface-%s-%s,15,%s" % (device, idx, gn.get_domain())
self.conf.search(sline, line)
# DNS search order
if gn.get_dns() and device:
- sline = "dhcp-option=tag:interface-%s,6" % device
+ sline = "dhcp-option=tag:interface-%s-%s,6" % (device, idx)
dns_list = [x for x in gn.get_dns() if x is not None]
- line = "dhcp-option=tag:interface-%s,6,%s" % (device, ','.join(dns_list))
+ line = "dhcp-option=tag:interface-%s-%s,6,%s" % (device, idx, ','.join(dns_list))
self.conf.search(sline, line)
# Gateway
gateway = ''
@@ -83,8 +85,8 @@
gateway = gn.get_gateway()
else:
gateway = i['gateway']
- sline = "dhcp-option=tag:interface-%s,3," % device
- line = "dhcp-option=tag:interface-%s,3,%s" % (device, gateway)
+ sline = "dhcp-option=tag:interface-%s-%s,3," % (device, idx)
+ line = "dhcp-option=tag:interface-%s-%s,3,%s" % (device, idx, gateway)
self.conf.search(sline, line)
# Netmask
netmask = ''
@@ -92,9 +94,10 @@
netmask = gn.get_netmask()
else:
netmask = self.config.address().get_guest_netmask()
- sline = "dhcp-option=tag:interface-%s,1," % device
- line = "dhcp-option=tag:interface-%s,1,%s" % (device, netmask)
+ sline = "dhcp-option=tag:interface-%s-%s,1," % (device, idx)
+ line = "dhcp-option=tag:interface-%s-%s,1,%s" % (device, idx, netmask)
self.conf.search(sline, line)
+ idx += 1
def delete_leases(self):
try:
@@ -104,7 +107,7 @@
def preseed(self):
self.add_host("127.0.0.1", "localhost")
- self.add_host("::1", "localhost ip6-localhost ip6-loopback")
+ self.add_host("::1", "localhost ip6-localhost ip6-loopback")
self.add_host("ff02::1", "ip6-allnodes")
self.add_host("ff02::2", "ip6-allrouters")
if self.config.is_vpc():
@@ -125,9 +128,15 @@
def add(self, entry):
self.add_host(entry['ipv4_adress'], entry['host_name'])
- self.cloud.add("%s,%s,%s,infinite" % (entry['mac_address'],
- entry['ipv4_adress'],
- entry['host_name']))
+
+ # lease time boils down to once a month
+ # with a splay of 60 hours to prevent storms
+ lease = randint(700, 760)
+ self.cloud.add("%s,%s,%s,%sh" % (entry['mac_address'],
+ entry['ipv4_adress'],
+ entry['host_name'],
+ lease
+ ))
i = IPAddress(entry['ipv4_adress'])
# Calculate the device
for v in self.devinfo:
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsGuestNetwork.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsGuestNetwork.py
index e1afb92..d23a870 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsGuestNetwork.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsGuestNetwork.py
@@ -38,13 +38,15 @@
def get_dns(self):
if not self.guest:
return self.config.get_dns()
- # Can a router provide dhcp but not dns?
- if 'dns' in self.data and 'router_guest_gateway' in self.data:
- return [self.data['router_guest_gateway']] + self.data['dns'].split(',')
- elif "router_guest_gateway" in self.data:
- return [self.data['router_guest_gateway']]
- else:
- return [""]
+
+ dns = []
+ if not self.config.use_extdns() and 'router_guest_gateway' in self.data:
+ dns.append(self.data['router_guest_gateway'])
+
+ if 'dns' in self.data:
+ dns.extend(self.data['dns'].split(','))
+
+ return dns or ['']
def set_dns(self, val):
self.data['dns'] = val
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsNetfilter.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsNetfilter.py
index 4b5b492..3ee5174 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsNetfilter.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsNetfilter.py
@@ -133,24 +133,29 @@
def compare(self, list):
""" Compare reality with what is needed """
- for c in self.chain.get("filter"):
- # Ensure all inbound/outbound chains have a default drop rule
- if c.startswith("ACL_INBOUND") or c.startswith("ACL_OUTBOUND"):
- list.append(["filter", "", "-A %s -j DROP" % c])
# PASS 1: Ensure all chains are present
for fw in list:
new_rule = CsNetfilter()
new_rule.parse(fw[2])
new_rule.set_table(fw[0])
self.add_chain(new_rule)
+
+ ruleSet = set()
# PASS 2: Create rules
for fw in list:
+ tupledFw = tuple(fw)
+ if tupledFw in ruleSet :
+ logging.debug("Already processed : %s", tupledFw)
+ continue
+
new_rule = CsNetfilter()
new_rule.parse(fw[2])
new_rule.set_table(fw[0])
if isinstance(fw[1], int):
new_rule.set_count(fw[1])
+ rule_chain = new_rule.get_chain()
+
logging.debug("Checking if the rule already exists: rule=%s table=%s chain=%s", new_rule.get_rule(), new_rule.get_table(), new_rule.get_chain())
if self.has_rule(new_rule):
logging.debug("Exists: rule=%s table=%s", fw[2], new_rule.get_table())
@@ -162,9 +167,15 @@
if fw[1] == "front":
cpy = cpy.replace('-A', '-I')
if isinstance(fw[1], int):
- cpy = cpy.replace("-A %s" % new_rule.get_chain(), '-I %s %s' % (new_rule.get_chain(), fw[1]))
-
+ # if the rule is for ACLs, we want to insert them in order, right before the DROP all
+ if rule_chain.startswith("ACL_INBOUND"):
+ rule_count = self.chain.get_count(rule_chain)
+ cpy = cpy.replace("-A %s" % new_rule.get_chain(), '-I %s %s' % (new_rule.get_chain(), rule_count))
+ else:
+ cpy = cpy.replace("-A %s" % new_rule.get_chain(), '-I %s %s' % (new_rule.get_chain(), fw[1]))
CsHelper.execute("iptables -t %s %s" % (new_rule.get_table(), cpy))
+ ruleSet.add(tupledFw)
+ self.chain.add_rule(rule_chain)
self.del_standard()
self.get_unseen()
diff --git a/systemvm/patches/debian/config/opt/cloud/bin/merge.py b/systemvm/patches/debian/config/opt/cloud/bin/merge.py
index aab29e8..50d9ee9 100755
--- a/systemvm/patches/debian/config/opt/cloud/bin/merge.py
+++ b/systemvm/patches/debian/config/opt/cloud/bin/merge.py
@@ -129,6 +129,13 @@
dbag = self.process_vpnusers(self.db.getDataBag())
elif self.qFile.type == 'staticroutes':
dbag = self.process_staticroutes(self.db.getDataBag())
+ elif self.qFile.type == 'ipaliases':
+ self.db.setKey('ips')
+ self.db.load()
+ dbag = self.process_ipaliases(self.db.getDataBag())
+ elif self.qFile.type == 'dhcpconfig':
+ logging.error("I don't think I need %s anymore", self.qFile.type)
+ return
else:
logging.error("Error I do not know what to do with file of type %s", self.qFile.type)
return
@@ -238,6 +245,30 @@
cs_vmdata.merge(dbag, self.qFile.data)
return dbag
+ def process_ipaliases(self, dbag):
+ nic_dev = None
+ # Should be a way to deal with this better
+ for intf, data in dbag.items():
+ if intf == 'id':
+ continue
+ elif any([net['nw_type'] == 'guest' for net in data]):
+ nic_dev = intf
+ break
+
+ assert nic_dev is not None, 'Unable to determine Guest interface'
+
+ nic_dev_id = nic_dev[3:]
+
+ for alias in self.qFile.data['aliases']:
+ ip = {
+ 'add': not alias['revoke'],
+ 'nw_type': 'guest',
+ 'public_ip': alias['ip_address'],
+ 'netmask': alias['netmask'],
+ 'nic_dev_id': nic_dev_id
+ }
+ dbag = cs_ip.merge(dbag, ip)
+ return dbag
class QueueFile:
diff --git a/systemvm/pom.xml b/systemvm/pom.xml
index 1439124..96b1c78 100644
--- a/systemvm/pom.xml
+++ b/systemvm/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
diff --git a/systemvm/scripts/config_ssl.sh b/systemvm/scripts/config_ssl.sh
index 9dfb927..8635887 100755
--- a/systemvm/scripts/config_ssl.sh
+++ b/systemvm/scripts/config_ssl.sh
@@ -16,9 +16,6 @@
# specific language governing permissions and limitations
# under the License.
-
-
-
help() {
printf " -c use customized key/cert\n"
printf " -k path of private key\n"
@@ -123,6 +120,8 @@
publicIp=
hostName=
keyStore=$(dirname $0)/certs/realhostip.keystore
+defaultJavaKeyStoreFile=/etc/ssl/certs/java/cacerts
+defaultJavaKeyStorePass="changeit"
aliasName="CPVMCertificate"
storepass="vmops.com"
while getopts 'i:h:k:p:t:u:c' OPTION
@@ -167,13 +166,13 @@
fi
if [ ! -f "$customPrivKey" ]
then
- printf "priviate key file is not exist\n"
+ printf "private key file does not exist\n"
exit 2
fi
if [ ! -f "$customPrivCert" ]
then
- printf "public certificate is not exist\n"
+ printf "public certificate does not exist\n"
exit 3
fi
@@ -181,7 +180,7 @@
then
if [ ! -f "$customCertChain" ]
then
- printf "certificate chain is not exist\n"
+ printf "certificate chain does not exist\n"
exit 4
fi
fi
@@ -204,6 +203,7 @@
then
keytool -delete -alias $aliasName -keystore $keyStore -storepass $storepass -noprompt
keytool -import -alias $aliasName -keystore $keyStore -storepass $storepass -noprompt -file $customCACert
+ keytool -importkeystore -srckeystore $defaultJavaKeyStoreFile -destkeystore $keyStore -srcstorepass $defaultJavaKeyStorePass -deststorepass $storepass -noprompt
fi
if [ -d /etc/apache2 ]
diff --git a/test/integration/component/maint/test_capacity_host_delete.py b/test/integration/component/maint/test_capacity_host_delete.py
new file mode 100644
index 0000000..aba5152
--- /dev/null
+++ b/test/integration/component/maint/test_capacity_host_delete.py
@@ -0,0 +1,210 @@
+# 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 by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Test from the Marvin - Testing in Python wiki
+
+# All tests inherit from cloudstackTestCase
+from marvin.cloudstackTestCase import cloudstackTestCase, unittest
+
+# Import Integration Libraries
+
+# base - contains all resources as entities and defines create, delete,
+# list operations on them
+from marvin.lib.base import Host, Cluster, Zone, Pod
+
+# utils - utility classes for common cleanup, external library wrappers etc
+from marvin.lib.utils import cleanup_resources
+
+# common - commonly used methods for all tests are listed here
+from marvin.lib.common import get_zone, get_domain, list_hosts, get_pod
+
+from nose.plugins.attrib import attr
+
+import time
+import logging
+# These tests need to be run separately and not in parallel with other tests.
+# Because it disables the host
+# host_id column of op_host_capacity refers to host_id or a storage pool id
+#
+# This test is to make sure that Disable host only disables the capacities of type
+# CPU and MEMORY
+#
+# TEST:
+# Base Condition: There exists a host and storage pool with same id
+#
+# Steps:
+# 1. Find a host and storage pool having same id
+# 2. Disable the host
+# 3. verify that the CPU(1) and MEMORY(0) capacity in op_host_capacity for above host
+# is disabled
+# 4. verify that the STORAGE(3) capacity in op_host_capacity for storage pool with id
+# same as above host is not disabled
+#
+
+def update_host(apiclient, state, host_id):
+ """
+ Function to Enable/Disable Host
+ """
+ host_status = Host.update(
+ apiclient,
+ id=host_id,
+ allocationstate=state
+ )
+ return host_status.resourcestate
+
+
+def check_db(self, host_state):
+ """
+ Function to check capacity_state in op_host_capacity table
+ """
+ capacity_state = None
+ if self.host_db_id and self.host_db_id[0]:
+ capacity_state = self.dbclient.execute(
+ "select capacity_state from op_host_capacity where host_id='%s' and capacity_type in (0,1) order by capacity_type asc;" %
+ self.host_db_id[0][0])
+
+ if capacity_state and len(capacity_state)==2:
+ if capacity_state[0]:
+ self.assertEqual(
+ capacity_state[0][0],
+ host_state +
+ "d",
+ "Invalid db query response for capacity_state %s" %
+ capacity_state[0][0])
+
+ if capacity_state[1]:
+ self.assertEqual(
+ capacity_state[1][0],
+ host_state +
+ "d",
+ "Invalid db query response for capacity_state %s" %
+ capacity_state[1][0])
+ else:
+ self.logger.debug("Could not find capacities of type 1 and 0. Does not have necessary data to run this test")
+
+ capacity_state = None
+ if self.host_db_id and self.host_db_id[0]:
+ capacity_state = self.dbclient.execute(
+ "select capacity_state from op_host_capacity where host_id='%s' and capacity_type = 3 order by capacity_type asc;" %
+ self.host_db_id[0][0])
+
+ if capacity_state and capacity_state[0]:
+ self.assertNotEqual(
+ capacity_state[0][0],
+ host_state +
+ "d",
+ "Invalid db query response for capacity_state %s" %
+ capacity_state[0][0])
+ else:
+ self.logger.debug("Could not find capacities of type 3. Does not have necessary data to run this test")
+
+
+class TestHosts(cloudstackTestCase):
+
+ """
+ Testing Hosts
+ """
+ @classmethod
+ def setUpClass(cls):
+ cls.testClient = super(TestHosts, cls).getClsTestClient()
+ cls.testdata = cls.testClient.getParsedTestDataConfig()
+ cls.apiclient = cls.testClient.getApiClient()
+ cls.dbclient = cls.testClient.getDbConnection()
+ cls._cleanup = []
+
+ # get zone, domain etc
+ cls.zone = Zone(get_zone(cls.apiclient, cls.testClient.getZoneForTests()).__dict__)
+ cls.domain = get_domain(cls.apiclient)
+ cls.pod = get_pod(cls.apiclient, cls.zone.id)
+
+ cls.logger = logging.getLogger('TestHosts')
+ cls.stream_handler = logging.StreamHandler()
+ cls.logger.setLevel(logging.DEBUG)
+ cls.logger.addHandler(cls.stream_handler)
+
+ cls.storage_pool_db_id = None
+ # list hosts
+ hosts = list_hosts(cls.apiclient, type="Routing")
+ i = 0
+ while (i < len(hosts)):
+ host_id = hosts[i].id
+ cls.logger.debug("Trying host id : %s" % host_id)
+ host_db_id = cls.dbclient.execute(
+ "select id from host where uuid='%s';" %
+ host_id)
+
+ if host_db_id and host_db_id[0]:
+ cls.logger.debug("found host db id : %s" % host_db_id)
+ storage_pool_db_id = cls.dbclient.execute(
+ "select id from storage_pool where id='%s' and removed is null;" %
+ host_db_id[0][0])
+
+ if storage_pool_db_id and storage_pool_db_id[0]:
+ cls.logger.debug("Found storage_pool_db_id : %s" % storage_pool_db_id[0][0])
+ capacity_state = cls.dbclient.execute(
+ "select count(capacity_state) from op_host_capacity where host_id='%s' and capacity_type in (0,1,3) and capacity_state = 'Enabled'" %
+ host_db_id[0][0])
+
+ if capacity_state and capacity_state[0]:
+ cls.logger.debug("Check capacity count : %s" % capacity_state[0][0])
+
+ if capacity_state[0][0] == 3:
+ cls.logger.debug("found host id : %s, can be used for this test" % host_id)
+ cls.my_host_id = host_id
+ cls.host_db_id = host_db_id
+ cls.storage_pool_db_id = storage_pool_db_id
+ break
+ if not cls.storage_pool_db_id:
+ i = i + 1
+
+
+ if cls.storage_pool_db_id is None:
+ raise unittest.SkipTest("There is no host and storage pool available in the setup to run this test")
+
+
+
+ @classmethod
+ def tearDownClass(cls):
+ cleanup_resources(cls.apiclient, cls._cleanup)
+ return
+
+ def setUp(self):
+ self.logger.debug("Capacity check for Disable host")
+ self.cleanup = []
+ return
+
+ def tearDown(self):
+ # Clean up
+ cleanup_resources(self.apiclient, self.cleanup)
+ return
+
+ @attr(tags=["advanced", "basic"], required_hardware="false")
+ def test_01_op_host_capacity_disable_host(self):
+
+ host_state = "Disable"
+ host_resourcestate = update_host(
+ self.apiclient,
+ host_state,
+ self.my_host_id)
+ self.assertEqual(
+ host_resourcestate,
+ host_state + "d",
+ "Host state not correct"
+ )
+ check_db(self, host_state)
+
+ return
diff --git a/test/integration/component/maint/test_ha_pool_maintenance.py b/test/integration/component/maint/test_ha_pool_maintenance.py
new file mode 100644
index 0000000..e737726
--- /dev/null
+++ b/test/integration/component/maint/test_ha_pool_maintenance.py
@@ -0,0 +1,236 @@
+#!/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.
+
+from nose.plugins.attrib import attr
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import (enableStorageMaintenance,
+ cancelStorageMaintenance
+ )
+from marvin.lib.utils import (cleanup_resources,
+ validateList)
+from marvin.lib.base import (Account,
+ VirtualMachine,
+ ServiceOffering,
+ Cluster,
+ StoragePool,
+ Volume)
+from marvin.lib.common import (get_zone,
+ get_domain,
+ get_template,
+ list_hosts
+ )
+from marvin.codes import PASS
+
+
+class testHaPoolMaintenance(cloudstackTestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ try:
+ cls._cleanup = []
+ cls.testClient = super(
+ testHaPoolMaintenance,
+ cls).getClsTestClient()
+ cls.api_client = cls.testClient.getApiClient()
+ cls.services = cls.testClient.getParsedTestDataConfig()
+ # Get Domain, Zone, Template
+ cls.domain = get_domain(cls.api_client)
+ cls.zone = get_zone(
+ cls.api_client,
+ cls.testClient.getZoneForTests())
+ cls.template = get_template(
+ cls.api_client,
+ cls.zone.id,
+ cls.services["ostype"]
+ )
+ cls.hypervisor = cls.testClient.getHypervisorInfo()
+ cls.services['mode'] = cls.zone.networktype
+ cls.hypervisor = cls.testClient.getHypervisorInfo()
+ cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+ cls.services["virtual_machine"]["template"] = cls.template.id
+ cls.clusterWithSufficientPool = None
+ cls.listResponse = None
+ clusters = Cluster.list(cls.api_client, zoneid=cls.zone.id)
+
+ if not validateList(clusters)[0]:
+
+ cls.debug(
+ "check list cluster response for zone id %s" %
+ cls.zone.id)
+ cls.listResponse = True
+ return
+
+ for cluster in clusters:
+ cls.pool = StoragePool.list(cls.api_client,
+ clusterid=cluster.id,
+ keyword="NetworkFilesystem"
+ )
+
+ if not validateList(cls.pool)[0]:
+
+ cls.debug(
+ "check list cluster response for zone id %s" %
+ cls.zone.id)
+ cls.listResponse = True
+ return
+
+ if len(cls.pool) >= 2:
+ cls.clusterWithSufficientPool = cluster
+ break
+ if not cls.clusterWithSufficientPool:
+ return
+
+ cls.services["service_offerings"][
+ "tiny"]["offerha"] = "True"
+
+ cls.services_off = ServiceOffering.create(
+ cls.api_client,
+ cls.services["service_offerings"]["tiny"])
+ cls._cleanup.append(cls.services_off)
+
+ except Exception as e:
+ cls.tearDownClass()
+ raise Exception("Warning: Exception in setup : %s" % e)
+ return
+
+ def setUp(self):
+
+ self.apiClient = self.testClient.getApiClient()
+ self.dbclient = self.testClient.getDbConnection()
+ self.cleanup = []
+ if self.listResponse:
+ self.fail(
+ "Check list response")
+ if not self.clusterWithSufficientPool:
+ self.skipTest(
+ "sufficient storage not available in any cluster for zone %s" %
+ self.zone.id)
+ self.account = Account.create(
+ self.api_client,
+ self.services["account"],
+ domainid=self.domain.id
+ )
+ self.cleanup.append(self.account)
+
+ def tearDown(self):
+ # Clean up, terminate the created resources
+ StoragePool.cancelMaintenance(self.api_client,
+ id=self.storageid[0][0])
+ cleanup_resources(self.apiClient, self.cleanup)
+ return
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ cleanup_resources(cls.api_client, cls._cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+
+ return
+
+ @attr(tags=["advanced", "cl", "advancedns", "sg",
+ "basic", "eip", "simulator", "multihost"])
+ def test_ha_with_storage_maintenance(self):
+ """put storage in maintenance mode and start ha vm and check usage"""
+ # Steps
+ # 1. Create a Compute service offering with the 'Offer HA' option
+ # selected.
+ # 2. Create a Guest VM with the compute service offering created above.
+ # 3. put PS into maintenance mode
+ # 4. vm should go in stop state
+ # 5. start vm ,vm should come up on another storage
+ # 6. check usage events are getting generated for root disk
+
+ host = list_hosts(
+ self.api_client,
+ clusterid=self.clusterWithSufficientPool.id)
+ self.assertEqual(validateList(host)[0],
+ PASS,
+ "check list host response for cluster id %s"
+ % self.clusterWithSufficientPool.id)
+
+ self.virtual_machine_with_ha = VirtualMachine.create(
+ self.api_client,
+ self.services["virtual_machine"],
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ serviceofferingid=self.services_off.id,
+ hostid=host[0].id
+ )
+
+ vms = VirtualMachine.list(
+ self.api_client,
+ id=self.virtual_machine_with_ha.id,
+ listall=True,
+ )
+
+ self.assertEqual(
+ validateList(vms)[0],
+ PASS,
+ "List VMs should return valid response for deployed VM"
+ )
+
+ vm = vms[0]
+
+ self.debug("Deployed VM on host: %s" % vm.hostid)
+
+ # Put storage in maintenance mode
+
+ self.list_root_volume = Volume.list(self.api_client,
+ virtualmachineid=vm.id,
+ type='ROOT',
+ account=self.account.name,
+ domainid=self.account.domainid)
+
+ self.assertEqual(validateList(self.list_root_volume)[0],
+ PASS,
+ "check list voume_response for vm id %s" % vm.id)
+
+ self.pool_id = self.dbclient.execute(
+ "select pool_id from volumes where uuid = '%s';"
+ % self.list_root_volume[0].id)
+ self.storageid = self.dbclient.execute(
+ "select uuid from storage_pool where id = '%s';"
+ % self.pool_id[0][0])
+
+ StoragePool.enableMaintenance(self.api_client,
+ id=self.storageid[0][0])
+
+ self.virtual_machine_with_ha.start(self.api_client)
+ self.events = self.dbclient.execute(
+ "select type from usage_event where resource_name='%s';"
+ % self.list_root_volume[0].name
+ )
+ self.assertEqual(len(self.events),
+ 3,
+ "check the usage event table for root disk %s"
+ % self.list_root_volume[0].name
+ )
+
+ self.assertEqual(str(self.events[0][0]),
+ "VOLUME.CREATE",
+ "check volume create events for volume %s"
+ % self.list_root_volume[0].name)
+ self.assertEqual(str(self.events[1][0]),
+ "VOLUME.DELETE",
+ "check fvolume delete events for volume%s"
+ % self.list_root_volume[0].name)
+ self.assertEqual(str(self.events[2][0]),
+ "VOLUME.CREATE",
+ "check volume create events for volume %s"
+ % self.list_root_volume[0].name)
diff --git a/test/integration/component/maint/test_vpc.py b/test/integration/component/maint/test_vpc.py
new file mode 100644
index 0000000..5973f85
--- /dev/null
+++ b/test/integration/component/maint/test_vpc.py
@@ -0,0 +1,400 @@
+# 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.
+
+""" Component tests for VPC functionality
+"""
+# Import Local Modules
+from nose.plugins.attrib import attr
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.utils import cleanup_resources, validateList, get_process_status
+from marvin.lib.base import (Account,
+ VPC,
+ VpcOffering,
+ VirtualMachine,
+ ServiceOffering,
+ Network,
+ NetworkOffering,
+ Configurations,
+ Router)
+from marvin.lib.common import (get_domain,
+ get_zone,
+ get_template)
+from marvin.sshClient import SshClient
+from marvin.codes import PASS
+import re
+import time
+
+class Services:
+
+ """Test VPC services
+ """
+
+ def __init__(self):
+ self.services = {
+ "account": {
+ "email": "test@test.com",
+ "firstname": "Test",
+ "lastname": "User",
+ "username": "test",
+ # Random characters are appended for unique
+ # username
+ "password": "password",
+ },
+ "domain_admin": {
+ "email": "domain@admin.com",
+ "firstname": "Domain",
+ "lastname": "Admin",
+ "username": "DoA",
+ # Random characters are appended for unique
+ # username
+ "password": "password",
+ },
+ "service_offering": {
+ "name": "Tiny Instance",
+ "displaytext": "Tiny Instance",
+ "cpunumber": 1,
+ "cpuspeed": 100,
+ "memory": 128,
+ },
+ "network_offering": {
+ "name": 'VPC Network offering',
+ "displaytext": 'VPC Network off',
+ "guestiptype": 'Isolated',
+ "supportedservices": 'Vpn,Dhcp,Dns,SourceNat,PortForwarding,Lb,UserData,StaticNat,NetworkACL',
+ "traffictype": 'GUEST',
+ "availability": 'Optional',
+ "useVpc": 'on',
+ "serviceProviderList": {
+ "Vpn": 'VpcVirtualRouter',
+ "Dhcp": 'VpcVirtualRouter',
+ "Dns": 'VpcVirtualRouter',
+ "SourceNat": 'VpcVirtualRouter',
+ "PortForwarding": 'VpcVirtualRouter',
+ "Lb": 'VpcVirtualRouter',
+ "UserData": 'VpcVirtualRouter',
+ "StaticNat": 'VpcVirtualRouter',
+ "NetworkACL": 'VpcVirtualRouter'
+ },
+ },
+ "network_offering_no_lb": {
+ "name": 'VPC Network offering',
+ "displaytext": 'VPC Network off',
+ "guestiptype": 'Isolated',
+ "supportedservices": 'Vpn,Dhcp,Dns,SourceNat,PortForwarding,UserData,StaticNat,NetworkACL',
+ "traffictype": 'GUEST',
+ "availability": 'Optional',
+ "useVpc": 'on',
+ "serviceProviderList": {
+ "Vpn": 'VpcVirtualRouter',
+ "Dhcp": 'VpcVirtualRouter',
+ "Dns": 'VpcVirtualRouter',
+ "SourceNat": 'VpcVirtualRouter',
+ "PortForwarding": 'VpcVirtualRouter',
+ "UserData": 'VpcVirtualRouter',
+ "StaticNat": 'VpcVirtualRouter',
+ "NetworkACL": 'VpcVirtualRouter'
+ },
+ },
+ "vpc_offering": {
+ "name": 'VPC off',
+ "displaytext": 'VPC off',
+ "supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding,Vpn,Lb,UserData,StaticNat,NetworkACL',
+ },
+ "vpc": {
+ "name": "TestVPC",
+ "displaytext": "TestVPC",
+ "cidr": '10.0.0.1/24'
+ },
+ "vpc_no_name": {
+ "displaytext": "TestVPC",
+ "cidr": '10.0.0.1/24'
+ },
+ "network": {
+ "name": "Test Network",
+ "displaytext": "Test Network",
+ "netmask": '255.255.255.0'
+ },
+ "lbrule": {
+ "name": "SSH",
+ "alg": "leastconn",
+ # Algorithm used for load balancing
+ "privateport": 22,
+ "publicport": 2222,
+ "openfirewall": False,
+ "startport": 22,
+ "endport": 2222,
+ "protocol": "TCP",
+ "cidrlist": '0.0.0.0/0',
+ },
+ "natrule": {
+ "privateport": 22,
+ "publicport": 22,
+ "startport": 22,
+ "endport": 22,
+ "protocol": "TCP",
+ "cidrlist": '0.0.0.0/0',
+ },
+ "fw_rule": {
+ "startport": 1,
+ "endport": 6000,
+ "cidr": '0.0.0.0/0',
+ # Any network (For creating FW rule)
+ "protocol": "TCP"
+ },
+ "icmp_rule": {
+ "icmptype": -1,
+ "icmpcode": -1,
+ "cidrlist": '0.0.0.0/0',
+ "protocol": "ICMP"
+ },
+ "virtual_machine": {
+ "displayname": "Test VM",
+ "username": "root",
+ "password": "password",
+ "ssh_port": 22,
+ # Hypervisor type should be same as
+ # hypervisor type of cluster
+ "privateport": 22,
+ "publicport": 22,
+ "protocol": 'TCP',
+ },
+ "domain": {
+ "name": "TestDomain"
+ },
+ "vpn_customer_gw": {
+ "ipsecpsk": "s2svpn",
+ "ikepolicy": "3des-md5",
+ "ikelifetime": "86400",
+ "esppolicy": "3des-md5",
+ "esplifetime": "3600",
+ },
+ "ostype": 'CentOS 5.3 (64-bit)',
+ # Cent OS 5.3 (64 bit)
+ "sleep": 90,
+ "timeout": 10,
+ "mode": 'advanced'
+ }
+
+
+class TestVPC(cloudstackTestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.testClient = super(TestVPC, cls).getClsTestClient()
+ cls.api_client = cls.testClient.getApiClient()
+ cls.hypervisor = cls.testClient.getHypervisorInfo()
+ cls.mgtSvrDetails = cls.config.__dict__["mgtSvr"][0].__dict__
+ cls.unsupportedHypervisor = False
+ if cls.hypervisor.lower() == 'hyperv':
+ cls._cleanup = []
+ cls.unsupportedHypervisor = True
+ return
+ cls.services = Services().services
+ # Get Zone, Domain and templates
+ cls.domain = get_domain(cls.api_client)
+ cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+ cls.template = get_template(
+ cls.api_client,
+ cls.zone.id,
+ cls.services["ostype"]
+ )
+ cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+ cls.services["virtual_machine"]["template"] = cls.template.id
+
+ cls.service_offering = ServiceOffering.create(
+ cls.api_client,
+ cls.services["service_offering"]
+ )
+ cls.vpc_off = VpcOffering.create(
+ cls.api_client,
+ cls.services["vpc_offering"]
+ )
+ cls.vpc_off.update(cls.api_client, state='Enabled')
+ cls._cleanup = [
+ cls.service_offering,
+ ]
+ return
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ # Cleanup resources used
+ cleanup_resources(cls.api_client, cls._cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+ return
+
+ def setUp(self):
+ self.apiclient = self.testClient.getApiClient()
+ self.dbclient = self.testClient.getDbConnection()
+ self.account = Account.create(
+ self.apiclient,
+ self.services["account"],
+ admin=True,
+ domainid=self.domain.id
+ )
+ self.cleanup = []
+ self.cleanup.insert(0, self.account)
+ if self.unsupportedHypervisor:
+ self.skipTest("not supported on %s" % self.hypervisor)
+ return
+
+ def tearDown(self):
+ try:
+ cleanup_resources(self.apiclient, self.cleanup)
+ except Exception as e:
+ self.debug("Warning: Exception during cleanup : %s" % e)
+ return
+
+ def updateConfigurAndRestart(self, name, value):
+ Configurations.update(self.apiclient, name, value)
+ self.RestartServers()
+ time.sleep(self.services["sleep"])
+
+ def RestartServers(self):
+ """ Restart management
+ server and usage server """
+ sshClient = SshClient(
+ self.mgtSvrDetails["mgtSvrIp"],
+ 22,
+ self.mgtSvrDetails["user"],
+ self.mgtSvrDetails["passwd"]
+ )
+ command = "service cloudstack-management restart"
+ sshClient.execute(command)
+ return
+
+ @attr(tags=["advanced", "intervlan", "dvs", "test"], required_hardware="true")
+ def test_01_create_tier_Vmxnet3(self):
+ """
+ Test to create vpc tier with nic type as Vmxnet3
+ #1.Set global setting parameter "vmware.systemvm.nic.device.type"
+ to "Vmxnet3"
+ #2.Create VPC
+ #3.Create one tier
+ #4.Deploy one guest vm in the tier created in step3
+ """
+ if self.hypervisor.lower() not in ['vmware']:
+ self.skipTest("This test can only run on vmware setup")
+
+ nic_types = Configurations.list(
+ self.apiclient,
+ name="vmware.systemvm.nic.device.type"
+ )
+ self.assertEqual(validateList(nic_types)[0], PASS, "Invalid list config")
+ nic_type = nic_types[0].value
+ reset = False
+ if nic_type.lower() != "vmxnet3":
+ self.updateConfigurAndRestart("vmware.systemvm.nic.device.type", "Vmxnet3")
+ reset = True
+
+ self.services["vpc"]["cidr"] = "10.1.1.1/16"
+ self.debug("creating a VPC network in the account: %s" %
+ self.account.name)
+ try:
+ vpc = VPC.create(
+ self.apiclient,
+ self.services["vpc"],
+ vpcofferingid=self.vpc_off.id,
+ zoneid=self.zone.id,
+ account=self.account.name,
+ domainid=self.account.domainid
+ )
+ vpc_res = VPC.list(self.apiclient, id=vpc.id)
+ self.assertEqual(validateList(vpc_res)[0], PASS, "Invalid response from listvpc")
+
+ self.network_offering = NetworkOffering.create(
+ self.apiclient,
+ self.services["network_offering"],
+ conservemode=False
+ )
+ # Enable Network offering
+ self.network_offering.update(self.apiclient, state='Enabled')
+ self.cleanup.append(self.network_offering)
+
+ gateway = vpc.cidr.split('/')[0]
+ # Split the cidr to retrieve gateway
+ # for eg. cidr = 10.0.0.1/24
+ # Gateway = 10.0.0.1
+ # Creating network using the network offering created
+ self.debug("Creating network with network offering: %s" %
+ self.network_offering.id)
+ network = Network.create(
+ self.apiclient,
+ self.services["network"],
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ networkofferingid=self.network_offering.id,
+ zoneid=self.zone.id,
+ gateway=gateway,
+ vpcid=vpc.id
+ )
+ self.debug("Created network with ID: %s" % network.id)
+ vm = VirtualMachine.create(
+ self.apiclient,
+ self.services["virtual_machine"],
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ serviceofferingid=self.service_offering.id,
+ networkids=[str(network.id)]
+ )
+ self.assertIsNotNone(vm, "VM creation failed")
+ self.debug("Deployed VM in network: %s" % network.id)
+ vm_res = VirtualMachine.list(self.apiclient, id=vm.id)
+ self.assertEqual(
+ validateList(vm_res)[0],
+ PASS,
+ "list vm returned invalid response"
+ )
+ vr_res = Router.list(
+ self.apiclient,
+ vpcid=vpc.id,
+ listall="true"
+ )
+ self.assertEqual(validateList(vr_res)[0], PASS, "list vrs failed for vpc")
+ vr_linklocal_ip = vr_res[0].linklocalip
+ result = get_process_status(
+ self.apiclient.connection.mgtSvr,
+ 22,
+ self.apiclient.connection.user,
+ self.apiclient.connection.passwd,
+ vr_linklocal_ip,
+ 'lspci | grep "Ethernet controller"',
+ hypervisor=self.hypervisor
+ )
+ self.assertEqual(
+ validateList(result)[0],
+ PASS,
+ "We didn't find NICS with adapter type VMXNET3"
+ )
+ reg = re.compile("VMware VMXNET3")
+ count = 0
+ for line in result:
+ if reg.search(line):
+ count += 1
+ self.assertEqual(
+ count,
+ 3,
+ "Not all NICs on VR are of type VMXNET3"
+ )
+ except Exception as e:
+ self.fail("NIC creation failed for vpc tier with systemvm nic \
+ adapter type as Vmxnet3: %s" % e)
+ finally:
+ if reset:
+ self.updateConfigurAndRestart("vmware.systemvm.nic.device.type", nic_type)
+ return
diff --git a/test/integration/component/maint/testpath_disable_enable_zone.py b/test/integration/component/maint/testpath_disable_enable_zone.py
index a15173e..1537fc5 100644
--- a/test/integration/component/maint/testpath_disable_enable_zone.py
+++ b/test/integration/component/maint/testpath_disable_enable_zone.py
@@ -21,6 +21,11 @@
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.lib.utils import (cleanup_resources,
validateList)
+from marvin.cloudstackAPI import (dedicateCluster,
+ listDedicatedClusters,
+ releaseDedicatedCluster,
+ listAffinityGroups)
+
from marvin.lib.base import (Account,
VirtualMachine,
ServiceOffering,
@@ -40,7 +45,10 @@
get_template,
list_volumes,
list_snapshots,
- get_builtin_template_info
+ get_builtin_template_info,
+ list_routers,
+ list_virtual_machines,
+ list_hosts
)
from marvin.cloudstackAPI import (updateZone,
@@ -280,7 +288,7 @@
self.testdata["privatetemplate"]["hypervisor"] = builtin_info[1]
self.testdata["privatetemplate"]["format"] = builtin_info[2]
"""
- //commenting it for now will uncomment once expected behaviour is known
+ //commenting it for now will uncomment once expected behaviour is known
Template.register(
self.apiclient,
self.testdata["privatetemplate"],
@@ -295,7 +303,7 @@
diskofferingid=self.disk_offering.id
)
"""
- //commenting it for now will uncomment once expected behaviour is known
+ //commenting it for now will uncomment once expected behaviour is known
Iso.create(
self.apiclient,
self.testdata["iso2"],
@@ -1691,3 +1699,188 @@
)
return
+
+
+class TestClusterDedication(cloudstackTestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ testClient = super(TestClusterDedication, cls).getClsTestClient()
+ cls.apiclient = testClient.getApiClient()
+ cls.testdata = testClient.getParsedTestDataConfig()
+ cls.hypervisor = cls.testClient.getHypervisorInfo()
+
+ # Get Zone, Domain and templates
+ cls.domain = get_domain(cls.apiclient)
+ cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+
+ cls.template = get_template(
+ cls.apiclient,
+ cls.zone.id,
+ cls.testdata["ostype"])
+
+ cls.Skiptest = False
+ cls._cleanup = []
+ cls.clusters = Cluster.list(cls.apiclient, zoneid=cls.zone.id)
+ if len(cls.clusters) < 2:
+ cls.Skiptest = True
+
+ try:
+ # Create an account
+ cls.account_1 = Account.create(
+ cls.apiclient,
+ cls.testdata["account"],
+ domainid=cls.domain.id
+ )
+
+ cls._cleanup.append(cls.account_1)
+
+ cls.account_2 = Account.create(
+ cls.apiclient,
+ cls.testdata["account"],
+ domainid=cls.domain.id
+ )
+
+ cls._cleanup.append(cls.account_2)
+ # Create user api client of the account
+ cls.userapiclient_1 = testClient.getUserApiClient(
+ UserName=cls.account_1.name,
+ DomainName=cls.account_1.domain
+ )
+ cls.userapiclient_2 = testClient.getUserApiClient(
+ UserName=cls.account_2.name,
+ DomainName=cls.account_2.domain
+ )
+
+ # Create Service offering
+ cls.service_offering = ServiceOffering.create(
+ cls.apiclient,
+ cls.testdata["service_offering"],
+ )
+ cls._cleanup.append(cls.service_offering)
+
+ cls.disk_offering = DiskOffering.create(
+ cls.apiclient,
+ cls.testdata["disk_offering"],
+ )
+
+ cls._cleanup.append(cls.disk_offering)
+
+ except Exception as e:
+ cls.tearDownClass()
+ raise e
+ return
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ cleanup_resources(cls.apiclient, cls._cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+
+ def setUp(self):
+
+ if self.Skiptest:
+ self.skipTest("Insufficient clusters to run the test")
+
+ self.apiclient = self.testClient.getApiClient()
+ self.dbclient = self.testClient.getDbConnection()
+ self.cleanup = []
+
+ def tearDown(self):
+ try:
+ listClusterscmd = listDedicatedClusters.listDedicatedClustersCmd()
+ listClusterscmd.clusterid = self.clusters[0].id
+ ret_list = self.apiclient.listDedicatedClusters(listClusterscmd)
+ if ret_list:
+ dedicateCmd = releaseDedicatedCluster.\
+ releaseDedicatedClusterCmd()
+ dedicateCmd.clusterid = self.clusters[0].id
+ self.apiclient.releaseDedicatedCluster(dedicateCmd)
+
+ cleanup_resources(self.apiclient, self.cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+ return
+
+ @attr(tags=["basic", "advanced"], required_hardware="false")
+ def test_01_dedicated_cluster_allocation(self):
+ """ Dedicated cluster and router allocation
+ 1. Dedicate a cluster to one account
+ 2. Deploy a VM on dedicated account
+ 3. Deploy another VM on another account.
+ 4. Verify the dedicated cluster is not used for
+ virtual routers that belong to non-dedicated account
+ """
+
+ # Step 1
+ dedicateCmd = dedicateCluster.dedicateClusterCmd()
+ dedicateCmd.clusterid = self.clusters[0].id
+ dedicateCmd.domainid = self.domain.id
+ dedicateCmd.account = self.account_1.name
+ self.apiclient.dedicateCluster(dedicateCmd)
+
+ afcmd = listAffinityGroups.listAffinityGroupsCmd()
+ afcmd.account = self.account_1.name
+ afcmd.domainid = self.account_1.domainid
+ affinitygr_list = self.apiclient.listAffinityGroups(afcmd)
+
+ # Step 2
+ self.vm = VirtualMachine.create(
+ self.userapiclient_1,
+ self.testdata["small"],
+ templateid=self.template.id,
+ accountid=self.account_1.name,
+ domainid=self.account_1.domainid,
+ serviceofferingid=self.service_offering.id,
+ affinitygroupids=[affinitygr_list[0].id],
+ zoneid=self.zone.id,
+ mode=self.zone.networktype
+ )
+ # Steps to verify if VM is created on dedicated account
+ vmlist = list_virtual_machines(self.apiclient,
+ id=self.vm.id)
+
+ hostlist = list_hosts(self.apiclient,
+ id=vmlist[0].hostid)
+
+ self.assertEqual(hostlist[0].clusterid,
+ self.clusters[0].id,
+ "check if vm gets deployed on dedicated clusture"
+ )
+ # Step 3
+ self.vm_1 = VirtualMachine.create(
+ self.userapiclient_2,
+ self.testdata["small"],
+ templateid=self.template.id,
+ accountid=self.account_2.name,
+ domainid=self.account_2.domainid,
+ serviceofferingid=self.service_offering.id,
+ zoneid=self.zone.id,
+ mode=self.zone.networktype
+ )
+
+ # Steps to verify if VM is created on dedicated account
+ vmlist_1 = list_virtual_machines(self.apiclient,
+ id=self.vm_1.id)
+
+ hostlist_1 = list_hosts(self.apiclient,
+ id=vmlist_1[0].hostid)
+
+ self.assertNotEqual(hostlist_1[0].clusterid,
+ self.clusters[0].id,
+ "check if vm gets deployed on correct clusture"
+ )
+
+ # Step 4
+ routerList = list_routers(self.apiclient,
+ clusterid=self.clusters[0].id,
+ networkid=self.vm_1.nic[0].networkid
+ )
+ self.assertEqual(
+ routerList,
+ None,
+ "Check Dedicated cluster is used for virtual routers \
+ that belong to non-dedicated account")
+
+ return
diff --git a/test/integration/component/test_acl_listsnapshot.py b/test/integration/component/test_acl_listsnapshot.py
index 36ec59e..f0fa7b7 100644
--- a/test/integration/component/test_acl_listsnapshot.py
+++ b/test/integration/component/test_acl_listsnapshot.py
@@ -360,8 +360,8 @@
cls.service_offering,
]
except Exception as e:
- cls.domain_1.delete(cls.apiclient,cleanup="true")
cls.domain_2.delete(cls.apiclient,cleanup="true")
+ cls.domain_1.delete(cls.apiclient,cleanup="true")
cleanup_resources(cls.apiclient, cls.cleanup)
raise Exception("Failed to create the setup required to execute the test cases: %s" % e)
@@ -370,10 +370,11 @@
cls.apiclient = super(TestSnapshotList, cls).getClsTestClient().getApiClient()
cls.apiclient.connection.apiKey = cls.default_apikey
cls.apiclient.connection.securityKey = cls.default_secretkey
- cls.domain_1.delete(cls.apiclient,cleanup="true")
- cls.domain_2.delete(cls.apiclient,cleanup="true")
+ try:
+ cls.domain_2.delete(cls.apiclient,cleanup="true")
+ cls.domain_1.delete(cls.apiclient,cleanup="true")
+ except: pass
cleanup_resources(cls.apiclient, cls.cleanup)
- return
def setUp(cls):
cls.apiclient = cls.testClient.getApiClient()
diff --git a/test/integration/component/test_acl_listvm.py b/test/integration/component/test_acl_listvm.py
index de99718..5ed937f 100644
--- a/test/integration/component/test_acl_listvm.py
+++ b/test/integration/component/test_acl_listvm.py
@@ -333,8 +333,8 @@
cls.service_offering,
]
except Exception as e:
- cls.domain_1.delete(cls.apiclient,cleanup="true")
cls.domain_2.delete(cls.apiclient,cleanup="true")
+ cls.domain_1.delete(cls.apiclient,cleanup="true")
cleanup_resources(cls.apiclient, cls.cleanup)
raise Exception("Failed to create the setup required to execute the test cases: %s" % e)
@@ -343,10 +343,11 @@
cls.apiclient = super(TestVMList, cls).getClsTestClient().getApiClient()
cls.apiclient.connection.apiKey = cls.default_apikey
cls.apiclient.connection.securityKey = cls.default_secretkey
- cls.domain_1.delete(cls.apiclient,cleanup="true")
- cls.domain_2.delete(cls.apiclient,cleanup="true")
+ try:
+ cls.domain_2.delete(cls.apiclient,cleanup="true")
+ cls.domain_1.delete(cls.apiclient,cleanup="true")
+ except: pass
cleanup_resources(cls.apiclient, cls.cleanup)
- return
def setUp(cls):
cls.apiclient = cls.testClient.getApiClient()
diff --git a/test/integration/component/test_acl_listvolume.py b/test/integration/component/test_acl_listvolume.py
index 65a1201..05cabeb 100644
--- a/test/integration/component/test_acl_listvolume.py
+++ b/test/integration/component/test_acl_listvolume.py
@@ -345,8 +345,8 @@
cls.service_offering,
]
except Exception as e:
- cls.domain_1.delete(cls.apiclient,cleanup="true")
cls.domain_2.delete(cls.apiclient,cleanup="true")
+ cls.domain_1.delete(cls.apiclient,cleanup="true")
cleanup_resources(cls.apiclient, cls.cleanup)
raise Exception("Failed to create the setup required to execute the test cases: %s" % e)
@@ -357,10 +357,11 @@
cls.apiclient = super(TestVolumeList, cls).getClsTestClient().getApiClient()
cls.apiclient.connection.apiKey = cls.default_apikey
cls.apiclient.connection.securityKey = cls.default_secretkey
- cls.domain_1.delete(cls.apiclient,cleanup="true")
- cls.domain_2.delete(cls.apiclient,cleanup="true")
cleanup_resources(cls.apiclient, cls.cleanup)
- return
+ try:
+ cls.domain_2.delete(cls.apiclient,cleanup="true")
+ cls.domain_1.delete(cls.apiclient,cleanup="true")
+ except: pass
def setUp(cls):
cls.apiclient = cls.testClient.getApiClient()
diff --git a/test/integration/component/test_add_remove_network.py b/test/integration/component/test_add_remove_network.py
index 55d0b0e..b76197d 100644
--- a/test/integration/component/test_add_remove_network.py
+++ b/test/integration/component/test_add_remove_network.py
@@ -1021,6 +1021,103 @@
self.fail("Failed to delete the nic from vm")
return
+ @attr(tags=["advanced"], required_hardware="true")
+ def test_30_remove_nic_reattach(self):
+ """
+ Test to verify vm start after NIC removal and reattach
+
+ # 1.Create vm which has 3 nics(e.g. #0,#1,#2)
+ # 2.Stop the vm
+ # 3.Remove second nic(#1)
+ # 4.Add/Reattach same network(#1)
+ # 5.Start the instance
+ """
+ self.ntwk2 = Network.create(
+ self.apiclient,
+ self.services["isolated_network"],
+ self.account.name,
+ self.account.domainid,
+ networkofferingid=self.isolated_network_offering.id
+ )
+ self.ntwk3 = Network.create(
+ self.apiclient,
+ self.services["isolated_network"],
+ self.account.name,
+ self.account.domainid,
+ networkofferingid=self.isolated_network_offering.id
+ )
+ self.test_vm = VirtualMachine.create(
+ self.apiclient,
+ self.services["virtual_machine"],
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ serviceofferingid=self.service_offering.id,
+ mode=self.zone.networktype,
+ networkids=[self.isolated_network.id, self.ntwk2.id, self.ntwk3.id]
+ )
+ self.assertIsNotNone(self.test_vm, "Failed to create vm with 3 nics")
+ map(lambda x: self.cleanup.append(x), [self.test_vm, self.ntwk2, self.ntwk3])
+ vm_res = VirtualMachine.list(
+ self.apiclient,
+ id=self.test_vm.id
+ )
+ self.assertEqual(validateList(vm_res)[0], PASS, "Invalid list vm response")
+ self.nics = vm_res[0].nic
+ self.assertEqual(
+ validateList(self.nics)[0],
+ PASS,
+ "vm response does not contain nics info"
+ )
+ self.assertEqual(len(self.nics), 3, "Not all nics found in vm response")
+ self.test_vm.stop(self.apiclient)
+ vm_res2 = VirtualMachine.list(
+ self.apiclient,
+ id=self.test_vm.id
+ )
+ self.assertEqual(validateList(vm_res2)[0], PASS, "Invalid response")
+ self.assertEqual(
+ vm_res2[0].state,
+ "Stopped",
+ "VM did not stop properly"
+ )
+
+ """
+ get the network id of the nic which we are remove from the nic, so that we can
+ use that network id for reattach
+ """
+ nic_to_attach = [x for x in [self.isolated_network, self.ntwk2, self.ntwk3]\
+ if x.id == self.nics[1].networkid]
+ self.assertEqual(validateList(nic_to_attach)[0], PASS, "No matching nics")
+ self.assertEqual(len(nic_to_attach), 1, "More than one nic in same network")
+ try:
+ self.test_vm.remove_nic(self.apiclient, nicId=self.nics[1].id)
+ self.test_vm.add_nic(
+ self.apiclient,
+ nic_to_attach[0].id
+ )
+ self.test_vm.start(self.apiclient)
+ except Exception as e:
+ self.fail("Failed to start vm after nic removal and attachment")
+ vm_res3 = VirtualMachine.list(self.apiclient, id=self.test_vm.id)
+ self.assertEqual(
+ validateList(vm_res3)[0],
+ PASS,
+ "Invalid listvm response after nic detach and attach"
+ )
+ self.assertEqual(
+ vm_res3[0].state,
+ "Running",
+ "VM didn't come to running state after nic detach and attach"
+ )
+ vm_nics = vm_res3[0].nic
+ self.assertEqual(validateList(vm_nics)[0], PASS, "Invalid nics after vm stop/start")
+ self.assertEqual(
+ len(vm_nics),
+ 3,
+ "Nic is not attached/detected"
+ )
+ return
+
class TestUpdateVirtualMachineNIC(cloudstackTestCase):
@classmethod
diff --git a/test/integration/component/test_blocker_bugs.py b/test/integration/component/test_blocker_bugs.py
index c229d38..c1aa1f0 100644
--- a/test/integration/component/test_blocker_bugs.py
+++ b/test/integration/component/test_blocker_bugs.py
@@ -409,7 +409,7 @@
)
self.assertEqual(
firewall_response[0].startport,
- str(self.services["firewall_rule"]["startport"]),
+ self.services["firewall_rule"]["startport"],
"Firewall rule is not with specific port"
)
diff --git a/test/integration/component/test_deploy_vm_userdata_multi_nic.py b/test/integration/component/test_deploy_vm_userdata_multi_nic.py
new file mode 100755
index 0000000..86c0f13
--- /dev/null
+++ b/test/integration/component/test_deploy_vm_userdata_multi_nic.py
@@ -0,0 +1,188 @@
+# 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 will cover VMdeployment with Userdata tests for MultiNic
+
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.base import (Account,
+ Network,
+ NetworkOffering,
+ ServiceOffering,
+ VirtualMachine)
+from marvin.lib.common import (get_domain,
+ get_template,
+ get_zone,
+ list_virtual_machines)
+from marvin.lib.utils import cleanup_resources
+from nose.plugins.attrib import attr
+import base64
+import random
+import string
+
+_multiprocess_shared_ = True
+
+
+class TestDeployVmWithUserDataMultiNic(cloudstackTestCase):
+ """Tests for UserData
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ cls.testClient = super(TestDeployVmWithUserDataMultiNic, cls).getClsTestClient()
+ cls.api_client = cls.testClient.getApiClient()
+ cls.test_data = cls.testClient.getParsedTestDataConfig()
+
+ # Get Domain, Zone, Template
+ cls.domain = get_domain(cls.api_client)
+ cls.zone = get_zone(
+ cls.api_client,
+ cls.testClient.getZoneForTests())
+ cls.template = get_template(
+ cls.api_client,
+ cls.zone.id,
+ cls.test_data["ostype"]
+ )
+ if cls.zone.localstorageenabled:
+ cls.storagetype = 'local'
+ cls.test_data["service_offerings"][
+ "tiny"]["storagetype"] = 'local'
+ else:
+ cls.storagetype = 'shared'
+ cls.test_data["service_offerings"][
+ "tiny"]["storagetype"] = 'shared'
+
+ cls.service_offering = ServiceOffering.create(
+ cls.api_client,
+ cls.test_data["service_offerings"]["tiny"]
+ )
+
+ # Create Network offering without userdata
+ cls.network_offering_nouserdata = NetworkOffering.create(
+ cls.api_client,
+ cls.test_data["network_offering"]
+ )
+ # Enable Network offering
+ cls.network_offering_nouserdata.update(cls.api_client, state='Enabled')
+
+ # Create Network Offering with all the serices
+ cls.network_offering_all = NetworkOffering.create(
+ cls.api_client,
+ cls.test_data["isolated_network_offering"]
+ )
+ # Enable Network offering
+ cls.network_offering_all.update(cls.api_client, state='Enabled')
+
+ cls._cleanup = [
+ cls.service_offering,
+ cls.network_offering_nouserdata,
+ cls.network_offering_all
+ ]
+
+ # Generate userdata of 2500 bytes. This is larger than the 2048 bytes limit.
+ # CS however allows for upto 4K bytes in the code. So this must succeed.
+ # Overall, the query length must not exceed 4K, for then the json decoder
+ # will fail this operation at the marvin client side itcls.
+
+ cls.userdata = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(2500))
+
+ def setUp(self):
+ self.apiclient = self.testClient.getApiClient()
+ self.hypervisor = self.testClient.getHypervisorInfo()
+ self.dbclient = self.testClient.getDbConnection()
+ self.account = Account.create(
+ self.apiclient,
+ self.test_data["account"],
+ admin=True,
+ domainid=self.domain.id
+ )
+ self.cleanup = []
+ return
+
+ def tearDown(self):
+ try:
+ self.account.delete(self.apiclient)
+ cleanup_resources(self.apiclient, self.cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+ return
+
+ @attr(tags=["simulator", "devcloud", "basic", "advanced"], required_hardware="false")
+ def test_deployvm_multinic(self):
+ """Test userdata update when non default nic is without userdata for deploy and update
+ """
+
+ self.userdata = base64.b64encode(self.userdata)
+
+ network1 = Network.create(
+ self.apiclient,
+ self.test_data["isolated_network"],
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ networkofferingid=self.network_offering_all.id,
+ zoneid=self.zone.id
+ )
+
+ self.test_data["network_without_acl"]["netmask"] = "255.255.255.128"
+
+ network2 = Network.create(
+ self.apiclient,
+ self.test_data["network_without_acl"],
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ networkofferingid=self.network_offering_nouserdata.id,
+ gateway="10.2.1.1",
+ zoneid=self.zone.id
+ )
+
+ deployVmResponse = VirtualMachine.create(
+ self.apiclient,
+ services=self.test_data["virtual_machine_userdata"],
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ serviceofferingid=self.service_offering.id,
+ networkids=[str(network1.id), str(network2.id)],
+ templateid=self.template.id,
+ zoneid=self.zone.id
+ )
+
+ vms = list_virtual_machines(
+ self.apiclient,
+ account=self.account.name,
+ domainid=self.account.domainid,
+ id=deployVmResponse.id
+ )
+ self.assert_(len(vms) > 0, "There are no Vms deployed in the account %s" % self.account.name)
+ vm = vms[0]
+ self.assert_(vm.id == str(deployVmResponse.id), "Vm deployed is different from the test")
+ self.assert_(vm.state == "Running", "VM is not in Running state")
+
+ try:
+ updateresponse = deployVmResponse.update(self.apiclient, userdata=self.userdata)
+ except Exception as e:
+ self.fail("Failed to update userdata: %s" % e)
+
+ self.debug("virtual machine update response is: %s" % updateresponse)
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ # Cleanup resources used
+ cleanup_resources(cls.api_client, cls._cleanup)
+
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
diff --git a/test/integration/component/test_egress_fw_rules.py b/test/integration/component/test_egress_fw_rules.py
index f362421..9d13a23 100755
--- a/test/integration/component/test_egress_fw_rules.py
+++ b/test/integration/component/test_egress_fw_rules.py
@@ -348,6 +348,26 @@
except Exception as e:
self.fail("Warning! Cleanup failed: %s" % e)
+ def create_another_vm(self):
+ self.debug("Deploying instance in the account: %s and network: %s" % (self.account.name, self.network.id))
+
+ project = None
+ self.virtual_machine1 = VirtualMachine.create(self.apiclient,
+ self.services["virtual_machine"],
+ accountid=self.account.name,
+ domainid=self.domain.id,
+ serviceofferingid=self.service_offering.id,
+ mode=self.zone.networktype,
+ networkids=[str(self.network.id)],
+ projectid=project.id if project else None)
+ self.debug("Deployed instance %s in account: %s" % (self.virtual_machine.id,self.account.name))
+
+ # Checking if VM is running or not, in case it is deployed in error state, test case fails
+ self.vm_list = list_virtual_machines(self.apiclient, id=self.virtual_machine.id)
+
+ self.assertEqual(validateList(self.vm_list)[0], PASS, "vm list validation failed, vm list is %s" % self.vm_list)
+ self.assertEqual(str(self.vm_list[0].state).lower(),'running',"VM state should be running, it is %s" % self.vm_list[0].state)
+
@attr(tags=["advanced"], required_hardware="true")
def test_01_egress_fr1(self):
"""Test By-default the communication from guest n/w to public n/w is allowed.
@@ -385,6 +405,25 @@
"['100']",
negative_test=False)
+ @attr(tags=["advanced"], required_hardware="true")
+ def test_01_2_egress_fr1(self):
+ """Test egress rule with /32 CIDR of a VM, and check other VM in the
+ network does not have public access
+ """
+ # Validate the following:
+ # 1. deploy VM using network offering with egress policy false.
+ # 2. deploy another VM into the network created in step #1
+ # 3. create egress rule with /32 CIDR of the second VM
+ # 4. login to first VM.
+ # 5. ping public network.
+ # 6. public network should not be reachable from the first VM.
+ self.create_vm(egress_policy=False)
+ self.create_another_vm()
+ self.createEgressRule(protocol='all', cidr=self.virtual_machine1.ipaddress+"/32")
+ self.exec_script_on_user_vm('ping -c 1 www.google.com',
+ "| grep -oP \'\d+(?=% packet loss)\'",
+ "['100']",
+ negative_test=False)
@attr(tags=["advanced"], required_hardware="true")
def test_02_egress_fr2(self):
@@ -421,6 +460,23 @@
negative_test=False)
@attr(tags=["advanced"], required_hardware="true")
+ def test_02_2_egress_fr2(self):
+ """Test Allow Communication using Egress rule with /32 CIDR + Port Range + Protocol.
+ """
+ # Validate the following:
+ # 1. deploy VM using network offering with egress policy false.
+ # 3. create egress rule with specific /32 CIDR + port range.
+ # 4. login to VM.
+ # 5. ping public network.
+ # 6. public network should be reachable from the VM.
+ self.create_vm(egress_policy=False)
+ self.createEgressRule(cidr=self.virtual_machine.ipaddress+"/32")
+ self.exec_script_on_user_vm('ping -c 1 www.google.com',
+ "| grep -oP \'\d+(?=% packet loss)\'",
+ "['0']",
+ negative_test=False)
+
+ @attr(tags=["advanced"], required_hardware="true")
def test_03_egress_fr3(self):
"""Test Communication blocked with network that is other than specified
"""
diff --git a/test/integration/component/test_host_ha.py b/test/integration/component/test_host_ha.py
new file mode 100644
index 0000000..6361564
--- /dev/null
+++ b/test/integration/component/test_host_ha.py
@@ -0,0 +1,516 @@
+# 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.
+from __builtin__ import False
+""" BVT tests for Hosts Maintenance
+"""
+
+# Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from marvin.lib.utils import *
+from marvin.lib.base import *
+from marvin.lib.common import *
+from nose.plugins.attrib import attr
+
+from time import sleep
+
+_multiprocess_shared_ = False
+
+
+class TestHostHA(cloudstackTestCase):
+
+ def setUp(self):
+ self.logger = logging.getLogger('TestHM')
+ self.stream_handler = logging.StreamHandler()
+ self.logger.setLevel(logging.DEBUG)
+ self.logger.addHandler(self.stream_handler)
+ self.apiclient = self.testClient.getApiClient()
+ self.hypervisor = self.testClient.getHypervisorInfo()
+ self.dbclient = self.testClient.getDbConnection()
+ self.services = self.testClient.getParsedTestDataConfig()
+ self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests())
+ self.pod = get_pod(self.apiclient, self.zone.id)
+ self.cleanup = []
+ self.services = {
+ "service_offering": {
+ "name": "Ultra Tiny Instance",
+ "displaytext": "Ultra Tiny Instance",
+ "cpunumber": 1,
+ "cpuspeed": 100,
+ "memory": 128,
+ },
+ "service_offering_local": {
+ "name": "Ultra Tiny Local Instance",
+ "displaytext": "Ultra Tiny Local Instance",
+ "cpunumber": 1,
+ "cpuspeed": 100,
+ "memory": 128,
+ "storagetype": "local"
+ },
+ "vm": {
+ "username": "root",
+ "password": "password",
+ "ssh_port": 22,
+ # Hypervisor type should be same as
+ # hypervisor type of cluster
+ "privateport": 22,
+ "publicport": 22,
+ "protocol": 'TCP',
+ },
+ "natrule": {
+ "privateport": 22,
+ "publicport": 22,
+ "startport": 22,
+ "endport": 22,
+ "protocol": "TCP",
+ "cidrlist": '0.0.0.0/0',
+ },
+ "ostype": 'CentOS 5.3 (64-bit)',
+ "sleep": 60,
+ "timeout": 10,
+ }
+
+
+ def tearDown(self):
+ try:
+ # Clean up, terminate the created templates
+ cleanup_resources(self.apiclient, self.cleanup)
+
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+
+ return
+
+ def createVMs(self, hostId, number, local):
+
+ self.template = get_template(
+ self.apiclient,
+ self.zone.id,
+ self.services["ostype"]
+ )
+
+ if self.template == FAILED:
+ assert False, "get_template() failed to return template with description %s" % self.services["ostype"]
+
+ self.logger.debug("Using template %s " % self.template.id)
+
+ if local:
+ self.service_offering = ServiceOffering.create(
+ self.apiclient,
+ self.services["service_offering_local"]
+ )
+ else:
+ self.service_offering = ServiceOffering.create(
+ self.apiclient,
+ self.services["service_offering"]
+ )
+
+
+ self.logger.debug("Using service offering %s " % self.service_offering.id)
+
+ vms = []
+ for i in range(0, number):
+ self.services["vm"]["zoneid"] = self.zone.id
+ self.services["vm"]["template"] = self.template.id
+ self.services["vm"]["displayname"] = 'vm' + str(i)
+ self.services["vm"]["hypervisor"] = self.hypervisor
+ vm = VirtualMachine.create(
+ self.apiclient,
+ self.services["vm"],
+ serviceofferingid=self.service_offering.id,
+ hostid=hostId
+ )
+ vms.append(vm)
+ self.cleanup.append(vm)
+ self.logger.debug("VM create = {}".format(vm.id))
+ return vm
+
+ def noOfVMsOnHost(self, hostId):
+ listVms = VirtualMachine.list(
+ self.apiclient,
+ hostid=hostId
+ )
+ vmnos = 0
+ if (listVms is not None):
+ for vm in listVms:
+ self.logger.debug('VirtualMachine on Hyp 1 = {}'.format(vm.id))
+ vmnos = vmnos + 1
+
+ return vmnos
+
+ def checkHostDown(self, fromHostIp, testHostIp):
+ try:
+ ssh = SshClient(fromHostIp, 22, "root", "password")
+ res = ssh.execute("ping -c 1 %s" % testHostIp)
+ result = str(res)
+ if result.count("100% packet loss") == 1:
+ return True, 1
+ else:
+ return False, 1
+ except Exception as e:
+ self.logger.debug("Got exception %s" % e)
+ return False, 1
+
+ def checkHostUp(self, fromHostIp, testHostIp):
+ try:
+ ssh = SshClient(fromHostIp, 22, "root", "password")
+ res = ssh.execute("ping -c 1 %s" % testHostIp)
+ result = str(res)
+ if result.count(" 0% packet loss") == 1:
+ return True, 1
+ else:
+ return False, 1
+ except Exception as e:
+ self.logger.debug("Got exception %s" % e)
+ return False, 1
+
+
+ def isOnlyNFSStorageAvailable(self):
+ if self.zone.localstorageenabled:
+ return False
+ storage_pools = StoragePool.list(
+ self.apiclient,
+ zoneid=self.zone.id,
+ listall=True
+ )
+ self.assertEqual(
+ isinstance(storage_pools, list),
+ True,
+ "Check if listStoragePools returns a valid response"
+ )
+ for storage_pool in storage_pools:
+ if storage_pool.type == u'NetworkFilesystem':
+ return True
+
+ return False
+
+ def isOnlyLocalStorageAvailable(self):
+ if not(self.zone.localstorageenabled):
+ return False
+
+ storage_pools = StoragePool.list(
+ self.apiclient,
+ zoneid=self.zone.id,
+ listall=True
+ )
+ self.assertEqual(
+ isinstance(storage_pools, list),
+ True,
+ "Check if listStoragePools returns a valid response"
+ )
+ for storage_pool in storage_pools:
+ if storage_pool.type == u'NetworkFilesystem':
+ return False
+
+ return True
+
+ def isLocalAndNFSStorageAvailable(self):
+ if not(self.zone.localstorageenabled):
+ return False
+
+ storage_pools = StoragePool.list(
+ self.apiclient,
+ zoneid=self.zone.id,
+ listall=True
+ )
+ self.assertEqual(
+ isinstance(storage_pools, list),
+ True,
+ "Check if listStoragePools returns a valid response"
+ )
+ for storage_pool in storage_pools:
+ if storage_pool.type == u'NetworkFilesystem':
+ return True
+
+ return False
+
+
+ def checkHostStateInCloudstack(self, state, hostId):
+ try:
+ listHost = Host.list(
+ self.apiclient,
+ type='Routing',
+ zoneid=self.zone.id,
+ podid=self.pod.id,
+ id=hostId
+ )
+ self.assertEqual(
+ isinstance(listHost, list),
+ True,
+ "Check if listHost returns a valid response"
+ )
+
+ self.assertEqual(
+ len(listHost),
+ 1,
+ "Check if listHost returns a host"
+ )
+ self.logger.debug(" Host state is %s " % listHost[0].state)
+ if listHost[0].state == state:
+ return True, 1
+ else:
+ return False, 1
+ except Exception as e:
+ self.logger.debug("Got exception %s" % e)
+ return False, 1
+
+
+ def disconnectHostfromNetwork(self, hostIp, timeout):
+ srcFile = os.path.dirname(os.path.realpath(__file__)) + "/test_host_ha.sh"
+ if not(os.path.isfile(srcFile)):
+ self.logger.debug("File %s not found" % srcFile)
+ raise unittest.SkipTest("Script file %s required for HA not found" % srcFile);
+
+ ssh = SshClient(hostIp, 22, "root", "password")
+ ssh.scp(srcFile, "/root/test_host_ha.sh")
+ ssh.execute("nohup sh /root/test_host_ha.sh %s > /dev/null 2>&1 &\n" % timeout)
+ return
+
+
+ @attr(
+ tags=[
+ "advanced",
+ "advancedns",
+ "smoke",
+ "basic",
+ "eip",
+ "sg"],
+ required_hardware="true")
+ def test_01_host_ha_with_nfs_storagepool_with_vm(self):
+
+ if not(self.isOnlyNFSStorageAvailable()):
+ raise unittest.SkipTest("Skipping this test as this is for NFS store only.");
+ return
+
+ listHost = Host.list(
+ self.apiclient,
+ type='Routing',
+ zoneid=self.zone.id,
+ podid=self.pod.id,
+ )
+ for host in listHost:
+ self.logger.debug('Hypervisor = {}'.format(host.id))
+
+
+ if len(listHost) != 2:
+ self.logger.debug("Host HA can be tested with two host only %s, found" % len(listHost));
+ raise unittest.SkipTest("Host HA can be tested with two host only %s, found" % len(listHost));
+ return
+
+ no_of_vms = self.noOfVMsOnHost(listHost[0].id)
+
+ no_of_vms = no_of_vms + self.noOfVMsOnHost(listHost[1].id)
+
+ self.logger.debug("Number of VMS on hosts = %s" % no_of_vms)
+
+
+ if no_of_vms < 5:
+ self.logger.debug("test_01: Create VMs as there are not enough vms to check host ha")
+ no_vm_req = 5 - no_of_vms
+ if (no_vm_req > 0):
+ self.logger.debug("Creating vms = {}".format(no_vm_req))
+ self.vmlist = self.createVMs(listHost[0].id, no_vm_req, False)
+
+ ha_host = listHost[1]
+ other_host = listHost[0]
+ if self.noOfVMsOnHost(listHost[0].id) > self.noOfVMsOnHost(listHost[1].id):
+ ha_host = listHost[0]
+ other_host = listHost[1]
+
+ self.disconnectHostfromNetwork(ha_host.ipaddress, 400)
+
+ hostDown = wait_until(10, 10, self.checkHostDown, other_host.ipaddress, ha_host.ipaddress)
+ if not(hostDown):
+ raise unittest.SkipTest("Host %s is not down, cannot proceed with test" % (ha_host.ipaddress))
+
+ hostDownInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Down", ha_host.id)
+ #the test could have failed here but we will try our best to get host back in consistent state
+
+ no_of_vms = self.noOfVMsOnHost(ha_host.id)
+ no_of_vms = no_of_vms + self.noOfVMsOnHost(other_host.id)
+ self.logger.debug("Number of VMS on hosts = %s" % no_of_vms)
+ #
+ hostUp = wait_until(10, 10, self.checkHostUp, other_host.ipaddress, ha_host.ipaddress)
+ if not(hostUp):
+ self.logger.debug("Host is down %s, though HA went fine, the environment is not consistent " % (ha_host.ipaddress))
+
+
+ hostUpInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Up", ha_host.id)
+
+ if not(hostDownInCloudstack):
+ raise self.fail("Host is not down %s, in cloudstack so failing test " % (ha_host.ipaddress))
+ if not(hostUpInCloudstack):
+ raise self.fail("Host is not up %s, in cloudstack so failing test " % (ha_host.ipaddress))
+
+ return
+
+
+ @attr(
+ tags=[
+ "advanced",
+ "advancedns",
+ "smoke",
+ "basic",
+ "eip",
+ "sg"],
+ required_hardware="true")
+ def test_02_host_ha_with_local_storage_and_nfs(self):
+
+ if not(self.isLocalAndNFSStorageAvailable()):
+ raise unittest.SkipTest("Skipping this test as this is for Local storage and NFS storage only.");
+ return
+
+ listHost = Host.list(
+ self.apiclient,
+ type='Routing',
+ zoneid=self.zone.id,
+ podid=self.pod.id,
+ )
+ for host in listHost:
+ self.logger.debug('Hypervisor = {}'.format(host.id))
+
+
+ if len(listHost) != 2:
+ self.logger.debug("Host HA can be tested with two host only %s, found" % len(listHost));
+ raise unittest.SkipTest("Host HA can be tested with two host only %s, found" % len(listHost));
+ return
+
+ no_of_vms = self.noOfVMsOnHost(listHost[0].id)
+
+ no_of_vms = no_of_vms + self.noOfVMsOnHost(listHost[1].id)
+
+ self.logger.debug("Number of VMS on hosts = %s" % no_of_vms)
+
+
+ if no_of_vms < 5:
+ self.logger.debug("test_02: Create VMs as there are not enough vms to check host ha")
+ no_vm_req = 5 - no_of_vms
+ if (no_vm_req > 0):
+ self.logger.debug("Creating vms = {}".format(no_vm_req))
+ self.vmlist = self.createVMs(listHost[0].id, no_vm_req, True)
+
+ ha_host = listHost[1]
+ other_host = listHost[0]
+ if self.noOfVMsOnHost(listHost[0].id) > self.noOfVMsOnHost(listHost[1].id):
+ ha_host = listHost[0]
+ other_host = listHost[1]
+
+ self.disconnectHostfromNetwork(ha_host.ipaddress, 400)
+
+ hostDown = wait_until(10, 10, self.checkHostDown, other_host.ipaddress, ha_host.ipaddress)
+ if not(hostDown):
+ raise unittest.SkipTest("Host %s is not down, cannot proceed with test" % (ha_host.ipaddress))
+
+ hostDownInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Down", ha_host.id)
+ #the test could have failed here but we will try our best to get host back in consistent state
+
+ no_of_vms = self.noOfVMsOnHost(ha_host.id)
+ no_of_vms = no_of_vms + self.noOfVMsOnHost(other_host.id)
+ self.logger.debug("Number of VMS on hosts = %s" % no_of_vms)
+ #
+ hostUp = wait_until(10, 10, self.checkHostUp, other_host.ipaddress, ha_host.ipaddress)
+ if not(hostUp):
+ self.logger.debug("Host is down %s, though HA went fine, the environment is not consistent " % (ha_host.ipaddress))
+
+
+ hostUpInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Up", ha_host.id)
+
+ if not(hostDownInCloudstack):
+ raise self.fail("Host is not down %s, in cloudstack so failing test " % (ha_host.ipaddress))
+ if not(hostUpInCloudstack):
+ raise self.fail("Host is not up %s, in cloudstack so failing test " % (ha_host.ipaddress))
+
+ return
+
+
+
+ @attr(
+ tags=[
+ "advanced",
+ "advancedns",
+ "smoke",
+ "basic",
+ "eip",
+ "sg"],
+ required_hardware="true")
+ def test_03_host_ha_with_only_local_storage(self):
+
+ if not(self.isOnlyLocalStorageAvailable()):
+ raise unittest.SkipTest("Skipping this test as this is for Local storage only.");
+ return
+
+ listHost = Host.list(
+ self.apiclient,
+ type='Routing',
+ zoneid=self.zone.id,
+ podid=self.pod.id,
+ )
+ for host in listHost:
+ self.logger.debug('Hypervisor = {}'.format(host.id))
+
+
+ if len(listHost) != 2:
+ self.logger.debug("Host HA can be tested with two host only %s, found" % len(listHost));
+ raise unittest.SkipTest("Host HA can be tested with two host only %s, found" % len(listHost));
+ return
+
+ no_of_vms = self.noOfVMsOnHost(listHost[0].id)
+
+ no_of_vms = no_of_vms + self.noOfVMsOnHost(listHost[1].id)
+
+ self.logger.debug("Number of VMS on hosts = %s" % no_of_vms)
+
+ if no_of_vms < 5:
+ self.logger.debug("test_03: Create VMs as there are not enough vms to check host ha")
+ no_vm_req = 5 - no_of_vms
+ if (no_vm_req > 0):
+ self.logger.debug("Creating vms = {}".format(no_vm_req))
+ self.vmlist = self.createVMs(listHost[0].id, no_vm_req, True)
+
+ ha_host = listHost[1]
+ other_host = listHost[0]
+ if self.noOfVMsOnHost(listHost[0].id) > self.noOfVMsOnHost(listHost[1].id):
+ ha_host = listHost[0]
+ other_host = listHost[1]
+
+ self.disconnectHostfromNetwork(ha_host.ipaddress, 400)
+
+ hostDown = wait_until(10, 10, self.checkHostDown, other_host.ipaddress, ha_host.ipaddress)
+ if not(hostDown):
+ raise unittest.SkipTest("Host %s is not down, cannot proceed with test" % (ha_host.ipaddress))
+
+ hostDownInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Alert", ha_host.id)
+ #the test could have failed here but we will try our best to get host back in consistent state
+
+ no_of_vms = self.noOfVMsOnHost(ha_host.id)
+ no_of_vms = no_of_vms + self.noOfVMsOnHost(other_host.id)
+ self.logger.debug("Number of VMS on hosts = %s" % no_of_vms)
+ #
+ hostUp = wait_until(10, 10, self.checkHostUp, other_host.ipaddress, ha_host.ipaddress)
+ if not(hostUp):
+ self.logger.debug("Host is down %s, though HA went fine, the environment is not consistent " % (ha_host.ipaddress))
+
+
+ hostUpInCloudstack = wait_until(40, 10, self.checkHostStateInCloudstack, "Up", ha_host.id)
+
+ if not(hostDownInCloudstack):
+ raise self.fail("Host is not in alert %s, in cloudstack so failing test " % (ha_host.ipaddress))
+ if not(hostUpInCloudstack):
+ raise self.fail("Host is not up %s, in cloudstack so failing test " % (ha_host.ipaddress))
+
+ return
\ No newline at end of file
diff --git a/test/integration/component/test_host_ha.sh b/test/integration/component/test_host_ha.sh
new file mode 100755
index 0000000..85aadb1
--- /dev/null
+++ b/test/integration/component/test_host_ha.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+#bring down all eth interfaces
+
+usage() { echo "Usage: $0 <duration in seconds for downing all network interfaces>"; exit 1; }
+
+case $1 in
+ ''|*[!0-9]*) echo "The parameter should be an integer"; exit ;;
+ *) echo $1 ;;
+esac
+
+if [ -z $1 ]; then
+ usage
+elif [ $1 -lt 1 ]; then
+ echo "Down time should be at least 1 second"
+ exit 1
+elif [ $1 -gt 5000 ]; then
+ echo "Down time should be less than 5000 second"
+ exit 1
+fi
+
+for i in `ifconfig -a | sed 's/[ \t].*//;/^\(lo\|\)$/d' | grep eth`
+do
+ ifconfig $i down
+done
+
+
+service cloudstack-agent stop
+update-rc.d -f cloudstack-agent remove
+
+sleep $1
+
+for i in `ifconfig -a | sed 's/[ \t].*//;/^\(lo\|\)$/d' | grep eth`
+do
+ ifconfig $i up
+done
+
+
+update-rc.d -f cloudstack-agent defaults
+service cloudstack-agent start
\ No newline at end of file
diff --git a/test/integration/component/test_host_maintenance.py b/test/integration/component/test_host_maintenance.py
new file mode 100644
index 0000000..94f964c
--- /dev/null
+++ b/test/integration/component/test_host_maintenance.py
@@ -0,0 +1,292 @@
+# 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.
+""" BVT tests for Hosts Maintenance
+"""
+
+# Import Local Modules
+from marvin.codes import FAILED
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from marvin.lib.utils import *
+from marvin.lib.base import *
+from marvin.lib.common import *
+from nose.plugins.attrib import attr
+
+from time import sleep
+
+_multiprocess_shared_ = False
+
+
+class TestHostMaintenance(cloudstackTestCase):
+
+ def setUp(self):
+ self.logger = logging.getLogger('TestHM')
+ self.stream_handler = logging.StreamHandler()
+ self.logger.setLevel(logging.DEBUG)
+ self.logger.addHandler(self.stream_handler)
+ self.apiclient = self.testClient.getApiClient()
+ self.hypervisor = self.testClient.getHypervisorInfo()
+ self.dbclient = self.testClient.getDbConnection()
+ self.services = self.testClient.getParsedTestDataConfig()
+ self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests())
+ self.pod = get_pod(self.apiclient, self.zone.id)
+ self.cleanup = []
+ self.services = {
+ "service_offering": {
+ "name": "Ultra Tiny Instance",
+ "displaytext": "Ultra Tiny Instance",
+ "cpunumber": 1,
+ "cpuspeed": 100,
+ "memory": 128,
+ },
+ "vm": {
+ "username": "root",
+ "password": "password",
+ "ssh_port": 22,
+ # Hypervisor type should be same as
+ # hypervisor type of cluster
+ "privateport": 22,
+ "publicport": 22,
+ "protocol": 'TCP',
+ },
+ "natrule": {
+ "privateport": 22,
+ "publicport": 22,
+ "startport": 22,
+ "endport": 22,
+ "protocol": "TCP",
+ "cidrlist": '0.0.0.0/0',
+ },
+ "ostype": 'CentOS 5.3 (64-bit)',
+ "sleep": 60,
+ "timeout": 10,
+ }
+
+
+ def tearDown(self):
+ try:
+ # Clean up, terminate the created templates
+ cleanup_resources(self.apiclient, self.cleanup)
+
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+
+ return
+
+ def createVMs(self, hostId, number):
+
+ self.template = get_template(
+ self.apiclient,
+ self.zone.id,
+ self.services["ostype"]
+ )
+
+ if self.template == FAILED:
+ assert False, "get_template() failed to return template with description %s" % self.services["ostype"]
+
+ self.logger.debug("Using template %s " % self.template.id)
+
+ self.service_offering = ServiceOffering.create(
+ self.apiclient,
+ self.services["service_offering"]
+ )
+ self.logger.debug("Using service offering %s " % self.service_offering.id)
+
+ vms=[]
+ for i in range(0, number):
+ self.services["vm"]["zoneid"] = self.zone.id
+ self.services["vm"]["template"] = self.template.id
+ self.services["vm"]["displayname"] = 'vm' + str(i)
+ self.services["vm"]["hypervisor"] = self.hypervisor
+ vm = VirtualMachine.create(
+ self.apiclient,
+ self.services["vm"],
+ serviceofferingid=self.service_offering.id,
+ hostid=hostId
+ )
+ vms.append(vm)
+ self.cleanup.append(vm)
+ self.logger.debug("VM create = {}".format(vm.id))
+ return vms
+
+ def checkVmMigratingOnHost(self, hostId):
+ vm_migrating=False
+ listVms1 = VirtualMachine.list(
+ self.apiclient,
+ hostid=hostId
+ )
+
+ if (listVms1 is not None):
+ self.logger.debug('Vms found = {} '.format(len(listVms1)))
+ for vm in listVms1:
+ if (vm.state == "Migrating"):
+ self.logger.debug('VirtualMachine on Hyp id = {} is in {}'.format(vm.id, vm.state))
+ vm_migrating=True
+ break
+
+ return (vm_migrating, None)
+
+ def checkNoVmMigratingOnHost(self, hostId):
+ no_vm_migrating=True
+ listVms1 = VirtualMachine.list(
+ self.apiclient,
+ hostid=hostId
+ )
+
+ if (listVms1 is not None):
+ self.logger.debug('Vms found = {} '.format(len(listVms1)))
+ for vm in listVms1:
+ if (vm.state == "Migrating"):
+ self.logger.debug('VirtualMachine on Hyp id = {} is in {}'.format(vm.id, vm.state))
+ no_vm_migrating=False
+ break
+
+ return (no_vm_migrating, None)
+
+ def noOfVMsOnHost(self, hostId):
+ listVms = VirtualMachine.list(
+ self.apiclient,
+ hostid=hostId
+ )
+ no_of_vms=0
+ if (listVms is not None):
+ for vm in listVms:
+ self.logger.debug('VirtualMachine on Hyp 1 = {}'.format(vm.id))
+ no_of_vms=no_of_vms+1
+
+ return no_of_vms
+
+ def hostPrepareAndCancelMaintenance(self, target_host_id, other_host_id, checkVMMigration):
+
+ cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd()
+ cmd.id = target_host_id
+ response = self.apiclient.prepareHostForMaintenance(cmd)
+
+ self.logger.debug('Host with id {} is in prepareHostForMaintenance'.format(target_host_id))
+
+ vm_migrating = wait_until(1, 10, checkVMMigration, other_host_id)
+
+ cmd = cancelHostMaintenance.cancelHostMaintenanceCmd()
+ cmd.id = target_host_id
+ response = self.apiclient.cancelHostMaintenance(cmd)
+
+ self.logger.debug('Host with id {} is in cancelHostMaintenance'.format(target_host_id) )
+
+ return vm_migrating
+
+ @attr(
+ tags=[
+ "advanced",
+ "advancedns",
+ "smoke",
+ "basic",
+ "eip",
+ "sg"],
+ required_hardware="true")
+ def test_01_cancel_host_maintenace_with_no_migration_jobs(self):
+ listHost = Host.list(
+ self.apiclient,
+ type='Routing',
+ zoneid=self.zone.id,
+ podid=self.pod.id,
+ )
+ for host in listHost:
+ self.logger.debug('1 Hypervisor = {}'.format(host.id))
+
+
+ if (len(listHost) < 2):
+ raise unittest.SkipTest("Cancel host maintenance when VMs are migrating should be tested for 2 or more hosts");
+ return
+
+ vm_migrating=False
+
+ try:
+
+ vm_migrating = self.hostPrepareAndCancelMaintenance(listHost[0].id, listHost[1].id, self.checkNoVmMigratingOnHost)
+
+ vm_migrating = self.hostPrepareAndCancelMaintenance(listHost[1].id, listHost[0].id, self.checkNoVmMigratingOnHost)
+
+ except Exception as e:
+ self.logger.debug("Exception {}".format(e))
+ self.fail("Cancel host maintenance failed {}".format(e[0]))
+
+
+ if (vm_migrating == True):
+ raise unittest.SkipTest("VMs are migrating and the test will not be able to check the conditions the test is intended for");
+
+
+ return
+
+
+
+
+ @attr(
+ tags=[
+ "advanced",
+ "advancedns",
+ "smoke",
+ "basic",
+ "eip",
+ "sg"],
+ required_hardware="true")
+ def test_02_cancel_host_maintenace_with_migration_jobs(self):
+
+ listHost = Host.list(
+ self.apiclient,
+ type='Routing',
+ zoneid=self.zone.id,
+ podid=self.pod.id,
+ )
+ for host in listHost:
+ self.logger.debug('2 Hypervisor = {}'.format(host.id))
+
+ if (len(listHost) != 2):
+ raise unittest.SkipTest("Cancel host maintenance when VMs are migrating can only be tested with 2 hosts");
+ return
+
+
+ no_of_vms = self.noOfVMsOnHost(listHost[0].id)
+
+ no_of_vms = no_of_vms + self.noOfVMsOnHost(listHost[1].id)
+
+ if no_of_vms < 5:
+ self.logger.debug("Create VMs as there are not enough vms to check host maintenance")
+ no_vm_req = 5 - no_of_vms
+ if (no_vm_req > 0):
+ self.logger.debug("Creating vms = {}".format(no_vm_req))
+ self.vmlist = self.createVMs(listHost[0].id, no_vm_req)
+
+ vm_migrating=False
+
+ try:
+
+ vm_migrating = self.hostPrepareAndCancelMaintenance(listHost[0].id, listHost[1].id, self.checkVmMigratingOnHost)
+
+ vm_migrating = self.hostPrepareAndCancelMaintenance(listHost[1].id, listHost[0].id, self.checkVmMigratingOnHost)
+
+ except Exception as e:
+ self.logger.debug("Exception {}".format(e))
+ self.fail("Cancel host maintenance failed {}".format(e[0]))
+
+
+ if (vm_migrating == False):
+ raise unittest.SkipTest("No VM is migrating and the test will not be able to check the conditions the test is intended for");
+
+
+ return
+
+
diff --git a/test/integration/component/test_nuage_vsp.py b/test/integration/component/test_nuage_vsp.py
deleted file mode 100644
index e7bd10e..0000000
--- a/test/integration/component/test_nuage_vsp.py
+++ /dev/null
@@ -1,334 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-""" P1 tests for NuageVsp network Plugin
-"""
-# Import Local Modules
-from nose.plugins.attrib import attr
-from marvin.cloudstackTestCase import cloudstackTestCase
-from marvin.cloudstackAPI import (listPhysicalNetworks,
- listNetworkServiceProviders,
- addNetworkServiceProvider,
- deleteNetworkServiceProvider,
- deleteNuageVspDevice,
- updateNetworkServiceProvider,
- addNuageVspDevice,
- destroyVirtualMachine)
-from marvin.lib.utils import (cleanup_resources)
-from marvin.lib.base import (Account,
- VirtualMachine,
- ServiceOffering,
- NetworkOffering,
- Network)
-from marvin.lib.common import (get_domain,
- get_zone,
- get_template)
-
-import logging
-import unittest
-
-
-class Services:
-
- """Test NuageVsp plugin
- """
-
- def __init__(self):
- print "in __init__"
- self.services = {
- "account": {
- "email": "cloudstack@cloudmonkey.com",
- "firstname": "cloudstack",
- "lastname": "bob",
- "username": "admin",
- "password": "password",
- },
- "service_offering": {
- "name": "Tiny Instance",
- "displaytext": "Tiny Instance",
- "cpunumber": 1,
- "cpuspeed": 100, # in MHz
- "memory": 128, # In MBs
- },
- "virtual_machine": {
- "displayname": "TestVM",
- "username": "root",
- "password": "password",
- "ssh_port": 22,
- "hypervisor": 'KVM',
- "privateport": 22,
- "publicport": 22,
- "protocol": 'TCP',
- },
- "nuage_vsp_device": {
- "hostname": '172.31.222.162',
- "username": 'cloudstackuser1',
- "password": 'cloudstackuser1',
- "port": '8443',
- "apiversion": 'v3_2',
- "retrycount": '4',
- "retryinterval": '60'
- },
- # services supported by Nuage for isolated networks.
- "network_offering": {
- "name": 'nuage_marvin',
- "displaytext": 'nuage_marvin',
- "guestiptype": 'Isolated',
- "supportedservices":
- 'Dhcp,SourceNat,Connectivity,StaticNat,UserData,Firewall',
- "traffictype": 'GUEST',
- "availability": 'Optional',
- "serviceProviderList": {
- "UserData": 'VirtualRouter',
- "Dhcp": 'NuageVsp',
- "Connectivity": 'NuageVsp',
- "StaticNat": 'NuageVsp',
- "SourceNat": 'NuageVsp',
- "Firewall": 'NuageVsp'
- },
- "serviceCapabilityList": {
- "SourceNat": {"SupportedSourceNatTypes": "perzone"},
- }
- },
- "network": {
- "name": "nuage",
- "displaytext": "nuage",
- },
- "ostype": 'CentOS 5.5 (64-bit)',
- "sleep": 60,
- "timeout": 10
- }
-
-
-class TestNuageVsp(cloudstackTestCase):
-
- @classmethod
- def setUpClass(cls):
- print "In setup class"
- cls._cleanup = []
- cls.testClient = super(TestNuageVsp, cls).getClsTestClient()
- cls.api_client = cls.testClient.getApiClient()
-
- cls.services = Services().services
- # Get Zone, Domain and templates
- cls.domain = get_domain(cls.api_client)
- cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
- cls.template = get_template(
- cls.api_client,
- cls.zone.id,
- cls.services["ostype"]
- )
- # nuage vsp device brings the Nuage virtual service platform into play
- cls.nuage_services = cls.services["nuage_vsp_device"]
- try:
-
- resp = listPhysicalNetworks.listPhysicalNetworksCmd()
- print "in cls.setupClass- resp: %s" % resp
- resp.zoneid = cls.zone.id
- physical_networks = cls.api_client.listPhysicalNetworks(resp)
- for pn in physical_networks:
- if pn.isolationmethods=='VSP':
- physical_network = pn
- #if isinstance(physical_networks, list):
- # physical_network = physical_networks[1]
- resp = listNetworkServiceProviders.listNetworkServiceProvidersCmd()
- resp.name = 'NuageVsp'
- resp.physicalnetworkid = physical_network.id
- nw_service_providers = cls.api_client.listNetworkServiceProviders(
- resp)
- if not isinstance(nw_service_providers, list):
- # create network service provider and add nuage vsp device
- resp_add_nsp =\
- addNetworkServiceProvider.addNetworkServiceProviderCmd()
- resp_add_nsp.name = 'NuageVsp'
- resp_add_nsp.physicalnetworkid = physical_network.id
- cls.api_client.addNetworkServiceProvider(resp_add_nsp)
- #Get NSP ID
- nw_service_providers = cls.api_client.listNetworkServiceProviders(
- resp)
- cls.debug("NuageVsp NSP ID: %s" % nw_service_providers[0].id)
-
- resp_add_device = addNuageVspDevice.addNuageVspDeviceCmd()
- resp_add_device.physicalnetworkid = physical_network.id
- resp_add_device.username = cls.nuage_services["username"]
- resp_add_device.password = cls.nuage_services["password"]
- resp_add_device.hostname = cls.nuage_services["hostname"]
- resp_add_device.port = cls.nuage_services["port"]
- resp_add_device.apiversion = cls.nuage_services[
- "apiversion"]
- resp_add_device.retrycount = cls.nuage_services[
- "retrycount"]
- resp_add_device.retryinterval = cls.nuage_services[
- "retryinterval"]
- cls.nuage = cls.api_client.addNuageVspDevice(
- resp_add_device)
- #Enable NuageVsp NSP
- cls.debug("NuageVsp NSP ID : %s" % nw_service_providers[0].id)
- resp_up_nsp = \
- updateNetworkServiceProvider.updateNetworkServiceProviderCmd()
- resp_up_nsp.id = nw_service_providers[0].id
- resp_up_nsp.state = 'Enabled'
- cls.api_client.updateNetworkServiceProvider(resp_up_nsp)
-
- cls.network_offering = NetworkOffering.create(
- cls.api_client,
- cls.services["network_offering"],
- conservemode=True
- )
- cls._cleanup.append(cls.network_offering)
-
- cls.network_offering.update(cls.api_client, state='Enabled')
- cls.services["virtual_machine"]["zoneid"] = cls.zone.id
- cls.services["virtual_machine"]["template"] = cls.template.id
- cls.service_offering = ServiceOffering.create(
- cls.api_client,
- cls.services["service_offering"]
- )
- cls._cleanup.append(cls.service_offering)
- except Exception as e:
- cls.tearDownClass()
- raise unittest.SkipTest("Unable to add VSP device")
- return
-
- @classmethod
- def tearDownClass(cls):
- try:
- cleanup_resources(cls.api_client, cls._cleanup)
- except Exception as e:
- raise Exception("Warning: Exception during cleanup : %s" % e)
- return
-
-
- def setUp(self):
- self.apiclient = self.testClient.getApiClient()
- self.dbclient = self.testClient.getDbConnection()
- self.account = Account.create(
- self.apiclient,
- self.services["account"],
- admin=True,
- domainid=self.domain.id
- )
- self.cleanup = [self.account]
- return
-
-
- def tearDown(self):
- try:
- self.debug("Cleaning up the resources")
- cleanup_resources(self.apiclient, self.cleanup)
- self.debug("Cleanup complete!")
- except Exception as e:
- raise Exception("Warning: Exception during cleanup : %s" % e)
- return
-
- @attr(tags=["advanced"])
- def test_network_vsp(self):
- """Test nuage Network and VM Creation
- """
-
- self.debug("Creating network with network offering: %s" %
- self.network_offering.id)
- self.network = Network.create(
- self.apiclient,
- self.services["network"],
- accountid=self.account.name,
- domainid=self.account.domainid,
- networkofferingid=self.network_offering.id,
- zoneid=self.zone.id,
- gateway = "10.1.1.1",
- netmask = '255.255.255.0'
- )
- self.debug("Created network with ID: %s" % self.network.id)
-
- self.debug("Deploying VM in account: %s" % self.account.name)
-
- virtual_machine_1 = VirtualMachine.create(
- self.apiclient,
- self.services["virtual_machine"],
- accountid=self.account.name,
- domainid=self.account.domainid,
- serviceofferingid=self.service_offering.id,
- networkids=[str(self.network.id)]
- )
- self.debug("Deployed VM in network: %s" % self.network.id)
- list_vm_response = VirtualMachine.list(
- self.apiclient,
- id=virtual_machine_1.id
- )
-
- self.debug(
- "Verify listVirtualMachines response for virtual machine: %s"
- % virtual_machine_1.id
- )
-
- self.assertEqual(
- isinstance(list_vm_response, list),
- True,
- "Check list response returns a valid list"
- )
- vm_response = list_vm_response[0]
-
- self.assertEqual(
- vm_response.state,
- "Running",
- "VM state should be running after deployment"
- )
-
- self.debug("Deploying another VM in account: %s" %
- self.account.name)
-
- virtual_machine_2 = VirtualMachine.create(
- self.apiclient,
- self.services["virtual_machine"],
- accountid=self.account.name,
- domainid=self.account.domainid,
- serviceofferingid=self.service_offering.id,
- networkids=[str(self.network.id)]
- )
- self.debug("Deployed VM in network: %s" % self.network.id)
- list_vm_response = VirtualMachine.list(
- self.apiclient,
- id=virtual_machine_2.id
- )
-
- self.debug(
- "Verify listVirtualMachines response for virtual machine: %s"
- % virtual_machine_2.id
- )
-
- self.assertEqual(
- isinstance(list_vm_response, list),
- True,
- "Check list response returns a valid list"
- )
- vm_response = list_vm_response[0]
-
- self.assertEqual(
- vm_response.state,
- "Running",
- "VM state should be running after deployment"
- )
-
- VirtualMachine.delete(virtual_machine_1, self.apiclient, expunge=True)
-
- # # Deleting a single VM
- VirtualMachine.delete(virtual_machine_2, self.apiclient, expunge=True)
-
- # Delete Network
- Network.delete(self.network, self.apiclient)
-
- return
diff --git a/test/integration/component/test_persistent_networks.py b/test/integration/component/test_persistent_networks.py
index ae18424..f8beed0 100644
--- a/test/integration/component/test_persistent_networks.py
+++ b/test/integration/component/test_persistent_networks.py
@@ -17,7 +17,7 @@
""" Tests for Persistent Networks without running VMs feature"""
from marvin.lib.utils import (cleanup_resources,
validateList,
- get_hypervisor_type)
+ get_hypervisor_type, get_process_status)
from marvin.lib.base import (Account,
VPC,
VirtualMachine,
@@ -40,7 +40,7 @@
get_template,
verifyNetworkState,
add_netscaler,
- wait_for_cleanup)
+ wait_for_cleanup,list_routers,list_hosts)
from nose.plugins.attrib import attr
from marvin.codes import PASS, FAIL, FAILED
from marvin.sshClient import SshClient
@@ -1459,6 +1459,116 @@
return
+ @attr(tags=["advanced"], required_hardware="true")
+ def test_volume_delete_event_errorState(self):
+ """
+ @summary: Test volume delete event generation in error state condition
+ @Steps:
+ Step1: Create a network using network created in Step1
+ Step2: Verifying that network creation is successful
+ Step3: Login to Virtual router and add iptable rule to block insertion of vm rules
+ Step6: deploy a vm using network created in step2
+ Step7: check the Vm status for failure
+ Step8: destroy and expunge the vm
+ Step9: list the generated events for volume delete event.
+ """
+
+ # Listing all the networks available
+
+ account = Account.create(
+ self.api_client,
+ self.services["account"],
+ domainid=self.domain.id)
+ network = Network.create(
+ self.apiclient,
+ self.services["isolated_network"],
+ networkofferingid=self.isolated_persistent_network_offering.id,
+ accountid=self.account.name,
+ domainid=self.domain.id,
+ zoneid=self.zone.id)
+ response = verifyNetworkState(
+ self.apiclient,
+ network.id,
+ "implemented")
+ exceptionOccured = response[0]
+ isNetworkInDesiredState = response[1]
+ exceptionMessage = response[2]
+
+ if (exceptionOccured or (not isNetworkInDesiredState)):
+ self.fail(exceptionMessage)
+ self.assertIsNotNone(
+ network.vlan,
+ "vlan must not be null for persistent network")
+ try:
+ list_router_response = list_routers(
+ self.apiclient,
+ account=self.account.name,
+ domainid=self.account.domainid
+ )
+
+ self.assertEqual(validateList(list_router_response)[0], PASS, "Check list response returns a valid list")
+ router = list_router_response[0]
+
+ self.debug("Router ID: %s, state: %s" % (router.id, router.state))
+
+ self.assertEqual(
+ router.state,
+ 'Running',
+ "Check list router response for router state"
+ )
+ self.hypervisor = self.testClient.getHypervisorInfo()
+ if self.hypervisor.lower() in ('vmware', 'hyperv'):
+ result = get_process_status(
+ self.apiclient.connection.mgtSvr,
+ 22,
+ self.apiclient.connection.user,
+ self.apiclient.connection.passwd,
+ router.linklocalip,
+ "iptables -I INPUT 1 -j DROP",
+ hypervisor=self.hypervisor
+ )
+ else:
+ try:
+ hosts = list_hosts(
+ self.apiclient,
+ zoneid=router.zoneid,
+ type='Routing',
+ state='Up',
+ id=router.hostid
+ )
+ self.assertEqual(validateList(hosts)[0],PASS,"Check list host returns a valid list")
+ host = hosts[0]
+ result = get_process_status(
+ host.ipaddress,22, self.services["acl"]["host"]["username"],self.services["acl"]["host"]["password"], router.linklocalip,
+ "iptables -I INPUT 1 -j DROP"
+ )
+ except Exception as e:
+ raise Exception("Exception raised in accessing/running the command on hosts : %s " % e)
+ except Exception as e:
+ raise Exception("Exception raised in getting hostcredentials: %s " % e)
+
+ with self.assertRaises(Exception) as context:
+ virtual_machine = VirtualMachine.create(
+ self.apiclient,
+ self.services["virtual_machine"],
+ networkids=[
+ network.id],
+ serviceofferingid=self.service_offering.id,
+ accountid=self.account.name,
+ domainid=self.domain.id)
+ #self.assertTrue('This is broken' in context.exception)
+ try:
+ account.delete(self.api_client)
+ except Exception as e:
+ self.cleanup.append(account)
+ qresultset = self.dbclient.execute(
+ "select id from usage_event where type = '%s' ORDER BY id DESC LIMIT 1;" %
+ str("VOLUME.DELETE"))
+ self.assertNotEqual(
+ len(qresultset),
+ 0,
+ "Check DB Query result set")
+ return
@ddt
class TestAssignVirtualMachine(cloudstackTestCase):
diff --git a/test/integration/component/test_redundant_router_cleanups.py b/test/integration/component/test_redundant_router_cleanups.py
index 295ce08..04f24a5 100644
--- a/test/integration/component/test_redundant_router_cleanups.py
+++ b/test/integration/component/test_redundant_router_cleanups.py
@@ -23,7 +23,7 @@
VirtualMachine,
Router,
Configurations)
-from marvin.lib.utils import cleanup_resources
+from marvin.lib.utils import cleanup_resources, validateList
from marvin.lib.common import (get_domain,
get_zone,
get_template)
@@ -31,6 +31,7 @@
#Import Local Modules
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.cloudstackAPI import startRouter
+from marvin.codes import PASS
import time
class Services:
@@ -666,3 +667,156 @@
"Router should be in stopped state"
)
return
+
+ @attr(tags=["advanced", "advancedns"], required_hardware="false")
+ def test_restart_network_with_destroyed_masterVR(self):
+ """Test restarting RvR network without cleanup after destroying master VR
+ """
+
+ # Steps to validate
+ # 1. createNetwork using network offering for redundant virtual router
+ # 2. listRouters in above network
+ # 3. deployVM in above user account in the created network
+ # 4. Destroy master VR
+ # 5. restartNetwork cleanup=false
+ # 6. Verify RVR status after network restart
+
+ # Creating network using the network offering created
+ self.debug("Creating network with network offering: %s" %
+ self.network_offering.id)
+ network = Network.create(
+ self.apiclient,
+ self.services["network"],
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ networkofferingid=self.network_offering.id,
+ zoneid=self.zone.id
+ )
+ self.debug("Created network with ID: %s" % network.id)
+ networks = Network.list(
+ self.apiclient,
+ id=network.id,
+ listall=True
+ )
+ self.assertEqual(
+ validateList(networks)[0],
+ PASS,
+ "List networks should return a valid response for created network"
+ )
+
+ self.debug("Deploying VM in account: %s" % self.account.name)
+ # Spawn an instance in that network
+ virtual_machine = VirtualMachine.create(
+ self.apiclient,
+ self.services["virtual_machine"],
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ serviceofferingid=self.service_offering.id,
+ networkids=[str(network.id)]
+ )
+ self.debug("Deployed VM in network: %s" % network.id)
+ vms = VirtualMachine.list(
+ self.apiclient,
+ id=virtual_machine.id,
+ listall=True
+ )
+ self.assertEqual(
+ validateList(vms)[0],
+ PASS,
+ "List Vms should return a valid list"
+ )
+ vm = vms[0]
+ self.assertEqual(
+ vm.state,
+ "Running",
+ "Vm should be in running state after deployment"
+ )
+
+ self.debug("Listing routers for network: %s" % network.name)
+ routers = Router.list(
+ self.apiclient,
+ networkid=network.id,
+ listall=True
+ )
+ self.assertEqual(
+ validateList(routers)[0],
+ PASS,
+ "list router should return Master and backup routers"
+ )
+ self.assertEqual(
+ len(routers),
+ 2,
+ "Length of the list router should be 2 (Backup & master)"
+ )
+ if routers[0].redundantstate == 'MASTER' and\
+ routers[1].redundantstate == 'BACKUP':
+ master_router = routers[0]
+ backup_router = routers[1]
+ elif routers[1].redundantstate == 'MASTER' and \
+ routers[0].redundantstate == 'BACKUP':
+ master_router = routers[1]
+ backup_router = routers[0]
+ else:
+ self.fail("Both the routers in RVR are in BackupState")
+
+ Router.stop(
+ self.apiclient,
+ id=master_router.id
+ )
+ Router.destroy(
+ self.apiclient,
+ id=master_router.id
+ )
+ masterVR = Router.list(
+ self.apiclient,
+ id=master_router.id
+ )
+ self.assertIsNone(masterVR, "Router is not destroyed")
+ new_master = Router.list(
+ self.apiclient,
+ id=backup_router.id
+ )
+ self.assertEqual(validateList(new_master)[0], PASS, "Invalid response after vr destroy")
+ self.assertEqual(
+ new_master[0].redundantstate,
+ "MASTER",
+ "Backup didn't switch to Master after destroying Master VR"
+ )
+
+ self.debug("restarting network with cleanup=False")
+ try:
+ network.restart(self.apiclient, cleanup=False)
+ except Exception as e:
+ self.fail("Failed to cleanup network - %s" % e)
+
+ self.debug("Listing routers for network: %s" % network.name)
+ routers = Router.list(
+ self.apiclient,
+ networkid=network.id,
+ listall=True
+ )
+ self.assertEqual(
+ validateList(routers)[0],
+ PASS,
+ "list router should return Master and backup routers afrer network restart"
+ )
+ self.assertEqual(
+ len(routers),
+ 2,
+ "Length of the list router should be 2 (Backup & master)"
+ )
+ for router in routers:
+ self.assertEqual(
+ router.state,
+ "Running",
+ "Router state should be running"
+ )
+ if routers[0].redundantstate == 'MASTER' and\
+ routers[1].redundantstate == 'BACKUP':
+ self.debug("Found master and backup VRs after network restart")
+ elif routers[0].redundantstate == 'BACKUP' and \
+ routers[1].redundantstate == 'MASTER':
+ self.debug("Found master and backup routers")
+ else:
+ self.fail("RVR is not in proper start after network restart")
+ return
diff --git a/test/integration/component/test_vpc.py b/test/integration/component/test_vpc.py
index f81f53f..5f7ea98 100644
--- a/test/integration/component/test_vpc.py
+++ b/test/integration/component/test_vpc.py
@@ -22,7 +22,7 @@
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.cloudstackException import CloudstackAPIException
from marvin.cloudstackAPI import updateZone
-from marvin.lib.utils import cleanup_resources
+from marvin.lib.utils import cleanup_resources, validateList
from marvin.lib.base import (Account,
VPC,
VpcOffering,
@@ -36,11 +36,13 @@
NetworkACL,
NATRule,
Zone,
- StaticNATRule)
+ StaticNATRule,
+ VpnCustomerGateway)
from marvin.lib.common import (get_domain,
get_zone,
get_template,
list_configurations)
+from marvin.codes import PASS
import time
@@ -182,6 +184,13 @@
"domain": {
"name": "TestDomain"
},
+ "vpn_customer_gw": {
+ "ipsecpsk": "s2svpn",
+ "ikepolicy": "3des-md5",
+ "ikelifetime": "86400",
+ "esppolicy": "3des-md5",
+ "esplifetime": "3600",
+ },
"ostype": 'CentOS 5.3 (64-bit)',
# Cent OS 5.3 (64 bit)
"sleep": 60,
@@ -2490,3 +2499,37 @@
"Failed to create VM with first ip address in the CIDR as the vm ip"
)
return
+
+ @attr(tags=["advanced", "intervlan"], required_hardware="false")
+ def test_22_vpn_customer_gw_with_hostname(self):
+ """
+ Test to create vpn customer gateway with hostname
+ instead of gateway ip address
+ """
+ try:
+ vpnGw = VpnCustomerGateway.create(
+ self.apiclient,
+ self.services["vpn_customer_gw"],
+ name="test_vpn_customer_gw",
+ gateway="GwWithHostName",
+ cidrlist="10.1.0.0/16"
+ )
+ self.cleanup.append(vpnGw)
+ except Exception as e:
+ self.fail("Creating vpn customer gateway with hostname\
+ Failed with error :%s" % e)
+ vpn_cgw_res = VpnCustomerGateway.list(
+ self.apiclient,
+ id=vpnGw.id
+ )
+ self.assertEqual(
+ validateList(vpn_cgw_res)[0],
+ PASS,
+ "Invalid response for list vpncustomer gateways"
+ )
+ self.assertEqual(
+ vpnGw.gateway,
+ vpn_cgw_res[0].gateway,
+ "Mismatch in vpn customer gateway names"
+ )
+ return
diff --git a/test/integration/component/test_vpcnetwork_nuage.py b/test/integration/component/test_vpcnetwork_nuage.py
deleted file mode 100644
index be76fa6..0000000
--- a/test/integration/component/test_vpcnetwork_nuage.py
+++ /dev/null
@@ -1,295 +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.
-""" Tests for NuageNetwork VPC
-"""
-#Import Local Modules
-from marvin.cloudstackTestCase import cloudstackTestCase, unittest
-from marvin.lib.utils import (cleanup_resources)
-from marvin.cloudstackAPI import (listPhysicalNetworks,
- listNetworkServiceProviders,
- addNetworkServiceProvider,
- updateNetworkServiceProvider,
- addNuageVspDevice,
- destroyVirtualMachine)
-from marvin.lib.base import (VirtualMachine,
- ServiceOffering,
- Account,
- NetworkOffering,
- Network,
- VPC,
- VpcOffering,
- NetworkACL,
- NetworkACLList)
-from marvin.lib.common import (get_zone,
- get_domain,
- get_template,
- wait_for_cleanup,
- list_networks)
-
-from nose.plugins.attrib import attr
-
-class Services:
-
- """Test NuageVsp plugin
- """
-
- def __init__(self):
- self.services = {
- "account": {
- "email": "cloudstack@cloudmonkey.com",
- "firstname": "cloudstack",
- "lastname": "bob",
- "username": "admin",
- "password": "password",
- },
- "service_offering": {
- "name": "Tiny Instance",
- "displaytext": "Tiny Instance",
- "cpunumber": 1,
- "cpuspeed": 100, # in MHz
- "memory": 128, # In MBs
- },
- "virtual_machine": {
- "displayname": "TestVM",
- "username": "root",
- "password": "password",
- "ssh_port": 22,
- "hypervisor": 'KVM',
- "privateport": 22,
- "publicport": 22,
- "protocol": 'TCP',
- },
- "nuage_vsp_device": {
- #"hostname": '192.168.0.7',
- #"hostname": '10.31.43.226',
- "hostname": '172.31.222.162',
- "username": 'cloudstackuser1',
- "password": 'cloudstackuser1',
- "port": '8443',
- "apiversion": 'v3_2',
- "retrycount": '4',
- "retryinterval": '60'
- },
- # services supported by Nuage for VPC networks.
- "vpc_network_offering": {
- "name": 'nuage_vpc_marvin',
- "displaytext": 'nuage_vpc_marvin',
- "guestiptype": 'Isolated',
- "supportedservices": 'UserData,Dhcp,SourceNat,StaticNat,NetworkACL,Connectivity',
- "traffictype": 'GUEST',
- "useVpc": 'on',
- "serviceProviderList": {
- "Dhcp": "NuageVsp",
- "SourceNat": "NuageVsp",
- "StaticNat": "NuageVsp",
- "NetworkACL": "NuageVsp",
- "UserData": "VpcVirtualRouter",
- "Connectivity": "NuageVsp"
- },
- "serviceCapabilityList": {
- "SourceNat": {"SupportedSourceNatTypes": "perzone"}
- }
- },
- "vpc": {
- "name": "vpc-networkacl-nuage",
- "displaytext": "vpc-networkacl-nuage",
- "cidr": '10.1.0.0/16'
- },
- "vpcnetwork": {
- "name": "nuagevpcnetwork",
- "displaytext": "nuagevpcnetwork",
- "netmask": '255.255.255.128'
- },
- "ostype": 'CentOS 5.5 (64-bit)',
- "sleep": 60,
- "timeout": 10
- }
-
-
-class TestVpcNetworkNuage(cloudstackTestCase):
-
- @classmethod
- def setUpClass(cls):
- cls._cleanup = []
- cls.testClient = super(TestVpcNetworkNuage, cls).getClsTestClient()
- cls.api_client = cls.testClient.getApiClient()
-
- cls.services = Services().services
- # Get Zone, Domain and templates
- cls.domain = get_domain(cls.api_client)
- cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
- cls.template = get_template(
- cls.api_client,
- cls.zone.id,
- cls.services["ostype"]
- )
- # nuage vsp device brings the Nuage virtual service platform into play
- cls.nuage_services = cls.services["nuage_vsp_device"]
- try:
-
- resp = listPhysicalNetworks.listPhysicalNetworksCmd()
- print "in cls.setupClass- resp: %s" % resp
- resp.zoneid = cls.zone.id
- physical_networks = cls.api_client.listPhysicalNetworks(resp)
- for pn in physical_networks:
- if pn.isolationmethods=='VSP':
- physical_network = pn
- #if isinstance(physical_networks, list):
- # physical_network = physical_networks[1]
- resp = listNetworkServiceProviders.listNetworkServiceProvidersCmd()
- resp.name = 'NuageVsp'
- resp.physicalnetworkid = physical_network.id
- nw_service_providers = cls.api_client.listNetworkServiceProviders(
- resp)
- if not isinstance(nw_service_providers, list):
- # create network service provider and add nuage vsp device
- resp_add_nsp = \
- addNetworkServiceProvider.addNetworkServiceProviderCmd()
- resp_add_nsp.name = 'NuageVsp'
- resp_add_nsp.physicalnetworkid = physical_network.id
- cls.api_client.addNetworkServiceProvider(resp_add_nsp)
- #Get NSP ID
- nw_service_providers = cls.api_client.listNetworkServiceProviders(
- resp)
- cls.debug("NuageVsp NSP ID: %s" % nw_service_providers[0].id)
-
- resp_add_device = addNuageVspDevice.addNuageVspDeviceCmd()
- resp_add_device.physicalnetworkid = physical_network.id
- resp_add_device.username = cls.nuage_services["username"]
- resp_add_device.password = cls.nuage_services["password"]
- resp_add_device.hostname = cls.nuage_services["hostname"]
- resp_add_device.port = cls.nuage_services["port"]
- resp_add_device.apiversion = cls.nuage_services[
- "apiversion"]
- resp_add_device.retrycount = cls.nuage_services[
- "retrycount"]
- resp_add_device.retryinterval = cls.nuage_services[
- "retryinterval"]
- cls.nuage = cls.api_client.addNuageVspDevice(
- resp_add_device)
- #Enable NuageVsp NSP
- cls.debug("NuageVsp NSP ID : %s" % nw_service_providers[0].id)
- resp_up_nsp = \
- updateNetworkServiceProvider.updateNetworkServiceProviderCmd()
- resp_up_nsp.id = nw_service_providers[0].id
- resp_up_nsp.state = 'Enabled'
- cls.api_client.updateNetworkServiceProvider(resp_up_nsp)
-
- cls.network_offering = NetworkOffering.create(
- cls.api_client,
- cls.services["vpc_network_offering"],
- conservemode=False
- )
- cls._cleanup.append(cls.network_offering)
-
- cls.network_offering.update(cls.api_client, state='Enabled')
- cls.services["virtual_machine"]["zoneid"] = cls.zone.id
- cls.services["virtual_machine"]["template"] = cls.template.id
- cls.service_offering = ServiceOffering.create(
- cls.api_client,
- cls.services["service_offering"]
- )
- cls._cleanup.append(cls.service_offering)
- except Exception as e:
- cls.tearDownClass()
- raise unittest.SkipTest("Unable to add VSP device")
- return
-
- @attr(tags=["advanced"])
- def test_vpcnetwork_nuage(self):
- """Test network VPC for Nuage"""
-
- # 1) Create VPC with Nuage VPC offering
- vpcOffering = VpcOffering.list(self.apiclient,name="Nuage VSP VPC offering")
- self.assert_(vpcOffering is not None and len(vpcOffering)>0, "Nuage VPC offering not found")
- vpc = VPC.create(
- apiclient=self.apiclient,
- services=self.services["vpc"],
- networkDomain="vpc.networkacl",
- vpcofferingid=vpcOffering[0].id,
- zoneid=self.zone.id,
- account=self.account.name,
- domainid=self.account.domainid
- )
- self.assert_(vpc is not None, "VPC creation failed")
-
- # 2) Create ACL
- aclgroup = NetworkACLList.create(apiclient=self.apiclient, services={}, name="acl", description="acl", vpcid=vpc.id)
- self.assertIsNotNone(aclgroup, "Failed to create NetworkACL list")
- self.debug("Created a network ACL list %s" % aclgroup.name)
-
- # 3) Create ACL Item
- aclitem = NetworkACL.create(apiclient=self.apiclient, services={},
- protocol="TCP", number="10", action="Deny", aclid=aclgroup.id, cidrlist=["0.0.0.0/0"])
- self.assertIsNotNone(aclitem, "Network failed to aclItem")
- self.debug("Added a network ACL %s to ACL list %s" % (aclitem.id, aclgroup.name))
-
- # 4) Create network with ACL
- nwNuage = Network.create(
- self.apiclient,
- self.services["vpcnetwork"],
- accountid=self.account.name,
- domainid=self.account.domainid,
- networkofferingid=self.network_offering.id,
- zoneid=self.zone.id,
- vpcid=vpc.id,
- aclid=aclgroup.id,
- gateway='10.1.0.1'
- )
- self.debug("Network %s created in VPC %s" %(nwNuage.id, vpc.id))
-
- # 5) Deploy a vm
- vm = VirtualMachine.create(
- self.apiclient,
- self.services["virtual_machine"],
- accountid=self.account.name,
- domainid=self.account.domainid,
- serviceofferingid=self.service_offering.id,
- networkids=[str(nwNuage.id)]
- )
- self.assert_(vm is not None, "VM failed to deploy")
- self.assert_(vm.state == 'Running', "VM is not running")
- self.debug("VM %s deployed in VPC %s" %(vm.id, vpc.id))
-
- @classmethod
- def tearDownClass(cls):
- try:
- cleanup_resources(cls.api_client, cls._cleanup)
- except Exception as e:
- raise Exception("Warning: Exception during cleanup : %s" % e)
- return
-
- def setUp(self):
- self.apiclient = self.testClient.getApiClient()
- self.dbclient = self.testClient.getDbConnection()
- self.account = Account.create(
- self.apiclient,
- self.services["account"],
- admin=True,
- domainid=self.domain.id
- )
- self.cleanup = [self.account]
- return
-
- def tearDown(self):
- try:
- self.debug("Cleaning up the resources")
- cleanup_resources(self.apiclient, self.cleanup)
- self.debug("Cleanup complete!")
- except Exception as e:
- raise Exception("Warning: Exception during cleanup : %s" % e)
- return
diff --git a/test/integration/component/test_vpn_service.py b/test/integration/component/test_vpn_service.py
new file mode 100644
index 0000000..8d27624
--- /dev/null
+++ b/test/integration/component/test_vpn_service.py
@@ -0,0 +1,212 @@
+# 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.
+
+""" P1 tests for VPN service
+"""
+# Import Local Modules
+from nose.plugins.attrib import attr
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.base import (
+ Account,
+ ServiceOffering,
+ VirtualMachine,
+ PublicIPAddress,
+ Vpn,
+ VpnUser,
+ Configurations,
+ NATRule
+ )
+from marvin.lib.common import (get_domain,
+ get_zone,
+ get_template
+ )
+from marvin.lib.utils import cleanup_resources
+
+
+class Services:
+ """Test VPN Service
+ """
+
+ def __init__(self):
+ self.services = {
+ "account": {
+ "email": "test@test.com",
+ "firstname": "Test",
+ "lastname": "User",
+ "username": "test",
+ # Random characters are appended for unique
+ # username
+ "password": "password",
+ },
+ "service_offering": {
+ "name": "Tiny Instance",
+ "displaytext": "Tiny Instance",
+ "cpunumber": 1,
+ "cpuspeed": 100, # in MHz
+ "memory": 128, # In MBs
+ },
+ "disk_offering": {
+ "displaytext": "Small Disk Offering",
+ "name": "Small Disk Offering",
+ "disksize": 1
+ },
+ "virtual_machine": {
+ "displayname": "TestVM",
+ "username": "root",
+ "password": "password",
+ "ssh_port": 22,
+ "hypervisor": 'KVM',
+ "privateport": 22,
+ "publicport": 22,
+ "protocol": 'TCP',
+ },
+ "vpn_user": {
+ "username": "test",
+ "password": "test",
+ },
+ "natrule": {
+ "privateport": 1701,
+ "publicport": 1701,
+ "protocol": "UDP"
+ },
+ "ostype": 'CentOS 5.5 (64-bit)',
+ "sleep": 60,
+ "timeout": 10,
+ # Networking mode: Advanced, Basic
+ }
+
+
+class TestVPNService(cloudstackTestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls.testClient = super(TestVPNService, cls).getClsTestClient()
+ cls.api_client = cls.testClient.getApiClient()
+
+ cls.services = Services().services
+ # Get Zone, Domain and templates
+ cls.domain = get_domain(cls.api_client)
+ cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+
+ cls.services["mode"] = cls.zone.networktype
+
+ cls.template = get_template(
+ cls.api_client,
+ cls.zone.id,
+ cls.services["ostype"]
+ )
+
+ cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+ cls.service_offering = ServiceOffering.create(
+ cls.api_client,
+ cls.services["service_offering"]
+ )
+
+ cls._cleanup = [cls.service_offering, ]
+ return
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ # Cleanup resources used
+ cleanup_resources(cls.api_client, cls._cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+ return
+
+ def setUp(self):
+ try:
+ self.apiclient = self.testClient.getApiClient()
+ self.dbclient = self.testClient.getDbConnection()
+ self.account = Account.create(
+ self.apiclient,
+ self.services["account"],
+ domainid=self.domain.id
+ )
+ self.cleanup = [
+ self.account,
+ ]
+ self.virtual_machine = VirtualMachine.create(
+ self.apiclient,
+ self.services["virtual_machine"],
+ templateid=self.template.id,
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ serviceofferingid=self.service_offering.id
+ )
+ self.public_ip = PublicIPAddress.create(
+ self.apiclient,
+ accountid=self.virtual_machine.account,
+ zoneid=self.virtual_machine.zoneid,
+ domainid=self.virtual_machine.domainid,
+ services=self.services["virtual_machine"]
+ )
+ return
+ except CloudstackAPIException as e:
+ self.tearDown()
+ raise e
+
+ def tearDown(self):
+ try:
+ # Clean up, terminate the created instance, volumes and snapshots
+ cleanup_resources(self.apiclient, self.cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+ return
+
+ def create_VPN(self, public_ip):
+ """Creates VPN for the network"""
+
+ self.debug("Creating VPN with public IP: %s" % public_ip.ipaddress.id)
+ try:
+ # Assign VPN to Public IP
+ vpn = Vpn.create(self.apiclient,
+ self.public_ip.ipaddress.id,
+ account=self.account.name,
+ domainid=self.account.domainid)
+
+ self.debug("Verifying the remote VPN access")
+ vpns = Vpn.list(self.apiclient,
+ publicipid=public_ip.ipaddress.id,
+ listall=True)
+ self.assertEqual(
+ isinstance(vpns, list),
+ True,
+ "List VPNs shall return a valid response"
+ )
+ return vpn
+ except Exception as e:
+ self.fail("Failed to create remote VPN access: %s" % e)
+
+
+ @attr(tags=["advanced", "advancedns"])
+ def test_01_VPN_service(self):
+ """Tests if VPN service is running"""
+
+ # Validate if IPSEC is running on the public
+ # IP by using ike-scan
+
+ self.create_VPN(self.public_ip)
+
+ cmd = ['ike-scan', self.public_ip, '-s', '4534'] # Random port
+
+ stdout = subprocess.check_output(cmd)
+
+ if "1 returned handshake" not in stdout:
+ self.fail("Unable to connect to VPN service")
+
+ return
diff --git a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup b/test/integration/plugins/nuagevsp/__init__.py
old mode 100755
new mode 100644
similarity index 66%
copy from systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
copy to test/integration/plugins/nuagevsp/__init__.py
index 9d254d3..13a8339
--- a/systemvm/patches/debian/config/etc/cron.daily/cloud-cleanup
+++ b/test/integration/plugins/nuagevsp/__init__.py
@@ -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
@@ -16,12 +14,3 @@
# KIND, either express or implied. See the License for the
# 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"
-
-[ "$output" != "" ] && logger -t cloud $output
-[ -z "$output" ] && logger -t cloud "No files removed"
-
-exit 0
diff --git a/test/integration/plugins/nuagevsp/nuageTestCase.py b/test/integration/plugins/nuagevsp/nuageTestCase.py
new file mode 100644
index 0000000..a71945c
--- /dev/null
+++ b/test/integration/plugins/nuagevsp/nuageTestCase.py
@@ -0,0 +1,837 @@
+# 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.
+
+""" Custom base class for Nuage VSP SDN plugin specific Marvin tests
+"""
+# Import Local Modules
+from marvin.cloudstackTestCase import cloudstackTestCase, unittest
+from marvin.lib.base import (EgressFireWallRule,
+ FireWallRule,
+ Host,
+ Hypervisor,
+ Network,
+ NetworkACL,
+ NetworkACLList,
+ NetworkOffering,
+ NetworkServiceProvider,
+ Nuage,
+ PhysicalNetwork,
+ PublicIPAddress,
+ Router,
+ ServiceOffering,
+ StaticNATRule,
+ VirtualMachine,
+ VPC,
+ VpcOffering)
+from marvin.lib.common import (get_domain,
+ get_template,
+ get_zone)
+from marvin.lib.utils import cleanup_resources
+from marvin.cloudstackAPI import restartVPC
+# Import System Modules
+import importlib
+import logging
+import socket
+import sys
+import time
+
+
+class nuageTestCase(cloudstackTestCase):
+
+ @classmethod
+ def setUpClass(cls, zone=None):
+ cls.debug("setUpClass nuageTestCase")
+
+ # We want to fail quicker, if it's a failure
+ socket.setdefaulttimeout(60)
+
+ test_client = super(nuageTestCase, cls).getClsTestClient()
+ cls.api_client = test_client.getApiClient()
+ cls.db_client = test_client.getDbConnection()
+ cls.test_data = test_client.getParsedTestDataConfig()
+
+ # Get Zone, Domain and templates
+ cls.zone = get_zone(cls.api_client,
+ zone_name=zone.name if zone else None,
+ zone_id=zone.id if zone else None
+ )
+ cls.domain = get_domain(cls.api_client)
+ cls.template = get_template(cls.api_client,
+ cls.zone.id,
+ cls.test_data["ostype"]
+ )
+ cls.test_data["virtual_machine"]["zoneid"] = cls.zone.id
+ cls.test_data["virtual_machine"]["template"] = cls.template.id
+
+ # Create service offering
+ cls.service_offering = ServiceOffering.create(cls.api_client,
+ cls.test_data["service_offering"]
+ )
+ cls._cleanup = [cls.service_offering]
+
+ # Check if the host hypervisor type is simulator
+ cls.isSimulator = Hypervisor.list(cls.api_client, zoneid=cls.zone.id)[0].name == "Simulator"
+
+ # Get configured Nuage VSP device details
+ try:
+ physical_networks = PhysicalNetwork.list(cls.api_client, zoneid=cls.zone.id)
+ for pn in physical_networks:
+ if pn.isolationmethods == "VSP":
+ cls.vsp_physical_network = pn
+ break
+ cls.nuage_vsp_device = Nuage.list(cls.api_client,
+ physicalnetworkid=cls.vsp_physical_network.id
+ )[0]
+ pns = cls.config.zones[0].physical_networks
+ providers = filter(lambda physical_network: "VSP" in physical_network.isolationmethods, pns)[0].providers
+ devices = filter(lambda provider: provider.name == "NuageVsp", providers)[0].devices
+ cls.nuage_vsp_device.username = devices[0].username
+ cls.nuage_vsp_device.password = devices[0].password
+ cls.cms_id = cls.nuage_vsp_device.cmsid
+ except Exception as e:
+ cls.tearDownClass()
+ raise unittest.SkipTest("Warning: Could not get configured Nuage VSP device details - %s" % e)
+
+ # VSD is a programmable policy and analytics engine of Nuage VSP SDN platform
+ # vspk is a Python SDK for Nuage VSP's VSD
+ # libVSD is a library that wraps vspk package
+ try:
+ vspk_module = "vspk." + cls.nuage_vsp_device.apiversion if int(cls.nuage_vsp_device.apiversion[1]) >= 4 \
+ else "vspk.vsdk." + cls.nuage_vsp_device.apiversion
+ cls.vsdk = importlib.import_module(vspk_module)
+ from libVSD import ApiClient, VSDHelpers
+ except Exception as e:
+ cls.tearDownClass()
+ raise unittest.SkipTest("Warning: vspk (and/or) libVSD package import failure - %s" % e)
+
+ # Configure VSD session
+ cls._session = cls.vsdk.NUVSDSession(username=cls.nuage_vsp_device.username,
+ password=cls.nuage_vsp_device.password,
+ enterprise="csp",
+ api_url="https://%s:%d" % (cls.nuage_vsp_device.hostname,
+ cls.nuage_vsp_device.port)
+ )
+ cls._session.start()
+
+ # Configure libVSD session
+ root = logging.getLogger()
+ log_handler = logging.StreamHandler(sys.stdout)
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ log_handler.setFormatter(formatter)
+ root.addHandler(log_handler)
+ vsd_info = cls.nuage_vsp_device.__dict__
+ cls.debug("Nuage VSP device (VSD) details - %s" % vsd_info)
+ vsd_api_client = ApiClient(address=vsd_info["hostname"],
+ user=vsd_info["username"],
+ password=vsd_info["password"],
+ version=vsd_info["apiversion"][1] + "." + vsd_info["apiversion"][3]
+ )
+ vsd_api_client.new_session()
+ cls.vsd = VSDHelpers(vsd_api_client)
+
+ cls.debug("setUpClass nuageTestCase [DONE]")
+
+ def setUp(self):
+ self.cleanup = []
+ return
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ # Cleanup resources used
+ cleanup_resources(cls.api_client, cls._cleanup)
+ except Exception as e:
+ cls.debug("Warning: Exception during cleanup: %s" % e)
+ return
+
+ def tearDown(self):
+ # Cleanup resources used
+ self.debug("Cleaning up the resources")
+ for obj in reversed(self.cleanup):
+ try:
+ if isinstance(obj, VirtualMachine):
+ obj.delete(self.api_client, expunge=True)
+ else:
+ obj.delete(self.api_client)
+ except Exception as e:
+ self.error("Failed to cleanup %s, got %s" % (obj, e))
+ # cleanup_resources(self.api_client, self.cleanup)
+ self.cleanup = []
+ self.debug("Cleanup complete!")
+ return
+
+ # create_VpcOffering - Creates VPC offering
+ def create_VpcOffering(self, vpc_offering, suffix=None):
+ self.debug("Creating VPC offering")
+ if suffix:
+ vpc_offering["name"] = "VPC_OFF-" + str(suffix)
+ vpc_off = VpcOffering.create(self.api_client,
+ vpc_offering
+ )
+ # Enable VPC offering
+ vpc_off.update(self.api_client, state="Enabled")
+ self.cleanup.append(vpc_off)
+ self.debug("Created and Enabled VPC offering")
+ return vpc_off
+
+ # create_Vpc - Creates VPC with the given VPC offering
+ def create_Vpc(self, vpc_offering, cidr='10.1.0.0/16', testdata=None, account=None, networkDomain=None,
+ cleanup=True):
+ if not account:
+ account = self.account
+ self.debug("Creating a VPC in the account - %s" % account.name)
+ if not testdata:
+ testdata = self.test_data["vpc"]
+ testdata["name"] = "TestVPC-" + cidr + "-" + str(vpc_offering.name)
+ testdata["displaytext"] = "Test VPC"
+ testdata["cidr"] = cidr
+ vpc = VPC.create(self.api_client,
+ testdata,
+ vpcofferingid=vpc_offering.id,
+ zoneid=self.zone.id,
+ account=account.name,
+ domainid=account.domainid,
+ networkDomain=networkDomain
+ )
+ self.debug("Created VPC with ID - %s" % vpc.id)
+ if cleanup:
+ self.cleanup.append(vpc)
+ return vpc
+
+ # restart_Vpc - Restarts the given VPC with/without cleanup
+ def restart_Vpc(self, vpc, cleanup=None):
+ self.debug("Restarting VPC with ID - %s" % vpc.id)
+ cmd = restartVPC.restartVPCCmd()
+ cmd.id = vpc.id
+ cmd.cleanup = cleanup
+ cmd.makeredundant = False
+ self.api_client.restartVPC(cmd)
+ self.debug("Restarted VPC with ID - %s" % vpc.id)
+
+ # create_NetworkOffering - Creates Network offering
+ def create_NetworkOffering(self, net_offering, suffix=None, conserve_mode=False):
+ self.debug("Creating Network offering")
+ if suffix:
+ net_offering["name"] = "NET_OFF-" + str(suffix)
+ nw_off = NetworkOffering.create(self.api_client,
+ net_offering,
+ conservemode=conserve_mode
+ )
+ # Enable Network offering
+ nw_off.update(self.api_client, state="Enabled")
+ self.cleanup.append(nw_off)
+ self.debug("Created and Enabled Network offering")
+ return nw_off
+
+ # create_Network - Creates network with the given Network offering
+ def create_Network(self, nw_off, gateway="10.1.1.1", netmask="255.255.255.0", vpc=None, acl_list=None,
+ testdata=None, account=None, cleanup=True):
+ if not account:
+ account = self.account
+ self.debug("Creating a network in the account - %s" % account.name)
+ if not testdata:
+ testdata = self.test_data["network"]
+ testdata["name"] = "TestNetwork-" + gateway + "-" + str(nw_off.name)
+ testdata["displaytext"] = "Test Network"
+ testdata["netmask"] = netmask
+ network = Network.create(self.api_client,
+ testdata,
+ accountid=account.name,
+ domainid=account.domainid,
+ networkofferingid=nw_off.id,
+ zoneid=self.zone.id,
+ gateway=gateway,
+ vpcid=vpc.id if vpc else self.vpc.id if hasattr(self, "vpc") else None,
+ aclid=acl_list.id if acl_list else None
+ )
+ self.debug("Created network with ID - %s" % network.id)
+ if cleanup:
+ self.cleanup.append(network)
+ return network
+
+ # upgrade_Network - Upgrades the given network
+ def upgrade_Network(self, nw_off, network):
+ if not hasattr(nw_off, "id"):
+ nw_off = self.create_NetworkOffering(nw_off, network.gateway)
+ self.debug("Updating Network with ID - %s" % network.id)
+ network.update(self.api_client,
+ networkofferingid=nw_off.id,
+ changecidr=False
+ )
+ self.debug("Updated network with ID - %s" % network.id)
+
+ # delete_Network - Deletes the given network
+ def delete_Network(self, network):
+ self.debug("Deleting Network with ID - %s" % network.id)
+ network.delete(self.api_client)
+ if network in self.cleanup:
+ self.cleanup.remove(network)
+ self.debug("Deleted Network with ID - %s" % network.id)
+
+ # create_VM - Creates VM in the given network(s)
+ def create_VM(self, network_list, host_id=None, start_vm=True, testdata=None, account=None, cleanup=True):
+ network_ids = []
+ if isinstance(network_list, list):
+ for network in network_list:
+ network_ids.append(str(network.id))
+ else:
+ network_ids.append(str(network_list.id))
+ if not account:
+ account = self.account
+ self.debug("Creating VM in network(s) with ID(s) - %s in the account - %s" % (network_ids, account.name))
+ if not testdata:
+ testdata = self.test_data["virtual_machine"]
+ vm = VirtualMachine.create(self.api_client,
+ testdata,
+ accountid=account.name,
+ domainid=account.domainid,
+ serviceofferingid=self.service_offering.id,
+ templateid=self.template.id,
+ zoneid=self.zone.id,
+ networkids=network_ids,
+ startvm=start_vm,
+ hostid=host_id
+ )
+ self.debug("Created VM with ID - %s in network(s) with ID(s) - %s" % (vm.id, network_ids))
+ if cleanup:
+ self.cleanup.append(vm)
+ return vm
+
+ # nic_operation_VM - Performs NIC operations such as add, remove, and update default NIC in the given VM and network
+ def nic_operation_VM(self, vm, network, operation="update"):
+ self.debug("Performing %s NIC operation in VM with ID - %s and network with ID - %s" %
+ (operation, vm.id, network.id))
+ for nic in vm.nic:
+ if nic.networkid == network.id:
+ nic_id = nic.id
+ if operation is "update":
+ vm.update_default_nic(self.api_client, nic_id)
+ self.debug("Updated default NIC to NIC with ID - %s in VM with ID - %s and network with ID - %s" %
+ (nic_id, vm.id, network.id))
+ if operation is "remove":
+ vm.remove_nic(self.api_client, nic_id)
+ self.debug("Removed NIC with ID - %s in VM with ID - %s and network with ID - %s" %
+ (nic_id, vm.id, network.id))
+ if operation is "add":
+ vm.add_nic(self.api_client, network.id)
+ self.debug("Added NIC with ID - %s in VM with ID - %s and network with ID - %s" %
+ (nic_id, vm.id, network.id))
+
+ # migrate_VM - Migrates VM to another host, if available
+ def migrate_VM(self, vm):
+ self.debug("Checking if a host is available for migration...")
+ hosts = Host.listForMigration(self.api_client, virtualmachineid=vm.id)
+ self.assertEqual(isinstance(hosts, list), True,
+ "List hosts should return a valid list"
+ )
+ # Remove the host of current VM from the hosts list
+ hosts[:] = [host for host in hosts if host.id != vm.hostid]
+ if len(hosts) <= 0:
+ self.skipTest("No host available for migration. Test requires at-least 2 hosts")
+ host = hosts[0]
+ self.debug("Migrating VM with ID: %s to Host: %s" % (vm.id, host.id))
+ try:
+ vm.migrate(self.api_client, hostid=host.id)
+ except Exception as e:
+ self.fail("Failed to migrate instance, %s" % e)
+ self.debug("Migrated VM with ID: %s to Host: %s" % (vm.id, host.id))
+
+ # delete_VM - Deletes the given VM
+ def delete_VM(self, vm, expunge=True):
+ self.debug("Deleting VM with ID - %s" % vm.id)
+ vm.delete(self.api_client, expunge=expunge)
+ if vm in self.cleanup:
+ self.cleanup.remove(vm)
+ self.debug("Deleted VM with ID - %s" % vm.id)
+
+ # get_Router - Returns router for the given network
+ def get_Router(self, network):
+ self.debug("Finding the virtual router for network with ID - %s" % network.id)
+ routers = Router.list(self.api_client,
+ networkid=network.id,
+ listall=True
+ )
+ self.assertEqual(isinstance(routers, list), True,
+ "List routers should return a valid virtual router for network"
+ )
+ return routers[0]
+
+ # acquire_PublicIPAddress - Acquires public IP address for the given network/VPC
+ def acquire_PublicIPAddress(self, network, vpc=None, account=None):
+ if not account:
+ account = self.account
+ self.debug("Associating public IP for network with ID - %s in the account - %s" % (network.id, account.name))
+ public_ip = PublicIPAddress.create(self.api_client,
+ accountid=account.name,
+ domainid=account.domainid,
+ zoneid=self.zone.id,
+ networkid=network.id if vpc is None else None,
+ vpcid=vpc.id if vpc else self.vpc.id if hasattr(self, "vpc") else None
+ )
+ self.debug("Associated public IP address - %s with network with ID - %s" %
+ (public_ip.ipaddress.ipaddress, network.id))
+ return public_ip
+
+ # create_StaticNatRule_For_VM - Creates Static NAT rule on the given public IP for the given VM in the given network
+ def create_StaticNatRule_For_VM(self, vm, public_ip, network, vmguestip=None):
+ self.debug("Enabling Static NAT rule on public IP - %s for VM with ID - %s in network with ID - %s" %
+ (public_ip.ipaddress.ipaddress, vm.id, network.id))
+ static_nat_rule = StaticNATRule.enable(self.api_client,
+ ipaddressid=public_ip.ipaddress.id,
+ virtualmachineid=vm.id,
+ networkid=network.id,
+ vmguestip=vmguestip
+ )
+ self.debug("Static NAT rule enabled on public IP - %s for VM with ID - %s in network with ID - %s" %
+ (public_ip.ipaddress.ipaddress, vm.id, network.id))
+ return static_nat_rule
+
+ # delete_StaticNatRule_For_VM - Deletes Static NAT rule on the given public IP
+ def delete_StaticNatRule_For_VM(self, public_ip):
+ self.debug("Disabling Static NAT rule on public IP - %s" % public_ip.ipaddress.ipaddress)
+ StaticNATRule.disable(self.api_client,
+ ipaddressid=public_ip.ipaddress.id
+ )
+ self.debug("Static NAT rule disabled on public IP - %s" % public_ip.ipaddress.ipaddress)
+
+ # create_FirewallRule - Creates (Ingress) Firewall rule on the given Static NAT rule enabled public IP for Isolated
+ # networks
+ def create_FirewallRule(self, public_ip, rule=None):
+ if not rule:
+ rule = self.test_data["ingress_rule"]
+ self.debug("Adding an (Ingress) Firewall rule to make Guest VMs accessible through Static NAT rule - %s" % rule)
+ return FireWallRule.create(self.api_client,
+ ipaddressid=public_ip.ipaddress.id,
+ protocol=rule["protocol"],
+ cidrlist=rule["cidrlist"],
+ startport=rule["startport"],
+ endport=rule["endport"]
+ )
+
+ # create_EgressFirewallRule - Creates Egress Firewall rule in the given Isolated network
+ def create_EgressFirewallRule(self, network, rule):
+ self.debug("Adding an Egress Firewall rule to allow/deny outgoing traffic from Guest VMs - %s" % rule)
+ return EgressFireWallRule.create(self.api_client,
+ networkid=network.id,
+ protocol=rule["protocol"],
+ cidrlist=rule["cidrlist"],
+ startport=rule["startport"],
+ endport=rule["endport"]
+ )
+
+ # create_NetworkAclList - Creates network ACL list in the given VPC
+ def create_NetworkAclList(self, name, description, vpc):
+ self.debug("Adding NetworkACL list in VPC with ID - %s" % vpc.id)
+ return NetworkACLList.create(self.api_client,
+ services={},
+ name=name,
+ description=description,
+ vpcid=vpc.id
+ )
+
+ # create_NetworkAclRule - Creates Ingress/Egress Network ACL rule in the given VPC network/acl list
+ def create_NetworkAclRule(self, rule, traffic_type="Ingress", network=None, acl_list=None):
+ self.debug("Adding NetworkACL rule - %s" % rule)
+ if acl_list:
+ return NetworkACL.create(self.api_client,
+ networkid=network.id if network else None,
+ services=rule,
+ traffictype=traffic_type,
+ aclid=acl_list.id
+ )
+ else:
+ return NetworkACL.create(self.api_client,
+ networkid=network.id if network else None,
+ services=rule,
+ traffictype=traffic_type
+ )
+
+ # ssh_into_VM - Gets into the shell of the given VM using its public IP
+ def ssh_into_VM(self, vm, public_ip, reconnect=True):
+ self.debug("SSH into VM with ID - %s on public IP address - %s" % (vm.id, public_ip.ipaddress.ipaddress))
+ tries = 0
+ while tries < 3:
+ try:
+ ssh_client = vm.get_ssh_client(ipaddress=public_ip.ipaddress.ipaddress, reconnect=reconnect)
+ except Exception as e:
+ self.debug("Failed to SSH into VM: %s" % e)
+ self.debug("Waiting for the VM to be fully resolved for SSH connection...")
+ time.sleep(120)
+ self.debug("Retrying SSH into VM...")
+ tries += 1
+ continue
+ self.debug("Successful to SSH into VM with ID - %s on public IP address - %s" %
+ (vm.id, public_ip.ipaddress.ipaddress))
+ return ssh_client
+
+ # execute_cmd - Executes the given command on the given ssh client
+ def execute_cmd(self, ssh_client, cmd):
+ self.debug("SSH client executing command - %s" % cmd)
+ ret_data = ""
+ out_list = ssh_client.execute(cmd)
+ if out_list is not None:
+ ret_data = ' '.join(map(str, out_list)).strip()
+ self.debug("SSH client executed command result - %s" % ret_data)
+ else:
+ self.debug("SSH client executed command result is None")
+ return ret_data
+
+ # wget_from_server - Fetches index.html file from a web server listening on the given public IP address and port
+ def wget_from_server(self, public_ip, port):
+ import urllib
+ self.debug("wget index.html file from a http web server listening on public IP address - %s and port - %s" %
+ (public_ip.ipaddress.ipaddress, port))
+ filename, headers = urllib.urlretrieve("http://%s:%s/index.html" % (public_ip.ipaddress.ipaddress, port),
+ filename="index.html"
+ )
+ return filename, headers
+
+ # validate_NetworkServiceProvider - Validates the given Network Service Provider in the Nuage VSP Physical Network,
+ # matches the given provider name and state against the list of providers fetched
+ def validate_NetworkServiceProvider(self, provider_name, state=None):
+ """Validates the Network Service Provider in the Nuage VSP Physical Network"""
+ self.debug("Validating the creation and state of Network Service Provider - %s" % provider_name)
+ providers = NetworkServiceProvider.list(self.api_client,
+ name=provider_name,
+ physicalnetworkid=self.vsp_physical_network.id)
+ self.assertEqual(isinstance(providers, list), True,
+ "List Network Service Provider should return a valid list"
+ )
+ self.assertEqual(provider_name, providers[0].name,
+ "Name of the Network Service Provider should match with the returned list data"
+ )
+ if state:
+ self.assertEqual(providers[0].state, state,
+ "Network Service Provider state should be '%s'" % state
+ )
+ self.debug("Successfully validated the creation and state of Network Service Provider - %s" % provider_name)
+
+ # validate_VpcOffering - Validates the given VPC offering, matches the given VPC offering name and state against the
+ # list of VPC offerings fetched
+ def validate_VpcOffering(self, vpc_offering, state=None):
+ """Validates the VPC offering"""
+ self.debug("Validating the creation and state of VPC offering - %s" % vpc_offering.name)
+ vpc_offs = VpcOffering.list(self.api_client,
+ id=vpc_offering.id
+ )
+ self.assertEqual(isinstance(vpc_offs, list), True,
+ "List VPC offering should return a valid list"
+ )
+ self.assertEqual(vpc_offering.name, vpc_offs[0].name,
+ "Name of the VPC offering should match with the returned list data"
+ )
+ if state:
+ self.assertEqual(vpc_offs[0].state, state,
+ "VPC offering state should be '%s'" % state
+ )
+ self.debug("Successfully validated the creation and state of VPC offering - %s" % vpc_offering.name)
+
+ # validate_Vpc - Validates the given VPC, matches the given VPC name and state against the list of VPCs fetched
+ def validate_Vpc(self, vpc, state=None):
+ """Validates the VPC"""
+ self.debug("Validating the creation and state of VPC - %s" % vpc.name)
+ vpcs = VPC.list(self.api_client,
+ id=vpc.id
+ )
+ self.assertEqual(isinstance(vpcs, list), True,
+ "List VPC should return a valid list"
+ )
+ self.assertEqual(vpc.name, vpcs[0].name,
+ "Name of the VPC should match with the returned list data"
+ )
+ if state:
+ self.assertEqual(vpcs[0].state, state,
+ "VPC state should be '%s'" % state
+ )
+ self.debug("Successfully validated the creation and state of VPC - %s" % vpc.name)
+
+ # validate_NetworkOffering - Validates the given Network offering, matches the given network offering name and state
+ # against the list of network offerings fetched
+ def validate_NetworkOffering(self, net_offering, state=None):
+ """Validates the Network offering"""
+ self.debug("Validating the creation and state of Network offering - %s" % net_offering.name)
+ net_offs = NetworkOffering.list(self.api_client,
+ id=net_offering.id
+ )
+ self.assertEqual(isinstance(net_offs, list), True,
+ "List Network offering should return a valid list"
+ )
+ self.assertEqual(net_offering.name, net_offs[0].name,
+ "Name of the Network offering should match with the returned list data"
+ )
+ if state:
+ self.assertEqual(net_offs[0].state, state,
+ "Network offering state should be '%s'" % state
+ )
+ self.debug("Successfully validated the creation and state of Network offering - %s" % net_offering.name)
+
+ # validate_Network - Validates the given network, matches the given network name and state against the list of
+ # networks fetched
+ def validate_Network(self, network, state=None):
+ """Validates the network"""
+ self.debug("Validating the creation and state of Network - %s" % network.name)
+ networks = Network.list(self.api_client,
+ id=network.id
+ )
+ self.assertEqual(isinstance(networks, list), True,
+ "List network should return a valid list"
+ )
+ self.assertEqual(network.name, networks[0].name,
+ "Name of the network should match with with the returned list data"
+ )
+ if state:
+ self.assertEqual(networks[0].state, state,
+ "Network state should be '%s'" % state
+ )
+ self.debug("Successfully validated the creation and state of Network - %s" % network.name)
+
+ # check_VM_state - Checks if the given VM is in the expected state form the list of fetched VMs
+ def check_VM_state(self, vm, state=None):
+ """Validates the VM state"""
+ self.debug("Validating the deployment and state of VM - %s" % vm.name)
+ vms = VirtualMachine.list(self.api_client,
+ id=vm.id,
+ listall=True
+ )
+ self.assertEqual(isinstance(vms, list), True,
+ "List virtual machine should return a valid list"
+ )
+ if state:
+ self.assertEqual(vms[0].state, state,
+ "Virtual machine is not in the expected state"
+ )
+ self.debug("Successfully validated the deployment and state of VM - %s" % vm.name)
+
+ # check_Router_state - Checks if the given router is in the expected state form the list of fetched routers
+ def check_Router_state(self, router, state=None):
+ """Validates the Router state"""
+ self.debug("Validating the deployment and state of Router - %s" % router.name)
+ routers = Router.list(self.api_client,
+ id=router.id,
+ listall=True
+ )
+ self.assertEqual(isinstance(routers, list), True,
+ "List router should return a valid list"
+ )
+ if state:
+ self.assertEqual(routers[0].state, state,
+ "Virtual router is not in the expected state"
+ )
+ self.debug("Successfully validated the deployment and state of Router - %s" % router.name)
+
+ # validate_PublicIPAddress - Validates if the given public IP address is in the expected state form the list of
+ # fetched public IP addresses
+ def validate_PublicIPAddress(self, public_ip, network, static_nat=False, vm=None):
+ """Validates the Public IP Address"""
+ self.debug("Validating the assignment and state of public IP address - %s" % public_ip.ipaddress.ipaddress)
+ public_ips = PublicIPAddress.list(self.api_client,
+ id=public_ip.ipaddress.id,
+ networkid=network.id,
+ isstaticnat=static_nat,
+ listall=True
+ )
+ self.assertEqual(isinstance(public_ips, list), True,
+ "List public IP for network should return a valid list"
+ )
+ self.assertEqual(public_ips[0].ipaddress, public_ip.ipaddress.ipaddress,
+ "List public IP for network should list the assigned public IP address"
+ )
+ self.assertEqual(public_ips[0].state, "Allocated",
+ "Assigned public IP is not in the allocated state"
+ )
+ if static_nat and vm:
+ self.assertEqual(public_ips[0].virtualmachineid, vm.id,
+ "Static NAT rule is not enabled for the VM on the assigned public IP"
+ )
+ self.debug("Successfully validated the assignment and state of public IP address - %s" %
+ public_ip.ipaddress.ipaddress)
+
+ # VSD verifications
+ # VSD is a programmable policy and analytics engine of Nuage VSP SDN platform
+
+ # get_externalID_filter - Returns corresponding external ID filter of the given object in VSD
+ def get_externalID_filter(self, object_id):
+ ext_id = object_id + "@" + self.cms_id
+ return self.vsd.set_externalID_filter(ext_id)
+
+ # fetch_by_externalID - Returns VSD object with the given external ID
+ def fetch_by_externalID(self, fetcher, *cs_objects):
+ """ Fetches a child object by external id using the given fetcher, and uuids of the given cloudstack objects.
+ E.G.
+ - fetch_by_external_id(vsdk.NUSubnet(id="954de425-b860-410b-be09-c560e7dbb474").vms, cs_vm)
+ - fetch_by_external_id(session.user.floating_ips, cs_network, cs_public_ip)
+ :param fetcher: VSPK Fetcher to use to find the child entity
+ :param cs_objects: Cloudstack objects to take the UUID from.
+ :return: the VSPK object having the correct externalID
+ """
+ return fetcher.get_first(filter="externalID BEGINSWITH '%s'" % ":".join([o.id for o in cs_objects]))
+
+ # verify_vsd_network - Verifies the given domain and network/VPC against the corresponding installed enterprise,
+ # domain, zone, and subnet in VSD
+ def verify_vsd_network(self, domain_id, network, vpc=None):
+ self.debug("Verifying the creation and state of Network - %s in VSD" % network.name)
+ vsd_enterprise = self.vsd.get_enterprise(filter=self.get_externalID_filter(domain_id))
+ ext_network_filter = self.get_externalID_filter(vpc.id) if vpc else self.get_externalID_filter(network.id)
+ vsd_domain = self.vsd.get_domain(filter=ext_network_filter)
+ vsd_zone = self.vsd.get_zone(filter=ext_network_filter)
+ vsd_subnet = self.vsd.get_subnet(filter=self.get_externalID_filter(network.id))
+ self.assertEqual(vsd_enterprise.name, domain_id,
+ "VSD enterprise name should match CloudStack domain uuid"
+ )
+ if vpc:
+ self.assertEqual(vsd_domain.description, "VPC_" + vpc.name,
+ "VSD domain description should match VPC name in CloudStack"
+ )
+ self.assertEqual(vsd_zone.description, "VPC_" + vpc.name,
+ "VSD zone description should match VPC name in CloudStack"
+ )
+ else:
+ self.assertEqual(vsd_domain.description, network.name,
+ "VSD domain description should match network name in CloudStack"
+ )
+ self.assertEqual(vsd_zone.description, network.name,
+ "VSD zone description should match network name in CloudStack"
+ )
+ self.assertEqual(vsd_subnet.description, network.name,
+ "VSD subnet description should match network name in CloudStack"
+ )
+ self.debug("Successfully verified the creation and state of Network - %s in VSD" % network.name)
+
+ # verify_vsd_vm - Verifies the given VM deployment and state in VSD
+ def verify_vsd_vm(self, vm, stopped=None):
+ self.debug("Verifying the deployment and state of VM - %s in VSD" % vm.name)
+ vsd_vm = self.vsd.get_vm(filter=self.get_externalID_filter(vm.id))
+ self.assertNotEqual(vsd_vm, None,
+ "VM data format in VSD should not be of type None"
+ )
+ for nic in vm.nic:
+ vsd_subnet = self.vsd.get_subnet(filter=self.get_externalID_filter(nic.networkid))
+ vsd_vport = self.vsd.get_vport(subnet=vsd_subnet, filter=self.get_externalID_filter(nic.id))
+ vsd_vm_interface = self.vsd.get_vm_interface(filter=self.get_externalID_filter(nic.id))
+ self.assertEqual(vsd_vport.active, True,
+ "VSD VM vport should be active"
+ )
+ self.assertEqual(vsd_vm_interface.ip_address, nic.ipaddress,
+ "VSD VM interface IP address should match VM's NIC IP address in CloudStack"
+ )
+ if not self.isSimulator:
+ if stopped:
+ self.assertEqual(vsd_vm.status, "DELETE_PENDING",
+ "VM state in VSD should be DELETE_PENDING"
+ )
+ else:
+ self.assertEqual(vsd_vm.status, vm.state.upper(),
+ "VM state in VSD should match its state in CloudStack"
+ )
+ self.debug("Successfully verified the deployment and state of VM - %s in VSD" % vm.name)
+
+ # verify_vsd_router - Verifies the given network router deployment and state in VSD
+ def verify_vsd_router(self, router, stopped=None):
+ self.debug("Verifying the deployment and state of Router - %s in VSD" % router.name)
+ vsd_router = self.vsd.get_vm(filter=self.get_externalID_filter(router.id))
+ self.assertNotEqual(vsd_router, None,
+ "Router data format in VSD should not be of type None"
+ )
+ if not self.isSimulator:
+ if stopped:
+ self.assertEqual(vsd_router.status, "DELETE_PENDING",
+ "Router state in VSD should be DELETE_PENDING"
+ )
+ else:
+ self.assertEqual(vsd_router.status, router.state.upper(),
+ "Router state in VSD should match its state in CloudStack"
+ )
+ self.debug("Successfully verified the deployment and state of Router - %s in VSD" % router.name)
+
+ # verify_vsd_lb_device - Verifies the given LB device deployment and state in VSD
+ def verify_vsd_lb_device(self, lb_device, stopped=None):
+ self.debug("Verifying the deployment and state of LB device - %s in VSD" % lb_device.name)
+ vsd_lb_device = self.vsd.get_vm(filter=self.get_externalID_filter(lb_device.id))
+ self.assertNotEqual(vsd_lb_device, None,
+ "LB device data format in VSD should not be of type None"
+ )
+ if not self.isSimulator:
+ if stopped:
+ self.assertEqual(vsd_lb_device.status, "DELETE_PENDING",
+ "LB device state in VSD should be DELETE_PENDING"
+ )
+ else:
+ self.assertEqual(vsd_lb_device.status, lb_device.state.upper(),
+ "LB device state in VSD should match its state in CloudStack"
+ )
+ self.debug("Successfully verified the deployment and state of LB device - %s in VSD" % lb_device.name)
+
+ # verify_vsd_floating_ip - Verifies the Static NAT rule on the given public IP of the given VM in the given network
+ # against the corresponding installed Floating IP in VSD
+ def verify_vsd_floating_ip(self, network, vm, public_ipaddress, vpc=None):
+ self.debug("Verifying the assignment and state of public IP address - %s in VSD" % public_ipaddress.ipaddress)
+ ext_fip_filter = self.get_externalID_filter(vpc.id + ":" + public_ipaddress.id) if vpc else \
+ self.get_externalID_filter(network.id + ":" + public_ipaddress.id)
+ vsd_fip = self.vsd.get_floating_ip(filter=ext_fip_filter)
+ self.assertEqual(vsd_fip.address, public_ipaddress.ipaddress,
+ "Floating IP address in VSD should match acquired public IP address in CloudStack"
+ )
+ self.assertEqual(vsd_fip.assigned, True,
+ "Floating IP in VSD should be assigned"
+ )
+ ext_network_filter = self.get_externalID_filter(vpc.id) if vpc else self.get_externalID_filter(network.id)
+ vsd_domain = self.vsd.get_domain(filter=ext_network_filter)
+ self.assertEqual(vsd_domain.id, vsd_fip.parent_id,
+ "Floating IP in VSD should be associated with the correct VSD domain, which in turn should "
+ "correspond to the correct VPC (or) network in CloudStack"
+ )
+ vsd_subnet = self.vsd.get_subnet(filter=self.get_externalID_filter(network.id))
+ for nic in vm.nic:
+ if nic.networkid == network.id:
+ vsd_vport = self.vsd.get_vport(subnet=vsd_subnet, filter=self.get_externalID_filter(nic.id))
+ self.assertEqual(vsd_vport.associated_floating_ip_id, vsd_fip.id,
+ "Floating IP in VSD should be associated to the correct VSD vport, which in turn should "
+ "correspond to the correct Static NAT rule enabled VM and network in CloudStack"
+ )
+ self.debug("Successfully verified the assignment and state of public IP address - %s in VSD" %
+ public_ipaddress.ipaddress)
+
+ # verify_vsd_firewall_rule - Verifies the given Network Firewall (Ingress/Egress ACL) rule against the corresponding
+ # installed firewall rule in VSD
+ def verify_vsd_firewall_rule(self, firewall_rule, traffic_type="Ingress"):
+ self.debug("Verifying the creation and state of Network Firewall (Ingress/Egress ACL) rule with ID - %s in VSD"
+ % firewall_rule.id)
+ ext_fw_rule_filter = self.get_externalID_filter(firewall_rule.id)
+ vsd_fw_rule = self.vsd.get_egress_acl_entry(filter=ext_fw_rule_filter) if traffic_type is "Ingress" else \
+ self.vsd.get_ingress_acl_entry(filter=ext_fw_rule_filter)
+ self.assertEqual(vsd_fw_rule.policy_state, "LIVE",
+ "Ingress/Egress ACL rule's policy state in VSD should be LIVE"
+ )
+ dest_port = str(firewall_rule.startport) + "-" + str(firewall_rule.endport)
+ self.assertEqual(vsd_fw_rule.destination_port, dest_port,
+ "Ingress/Egress ACL rule's destination port in VSD should match corresponding rule's "
+ "destination port in CloudStack"
+ )
+ vsd_protocol = int(vsd_fw_rule.protocol)
+ protocol = "tcp"
+ if vsd_protocol == 6:
+ protocol = "tcp"
+ elif vsd_protocol == 1:
+ protocol = "icmp"
+ elif vsd_protocol == 17:
+ protocol = "udp"
+ self.assertEqual(protocol, firewall_rule.protocol.lower(),
+ "Ingress/Egress ACL rule's protocol in VSD should match corresponding rule's protocol in "
+ "CloudStack"
+ )
+ self.debug("Successfully verified the creation and state of Network Firewall (Ingress/Egress ACL) rule with ID "
+ "- %s in VSD" % firewall_rule.id)
diff --git a/test/integration/plugins/nuagevsp/test_nuage_password_reset.py b/test/integration/plugins/nuagevsp/test_nuage_password_reset.py
new file mode 100644
index 0000000..bd8bba6
--- /dev/null
+++ b/test/integration/plugins/nuagevsp/test_nuage_password_reset.py
@@ -0,0 +1,285 @@
+# 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.
+
+""" Component tests for user data and password reset functionality with Nuage VSP SDN plugin
+"""
+# Import Local Modules
+from nuageTestCase import nuageTestCase
+from marvin.lib.base import (Account,
+ Template,
+ VirtualMachine,
+ Volume)
+from marvin.lib.common import list_templates
+from marvin.cloudstackAPI import updateTemplate
+# Import System Modules
+from nose.plugins.attrib import attr
+import base64
+
+
+class TestNuagePasswordReset(nuageTestCase):
+ """Test user data and password reset functionality with Nuage VSP SDN plugin
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestNuagePasswordReset, cls).setUpClass()
+ return
+
+ def setUp(self):
+ # Create an account
+ self.account = Account.create(self.api_client,
+ self.test_data["account"],
+ admin=True,
+ domainid=self.domain.id
+ )
+ self.cleanup = [self.account]
+ return
+
+ # create_template - Creates guest VM template with the given VM object
+ def create_template(self, vm):
+ self.debug("Creating guest VM template")
+ list_volume = Volume.list(self.api_client,
+ virtualmachineid=vm.id,
+ type='ROOT',
+ listall=True
+ )
+ if isinstance(list_volume, list):
+ self.volume = list_volume[0]
+ else:
+ raise Exception("Exception: Unable to find root volume for VM with ID - %s" % vm.id)
+ self.pw_enabled_template = Template.create(self.api_client,
+ self.test_data["template"],
+ self.volume.id,
+ account=self.account.name,
+ domainid=self.account.domainid
+ )
+ self.assertEqual(self.pw_enabled_template.passwordenabled, True,
+ "template is not passwordenabled"
+ )
+ self.cleanup.append(self.pw_enabled_template)
+ self.debug("Created guest VM template")
+
+ # updateTemplate - Updates value of the guest VM template's password enabled setting
+ def updateTemplate(self, value):
+ self.debug("Updating value of guest VM template's password enabled setting")
+ cmd = updateTemplate.updateTemplateCmd()
+ cmd.id = self.template.id
+ cmd.passwordenabled = value
+ self.api_client.updateTemplate(cmd)
+ list_template_response = list_templates(self.api_client,
+ templatefilter="all",
+ id=self.template.id
+ )
+ self.template = list_template_response[0]
+ self.debug("Updated guest VM template")
+
+ # get_userdata_url - Returns user data URL for the given VM object
+ def get_userdata_url(self, vm):
+ self.debug("Getting user data url")
+ nic = vm.nic[0]
+ gateway = str(nic.gateway)
+ self.debug("Gateway: " + gateway)
+ user_data_url = 'curl "http://' + gateway + ':80/latest/user-data"'
+ return user_data_url
+
+ # create_and_verify_fw - Creates and verifies (Ingress) firewall rule with a Static NAT rule enabled public IP
+ def create_and_verify_fw(self, vm, public_ip, network):
+ self.debug("Creating and verifying firewall rule")
+ self.create_StaticNatRule_For_VM(vm, public_ip, network)
+
+ # VSD verification
+ self.verify_vsd_floating_ip(network, vm, public_ip.ipaddress)
+
+ fw_rule = self.create_FirewallRule(public_ip, self.test_data["ingress_rule"])
+
+ # VSD verification
+ self.verify_vsd_firewall_rule(fw_rule)
+ self.debug("Successfully created and verified firewall rule")
+
+ # stop_vm - Stops the given VM, and verifies its state
+ def stop_vm(self, vm):
+ self.debug("Stoping VM")
+ vm.stop(self.api_client)
+ list_vm_response = VirtualMachine.list(self.api_client,
+ id=vm.id
+ )
+ if isinstance(list_vm_response, list):
+ vm = list_vm_response[0]
+ if vm.state != 'Stopped':
+ raise Exception("Failed to stop VM (ID: %s) " % self.vm.id)
+ else:
+ raise Exception("Invalid response from list_virtual_machines VM (ID: %s) " % self.vm.id)
+ self.debug("Stopped VM")
+
+ # install_cloud_set_guest_password_script - Installs the cloud-set-guest-password script from people.apache.org in
+ # the given VM (SSH client)
+ def install_cloud_set_guest_password_script(self, ssh_client):
+ self.debug("Installing cloud-set-guest-password script")
+ cmd = "cd /etc/init.d;wget http://people.apache.org/~tsp/cloud-set-guest-password"
+ result = self.execute_cmd(ssh_client, cmd)
+ self.debug("wget file cloud-set-guest-password: " + result)
+ if "200 OK" not in result:
+ self.fail("failed to wget file cloud-set-guest-password")
+ cmds = ["chmod +x /etc/init.d/cloud-set-guest-password",
+ "chkconfig --add cloud-set-guest-password"
+ ]
+ for c in cmds:
+ result = self.execute_cmd(ssh_client, c)
+ self.debug("get_set_password_file cmd " + c)
+ self.debug("get_set_password_file result " + result)
+ self.debug("Installed cloud-set-guest-password script")
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="true")
+ def test_nuage_UserDataPasswordReset(self):
+ """Test user data and password reset functionality with Nuage VSP SDN plugin
+ """
+
+ # 1. Create an Isolated Network with Nuage VSP Isolated Network offering, check if it is successfully created
+ # and is in the "Allocated" state.
+ # 2. Set password enabled to false in the guest VM template.
+ # 3. Deploy a VM in the created Isolated network with user data, check if the Isolated network state is changed
+ # to "Implemented", and both the VM & VR are successfully deployed and are in the "Running" state.
+ # 4. Verify that the guest VM template is not password enabled by checking the deployed VM's password
+ # (password == "password").
+ # 5. SSH into the deployed VM and verify its user data (expected user data == actual user data).
+ # 6. Check for cloud-set-guest-password script in the deployed VM for testing password reset functionality.
+ # 7. if cloud-set-guest-password script does not exist in the deployed VM:
+ # 7.1 Install the cloud-set-guest-password script from people.apache.org in the deployed VM.
+ # 7.2 Stop the deployed VM, and create a new password enabled guest VM template with it.
+ # 7.3 Deploy a new VM in the created Isolated network with the newly created guest VM template,
+ # check if the VM is successfully deployed and is in the "Running" state.
+ # 7.4 Verify that the new guest VM template is password enabled by checking the newly deployed VM's
+ # password (password != "password").
+ # 7.5 SSH into the newly deployed VM for verifying its password.
+ # 8. else cloud-set-guest-password script exists in the deployed VM:
+ # 8.1 Change password enabled to true in the guest VM template.
+ # 8.2 Verify that the guest VM template is password enabled.
+ # 9. Reset VM password, and start the VM.
+ # 10. Verify that the new guest VM template is password enabled by checking the VM's password
+ # (password != "password").
+ # 11. SSH into the VM for verifying its new password after its password reset.
+ # 12. Set password enabled to the default value in the guest VM template.
+ # 13. Delete all the created objects (cleanup).
+
+ self.debug("Testing user data & password reset functionality in an Isolated network...")
+
+ self.debug("Creating an Isolated network...")
+ net_off = self.create_NetworkOffering(self.test_data["nuagevsp"]["isolated_network_offering"])
+ self.network = self.create_Network(net_off)
+ self.validate_Network(self.network, state="Allocated")
+
+ self.debug("Setting password enabled to false in the guest VM template...")
+ self.defaultTemplateVal = self.template.passwordenabled
+ if self.template.passwordenabled:
+ self.updateTemplate(False)
+
+ self.debug("Deploying a VM in the created Isolated network with user data...")
+ expected_user_data = "hello world vm1"
+ user_data = base64.b64encode(expected_user_data)
+ self.test_data["virtual_machine_userdata"]["userdata"] = user_data
+ self.vm_1 = self.create_VM(self.network, testdata=self.test_data["virtual_machine_userdata"])
+ self.validate_Network(self.network, state="Implemented")
+ vr = self.get_Router(self.network)
+ self.check_Router_state(vr, state="Running")
+ self.check_VM_state(self.vm_1, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, self.network)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(self.vm_1)
+
+ self.debug("verifying that the guest VM template is not password enabled...")
+ self.debug("VM - %s password - %s !" % (self.vm_1.name, self.vm_1.password))
+ self.assertEqual(self.vm_1.password, self.test_data["virtual_machine_userdata"]["password"],
+ "Password is enabled for the VM (vm_1)"
+ )
+
+ self.debug("SSHing into the VM for verifying its user data...")
+ public_ip_1 = self.acquire_PublicIPAddress(self.network)
+ self.create_and_verify_fw(self.vm_1, public_ip_1, self.network)
+ ssh = self.ssh_into_VM(self.vm_1, public_ip_1)
+ user_data_cmd = self.get_userdata_url(self.vm_1)
+ self.debug("Getting user data with command: " + user_data_cmd)
+ actual_user_data = base64.b64decode(self.execute_cmd(ssh, user_data_cmd))
+ self.debug("Actual user data - " + actual_user_data + ", Expected user data - " + expected_user_data)
+ self.assertEqual(actual_user_data, expected_user_data,
+ "Un-expected VM (VM_1) user data"
+ )
+
+ self.debug("Checking for cloud-set-guest-password script in the VM for testing password reset functionality...")
+ ls_cmd = "ls /etc/init.d/cloud-set-guest-password"
+ ls_result = self.execute_cmd(ssh, ls_cmd)
+ ls_result = ls_result.lower()
+ self.debug("Response from ls_cmd: " + ls_result)
+ if "no such file" in ls_result:
+ self.debug("No cloud-set-guest-password script in the VM")
+ self.debug("Installing the cloud-set-guest-password script from people.apache.org in the VM...")
+ self.install_cloud_set_guest_password_script(ssh)
+ self.debug("Stopping the VM, and creating a new password enabled guest VM template with it...")
+ self.stop_vm(self.vm_1)
+ self.create_template(self.vm_1)
+
+ self.debug("Deploying a new VM in the created Isolated network with the newly created guest VM template...")
+ self.vm_2 = self.create_VM(self.network, testdata=self.test_data["virtual_machine_userdata"])
+ self.debug("Starting the VM...")
+ vm_2a = self.vm_2.start(self.api_client)
+ self.vm_2.password = vm_2a.password.strip()
+ self.vm_2.nic = vm_2a.nic
+
+ # VSD verification
+ self.verify_vsd_vm(self.vm_2)
+
+ self.debug("verifying that the guest VM template is password enabled...")
+ self.debug("VM - %s password - %s !" % (self.vm_2.name, self.vm_2.password))
+ self.assertNotEqual(self.vm_2.password, self.test_data["virtual_machine_userdata"]["password"],
+ "Password is not enabled for the VM"
+ )
+
+ self.debug("SSHing into the VM for verifying its password...")
+ public_ip_2 = self.acquire_PublicIPAddress(self.network)
+ self.create_and_verify_fw(self.vm_2, public_ip_2, self.network)
+ self.ssh_into_VM(self.vm_2, public_ip_2)
+
+ vm_test = self.vm_2
+ vm_test_public_ip = public_ip_2
+ else:
+ self.debug("Updating the guest VM template to password enabled")
+ self.updateTemplate(True)
+ self.assertEqual(self.template.passwordenabled, True,
+ "Guest VM template is not password enabled"
+ )
+ vm_test = self.vm_1
+ vm_test_public_ip = public_ip_1
+
+ self.debug("Resetting password for VM - %s" % vm_test.name)
+ vm_test.password = vm_test.resetPassword(self.api_client)
+ self.debug("Password reset to - %s" % vm_test.password)
+
+ self.debug("Starting the VM")
+ vm_test.start(self.api_client)
+
+ self.debug("verifying that the guest VM template is password enabled...")
+ self.debug("VM - %s password - %s !" % (vm_test.name, vm_test.password))
+ self.assertNotEqual(vm_test.password, self.test_data["virtual_machine_userdata"]["password"],
+ "Password is not enabled for the VM"
+ )
+
+ self.debug("SSHing into the VM for verifying its new password after its password reset...")
+ self.ssh_into_VM(vm_test, vm_test_public_ip)
+
+ self.debug("Setting password enabled to the default value in the guest VM template...")
+ self.updateTemplate(self.defaultTemplateVal)
diff --git a/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py b/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py
new file mode 100644
index 0000000..0814689
--- /dev/null
+++ b/test/integration/plugins/nuagevsp/test_nuage_vpc_internal_lb.py
@@ -0,0 +1,2071 @@
+# 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.
+
+""" Component tests for VPC Internal Load Balancer functionality with Nuage VSP SDN plugin
+"""
+# Import Local Modules
+from nuageTestCase import nuageTestCase
+from marvin.lib.base import (Account,
+ ApplicationLoadBalancer,
+ Network,
+ Router)
+from marvin.cloudstackAPI import (listInternalLoadBalancerVMs,
+ stopInternalLoadBalancerVM,
+ startInternalLoadBalancerVM)
+# Import System Modules
+from nose.plugins.attrib import attr
+import copy
+import time
+
+
+class TestNuageInternalLb(nuageTestCase):
+ """Test VPC Internal LB functionality with Nuage VSP SDN plugin
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestNuageInternalLb, cls).setUpClass()
+ return
+
+ def setUp(self):
+ # Create an account
+ self.account = Account.create(self.api_client,
+ self.test_data["account"],
+ admin=True,
+ domainid=self.domain.id
+ )
+ self.cleanup = [self.account]
+ return
+
+ # create_Internal_LB_Rule - Creates Internal LB rule in the given VPC network
+ def create_Internal_LB_Rule(self, network, vm_array=None, services=None, source_ip=None):
+ self.debug("Creating Internal LB rule in VPC network with ID - %s" % network.id)
+ if not services:
+ services = self.test_data["internal_lbrule"]
+ int_lb_rule = ApplicationLoadBalancer.create(self.api_client,
+ services=services,
+ sourcenetworkid=network.id,
+ networkid=network.id,
+ sourceipaddress=source_ip
+ )
+ self.debug("Created Internal LB rule")
+ # Assigning VMs to the created Internal Load Balancer rule
+ if vm_array:
+ self.debug("Assigning virtual machines - %s to the created Internal LB rule" % vm_array)
+ int_lb_rule.assign(self.api_client, vms=vm_array)
+ self.debug("Assigned VMs to the created Internal LB rule")
+ return int_lb_rule
+
+ # validate_Internal_LB_Rule - Validates the given Internal LB rule,
+ # matches the given Internal LB rule name and state against the list of Internal LB rules fetched
+ def validate_Internal_LB_Rule(self, int_lb_rule, state=None, vm_array=None):
+ """Validates the Internal LB Rule"""
+ self.debug("Check if the Internal LB Rule is created successfully ?")
+ int_lb_rules = ApplicationLoadBalancer.list(self.api_client,
+ id=int_lb_rule.id
+ )
+ self.assertEqual(isinstance(int_lb_rules, list), True,
+ "List Internal LB Rule should return a valid list"
+ )
+ self.assertEqual(int_lb_rule.name, int_lb_rules[0].name,
+ "Name of the Internal LB Rule should match with the returned list data"
+ )
+ if state:
+ self.assertEqual(int_lb_rules[0].loadbalancerrule[0].state, state,
+ "Internal LB Rule state should be '%s'" % state
+ )
+ if vm_array:
+ instance_ids = [instance.id for instance in int_lb_rules[0].loadbalancerinstance]
+ for vm in vm_array:
+ self.assertEqual(vm.id in instance_ids, True,
+ "Internal LB instance list should have the VM with ID - %s" % vm.id
+ )
+ self.debug("Internal LB Rule creation successfully validated for %s" % int_lb_rule.name)
+
+ # list_InternalLbVms - Lists deployed Internal LB VM instances
+ def list_InternalLbVms(self, network_id=None, source_ip=None):
+ listInternalLoadBalancerVMsCmd = listInternalLoadBalancerVMs.listInternalLoadBalancerVMsCmd()
+ listInternalLoadBalancerVMsCmd.account = self.account.name
+ listInternalLoadBalancerVMsCmd.domainid = self.account.domainid
+ if network_id:
+ listInternalLoadBalancerVMsCmd.networkid = network_id
+ internal_lb_vms = self.api_client.listInternalLoadBalancerVMs(listInternalLoadBalancerVMsCmd)
+ if source_ip:
+ return [internal_lb_vm for internal_lb_vm in internal_lb_vms
+ if str(internal_lb_vm.guestipaddress) == source_ip]
+ else:
+ return internal_lb_vms
+
+ # get_InternalLbVm - Returns Internal LB VM instance for the given VPC network and source ip
+ def get_InternalLbVm(self, network, source_ip):
+ self.debug("Finding the InternalLbVm for network with ID - %s and source IP address - %s" %
+ (network.id, source_ip))
+ internal_lb_vms = self.list_InternalLbVms(network.id, source_ip)
+ self.assertEqual(isinstance(internal_lb_vms, list), True,
+ "List InternalLbVms should return a valid list"
+ )
+ return internal_lb_vms[0]
+
+ # stop_InternalLbVm - Stops the given Internal LB VM instance
+ def stop_InternalLbVm(self, int_lb_vm, force=None):
+ self.debug("Stopping InternalLbVm with ID - %s" % int_lb_vm.id)
+ cmd = stopInternalLoadBalancerVM.stopInternalLoadBalancerVMCmd()
+ cmd.id = int_lb_vm.id
+ if force:
+ cmd.forced = force
+ self.api_client.stopInternalLoadBalancerVM(cmd)
+
+ # start_InternalLbVm - Starts the given Internal LB VM instance
+ def start_InternalLbVm(self, int_lb_vm):
+ self.debug("Starting InternalLbVm with ID - %s" % int_lb_vm.id)
+ cmd = startInternalLoadBalancerVM.startInternalLoadBalancerVMCmd()
+ cmd.id = int_lb_vm.id
+ self.api_client.startInternalLoadBalancerVM(cmd)
+
+ # check_InternalLbVm_state - Checks if the Internal LB VM instance of the given VPC network and source IP is in the
+ # expected state form the list of fetched Internal LB VM instances
+ def check_InternalLbVm_state(self, network, source_ip, state=None):
+ self.debug("Check if the InternalLbVm is in state - %s" % state)
+ internal_lb_vms = self.list_InternalLbVms(network.id, source_ip)
+ self.assertEqual(isinstance(internal_lb_vms, list), True,
+ "List InternalLbVm should return a valid list"
+ )
+ if state:
+ self.assertEqual(internal_lb_vms[0].state, state,
+ "InternalLbVm is not in the expected state"
+ )
+ self.debug("InternalLbVm instance - %s is in the expected state - %s" % (internal_lb_vms[0].name, state))
+
+ # wget_from_vm_cmd - From within the given VM (ssh client),
+ # fetches index.html file of web server running with the given public IP
+ def wget_from_vm_cmd(self, ssh_client, ip_address, port):
+ cmd = "wget --no-cache -t 1 http://" + ip_address + ":" + str(port) + "/"
+ response = self.execute_cmd(ssh_client, cmd)
+ if "200 OK" not in response:
+ self.fail("Failed to wget from a VM with http server IP address - %s" % ip_address)
+ # Reading the wget file
+ cmd = "cat index.html"
+ wget_file = self.execute_cmd(ssh_client, cmd)
+ # Removing the wget file
+ cmd = "rm -r index.html"
+ self.execute_cmd(ssh_client, cmd)
+ return wget_file
+
+ # verify_lb_wget_file - Verifies that the given wget file (index.html) belongs to the given Internal LB rule
+ # assigned VMs (vm array)
+ def verify_lb_wget_file(self, wget_file, vm_array):
+ wget_server_ip = None
+ for vm in vm_array:
+ for nic in vm.nic:
+ if str(nic.ipaddress) in str(wget_file):
+ wget_server_ip = str(nic.ipaddress)
+ if wget_server_ip:
+ self.debug("Verified wget file from an Internal Load Balanced VM with http server IP address - %s"
+ % wget_server_ip)
+ else:
+ self.fail("Did not wget file from the Internal Load Balanced VMs - %s" % vm_array)
+ return wget_server_ip
+
+ # validate_internallb_algorithm_traffic - Validates Internal LB algorithms by performing multiple wget traffic tests
+ # against the given Internal LB VM instance (source port)
+ def validate_internallb_algorithm_traffic(self, ssh_client, source_ip, port, vm_array, algorithm):
+ # Internal LB (wget) traffic tests
+ iterations = 2 * len(vm_array)
+ wget_files = []
+ for i in range(iterations):
+ wget_files.append(self.wget_from_vm_cmd(ssh_client, source_ip, port))
+ # Verifying Internal LB (wget) traffic tests
+ wget_servers_ip_list = []
+ for i in range(iterations):
+ wget_servers_ip_list.append(self.verify_lb_wget_file(wget_files[i], vm_array))
+ # Validating Internal LB algorithm
+ if algorithm == "roundrobin" or algorithm == "leastconn":
+ for i in range(iterations):
+ if wget_servers_ip_list.count(wget_servers_ip_list[i]) is not 2:
+ self.fail("Round Robin Internal LB algorithm validation failed - %s" % wget_servers_ip_list)
+ self.debug("Successfully validated Round Robin/Least connections Internal LB algorithm - %s" %
+ wget_servers_ip_list)
+ if algorithm == "source":
+ for i in range(iterations):
+ if wget_servers_ip_list.count(wget_servers_ip_list[i]) is not iterations:
+ self.fail("Source Internal LB algorithm validation failed - %s" % wget_servers_ip_list)
+ self.debug("Successfully validated Source Internal LB algorithm - %s" % wget_servers_ip_list)
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="false")
+ def test_01_nuage_internallb_vpc_Offering(self):
+ """Test Nuage VSP VPC Offering with different combinations of LB service providers
+ """
+
+ # 1. Verify that the network service providers supported by Nuage VSP for VPC Internal LB functionality are all
+ # successfully created and enabled.
+ # 2. Create Nuage VSP VPC offering with LB service provider as "InternalLbVm", check if it is successfully
+ # created and enabled. Verify that the VPC creation succeeds with this VPC offering.
+ # 3. Create Nuage VSP VPC offering with LB service provider as "VpcVirtualRouter", check if it is successfully
+ # created and enabled. Verify that the VPC creation fails with this VPC offering as Nuage VSP does not
+ # support provider "VpcVirtualRouter" for service LB.
+ # 4. Create Nuage VSP VPC offering with LB service provider as "Netscaler", check if it is successfully
+ # created and enabled. Verify that the VPC creation fails with this VPC offering as Nuage VSP does not
+ # support provider "Netscaler" for service LB.
+ # 5. Delete all the created objects (cleanup).
+
+ self.debug("Validating network service providers supported by Nuage VSP for VPC Internal LB functionality")
+ providers = ["NuageVsp", "VpcVirtualRouter", "InternalLbVm"]
+ for provider in providers:
+ self.validate_NetworkServiceProvider(provider, state="Enabled")
+
+ # Creating VPC offerings
+ self.debug("Creating Nuage VSP VPC offering with LB service provider as InternalLbVm...")
+ vpc_off_1 = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"])
+ self.validate_VpcOffering(vpc_off_1, state="Enabled")
+
+ self.debug("Creating Nuage VSP VPC offering with LB service provider as VpcVirtualRouter...")
+ vpc_offering_lb = copy.deepcopy(self.test_data["nuagevsp"]["vpc_offering_lb"])
+ vpc_offering_lb["serviceProviderList"]["Lb"] = "VpcVirtualRouter"
+ vpc_off_2 = self.create_VpcOffering(vpc_offering_lb)
+ self.validate_VpcOffering(vpc_off_2, state="Enabled")
+
+ self.debug("Creating Nuage VSP VPC offering with LB service provider as Netscaler...")
+ vpc_offering_lb["serviceProviderList"]["Lb"] = "Netscaler"
+ vpc_off_3 = self.create_VpcOffering(vpc_offering_lb)
+ self.validate_VpcOffering(vpc_off_3, state="Enabled")
+
+ self.debug("Creating Nuage VSP VPC offering without LB service...")
+ vpc_off_4 = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering"])
+ self.validate_VpcOffering(vpc_off_4, state="Enabled")
+
+ # Creating VPCs
+ self.debug("Creating a VPC with LB service provider as InternalLbVm...")
+ vpc_1 = self.create_Vpc(vpc_off_1, cidr='10.1.0.0/16')
+ self.validate_Vpc(vpc_1, state="Enabled")
+
+ self.debug("Creating a VPC with LB service provider as VpcVirtualRouter...")
+ with self.assertRaises(Exception):
+ self.create_Vpc(vpc_off_2, cidr='10.1.0.0/16')
+ self.debug("Nuage VSP does not support provider VpcVirtualRouter for service LB for VPCs")
+
+ self.debug("Creating a VPC with LB service provider as Netscaler...")
+ with self.assertRaises(Exception):
+ self.create_Vpc(vpc_off_3, cidr='10.1.0.0/16')
+ self.debug("Nuage VSP does not support provider Netscaler for service LB for VPCs")
+
+ self.debug("Creating a VPC without LB service...")
+ vpc_2 = self.create_Vpc(vpc_off_4, cidr='10.1.0.0/16')
+ self.validate_Vpc(vpc_2, state="Enabled")
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="false")
+ def test_02_nuage_internallb_vpc_network_offering(self):
+ """Test Nuage VSP VPC Network Offering with and without Internal LB service
+ """
+
+ # 1. Create Nuage VSP VPC Network offering with LB Service Provider as "InternalLbVm" and LB Service Capability
+ # "lbSchemes" as "internal", check if it is successfully created and enabled. Verify that the VPC network
+ # creation succeeds with this Network offering.
+ # 2. Recreate above Network offering with ispersistent False, check if it is successfully created and enabled.
+ # Verify that the VPC network creation fails with this Network offering as Nuage VSP does not support non
+ # persistent VPC networks.
+ # 3. Recreate above Network offering with conserve mode On, check if the network offering creation failed
+ # as only networks with conserve mode Off can belong to VPC.
+ # 4. Create Nuage VSP VPC Network offering with LB Service Provider as "InternalLbVm" and LB Service Capability
+ # "lbSchemes" as "public", check if the network offering creation failed as "public" lbScheme is not
+ # supported for LB Service Provider "InternalLbVm".
+ # 5. Create Nuage VSP VPC Network offering without Internal LB Service, check if it is successfully created and
+ # enabled. Verify that the VPC network creation succeeds with this Network offering.
+ # 6. Recreate above Network offering with ispersistent False, check if it is successfully created and enabled.
+ # Verify that the VPC network creation fails with this Network offering as Nuage VSP does not support non
+ # persistent VPC networks.
+ # 7. Recreate the above Network offering with conserve mode On, check if the network offering creation failed
+ # as only networks with conserve mode Off can belong to VPC.
+ # 8. Delete all the created objects (cleanup).
+
+ # Creating VPC offering
+ self.debug("Creating Nuage VSP VPC offering with Internal LB service...")
+ vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"])
+ self.validate_VpcOffering(vpc_off, state="Enabled")
+
+ # Creating VPC
+ self.debug("Creating a VPC with Internal LB service...")
+ vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16')
+ self.validate_Vpc(vpc, state="Enabled")
+
+ # Creating network offerings
+ self.debug("Creating Nuage VSP VPC Network offering with LB Service Provider as InternalLbVm and LB Service "
+ "Capability lbSchemes as internal...")
+ net_off_1 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"])
+ self.validate_NetworkOffering(net_off_1, state="Enabled")
+
+ self.debug("Recreating above Network offering with ispersistent False...")
+ vpc_net_off_lb_non_persistent = copy.deepcopy(self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"])
+ vpc_net_off_lb_non_persistent["ispersistent"] = "False"
+ net_off_2 = self.create_NetworkOffering(vpc_net_off_lb_non_persistent)
+ self.validate_NetworkOffering(net_off_2, state="Enabled")
+
+ self.debug("Recreating above Network offering with conserve mode On...")
+ with self.assertRaises(Exception):
+ self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"],
+ conserve_mode=True)
+ self.debug("Network offering creation failed as only networks with conserve mode Off can belong to VPC")
+
+ self.debug("Creating Nuage VSP VPC Network offering with LB Service Provider as InternalLbVm and LB Service "
+ "Capability lbSchemes as public...")
+ network_offering_internal_lb = copy.deepcopy(self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"])
+ network_offering_internal_lb["serviceCapabilityList"]["Lb"]["lbSchemes"] = "public"
+ with self.assertRaises(Exception):
+ self.create_NetworkOffering(network_offering_internal_lb)
+ self.debug("Network offering creation failed as public lbScheme is not supported for LB Service Provider "
+ "InternalLbVm")
+
+ self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...")
+ net_off_3 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"])
+ self.validate_NetworkOffering(net_off_3, state="Enabled")
+
+ self.debug("Recreating above Network offering with ispersistent False...")
+ vpc_net_off_non_persistent = copy.deepcopy(self.test_data["nuagevsp"]["vpc_network_offering"])
+ vpc_net_off_non_persistent["ispersistent"] = "False"
+ net_off_4 = self.create_NetworkOffering(vpc_net_off_non_persistent)
+ self.validate_NetworkOffering(net_off_4, state="Enabled")
+
+ self.debug("Recreating above Network offering with conserve mode On...")
+ with self.assertRaises(Exception):
+ self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"], conserve_mode=True)
+ self.debug("Network offering creation failed as only networks with conserve mode Off can belong to VPC")
+
+ # Creating VPC networks in the VPC
+ self.debug("Creating a persistent VPC network with Internal LB service...")
+ internal_tier = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc)
+ self.validate_Network(internal_tier, state="Implemented")
+ vr = self.get_Router(internal_tier)
+ self.check_Router_state(vr, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+ self.verify_vsd_router(vr)
+
+ self.debug("Creating a non persistent VPC network with Internal LB service...")
+ with self.assertRaises(Exception):
+ self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc)
+ self.debug("Nuage VSP does not support non persistent VPC networks")
+
+ self.debug("Creating a persistent VPC network without Internal LB service...")
+ public_tier = self.create_Network(net_off_3, gateway='10.1.3.1', vpc=vpc)
+ self.validate_Network(public_tier, state="Implemented")
+ vr = self.get_Router(public_tier)
+ self.check_Router_state(vr, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_router(vr)
+
+ self.debug("Creating a non persistent VPC network without Internal LB service...")
+ with self.assertRaises(Exception):
+ self.create_Network(net_off_4, gateway='10.1.4.1', vpc=vpc)
+ self.debug("Nuage VSP does not support non persistent VPC networks")
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="false")
+ def test_03_nuage_internallb_vpc_networks(self):
+ """Test Nuage VSP VPC Networks with and without Internal LB service
+ """
+
+ # 1. Create Nuage VSP VPC offering with Internal LB service, check if it is successfully created and enabled.
+ # 2. Create Nuage VSP VPC offering without Internal LB service, check if it is successfully created and enabled.
+ # 3. Create a VPC "vpc_1" with Internal LB service, check if it is successfully created and enabled.
+ # 4. Create a VPC "vpc_2" without Internal LB service, check if it is successfully created and enabled.
+ # 5. Create Nuage VSP VPC Network offering with Internal LB service, check if it is successfully created and
+ # enabled.
+ # 6. Create Nuage VSP VPC Network offering without Internal LB service, check if it is successfully created and
+ # enabled.
+ # 7. Create a VPC network in vpc_1 with Internal LB service and spawn a VM, check if the tier is added to the
+ # VPC VR, and the VM is deployed successfully in the tier.
+ # 8. Create one more VPC network in vpc_1 with Internal LB service and spawn a VM, check if the tier is added
+ # to the VPC VR, and the VM is deployed successfully in the tier.
+ # 9. Create a VPC network in vpc_2 with Internal LB service, check if the tier creation failed.
+ # 10. Create a VPC network in vpc_1 without Internal LB service and spawn a VM, check if the tier is added to
+ # the VPC VR, and the VM is deployed successfully in the tier.
+ # 11. Create a VPC network in vpc_2 without Internal LB service and spawn a VM, check if the tier is added to
+ # the VPC VR, and the VM is deployed successfully in the tier.
+ # 12. Upgrade the VPC network with Internal LB service to one with no Internal LB service and vice-versa, check
+ # if the VPC Network offering upgrade passed in both directions.
+ # 13. Delete the VPC network with Internal LB service, check if the tier is successfully deleted.
+ # 14. Recreate the VPC network with Internal LB service, check if the tier is successfully re-created.
+ # 15. Delete all the created objects (cleanup).
+
+ # Creating VPC offerings
+ self.debug("Creating Nuage VSP VPC offering with Internal LB service...")
+ vpc_off_1 = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"])
+ self.validate_VpcOffering(vpc_off_1, state="Enabled")
+
+ self.debug("Creating Nuage VSP VPC offering without Internal LB service...")
+ vpc_off_2 = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering"])
+ self.validate_VpcOffering(vpc_off_2, state="Enabled")
+
+ # Creating VPCs
+ self.debug("Creating a VPC with Internal LB service...")
+ vpc_1 = self.create_Vpc(vpc_off_1, cidr='10.1.0.0/16')
+ self.validate_Vpc(vpc_1, state="Enabled")
+
+ self.debug("Creating a VPC without Internal LB service...")
+ vpc_2 = self.create_Vpc(vpc_off_2, cidr='10.1.0.0/16')
+ self.validate_Vpc(vpc_2, state="Enabled")
+
+ # Creating network offerings
+ self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...")
+ net_off_1 = self.create_NetworkOffering(
+ self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"])
+ self.validate_NetworkOffering(net_off_1, state="Enabled")
+
+ self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...")
+ net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"])
+ self.validate_NetworkOffering(net_off_2, state="Enabled")
+
+ # Creating VPC networks in VPCs, and deploying VMs
+ self.debug("Creating a VPC network in vpc_1 with Internal LB service...")
+ internal_tier_1 = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc_1)
+ self.validate_Network(internal_tier_1, state="Implemented")
+ vr_1 = self.get_Router(internal_tier_1)
+ self.check_Router_state(vr_1, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ internal_vm_1 = self.create_VM(internal_tier_1)
+ self.check_VM_state(internal_vm_1, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier_1, vpc_1)
+ self.verify_vsd_router(vr_1)
+ self.verify_vsd_vm(internal_vm_1)
+
+ self.debug("Creating one more VPC network in vpc_1 with Internal LB service...")
+ internal_tier_2 = self.create_Network(net_off_1, gateway='10.1.2.1', vpc=vpc_1)
+ self.validate_Network(internal_tier_2, state="Implemented")
+ vr_1 = self.get_Router(internal_tier_2)
+ self.check_Router_state(vr_1, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ internal_vm_2 = self.create_VM(internal_tier_2)
+ self.check_VM_state(internal_vm_2, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier_2, vpc_1)
+ self.verify_vsd_router(vr_1)
+ self.verify_vsd_vm(internal_vm_2)
+
+ self.debug("Creating a VPC network in vpc_2 with Internal LB service...")
+ with self.assertRaises(Exception):
+ self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc_2)
+ self.debug("VPC Network creation failed as vpc_2 does not support Internal Lb service")
+
+ self.debug("Creating a VPC network in vpc_1 without Internal LB service...")
+ public_tier_1 = self.create_Network(net_off_2, gateway='10.1.3.1', vpc=vpc_1)
+ self.validate_Network(public_tier_1, state="Implemented")
+ vr_1 = self.get_Router(public_tier_1)
+ self.check_Router_state(vr_1, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ public_vm_1 = self.create_VM(public_tier_1)
+ self.check_VM_state(public_vm_1, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier_1, vpc_1)
+ self.verify_vsd_router(vr_1)
+ self.verify_vsd_vm(public_vm_1)
+
+ self.debug("Creating a VPC network in vpc_2 without Internal LB service...")
+ public_tier_2 = self.create_Network(net_off_2, gateway='10.1.1.1', vpc=vpc_2)
+ self.validate_Network(public_tier_2, state="Implemented")
+ vr_2 = self.get_Router(public_tier_2)
+ self.check_Router_state(vr_2, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ public_vm_2 = self.create_VM(public_tier_2)
+ self.check_VM_state(public_vm_2, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier_2, vpc_2)
+ self.verify_vsd_router(vr_2)
+ self.verify_vsd_vm(public_vm_2)
+
+ # Upgrading a VPC network
+ self.debug("Upgrading a VPC network with Internal LB Service to one without Internal LB Service...")
+ self.upgrade_Network(net_off_2, internal_tier_2)
+ self.validate_Network(internal_tier_2, state="Implemented")
+ vr_1 = self.get_Router(internal_tier_2)
+ self.check_Router_state(vr_1, state="Running")
+ self.check_VM_state(internal_vm_2, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier_2, vpc_1)
+ self.verify_vsd_router(vr_1)
+ self.verify_vsd_vm(internal_vm_2)
+
+ self.debug("Upgrading a VPC network without Internal LB Service to one with Internal LB Service...")
+ self.upgrade_Network(net_off_1, internal_tier_2)
+ self.validate_Network(internal_tier_2, state="Implemented")
+ vr_1 = self.get_Router(internal_tier_2)
+ self.check_Router_state(vr_1, state="Running")
+ self.check_VM_state(internal_vm_2, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier_2, vpc_1)
+ self.verify_vsd_router(vr_1)
+ self.verify_vsd_vm(internal_vm_2)
+
+ # Deleting and re-creating a VPC network
+ self.debug("Deleting a VPC network with Internal LB Service...")
+ self.delete_VM(internal_vm_2)
+ self.delete_Network(internal_tier_2)
+ with self.assertRaises(Exception):
+ self.validate_Network(internal_tier_2)
+ self.debug("VPC network successfully deleted in CloudStack")
+
+ # VSD verification
+ with self.assertRaises(Exception):
+ self.verify_vsd_network(self.domain.id, internal_tier_2, vpc_1)
+ self.debug("VPC network successfully deleted in VSD")
+
+ self.debug("Recreating a VPC network with Internal LB Service...")
+ internal_tier_2 = self.create_Network(net_off_1, gateway='10.1.2.1', vpc=vpc_1)
+ internal_vm_2 = self.create_VM(internal_tier_2)
+ self.validate_Network(internal_tier_2, state="Implemented")
+ vr_1 = self.get_Router(internal_tier_2)
+ self.check_Router_state(vr_1, state="Running")
+ self.check_VM_state(internal_vm_2, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier_2, vpc_1)
+ self.verify_vsd_router(vr_1)
+ self.verify_vsd_vm(internal_vm_2)
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="false")
+ def test_04_nuage_internallb_rules(self):
+ """Test Nuage VSP VPC Internal LB functionality with different combinations of Internal LB rules
+ """
+
+ # 1. Create an Internal LB Rule with source IP Address specified, check if the Internal LB Rule is successfully
+ # created.
+ # 2. Create an Internal LB Rule without source IP Address specified, check if the Internal LB Rule is
+ # successfully created.
+ # 3. Create an Internal LB Rule when the specified source IP Address is outside the VPC network (tier) CIDR
+ # range, check if the Internal LB Rule creation failed as the requested source IP is not in the network's
+ # CIDR subnet.
+ # 4. Create an Internal LB Rule when the specified source IP Address is outside the VPC super CIDR range,
+ # check if the Internal LB Rule creation failed as the requested source IP is not in the network's CIDR
+ # subnet.
+ # 5. Create an Internal LB Rule in the tier with LB service provider as VpcInlineLbVm, check if the Internal LB
+ # Rule creation failed as Scheme Internal is not supported by this network offering.
+ # 6. Create multiple Internal LB Rules using different Load Balancing source IP Addresses, check if the Internal
+ # LB Rules are successfully created.
+ # 7. Create multiple Internal LB Rules with different ports but using the same Load Balancing source IP Address,
+ # check if the Internal LB Rules are successfully created.
+ # 8. Create multiple Internal LB Rules with same ports and using the same Load Balancing source IP Address,
+ # check if the second Internal LB Rule creation failed as it conflicts with the first Internal LB rule.
+ # 9. Attach a VM to the above created Internal LB Rules, check if the VM is successfully attached to the
+ # Internal LB Rules.
+ # 10. Verify the InternalLbVm deployment after successfully creating the first Internal LB Rule and attaching a
+ # VM to it.
+ # 11. Verify the failure of attaching a VM from a different tier to an Internal LB Rule created on a tier.
+ # 12. Delete the above created Internal LB Rules, check if the Internal LB Rules are successfully deleted.
+ # 13. Delete all the created objects (cleanup).
+
+ # Creating a VPC offering
+ self.debug("Creating Nuage VSP VPC offering with Internal LB service...")
+ vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"])
+ self.validate_VpcOffering(vpc_off, state="Enabled")
+
+ # Creating a VPC
+ self.debug("Creating a VPC with Internal LB service...")
+ vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16')
+ self.validate_Vpc(vpc, state="Enabled")
+
+ # Creating network offerings
+ self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...")
+ net_off_1 = self.create_NetworkOffering(
+ self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"])
+ self.validate_NetworkOffering(net_off_1, state="Enabled")
+
+ self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...")
+ net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"])
+ self.validate_NetworkOffering(net_off_2, state="Enabled")
+
+ # Creating VPC networks in the VPC, and deploying VMs
+ self.debug("Creating a VPC network with Internal LB service...")
+ internal_tier = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc)
+ self.validate_Network(internal_tier, state="Implemented")
+ vr = self.get_Router(internal_tier)
+ self.check_Router_state(vr, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ internal_vm = self.create_VM(internal_tier)
+ self.check_VM_state(internal_vm, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(internal_vm)
+
+ self.debug("Creating a VPC network without Internal LB service...")
+ public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc)
+ self.validate_Network(public_tier, state="Implemented")
+ vr = self.get_Router(public_tier)
+ self.check_Router_state(vr, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ public_vm = self.create_VM(public_tier)
+ self.check_VM_state(public_vm, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(public_vm)
+
+ # Creating Internal LB Rules
+ self.debug("Creating an Internal LB Rule without source IP Address specified...")
+ int_lb_rule = self.create_Internal_LB_Rule(internal_tier)
+ self.validate_Internal_LB_Rule(int_lb_rule, state="Add")
+
+ # Validating InternalLbVm deployment
+ with self.assertRaises(Exception):
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress)
+ self.debug("InternalLbVm is not deployed in the network as there are no VMs assigned to this Internal LB Rule")
+
+ self.debug('Deleting the Internal LB Rule - %s' % int_lb_rule.name)
+ int_lb_rule.delete(self.api_client)
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule)
+ self.debug("Internal LB Rule successfully deleted in CloudStack")
+
+ free_source_ip = int_lb_rule.sourceipaddress
+
+ self.debug("Creating an Internal LB Rule with source IP Address specified...")
+ int_lb_rule = self.create_Internal_LB_Rule(internal_tier, source_ip=free_source_ip)
+ self.validate_Internal_LB_Rule(int_lb_rule, state="Add")
+
+ # Validating InternalLbVm deployment
+ with self.assertRaises(Exception):
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress)
+ self.debug("InternalLbVm is not deployed in the network as there are no VMs assigned to this Internal LB Rule")
+
+ self.debug('Deleting the Internal LB Rule - %s' % int_lb_rule.name)
+ int_lb_rule.delete(self.api_client)
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule)
+ self.debug("Internal LB Rule successfully deleted in CloudStack")
+
+ self.debug("Creating an Internal LB Rule when the specified source IP Address is outside the VPC network CIDR "
+ "range...")
+ with self.assertRaises(Exception):
+ self.create_Internal_LB_Rule(internal_tier, source_ip="10.1.1.256")
+ self.debug("Internal LB Rule creation failed as the requested IP is not in the network's CIDR subnet")
+
+ self.debug("Creating an Internal LB Rule when the specified source IP Address is outside the VPC super CIDR "
+ "range...")
+ with self.assertRaises(Exception):
+ self.create_Internal_LB_Rule(internal_tier, source_ip="10.2.1.256")
+ self.debug("Internal LB Rule creation failed as the requested IP is not in the network's CIDR subnet")
+
+ self.debug("Creating an Internal LB Rule in a VPC network without Internal Lb service...")
+ with self.assertRaises(Exception):
+ self.create_Internal_LB_Rule(public_tier)
+ self.debug("Internal LB Rule creation failed as Scheme Internal is not supported by this network offering")
+
+ self.debug("Creating multiple Internal LB Rules using different Load Balancing source IP Addresses...")
+ int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm])
+ self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm])
+ int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm])
+ self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm])
+
+ # Validating InternalLbVms deployment and state
+ int_lb_vm_1 = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+ int_lb_vm_2 = self.get_InternalLbVm(internal_tier, int_lb_rule_2.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_2.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm_1)
+ self.verify_vsd_lb_device(int_lb_vm_2)
+
+ self.debug('Removing VMs from the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name))
+ int_lb_rule_1.remove(self.api_client, vms=[internal_vm])
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule_1, vm_array=[internal_vm])
+ self.debug("VMs successfully removed from the Internal LB Rule in CloudStack")
+ int_lb_rule_2.remove(self.api_client, vms=[internal_vm])
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule_2, vm_array=[internal_vm])
+ self.debug("VMs successfully removed from the Internal LB Rule in CloudStack")
+
+ # Validating InternalLbVms state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_2.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm_1)
+ self.verify_vsd_lb_device(int_lb_vm_2)
+
+ self.debug('Deleting the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name))
+ int_lb_rule_1.delete(self.api_client)
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule_1)
+ self.debug("Internal LB Rule successfully deleted in CloudStack")
+ int_lb_rule_2.delete(self.api_client)
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule_2)
+ self.debug("Internal LB Rule successfully deleted in CloudStack")
+
+ # Validating InternalLbVms un-deployment
+ with self.assertRaises(Exception):
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress)
+ self.debug("InternalLbVm successfully destroyed in CloudStack")
+ with self.assertRaises(Exception):
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_2.sourceipaddress)
+ self.debug("InternalLbVm successfully destroyed in CloudStack")
+
+ # VSD Verification
+ with self.assertRaises(Exception):
+ self.verify_vsd_lb_device(int_lb_vm_1)
+ self.debug("InternalLbVm successfully destroyed in VSD")
+ with self.assertRaises(Exception):
+ self.verify_vsd_lb_device(int_lb_vm_2)
+ self.debug("InternalLbVm successfully destroyed in VSD")
+
+ self.debug("Creating multiple Internal LB Rules with different ports but using the same Load Balancing source "
+ "IP Address...")
+ int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm])
+ self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm])
+ int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier,
+ vm_array=[internal_vm],
+ services=self.test_data["internal_lbrule_http"],
+ source_ip=int_lb_rule_1.sourceipaddress
+ )
+ self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm])
+
+ # Validating InternalLbVm deployment and state
+ int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ self.debug('Removing VMs from the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name))
+ int_lb_rule_1.remove(self.api_client, vms=[internal_vm])
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule_1, vm_array=[internal_vm])
+ self.debug("VMs successfully removed from the Internal LB Rule in CloudStack")
+ int_lb_rule_2.remove(self.api_client, vms=[internal_vm])
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule_2, vm_array=[internal_vm])
+ self.debug("VMs successfully removed from the Internal LB Rule in CloudStack")
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ self.debug('Deleting the Internal LB Rules - %s, %s' % (int_lb_rule_1.name, int_lb_rule_2.name))
+ int_lb_rule_1.delete(self.api_client)
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule_1)
+ self.debug("Internal LB Rule successfully deleted in CloudStack")
+ int_lb_rule_2.delete(self.api_client)
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule_2)
+ self.debug("Internal LB Rule successfully deleted in CloudStack")
+
+ # Validating InternalLbVm un-deployment
+ with self.assertRaises(Exception):
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress)
+ self.debug("InternalLbVm successfully destroyed in CloudStack")
+
+ # VSD Verification
+ with self.assertRaises(Exception):
+ self.verify_vsd_lb_device(int_lb_vm)
+ self.debug("InternalLbVm successfully destroyed in VSD")
+
+ self.debug("Creating multiple Internal LB Rules with same ports and using the same Load Balancing source IP "
+ "Address...")
+ int_lb_rule = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm])
+ self.validate_Internal_LB_Rule(int_lb_rule, state="Active", vm_array=[internal_vm])
+ with self.assertRaises(Exception):
+ self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm], source_ip=int_lb_rule.sourceipaddress)
+ self.debug("Internal LB Rule creation failed as it conflicts with the existing rule")
+
+ # Validating InternalLbVm deployment and state
+ int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ self.debug('Removing VMs from the Internal LB Rule - %s' % int_lb_rule.name)
+ int_lb_rule.remove(self.api_client, vms=[internal_vm])
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule, vm_array=[internal_vm])
+ self.debug("VMs successfully removed from the Internal LB Rule in CloudStack")
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ self.debug('Deleting the Internal LB Rule - %s' % int_lb_rule.name)
+ int_lb_rule.delete(self.api_client)
+ with self.assertRaises(Exception):
+ self.validate_Internal_LB_Rule(int_lb_rule)
+ self.debug("Internal LB Rule successfully deleted in CloudStack")
+
+ # Validating InternalLbVm un-deployment
+ with self.assertRaises(Exception):
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule.sourceipaddress)
+ self.debug("InternalLbVm successfully destroyed in CloudStack")
+
+ # VSD Verification
+ with self.assertRaises(Exception):
+ self.verify_vsd_lb_device(int_lb_vm)
+ self.debug("InternalLbVm successfully destroyed in VSD")
+
+ self.debug("Attaching a VM from a different tier to an Internal LB Rule created on a tier...")
+ with self.assertRaises(Exception):
+ self.create_Internal_LB_Rule(internal_tier, vm_array=[public_vm])
+ self.debug("Internal LB Rule creation failed as the VM belongs to a different network")
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="true")
+ def test_05_nuage_internallb_traffic(self):
+ """Test Nuage VSP VPC Internal LB functionality by performing (wget) traffic tests within a VPC
+ """
+
+ # 1. Create an Internal LB Rule "internal_lbrule" with source IP Address specified on the Internal tier, check
+ # if the Internal LB Rule is successfully created.
+ # 2. Create an Internal LB Rule "internal_lbrule_http" with source IP Address (same as above) specified on the
+ # Internal tier, check if the Internal LB Rule is successfully created.
+ # 3. Attach a VM to the above created Internal LB Rules, check if the InternalLbVm is successfully deployed in
+ # the Internal tier.
+ # 4. Deploy two more VMs in the Internal tier, check if the VMs are successfully deployed.
+ # 5. Attach the newly deployed VMs to the above created Internal LB Rules, verify the validity of the above
+ # created Internal LB Rules over three Load Balanced VMs in the Internal tier.
+ # 6. Create the corresponding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible,
+ # check if the Network ACL rules are successfully added to the internal tier.
+ # 7. Validate the Internal LB functionality by performing (wget) traffic tests from a VM in the Public tier to
+ # the Internal load balanced guest VMs in the Internal tier, using Static NAT functionality to access (ssh)
+ # the VM on the Public tier.
+ # 8. Verify that the InternalLbVm gets destroyed when the last Internal LB rule is removed from the Internal
+ # tier.
+ # 9. Repeat the above steps for one more Internal tier as well, validate the Internal LB functionality.
+ # 10. Delete all the created objects (cleanup).
+
+ # Creating a VPC offering
+ self.debug("Creating Nuage VSP VPC offering with Internal LB service...")
+ vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"])
+ self.validate_VpcOffering(vpc_off, state="Enabled")
+
+ # Creating a VPC
+ self.debug("Creating a VPC with Internal LB service...")
+ vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16')
+ self.validate_Vpc(vpc, state="Enabled")
+
+ # Creating network offerings
+ self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...")
+ net_off_1 = self.create_NetworkOffering(
+ self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"])
+ self.validate_NetworkOffering(net_off_1, state="Enabled")
+
+ self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...")
+ net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"])
+ self.validate_NetworkOffering(net_off_2, state="Enabled")
+
+ # Creating VPC networks in the VPC, and deploying VMs
+ self.debug("Creating a VPC network with Internal LB service...")
+ internal_tier_1 = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc)
+ self.validate_Network(internal_tier_1, state="Implemented")
+ vr = self.get_Router(internal_tier_1)
+ self.check_Router_state(vr, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ internal_vm_1 = self.create_VM(internal_tier_1)
+ self.check_VM_state(internal_vm_1, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier_1, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(internal_vm_1)
+
+ self.debug("Creating one more VPC network with Internal LB service...")
+ internal_tier_2 = self.create_Network(net_off_1, gateway='10.1.2.1', vpc=vpc)
+ self.validate_Network(internal_tier_2, state="Implemented")
+ vr = self.get_Router(internal_tier_2)
+ self.check_Router_state(vr, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ internal_vm_2 = self.create_VM(internal_tier_2)
+ self.check_VM_state(internal_vm_2, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier_2, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(internal_vm_2)
+
+ self.debug("Creating a VPC network without Internal LB service...")
+ public_tier = self.create_Network(net_off_2, gateway='10.1.3.1', vpc=vpc)
+ self.validate_Network(public_tier, state="Implemented")
+ vr = self.get_Router(public_tier)
+ self.check_Router_state(vr, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ public_vm = self.create_VM(public_tier)
+ self.check_VM_state(public_vm, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(public_vm)
+
+ # Creating Internal LB Rules in the Internal tiers
+ self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...")
+ int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier_1, vm_array=[internal_vm_1])
+ self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm_1])
+ int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier_1,
+ vm_array=[internal_vm_1],
+ services=self.test_data["internal_lbrule_http"],
+ source_ip=int_lb_rule_1.sourceipaddress
+ )
+ self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm_1])
+
+ # Validating InternalLbVm deployment and state
+ int_lb_vm_1 = self.get_InternalLbVm(internal_tier_1, int_lb_rule_1.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier_1, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm_1)
+
+ # Deploying more VMs in the Internal tier
+ self.debug("Deploying two more VMs in network - %s" % internal_tier_1.name)
+ internal_vm_1_1 = self.create_VM(internal_tier_1)
+ internal_vm_1_2 = self.create_VM(internal_tier_1)
+
+ # VSD verification
+ self.verify_vsd_vm(internal_vm_1_1)
+ self.verify_vsd_vm(internal_vm_1_2)
+
+ # Adding newly deployed VMs to the created Internal LB rules
+ self.debug("Adding two more virtual machines to the created Internal LB rules...")
+ int_lb_rule_1.assign(self.api_client, [internal_vm_1_1, internal_vm_1_2])
+ self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active",
+ vm_array=[internal_vm_1, internal_vm_1_1, internal_vm_1_2])
+ int_lb_rule_2.assign(self.api_client, [internal_vm_1_1, internal_vm_1_2])
+ self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active",
+ vm_array=[internal_vm_1, internal_vm_1_1, internal_vm_1_2])
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier_1, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm_1)
+
+ # Adding Network ACL rules in the Internal tier
+ self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...")
+ ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=internal_tier_1)
+ http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier_1)
+
+ # VSD verification
+ self.verify_vsd_firewall_rule(ssh_rule)
+ self.verify_vsd_firewall_rule(http_rule)
+
+ # Creating Internal LB Rules in the Internal tier
+ self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...")
+ int_lb_rule_3 = self.create_Internal_LB_Rule(internal_tier_2, vm_array=[internal_vm_2])
+ self.validate_Internal_LB_Rule(int_lb_rule_3, state="Active", vm_array=[internal_vm_2])
+ int_lb_rule_4 = self.create_Internal_LB_Rule(internal_tier_2,
+ vm_array=[internal_vm_2],
+ services=self.test_data["internal_lbrule_http"],
+ source_ip=int_lb_rule_3.sourceipaddress
+ )
+ self.validate_Internal_LB_Rule(int_lb_rule_4, state="Active", vm_array=[internal_vm_2])
+
+ # Validating InternalLbVm deployment and state
+ int_lb_vm_2 = self.get_InternalLbVm(internal_tier_2, int_lb_rule_3.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier_2, int_lb_rule_3.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm_2)
+
+ # Deploying more VMs in the Internal tier
+ self.debug("Deploying two more VMs in network - %s" % internal_tier_2.name)
+ internal_vm_2_1 = self.create_VM(internal_tier_2)
+ internal_vm_2_2 = self.create_VM(internal_tier_2)
+
+ # VSD verification
+ self.verify_vsd_vm(internal_vm_2_1)
+ self.verify_vsd_vm(internal_vm_2_2)
+
+ # Adding newly deployed VMs to the created Internal LB rules
+ self.debug("Adding two more virtual machines to the created Internal LB rules...")
+ int_lb_rule_3.assign(self.api_client, [internal_vm_2_1, internal_vm_2_2])
+ self.validate_Internal_LB_Rule(int_lb_rule_3, state="Active",
+ vm_array=[internal_vm_2, internal_vm_2_1, internal_vm_2_2])
+ int_lb_rule_4.assign(self.api_client, [internal_vm_2_1, internal_vm_2_2])
+ self.validate_Internal_LB_Rule(int_lb_rule_4, state="Active",
+ vm_array=[internal_vm_2, internal_vm_2_1, internal_vm_2_2])
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier_2, int_lb_rule_3.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm_2)
+
+ # Adding Network ACL rules in the Internal tier
+ self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...")
+ ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=internal_tier_2)
+ http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier_2)
+
+ # VSD verification
+ self.verify_vsd_firewall_rule(ssh_rule)
+ self.verify_vsd_firewall_rule(http_rule)
+
+ # Creating Static NAT rule for the VM in the Public tier
+ public_ip = self.acquire_PublicIPAddress(public_tier, vpc)
+ self.validate_PublicIPAddress(public_ip, public_tier)
+ self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier)
+ self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm)
+
+ # VSD verification
+ self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc)
+
+ # Adding Network ACL rule in the Public tier
+ self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...")
+ public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier)
+
+ # VSD verification
+ self.verify_vsd_firewall_rule(public_ssh_rule)
+
+ # Internal LB (wget) traffic tests
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ wget_file_1 = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ wget_file_2 = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_3.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+
+ # Verifying Internal LB (wget) traffic tests
+ self.verify_lb_wget_file(wget_file_1, [internal_vm_1, internal_vm_1_1, internal_vm_1_2])
+ self.verify_lb_wget_file(wget_file_2, [internal_vm_2, internal_vm_2_1, internal_vm_2_2])
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="true")
+ def test_06_nuage_internallb_algorithms_traffic(self):
+ """Test Nuage VSP VPC Internal LB functionality with different LB algorithms by performing (wget) traffic tests
+ within a VPC
+ """
+
+ # Repeat the tests in the testcase "test_05_nuage_internallb_traffic" with different Internal LB algorithms:
+ # 1. Round Robin
+ # 2. Least connections
+ # 3. Source
+ # Verify the above Internal LB algorithms by performing multiple (wget) traffic tests within a VPC.
+ # Delete all the created objects (cleanup).
+
+ # Creating a VPC offering
+ self.debug("Creating Nuage VSP VPC offering with Internal LB service...")
+ vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"])
+ self.validate_VpcOffering(vpc_off, state="Enabled")
+
+ # Creating a VPC
+ self.debug("Creating a VPC with Internal LB service...")
+ vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16')
+ self.validate_Vpc(vpc, state="Enabled")
+
+ # Creating network offerings
+ self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...")
+ net_off_1 = self.create_NetworkOffering(
+ self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"])
+ self.validate_NetworkOffering(net_off_1, state="Enabled")
+
+ self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...")
+ net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"])
+ self.validate_NetworkOffering(net_off_2, state="Enabled")
+
+ # Creating VPC networks in the VPC, and deploying VMs
+ self.debug("Creating a VPC network with Internal LB service...")
+ internal_tier = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc)
+ self.validate_Network(internal_tier, state="Implemented")
+ vr = self.get_Router(internal_tier)
+ self.check_Router_state(vr, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ internal_vm = self.create_VM(internal_tier)
+ self.check_VM_state(internal_vm, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(internal_vm)
+
+ self.debug("Creating a VPC network without Internal LB service...")
+ public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc)
+ self.validate_Network(public_tier, state="Implemented")
+ vr = self.get_Router(public_tier)
+ self.check_Router_state(vr, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ public_vm = self.create_VM(public_tier)
+ self.check_VM_state(public_vm, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(public_vm)
+
+ # Creating Internal LB Rules in the Internal tier with Round Robin Algorithm
+ self.debug("Creating two Internal LB Rules (SSH & HTTP) with Round Robin Algorithm...")
+ int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm])
+ self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm])
+ int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier,
+ vm_array=[internal_vm],
+ services=self.test_data["internal_lbrule_http"],
+ source_ip=int_lb_rule_1.sourceipaddress
+ )
+ self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm])
+
+ # Validating InternalLbVm deployment and state
+ int_lb_vm_1 = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm_1)
+
+ # Deploying more VMs in the Internal tier
+ self.debug("Deploying two more VMs in network - %s" % internal_tier.name)
+ internal_vm_1 = self.create_VM(internal_tier)
+ internal_vm_2 = self.create_VM(internal_tier)
+
+ # VSD verification
+ self.verify_vsd_vm(internal_vm_1)
+ self.verify_vsd_vm(internal_vm_2)
+
+ # Adding newly deployed VMs to the created Internal LB rules
+ self.debug("Adding two more virtual machines to the created Internal LB rules...")
+ int_lb_rule_1.assign(self.api_client, [internal_vm_1, internal_vm_2])
+ self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active",
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2])
+ int_lb_rule_2.assign(self.api_client, [internal_vm_1, internal_vm_2])
+ self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active",
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2])
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm_1)
+
+ # Creating Internal LB Rules in the Internal tier with Least connections Algorithm
+ self.debug("Creating two Internal LB Rules (SSH & HTTP) with Least connections Algorithm...")
+ self.test_data["internal_lbrule"]["algorithm"] = "leastconn"
+ int_lb_rule_3 = self.create_Internal_LB_Rule(internal_tier,
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2],
+ services=self.test_data["internal_lbrule"]
+ )
+ self.validate_Internal_LB_Rule(int_lb_rule_3, state="Active",
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2])
+ self.test_data["internal_lbrule_http"]["algorithm"] = "leastconn"
+ int_lb_rule_4 = self.create_Internal_LB_Rule(internal_tier,
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2],
+ services=self.test_data["internal_lbrule_http"],
+ source_ip=int_lb_rule_3.sourceipaddress
+ )
+ self.validate_Internal_LB_Rule(int_lb_rule_4, state="Active",
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2])
+
+ # Validating InternalLbVm deployment and state
+ int_lb_vm_2 = self.get_InternalLbVm(internal_tier, int_lb_rule_3.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_3.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm_2)
+
+ # Creating Internal LB Rules in the Internal tier with Source Algorithm
+ self.debug("Creating two Internal LB Rules (SSH & HTTP) with Source Algorithm...")
+ self.test_data["internal_lbrule"]["algorithm"] = "source"
+ int_lb_rule_5 = self.create_Internal_LB_Rule(internal_tier,
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2],
+ services=self.test_data["internal_lbrule"]
+ )
+ self.validate_Internal_LB_Rule(int_lb_rule_5, state="Active",
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2])
+ self.test_data["internal_lbrule_http"]["algorithm"] = "source"
+ int_lb_rule_6 = self.create_Internal_LB_Rule(internal_tier,
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2],
+ services=self.test_data["internal_lbrule_http"],
+ source_ip=int_lb_rule_5.sourceipaddress
+ )
+ self.validate_Internal_LB_Rule(int_lb_rule_6, state="Active",
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2])
+
+ # Validating InternalLbVm deployment and state
+ int_lb_vm_3 = self.get_InternalLbVm(internal_tier, int_lb_rule_5.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_5.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm_3)
+
+ # Adding Network ACL rules in the Internal tier
+ self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...")
+ ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=internal_tier)
+ http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier)
+
+ # VSD verification
+ self.verify_vsd_firewall_rule(ssh_rule)
+ self.verify_vsd_firewall_rule(http_rule)
+
+ # Creating Static NAT rule for the VM in the Public tier
+ public_ip = self.acquire_PublicIPAddress(public_tier, vpc)
+ self.validate_PublicIPAddress(public_ip, public_tier)
+ self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier)
+ self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm)
+
+ # VSD verification
+ self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc)
+
+ # Adding Network ACL rule in the Public tier
+ self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...")
+ public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier)
+
+ # VSD verification
+ self.verify_vsd_firewall_rule(public_ssh_rule)
+
+ # Internal LB (wget) traffic tests with Round Robin Algorithm
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ self.validate_internallb_algorithm_traffic(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"],
+ [internal_vm, internal_vm_1, internal_vm_2],
+ "roundrobin"
+ )
+
+ # Internal LB (wget) traffic tests with Least connections Algorithm
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ self.validate_internallb_algorithm_traffic(ssh_client,
+ int_lb_rule_3.sourceipaddress,
+ self.test_data["http_rule"]["publicport"],
+ [internal_vm, internal_vm_1, internal_vm_2],
+ "leastconn"
+ )
+
+ # Internal LB (wget) traffic tests with Source Algorithm
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ self.validate_internallb_algorithm_traffic(ssh_client,
+ int_lb_rule_5.sourceipaddress,
+ self.test_data["http_rule"]["publicport"],
+ [internal_vm, internal_vm_1, internal_vm_2],
+ "source"
+ )
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="true")
+ def test_07_nuage_internallb_vpc_network_restarts_traffic(self):
+ """Test Nuage VSP VPC Internal LB functionality with restarts of VPC network components by performing (wget)
+ traffic tests within a VPC
+ """
+
+ # Repeat the tests in the testcase "test_05_nuage_internallb_traffic" with restarts of VPC networks (tiers):
+ # 1. Restart tier with InternalLbVm (cleanup = false), verify that the InternalLbVm gets destroyed and deployed
+ # again in the Internal tier.
+ # 2. Restart tier with InternalLbVm (cleanup = true), verify that the InternalLbVm gets destroyed and deployed
+ # again in the Internal tier.
+ # 3. Restart tier without InternalLbVm (cleanup = false), verify that this restart has no effect on the
+ # InternalLbVm functionality.
+ # 4. Restart tier without InternalLbVm (cleanup = true), verify that this restart has no effect on the
+ # InternalLbVm functionality.
+ # 5. Stop all the VMs configured with InternalLbVm, verify that the InternalLbVm gets destroyed in the Internal
+ # tier.
+ # 6. Start all the VMs configured with InternalLbVm, verify that the InternalLbVm gets deployed again in the
+ # Internal tier.
+ # 7. Restart VPC (cleanup = false), verify that the VPC VR gets rebooted and this restart has no effect on the
+ # InternalLbVm functionality.
+ # 7. Restart VPC (cleanup = true), verify that the VPC VR gets rebooted and this restart has no effect on the
+ # InternalLbVm functionality.
+ # Verify the above restarts of VPC networks (tiers) by performing (wget) traffic tests within a VPC.
+ # Delete all the created objects (cleanup).
+
+ # Creating a VPC offering
+ self.debug("Creating Nuage VSP VPC offering with Internal LB service...")
+ vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"])
+ self.validate_VpcOffering(vpc_off, state="Enabled")
+
+ # Creating a VPC
+ self.debug("Creating a VPC with Internal LB service...")
+ vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16')
+ self.validate_Vpc(vpc, state="Enabled")
+
+ # Creating network offerings
+ self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...")
+ net_off_1 = self.create_NetworkOffering(
+ self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"])
+ self.validate_NetworkOffering(net_off_1, state="Enabled")
+
+ self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...")
+ net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"])
+ self.validate_NetworkOffering(net_off_2, state="Enabled")
+
+ # Creating VPC networks in the VPC, and deploying VMs
+ self.debug("Creating a VPC network with Internal LB service...")
+ internal_tier = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc)
+ self.validate_Network(internal_tier, state="Implemented")
+ vr = self.get_Router(internal_tier)
+ self.check_Router_state(vr, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ internal_vm = self.create_VM(internal_tier)
+ self.check_VM_state(internal_vm, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(internal_vm)
+
+ self.debug("Creating a VPC network without Internal LB service...")
+ public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc)
+ self.validate_Network(public_tier, state="Implemented")
+ vr = self.get_Router(public_tier)
+ self.check_Router_state(vr, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ public_vm = self.create_VM(public_tier)
+ self.check_VM_state(public_vm, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(public_vm)
+
+ # Creating Internal LB Rules in the Internal tier
+ self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...")
+ int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm])
+ self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm])
+ int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier,
+ vm_array=[internal_vm],
+ services=self.test_data["internal_lbrule_http"],
+ source_ip=int_lb_rule_1.sourceipaddress
+ )
+ self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm])
+
+ # Validating InternalLbVm deployment and state
+ int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Deploying more VMs in the Internal tier
+ self.debug("Deploying two more VMs in network - %s" % internal_tier.name)
+ internal_vm_1 = self.create_VM(internal_tier)
+ internal_vm_2 = self.create_VM(internal_tier)
+
+ # VSD verification
+ self.verify_vsd_vm(internal_vm_1)
+ self.verify_vsd_vm(internal_vm_2)
+
+ # Adding newly deployed VMs to the created Internal LB rules
+ self.debug("Adding two more virtual machines to the created Internal LB rules...")
+ int_lb_rule_1.assign(self.api_client, [internal_vm_1, internal_vm_2])
+ self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active",
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2])
+ int_lb_rule_2.assign(self.api_client, [internal_vm_1, internal_vm_2])
+ self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active",
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2])
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Adding Network ACL rules in the Internal tier
+ self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...")
+ ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=internal_tier)
+ http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier)
+
+ # VSD verification
+ self.verify_vsd_firewall_rule(ssh_rule)
+ self.verify_vsd_firewall_rule(http_rule)
+
+ # Creating Static NAT rule for the VM in the Public tier
+ public_ip = self.acquire_PublicIPAddress(public_tier, vpc)
+ self.validate_PublicIPAddress(public_ip, public_tier)
+ self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier)
+ self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm)
+
+ # VSD verification
+ self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc)
+
+ # Adding Network ACL rule in the Public tier
+ self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...")
+ public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier)
+
+ # VSD verification
+ self.verify_vsd_firewall_rule(public_ssh_rule)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
+
+ # Restart Internal tier (cleanup = false)
+ # InternalLbVm gets destroyed and deployed again in the Internal tier
+ self.debug("Restarting the Internal tier without cleanup...")
+ Network.restart(internal_tier, self.api_client, cleanup=False)
+ self.validate_Network(internal_tier, state="Implemented")
+ self.check_Router_state(vr, state="Running")
+ self.check_VM_state(internal_vm, state="Running")
+ self.check_VM_state(internal_vm_1, state="Running")
+ self.check_VM_state(internal_vm_2, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(internal_vm)
+ self.verify_vsd_vm(internal_vm_1)
+ self.verify_vsd_vm(internal_vm_2)
+ self.verify_vsd_firewall_rule(ssh_rule)
+ self.verify_vsd_firewall_rule(http_rule)
+
+ # Validating InternalLbVm state
+ # InternalLbVm gets destroyed and deployed again in the Internal tier
+ int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ tries = 0
+ while tries < 10:
+ try:
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+ except Exception as e:
+ self.debug("Failed to wget file via the InternalLbVm after re-starting the Internal tier: %s" % e)
+ self.debug("Waiting for the InternalLbVm in the Internal tier to be fully resolved for (wget) traffic "
+ "test...")
+ time.sleep(30)
+ tries += 1
+ continue
+ self.debug("Internal LB (wget) traffic test is successful after re-starting the Internal tier")
+ break
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
+
+ # Restart Internal tier (cleanup = true)
+ # InternalLbVm gets destroyed and deployed again in the Internal tier
+ self.debug("Restarting the Internal tier with cleanup...")
+ Network.restart(internal_tier, self.api_client, cleanup=True)
+ self.validate_Network(internal_tier, state="Implemented")
+ self.check_Router_state(vr, state="Running")
+ self.check_VM_state(internal_vm, state="Running")
+ self.check_VM_state(internal_vm_1, state="Running")
+ self.check_VM_state(internal_vm_2, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(internal_vm)
+ self.verify_vsd_vm(internal_vm_1)
+ self.verify_vsd_vm(internal_vm_2)
+ self.verify_vsd_firewall_rule(ssh_rule)
+ self.verify_vsd_firewall_rule(http_rule)
+
+ # Validating InternalLbVm state
+ # InternalLbVm gets destroyed and deployed again in the Internal tier
+ int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ tries = 0
+ while tries < 10:
+ try:
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+ except Exception as e:
+ self.debug("Failed to wget file via the InternalLbVm after re-starting the Internal tier with cleanup: "
+ "%s" % e)
+ self.debug("Waiting for the InternalLbVm in the Internal tier to be fully resolved for (wget) traffic "
+ "test...")
+ time.sleep(30)
+ tries += 1
+ continue
+ self.debug("Internal LB (wget) traffic test is successful after re-starting the Internal tier with cleanup")
+ break
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
+
+ # Restart Public tier (cleanup = false)
+ # This restart has no effect on the InternalLbVm functionality
+ self.debug("Restarting the Public tier without cleanup...")
+ Network.restart(public_tier, self.api_client, cleanup=False)
+ self.validate_Network(public_tier, state="Implemented")
+ self.check_Router_state(vr, state="Running")
+ self.check_VM_state(public_vm, state="Running")
+ self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm)
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(public_vm)
+ self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc)
+ self.verify_vsd_firewall_rule(public_ssh_rule)
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
+
+ # Restart Public tier (cleanup = true)
+ # This restart has no effect on the InternalLbVm functionality
+ self.debug("Restarting the Public tier with cleanup...")
+ Network.restart(public_tier, self.api_client, cleanup=True)
+ self.validate_Network(public_tier, state="Implemented")
+ self.check_Router_state(vr, state="Running")
+ self.check_VM_state(public_vm, state="Running")
+ self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm)
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(public_vm)
+ self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc)
+ self.verify_vsd_firewall_rule(public_ssh_rule)
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
+
+ # Stopping VMs in the Internal tier
+ # wget traffic test fails as all the VMs in the Internal tier are in stopped state
+ self.debug("Stopping all the VMs in the Internal tier...")
+ internal_vm.stop(self.api_client)
+ internal_vm_1.stop(self.api_client)
+ internal_vm_2.stop(self.api_client)
+ self.validate_Network(internal_tier, state="Implemented")
+ self.check_Router_state(vr, state="Running")
+ self.check_VM_state(internal_vm, state="Stopped")
+ self.check_VM_state(internal_vm_1, state="Stopped")
+ self.check_VM_state(internal_vm_2, state="Stopped")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(internal_vm, stopped=True)
+ self.verify_vsd_vm(internal_vm_1, stopped=True)
+ self.verify_vsd_vm(internal_vm_2, stopped=True)
+ self.verify_vsd_firewall_rule(ssh_rule)
+ self.verify_vsd_firewall_rule(http_rule)
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ with self.assertRaises(Exception):
+ self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+ self.debug("Failed to wget file as all the VMs in the Internal tier are in stopped state")
+
+ # Starting VMs in the Internal tier
+ # wget traffic test succeeds as all the VMs in the Internal tier are back in running state
+ self.debug("Starting all the VMs in the Internal tier...")
+ internal_vm.start(self.api_client)
+ internal_vm_1.start(self.api_client)
+ internal_vm_2.start(self.api_client)
+ self.validate_Network(internal_tier, state="Implemented")
+ self.check_Router_state(vr, state="Running")
+ self.check_VM_state(internal_vm, state="Running")
+ self.check_VM_state(internal_vm_1, state="Running")
+ self.check_VM_state(internal_vm_2, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(internal_vm)
+ self.verify_vsd_vm(internal_vm_1)
+ self.verify_vsd_vm(internal_vm_2)
+ self.verify_vsd_firewall_rule(ssh_rule)
+ self.verify_vsd_firewall_rule(http_rule)
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ tries = 0
+ while tries < 10:
+ try:
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+ except Exception as e:
+ self.debug("Failed to wget file via the InternalLbVm after re-starting all the VMs in the Internal tier"
+ ": %s" % e)
+ self.debug("Waiting for the InternalLbVm and all the VMs in the Internal tier to be fully resolved for "
+ "(wget) traffic test...")
+ time.sleep(30)
+ tries += 1
+ continue
+ self.debug("Internal LB (wget) traffic test is successful after re-starting all the VMs in the Internal "
+ "tier")
+ break
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
+
+ # Restarting VPC (cleanup = false)
+ # VPC VR gets destroyed and deployed again in the VPC
+ # This restart has no effect on the InternalLbVm functionality
+ self.debug("Restarting the VPC without cleanup...")
+ self.restart_Vpc(vpc, cleanup=False)
+ self.validate_Network(public_tier, state="Implemented")
+ self.validate_Network(internal_tier, state="Implemented")
+ vr = self.get_Router(public_tier)
+ self.check_Router_state(vr, state="Running")
+ self.check_VM_state(public_vm, state="Running")
+ self.check_VM_state(internal_vm, state="Running")
+ self.check_VM_state(internal_vm_1, state="Running")
+ self.check_VM_state(internal_vm_2, state="Running")
+ self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm)
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(public_vm)
+ self.verify_vsd_vm(internal_vm)
+ self.verify_vsd_vm(internal_vm_1)
+ self.verify_vsd_vm(internal_vm_2)
+ self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc)
+ self.verify_vsd_firewall_rule(public_ssh_rule)
+ self.verify_vsd_firewall_rule(ssh_rule)
+ self.verify_vsd_firewall_rule(http_rule)
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
+
+ # Restarting VPC (cleanup = true)
+ # VPC VR gets destroyed and deployed again in the VPC
+ # This restart has no effect on the InternalLbVm functionality
+ self.debug("Restarting the VPC with cleanup...")
+ self.restart_Vpc(vpc, cleanup=True)
+ self.validate_Network(public_tier, state="Implemented")
+ self.validate_Network(internal_tier, state="Implemented")
+ vr = self.get_Router(public_tier)
+ self.check_Router_state(vr, state="Running")
+ self.check_VM_state(public_vm, state="Running")
+ self.check_VM_state(internal_vm, state="Running")
+ self.check_VM_state(internal_vm_1, state="Running")
+ self.check_VM_state(internal_vm_2, state="Running")
+ self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm)
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(public_vm)
+ self.verify_vsd_vm(internal_vm)
+ self.verify_vsd_vm(internal_vm_1)
+ self.verify_vsd_vm(internal_vm_2)
+ self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc)
+ self.verify_vsd_firewall_rule(public_ssh_rule)
+ self.verify_vsd_firewall_rule(ssh_rule)
+ self.verify_vsd_firewall_rule(http_rule)
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="true")
+ def test_08_nuage_internallb_appliance_operations_traffic(self):
+ """Test Nuage VSP VPC Internal LB functionality with InternalLbVm appliance operations by performing (wget)
+ traffic tests within a VPC
+ """
+
+ # Repeat the tests in the testcase "test_05_nuage_internallb_traffic" with InternalLbVm appliance operations:
+ # 1. Verify the InternalLbVm deployment by creating the Internal LB Rules when the VPC VR is in Stopped state,
+ # VPC VR has no effect on the InternalLbVm functionality.
+ # 2. Stop the InternalLbVm when the VPC VR is in Stopped State
+ # 3. Start the InternalLbVm when the VPC VR is in Stopped state
+ # 4. Stop the InternalLbVm when the VPC VR is in Running State
+ # 5. Start the InternalLbVm when the VPC VR is in Running state
+ # 6. Force stop the InternalLbVm when the VPC VR is in Running State
+ # 7. Start the InternalLbVm when the VPC VR is in Running state
+ # Verify the above restarts of VPC networks by performing (wget) traffic tests within a VPC.
+ # Delete all the created objects (cleanup).
+
+ # Creating a VPC offering
+ self.debug("Creating Nuage VSP VPC offering with Internal LB service...")
+ vpc_off = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering_lb"])
+ self.validate_VpcOffering(vpc_off, state="Enabled")
+
+ # Creating a VPC
+ self.debug("Creating a VPC with Internal LB service...")
+ vpc = self.create_Vpc(vpc_off, cidr='10.1.0.0/16')
+ self.validate_Vpc(vpc, state="Enabled")
+
+ # Creating network offerings
+ self.debug("Creating Nuage VSP VPC Network offering with Internal LB service...")
+ net_off_1 = self.create_NetworkOffering(
+ self.test_data["nuagevsp"]["vpc_network_offering_internal_lb"])
+ self.validate_NetworkOffering(net_off_1, state="Enabled")
+
+ self.debug("Creating Nuage VSP VPC Network offering without Internal LB service...")
+ net_off_2 = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"])
+ self.validate_NetworkOffering(net_off_2, state="Enabled")
+
+ # Creating VPC networks in the VPC, and deploying VMs
+ self.debug("Creating a VPC network with Internal LB service...")
+ internal_tier = self.create_Network(net_off_1, gateway='10.1.1.1', vpc=vpc)
+ self.validate_Network(internal_tier, state="Implemented")
+ vr = self.get_Router(internal_tier)
+ self.check_Router_state(vr, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ internal_vm = self.create_VM(internal_tier)
+ self.check_VM_state(internal_vm, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(internal_vm)
+
+ self.debug("Creating a VPC network without Internal LB service...")
+ public_tier = self.create_Network(net_off_2, gateway='10.1.2.1', vpc=vpc)
+ self.validate_Network(public_tier, state="Implemented")
+ vr = self.get_Router(public_tier)
+ self.check_Router_state(vr, state="Running")
+
+ self.debug("Deploying a VM in the created VPC network...")
+ public_vm = self.create_VM(public_tier)
+ self.check_VM_state(public_vm, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(public_vm)
+
+ # Stopping the VPC VR
+ # VPC VR has no effect on the InternalLbVm functionality
+ Router.stop(self.api_client, id=vr.id)
+ self.check_Router_state(vr, state="Stopped")
+ self.validate_Network(public_tier, state="Implemented")
+ self.validate_Network(internal_tier, state="Implemented")
+
+ # VSD verification
+ self.verify_vsd_router(vr, stopped=True)
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+
+ # Creating Internal LB Rules in the Internal tier
+ self.debug("Creating two Internal LB Rules (SSH & HTTP) using the same Load Balancing source IP Address...")
+ int_lb_rule_1 = self.create_Internal_LB_Rule(internal_tier, vm_array=[internal_vm])
+ self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active", vm_array=[internal_vm])
+ int_lb_rule_2 = self.create_Internal_LB_Rule(internal_tier,
+ vm_array=[internal_vm],
+ services=self.test_data["internal_lbrule_http"],
+ source_ip=int_lb_rule_1.sourceipaddress
+ )
+ self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active", vm_array=[internal_vm])
+
+ # Validating InternalLbVm deployment and state
+ int_lb_vm = self.get_InternalLbVm(internal_tier, int_lb_rule_1.sourceipaddress)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Deploying more VMs in the Internal tier
+ self.debug("Deploying two more VMs in network - %s" % internal_tier.name)
+ internal_vm_1 = self.create_VM(internal_tier)
+ internal_vm_2 = self.create_VM(internal_tier)
+
+ # VSD verification
+ self.verify_vsd_vm(internal_vm_1)
+ self.verify_vsd_vm(internal_vm_2)
+
+ # Adding newly deployed VMs to the created Internal LB rules
+ self.debug("Adding two more virtual machines to the created Internal LB rules...")
+ int_lb_rule_1.assign(self.api_client, [internal_vm_1, internal_vm_2])
+ self.validate_Internal_LB_Rule(int_lb_rule_1, state="Active",
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2])
+ int_lb_rule_2.assign(self.api_client, [internal_vm_1, internal_vm_2])
+ self.validate_Internal_LB_Rule(int_lb_rule_2, state="Active",
+ vm_array=[internal_vm, internal_vm_1, internal_vm_2])
+
+ # Validating InternalLbVm state
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Adding Network ACL rules in the Internal tier
+ self.debug("Adding Network ACL rules to make the created Internal LB rules (SSH & HTTP) accessible...")
+ ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=internal_tier)
+ http_rule = self.create_NetworkAclRule(self.test_data["http_rule"], network=internal_tier)
+
+ # VSD verification
+ self.verify_vsd_firewall_rule(ssh_rule)
+ self.verify_vsd_firewall_rule(http_rule)
+
+ # Creating Static NAT rule for the VM in the Public tier
+ public_ip = self.acquire_PublicIPAddress(public_tier, vpc)
+ self.validate_PublicIPAddress(public_ip, public_tier)
+ self.create_StaticNatRule_For_VM(public_vm, public_ip, public_tier)
+ self.validate_PublicIPAddress(public_ip, public_tier, static_nat=True, vm=public_vm)
+
+ # VSD verification
+ self.verify_vsd_floating_ip(public_tier, public_vm, public_ip.ipaddress, vpc)
+
+ # Adding Network ACL rule in the Public tier
+ self.debug("Adding Network ACL rule to make the created NAT rule (SSH) accessible...")
+ public_ssh_rule = self.create_NetworkAclRule(self.test_data["ingress_rule"], network=public_tier)
+
+ # VSD verification
+ self.verify_vsd_firewall_rule(public_ssh_rule)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
+
+ # # Stopping the InternalLbVm when the VPC VR is in Stopped state
+ self.stop_InternalLbVm(int_lb_vm)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Stopped")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm, stopped=True)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ with self.assertRaises(Exception):
+ self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+ self.debug("Failed to wget file as the InternalLbVm is in stopped state")
+
+ # # Starting the InternalLbVm when the VPC VR is in Stopped state
+ self.start_InternalLbVm(int_lb_vm)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ tries = 0
+ while tries < 10:
+ try:
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+ except Exception as e:
+ self.debug("Failed to wget file via the InternalLbVm after re-starting the InternalLbVm appliance: %s"
+ % e)
+ self.debug("Waiting for the InternalLbVm to be fully resolved for (wget) traffic test...")
+ time.sleep(30)
+ tries += 1
+ continue
+ self.debug("Internal LB (wget) traffic test is successful after re-starting the InternalLbVm appliance")
+ break
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
+
+ # Starting the VPC VR
+ # VPC VR has no effect on the InternalLbVm functionality
+ Router.start(self.api_client, id=vr.id)
+ self.check_Router_state(vr)
+ self.validate_Network(public_tier, state="Implemented")
+ self.validate_Network(internal_tier, state="Implemented")
+
+ # VSD verification
+ self.verify_vsd_router(vr)
+ self.verify_vsd_network(self.domain.id, public_tier, vpc)
+ self.verify_vsd_network(self.domain.id, internal_tier, vpc)
+
+ # # Stopping the InternalLbVm when the VPC VR is in Running state
+ self.stop_InternalLbVm(int_lb_vm)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Stopped")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm, stopped=True)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ with self.assertRaises(Exception):
+ self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+ self.debug("Failed to wget file as the InternalLbVm is in stopped state")
+
+ # # Starting the InternalLbVm when the VPC VR is in Running state
+ self.start_InternalLbVm(int_lb_vm)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ tries = 0
+ while tries < 10:
+ try:
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+ except Exception as e:
+ self.debug("Failed to wget file via the InternalLbVm after re-starting the InternalLbVm appliance: %s"
+ % e)
+ self.debug("Waiting for the InternalLbVm to be fully resolved for (wget) traffic test...")
+ time.sleep(30)
+ tries += 1
+ continue
+ self.debug("Internal LB (wget) traffic test is successful after re-starting the InternalLbVm appliance")
+ break
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
+
+ # # Force Stopping the InternalLbVm when the VPC VR is in Running state
+ self.stop_InternalLbVm(int_lb_vm, force=True)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Stopped")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm, stopped=True)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ with self.assertRaises(Exception):
+ self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+ self.debug("Failed to wget file as the InternalLbVm is in stopped state")
+
+ # # Starting the InternalLbVm when the VPC VR is in Running state
+ self.start_InternalLbVm(int_lb_vm)
+ self.check_InternalLbVm_state(internal_tier, int_lb_rule_1.sourceipaddress, state="Running")
+
+ # VSD Verification
+ self.verify_vsd_lb_device(int_lb_vm)
+
+ # Internal LB (wget) traffic test
+ ssh_client = self.ssh_into_VM(public_vm, public_ip)
+ tries = 0
+ while tries < 10:
+ try:
+ wget_file = self.wget_from_vm_cmd(ssh_client,
+ int_lb_rule_1.sourceipaddress,
+ self.test_data["http_rule"]["publicport"]
+ )
+ except Exception as e:
+ self.debug("Failed to wget file via the InternalLbVm after re-starting the InternalLbVm appliance: %s"
+ % e)
+ self.debug("Waiting for the InternalLbVm to be fully resolved for (wget) traffic test...")
+ time.sleep(30)
+ tries += 1
+ continue
+ self.debug("Internal LB (wget) traffic test is successful after re-starting the InternalLbVm appliance")
+ break
+
+ # Verifying Internal LB (wget) traffic test
+ self.verify_lb_wget_file(wget_file, [internal_vm, internal_vm_1, internal_vm_2])
diff --git a/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py b/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py
new file mode 100644
index 0000000..7dec5a6
--- /dev/null
+++ b/test/integration/plugins/nuagevsp/test_nuage_vpc_network.py
@@ -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.
+
+""" Component tests for basic VPC Network functionality with Nuage VSP SDN plugin
+"""
+# Import Local Modules
+from nuageTestCase import nuageTestCase
+from marvin.lib.base import Account, Zone
+# Import System Modules
+from nose.plugins.attrib import attr
+
+
+class TestNuageVpcNetwork(nuageTestCase):
+ """ Test basic VPC Network functionality with Nuage VSP SDN plugin
+ """
+
+ @classmethod
+ def setUpClass(cls, zone=None):
+ super(TestNuageVpcNetwork, cls).setUpClass(zone=zone)
+ return
+
+ def setUp(self):
+ # Create an account
+ self.account = Account.create(self.api_client,
+ self.test_data["account"],
+ admin=True,
+ domainid=self.domain.id
+ )
+ self.cleanup = [self.account]
+ return
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="false")
+ def test_nuage_vpc_network(self):
+ """ Test basic VPC Network functionality with Nuage VSP SDN plugin
+ """
+
+ # 1. Create Nuage VSP VPC offering, check if it is successfully created and enabled.
+ # 2. Create a VPC with Nuage VSP VPC offering, check if it is successfully created and enabled.
+ # 3. Create Nuage VSP VPC Network offering, check if it is successfully created and enabled.
+ # 4. Create an ACL list in the created VPC, and add an ACL item to it.
+ # 5. Create a VPC Network with Nuage VSP VPC Network offering and the created ACL list, check if it is
+ # successfully created, is in the "Implemented" state, and is added to the VPC VR.
+ # 6. Deploy a VM in the created VPC network, check if the VM is successfully deployed and is in the "Running"
+ # state.
+ # 7. Verify that the created ACL item is successfully implemented in Nuage VSP.
+ # 8. Delete all the created objects (cleanup).
+
+ # Creating a VPC offering
+ self.debug("Creating Nuage VSP VPC offering...")
+ vpc_offering = self.create_VpcOffering(self.test_data["nuagevsp"]["vpc_offering"])
+ self.validate_VpcOffering(vpc_offering, state="Enabled")
+
+ # Creating a VPC
+ self.debug("Creating a VPC with Nuage VSP VPC offering...")
+ vpc = self.create_Vpc(vpc_offering, cidr='10.1.0.0/16')
+ self.validate_Vpc(vpc, state="Enabled")
+
+ # Creating a network offering
+ self.debug("Creating Nuage VSP VPC Network offering...")
+ network_offering = self.create_NetworkOffering(self.test_data["nuagevsp"]["vpc_network_offering"])
+ self.validate_NetworkOffering(network_offering, state="Enabled")
+
+ # Creating an ACL list
+ acl_list = self.create_NetworkAclList(name="acl", description="acl", vpc=vpc)
+
+ # Creating an ACL item
+ acl_item = self.create_NetworkAclRule(self.test_data["ingress_rule"], acl_list=acl_list)
+
+ # Creating a VPC network in the VPC
+ self.debug("Creating a VPC network with Nuage VSP VPC Network offering...")
+ vpc_network = self.create_Network(network_offering, vpc=vpc, acl_list=acl_list)
+ self.validate_Network(vpc_network, state="Implemented")
+ vr = self.get_Router(vpc_network)
+ self.check_Router_state(vr, state="Running")
+
+ # Deploying a VM in the VPC network
+ vm = self.create_VM(vpc_network)
+ self.check_VM_state(vm, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, vpc_network, vpc)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(vm)
+
+ # VSD verification for ACL item
+ self.verify_vsd_firewall_rule(acl_item)
+
+ @attr(tags=["advanced", "nuagevsp", "multizone"], required_hardware="false")
+ def test_nuage_vpc_network_multizone(self):
+ """ Test basic VPC Network functionality with Nuage VSP SDN plugin on multiple zones
+ """
+
+ # Repeat the tests in the above testcase "test_nuage_vpc_network" on multiple zones
+
+ self.debug("Testing basic VPC Network functionality with Nuage VSP SDN plugin on multiple zones...")
+ zones = Zone.list(self.api_client)
+ if len(zones) == 1:
+ self.skipTest("There is only one Zone configured: skipping test")
+ for zone in zones:
+ self.debug("Zone - %s" % zone.name)
+ self.setUpClass(zone=zone)
+ self.test_nuage_vpc_network()
diff --git a/test/integration/plugins/nuagevsp/test_nuage_vsp.py b/test/integration/plugins/nuagevsp/test_nuage_vsp.py
new file mode 100644
index 0000000..d71d0c1
--- /dev/null
+++ b/test/integration/plugins/nuagevsp/test_nuage_vsp.py
@@ -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.
+
+""" P1 tests for Nuage VSP SDN plugin
+"""
+# Import Local Modules
+from nuageTestCase import nuageTestCase
+from marvin.lib.base import Account, Nuage
+from marvin.cloudstackAPI import deleteNuageVspDevice
+# Import System Modules
+from nose.plugins.attrib import attr
+import copy
+
+
+class TestNuageVsp(nuageTestCase):
+ """ Test Nuage VSP SDN plugin
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestNuageVsp, cls).setUpClass()
+ return
+
+ def setUp(self):
+ # Create an account
+ self.account = Account.create(self.api_client,
+ self.test_data["account"],
+ admin=True,
+ domainid=self.domain.id
+ )
+ self.cleanup = [self.account]
+ return
+
+ # validate_NuageVspDevice - Validates the addition of Nuage VSP device in the Nuage VSP Physical Network
+ def validate_NuageVspDevice(self):
+ """Validates the addition of Nuage VSP device in the Nuage VSP Physical Network"""
+ self.debug("Validating the addition of Nuage VSP device in the Nuage VSP Physical Network - %s" %
+ self.vsp_physical_network.id)
+ nuage_vsp_device = Nuage.list(self.api_client,
+ physicalnetworkid=self.vsp_physical_network.id
+ )
+ self.assertEqual(isinstance(nuage_vsp_device, list), True,
+ "List Nuage VSP device should return a valid list"
+ )
+ self.debug("Successfully validated the addition of Nuage VSP device in the Nuage VSP Physical Network - %s" %
+ self.vsp_physical_network.id)
+
+ # delete_NuageVspDevice - Deletes the Nuage VSP device in the Nuage VSP Physical Network
+ def delete_NuageVspDevice(self):
+ """Deletes the Nuage VSP device in the Nuage VSP Physical Network"""
+ self.debug("Deleting the Nuage VSP device in the Nuage VSP Physical Network - %s" %
+ self.vsp_physical_network.id)
+ nuage_vsp_device = Nuage.list(self.api_client,
+ physicalnetworkid=self.vsp_physical_network.id
+ )[0]
+ cmd = deleteNuageVspDevice.deleteNuageVspDeviceCmd()
+ cmd.vspdeviceid = nuage_vsp_device.vspdeviceid
+ self.api_client.deleteNuageVspDevice(cmd)
+ self.debug("Successfully deleted the Nuage VSP device in the Nuage VSP Physical Network - %s" %
+ self.vsp_physical_network.id)
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="false")
+ def test_nuage_vsp_device(self):
+ """ Test Nuage VSP device in the Nuage VSP Physical Network
+ """
+
+ # 1. Verify that the Nuage VSP network service provider is successfully created and enabled in the Nuage VSP
+ # Physical Network.
+ # 2. Verify that the Nuage VSP device is successfully created in the Nuage VSP Physical Network.
+ # 3. Delete the Nuage VSP device in the Nuage VSP Physical Network, verify that the Nuage VSP device is
+ # successfully deleted in the Nuage VSP Physical Network.
+ # 4. Add the Nuage VSP device in the Nuage VSP Physical Network with invalid VSD credentials, verify that the
+ # Nuage VSP device failed to add in the Nuage VSP Physical Network.
+ # 5. Add the Nuage VSP device in the Nuage VSP Physical Network with valid VSD credentials, verify that the
+ # Nuage VSP device is successfully added in the Nuage VSP Physical Network.
+
+ # Nuage VSP network service provider validation
+ self.debug("Validating the Nuage VSP network service provider in the Nuage VSP Physical Network...")
+ self.validate_NetworkServiceProvider("NuageVsp", state="Enabled")
+
+ # Nuage VSP device validation
+ self.debug("Validating the Nuage VSP device in the Nuage VSP Physical Network...")
+ self.validate_NuageVspDevice()
+
+ # Nuage VSP device deletion
+ self.debug("Deleting the Nuage VSP device in the Nuage VSP Physical Network...")
+ self.delete_NuageVspDevice()
+
+ # Nuage VSP device validation
+ self.debug("Validating the Nuage VSP device in the Nuage VSP Physical Network...")
+ with self.assertRaises(Exception):
+ self.validate_NuageVspDevice()
+ self.debug("Successfully deleted the Nuage VSP device in the Nuage VSP Physical Network")
+
+ # Adding the Nuage VSP device with invalid VSD credentials
+ self.debug("Adding the Nuage VSP device in the Nuage VSP Physical Network with invalid VSD credentials...")
+ vsd_info = self.nuage_vsp_device.__dict__
+ invalid_vsd_info = copy.deepcopy(vsd_info)
+ invalid_vsd_info["password"] = ""
+ with self.assertRaises(Exception):
+ Nuage.add(self.api_client, invalid_vsd_info, self.vsp_physical_network.id)
+ self.debug("Failed to add the Nuage VSP device in the Nuage VSP Physical Network due to invalid VSD "
+ "credentials")
+
+ # Nuage VSP device validation
+ self.debug("Validating the Nuage VSP device in the Nuage VSP Physical Network...")
+ with self.assertRaises(Exception):
+ self.validate_NuageVspDevice()
+ self.debug("The Nuage VSP device is not added in the Nuage VSP Physical Network")
+
+ # Adding the Nuage VSP device with valid VSD credentials
+ self.debug("Adding the Nuage VSP device in the Nuage VSP Physical Network with valid VSD credentials...")
+ Nuage.add(self.api_client, vsd_info, self.vsp_physical_network.id)
+
+ # Nuage VSP device validation
+ self.debug("Validating the Nuage VSP device in the Nuage VSP Physical Network...")
+ self.validate_NuageVspDevice()
+
+ @attr(tags=["advanced", "nuagevsp"], required_hardware="false")
+ def test_nuage_vsp(self):
+ """ Test Nuage VSP SDN plugin with basic Isolated Network functionality
+ """
+
+ # 1. Verify that the Nuage VSP network service provider is successfully created and enabled.
+ # 2. Create and enable Nuage VSP Isolated Network offering, check if it is successfully created and enabled.
+ # 3. Create an Isolated Network with Nuage VSP Isolated Network offering, check if it is successfully created
+ # and is in the "Allocated" state.
+ # 4. Deploy a VM in the created Isolated network, check if the Isolated network state is changed to
+ # "Implemented", and both the VM & VR are successfully deployed and are in the "Running" state.
+ # 5. Deploy one more VM in the created Isolated network, check if the VM is successfully deployed and is in the
+ # "Running" state.
+ # 6. Delete the created Isolated Network after destroying its VMs, check if the Isolated network is successfully
+ # deleted.
+ # 7. Delete all the created objects (cleanup).
+
+ # Creating a network offering
+ self.debug("Creating and enabling Nuage VSP Isolated Network offering...")
+ network_offering = self.create_NetworkOffering(
+ self.test_data["nuagevsp"]["isolated_network_offering"])
+ self.validate_NetworkOffering(network_offering, state="Enabled")
+
+ # Creating a network
+ self.debug("Creating an Isolated Network with Nuage VSP Isolated Network offering...")
+ network = self.create_Network(network_offering)
+ self.validate_Network(network, state="Allocated")
+
+ # Deploying a VM in the network
+ vm_1 = self.create_VM(network)
+ self.validate_Network(network, state="Implemented")
+ vr = self.get_Router(network)
+ self.check_Router_state(vr, state="Running")
+ self.check_VM_state(vm_1, state="Running")
+
+ # VSD verification
+ self.verify_vsd_network(self.domain.id, network)
+ self.verify_vsd_router(vr)
+ self.verify_vsd_vm(vm_1)
+
+ # Deploying one more VM in the network
+ vm_2 = self.create_VM(network)
+ self.check_VM_state(vm_2, state="Running")
+
+ # VSD verification
+ self.verify_vsd_vm(vm_2)
+
+ # Deleting the network
+ self.debug("Deleting the Isolated Network with Nuage VSP Isolated Network offering...")
+ self.delete_VM(vm_1)
+ self.delete_VM(vm_2)
+ self.delete_Network(network)
+ with self.assertRaises(Exception):
+ self.validate_Network(network)
+ self.debug("Isolated Network successfully deleted in CloudStack")
+
+ # VSD verification
+ with self.assertRaises(Exception):
+ self.verify_vsd_network(self.domain.id, network)
+ self.debug("Isolated Network successfully deleted in VSD")
diff --git a/test/integration/plugins/solidfire/TestAddRemoveHosts.py b/test/integration/plugins/solidfire/TestAddRemoveHosts.py
new file mode 100644
index 0000000..518d022
--- /dev/null
+++ b/test/integration/plugins/solidfire/TestAddRemoveHosts.py
@@ -0,0 +1,710 @@
+# 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 logging
+import random
+import SignedAPICall
+import time
+import XenAPI
+
+# All tests inherit from cloudstackTestCase
+from marvin.cloudstackTestCase import cloudstackTestCase
+
+# Import Integration Libraries
+
+# base - contains all resources as entities and defines create, delete, list operations on them
+from marvin.lib.base import Account, ServiceOffering, User, Host, StoragePool, VirtualMachine
+
+# common - commonly used methods for all tests are listed here
+from marvin.lib.common import get_domain, get_template, get_zone, list_hosts, list_clusters, list_volumes
+
+# utils - utility classes for common cleanup, external library wrappers, etc.
+from marvin.lib.utils import cleanup_resources
+
+from solidfire import solidfire_element_api as sf_api
+
+
+class TestData:
+ account = "account"
+ capacityBytes = "capacitybytes"
+ capacityIops = "capacityiops"
+ clusterId = "clusterId"
+ computeOffering = "computeoffering"
+ displayText = "displaytext"
+ diskSize = "disksize"
+ domainId = "domainId"
+ hypervisor = "hypervisor"
+ login = "login"
+ mvip = "mvip"
+ name = "name"
+ newHost = "newHost"
+ newHostDisplayName = "newHostDisplayName"
+ osType = "ostype"
+ password = "password"
+ podId = "podid"
+ port = "port"
+ primaryStorage = "primarystorage"
+ primaryStorage2 = "primarystorage2"
+ provider = "provider"
+ scope = "scope"
+ solidFire = "solidfire"
+ storageTag = "SolidFire_SAN_1"
+ storageTag2 = "SolidFire_Volume_1"
+ tags = "tags"
+ url = "url"
+ urlOfNewHost = "urlOfNewHost"
+ user = "user"
+ username = "username"
+ virtualMachine = "virtualmachine"
+ volume_1 = "volume_1"
+ xenServer = "xenserver"
+ zoneId = "zoneid"
+
+ def __init__(self):
+ self.testdata = {
+ TestData.solidFire: {
+ TestData.mvip: "192.168.139.112",
+ TestData.login: "admin",
+ TestData.password: "admin",
+ TestData.port: 443,
+ TestData.url: "https://192.168.139.112:443"
+ },
+ TestData.xenServer: {
+ TestData.username: "root",
+ TestData.password: "solidfire"
+ },
+ TestData.urlOfNewHost: "https://192.168.129.243",
+ TestData.account: {
+ "email": "test@test.com",
+ "firstname": "John",
+ "lastname": "Doe",
+ TestData.username: "test",
+ TestData.password: "test"
+ },
+ TestData.user: {
+ "email": "user@test.com",
+ "firstname": "Jane",
+ "lastname": "Doe",
+ TestData.username: "testuser",
+ TestData.password: "password"
+ },
+ TestData.newHost: {
+ TestData.username: "root",
+ TestData.password: "solidfire",
+ TestData.url: "http://192.168.129.243",
+ TestData.podId : "1",
+ TestData.zoneId: "1"
+ },
+ TestData.primaryStorage: {
+ TestData.name: "SolidFire-%d" % random.randint(0, 100),
+ TestData.scope: "ZONE",
+ TestData.url: "MVIP=192.168.139.112;SVIP=10.10.8.112;" +
+ "clusterAdminUsername=admin;clusterAdminPassword=admin;" +
+ "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" +
+ "clusterDefaultBurstIopsPercentOfMaxIops=1.5;",
+ TestData.provider: "SolidFire",
+ TestData.tags: TestData.storageTag,
+ TestData.capacityIops: 4500000,
+ TestData.capacityBytes: 2251799813685248,
+ TestData.hypervisor: "Any"
+ },
+ TestData.primaryStorage2: {
+ TestData.name: "SolidFireShared-%d" % random.randint(0, 100),
+ TestData.scope: "CLUSTER",
+ TestData.url: "MVIP=192.168.139.112;SVIP=10.10.8.112;" +
+ "clusterAdminUsername=admin;clusterAdminPassword=admin;" +
+ "minIops=5000;maxIops=50000;burstIops=75000",
+ TestData.provider: "SolidFireShared",
+ TestData.tags: TestData.storageTag2,
+ TestData.capacityIops: 5000,
+ TestData.capacityBytes: 1099511627776,
+ TestData.hypervisor: "XenServer",
+ TestData.podId: 1
+ },
+ TestData.virtualMachine: {
+ TestData.name: "TestVM",
+ "displayname": "Test VM"
+ },
+ TestData.computeOffering: {
+ TestData.name: "SF_CO_1",
+ TestData.displayText: "SF_CO_1 (Min IOPS = 10,000; Max IOPS = 15,000)",
+ "cpunumber": 1,
+ "cpuspeed": 100,
+ "memory": 128,
+ "storagetype": "shared",
+ "customizediops": False,
+ "miniops": "10000",
+ "maxiops": "15000",
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag
+ },
+ TestData.volume_1: {
+ "diskname": "testvolume",
+ },
+ "volume2": {
+ "diskname": "testvolume2",
+ },
+ TestData.newHostDisplayName: "XenServer-6.5-3",
+ TestData.osType: "CentOS 5.6(64-bit) no GUI (XenServer)",
+ TestData.zoneId: 1,
+ TestData.clusterId: 1,
+ TestData.domainId: 1,
+ TestData.url: "192.168.129.50"
+ }
+
+
+class TestAddRemoveHosts(cloudstackTestCase):
+ _vag_id_should_be_non_zero_int_err_msg = "The SolidFire VAG ID should be a non-zero integer."
+ _sf_account_id_should_be_non_zero_int_err_msg = "The SolidFire account ID should be a non-zero integer."
+
+ @classmethod
+ def setUpClass(cls):
+ # Set up API client
+ testclient = super(TestAddRemoveHosts, cls).getClsTestClient()
+ cls.apiClient = testclient.getApiClient()
+ cls.dbConnection = testclient.getDbConnection()
+
+ cls.testdata = TestData().testdata
+
+ cls.xs_pool_master_ip = list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress
+
+ # Set up XenAPI connection
+ host_ip = "https://" + cls.xs_pool_master_ip
+
+ cls.xen_session = XenAPI.Session(host_ip)
+
+ xenserver = cls.testdata[TestData.xenServer]
+
+ cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password])
+
+ # Set up SolidFire connection
+ cls.sf_client = sf_api.SolidFireAPI(endpoint_dict=cls.testdata[TestData.solidFire])
+
+ # Get Resources from Cloud Infrastructure
+ cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId])
+ cls.cluster = list_clusters(cls.apiClient)[0]
+ cls.template = get_template(cls.apiClient, cls.zone.id, cls.testdata[TestData.osType])
+ cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId])
+
+ # Create test account
+ cls.account = Account.create(
+ cls.apiClient,
+ cls.testdata[TestData.account],
+ admin=1
+ )
+
+ # Set up connection to make customized API calls
+ user = User.create(
+ cls.apiClient,
+ cls.testdata[TestData.user],
+ account=cls.account.name,
+ domainid=cls.domain.id
+ )
+
+ url = cls.testdata[TestData.url]
+
+ api_url = "http://" + url + ":8080/client/api"
+ userkeys = User.registerUserKeys(cls.apiClient, user.id)
+
+ cls.cs_api = SignedAPICall.CloudStack(api_url, userkeys.apikey, userkeys.secretkey)
+
+ cls.compute_offering = ServiceOffering.create(
+ cls.apiClient,
+ cls.testdata[TestData.computeOffering]
+ )
+
+ cls._cleanup = [
+ cls.compute_offering,
+ user,
+ cls.account
+ ]
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ cleanup_resources(cls.apiClient, cls._cleanup)
+
+ cls._purge_solidfire_volumes()
+ except Exception as e:
+ logging.debug("Exception in tearDownClass(cls): %s" % e)
+
+ def setUp(self):
+ self.virtual_machine = None
+
+ self.cleanup = []
+
+ def tearDown(self):
+ try:
+ if self.virtual_machine is not None:
+ self.virtual_machine.delete(self.apiClient, True)
+
+ cleanup_resources(self.apiClient, self.cleanup)
+ except Exception as e:
+ logging.debug("Exception in tearDown(self): %s" % e)
+
+ def test_add_remove_host_with_solidfire_plugin_1(self):
+ primarystorage = self.testdata[TestData.primaryStorage]
+
+ primary_storage = StoragePool.create(
+ self.apiClient,
+ primarystorage,
+ scope=primarystorage[TestData.scope],
+ zoneid=self.zone.id,
+ provider=primarystorage[TestData.provider],
+ tags=primarystorage[TestData.tags],
+ capacityiops=primarystorage[TestData.capacityIops],
+ capacitybytes=primarystorage[TestData.capacityBytes],
+ hypervisor=primarystorage[TestData.hypervisor]
+ )
+
+ self.cleanup.append(primary_storage)
+
+ self.virtual_machine = VirtualMachine.create(
+ self.apiClient,
+ self.testdata[TestData.virtualMachine],
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=self.template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ root_volume = self._get_root_volume(self.virtual_machine)
+
+ sf_iscsi_name = self._get_iqn(root_volume)
+
+ self._perform_add_remove_host(primary_storage.id, sf_iscsi_name)
+
+ def test_add_remove_host_with_solidfire_plugin_2(self):
+ primarystorage2 = self.testdata[TestData.primaryStorage2]
+
+ primary_storage_2 = StoragePool.create(
+ self.apiClient,
+ primarystorage2,
+ scope=primarystorage2[TestData.scope],
+ zoneid=self.zone.id,
+ clusterid=self.cluster.id,
+ provider=primarystorage2[TestData.provider],
+ tags=primarystorage2[TestData.tags],
+ capacityiops=primarystorage2[TestData.capacityIops],
+ capacitybytes=primarystorage2[TestData.capacityBytes],
+ hypervisor=primarystorage2[TestData.hypervisor]
+ )
+
+ self.cleanup.append(primary_storage_2)
+
+ sf_iscsi_name = self._get_iqn_2(primary_storage_2)
+
+ self._perform_add_remove_host(primary_storage_2.id, sf_iscsi_name)
+
+ def test_add_remove_host_with_solidfire_plugin_3(self):
+ primarystorage = self.testdata[TestData.primaryStorage]
+
+ primary_storage = StoragePool.create(
+ self.apiClient,
+ primarystorage,
+ scope=primarystorage[TestData.scope],
+ zoneid=self.zone.id,
+ provider=primarystorage[TestData.provider],
+ tags=primarystorage[TestData.tags],
+ capacityiops=primarystorage[TestData.capacityIops],
+ capacitybytes=primarystorage[TestData.capacityBytes],
+ hypervisor=primarystorage[TestData.hypervisor]
+ )
+
+ self.cleanup.append(primary_storage)
+
+ self.virtual_machine = VirtualMachine.create(
+ self.apiClient,
+ self.testdata[TestData.virtualMachine],
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=self.template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ root_volume = self._get_root_volume(self.virtual_machine)
+
+ sf_iscsi_name = self._get_iqn(root_volume)
+
+ primarystorage2 = self.testdata[TestData.primaryStorage2]
+
+ primary_storage_2 = StoragePool.create(
+ self.apiClient,
+ primarystorage2,
+ scope=primarystorage2[TestData.scope],
+ zoneid=self.zone.id,
+ clusterid=self.cluster.id,
+ provider=primarystorage2[TestData.provider],
+ tags=primarystorage2[TestData.tags],
+ capacityiops=primarystorage2[TestData.capacityIops],
+ capacitybytes=primarystorage2[TestData.capacityBytes],
+ hypervisor=primarystorage2[TestData.hypervisor]
+ )
+
+ self.cleanup.append(primary_storage_2)
+
+ self._perform_add_remove_host(primary_storage.id, sf_iscsi_name)
+
+ def test_add_remove_host_with_solidfire_plugin_4(self):
+ primarystorage2 = self.testdata[TestData.primaryStorage2]
+
+ primary_storage_2 = StoragePool.create(
+ self.apiClient,
+ primarystorage2,
+ scope=primarystorage2[TestData.scope],
+ zoneid=self.zone.id,
+ clusterid=self.cluster.id,
+ provider=primarystorage2[TestData.provider],
+ tags=primarystorage2[TestData.tags],
+ capacityiops=primarystorage2[TestData.capacityIops],
+ capacitybytes=primarystorage2[TestData.capacityBytes],
+ hypervisor=primarystorage2[TestData.hypervisor]
+ )
+
+ self.cleanup.append(primary_storage_2)
+
+ sf_iscsi_name = self._get_iqn_2(primary_storage_2)
+
+ primarystorage = self.testdata[TestData.primaryStorage]
+
+ primary_storage = StoragePool.create(
+ self.apiClient,
+ primarystorage,
+ scope=primarystorage[TestData.scope],
+ zoneid=self.zone.id,
+ provider=primarystorage[TestData.provider],
+ tags=primarystorage[TestData.tags],
+ capacityiops=primarystorage[TestData.capacityIops],
+ capacitybytes=primarystorage[TestData.capacityBytes],
+ hypervisor=primarystorage[TestData.hypervisor]
+ )
+
+ self.cleanup.append(primary_storage)
+
+ self.virtual_machine = VirtualMachine.create(
+ self.apiClient,
+ self.testdata[TestData.virtualMachine],
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=self.template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ self._perform_add_remove_host(primary_storage_2.id, sf_iscsi_name)
+
+ def _perform_add_remove_host(self, primary_storage_id, sf_iscsi_name):
+ xen_sr = self.xen_session.xenapi.SR.get_by_name_label(sf_iscsi_name)[0]
+
+ pbds = self.xen_session.xenapi.SR.get_PBDs(xen_sr)
+
+ self._verify_all_pbds_attached(pbds)
+
+ num_pbds = len(pbds)
+
+ sf_vag_id = self._get_sf_vag_id(self.cluster.id, primary_storage_id)
+
+ host_iscsi_iqns = self._get_host_iscsi_iqns()
+
+ sf_vag = self._get_sf_vag(sf_vag_id)
+
+ sf_vag_initiators = self._get_sf_vag_initiators(sf_vag)
+
+ self._verifyVag(host_iscsi_iqns, sf_vag_initiators)
+
+ sf_vag_initiators_len_orig = len(sf_vag_initiators)
+
+ xen_session = XenAPI.Session(self.testdata[TestData.urlOfNewHost])
+
+ xenserver = self.testdata[TestData.xenServer]
+
+ xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password])
+
+ xen_session.xenapi.pool.join(self.xs_pool_master_ip, xenserver[TestData.username], xenserver[TestData.password])
+
+ time.sleep(60)
+
+ pbds = self.xen_session.xenapi.SR.get_PBDs(xen_sr)
+
+ self.assertEqual(
+ len(pbds),
+ num_pbds + 1,
+ "'len(pbds)' is not equal to 'num_pbds + 1'."
+ )
+
+ num_pbds = num_pbds + 1
+
+ num_pbds_not_attached = 0
+
+ for pbd in pbds:
+ pbd_record = self.xen_session.xenapi.PBD.get_record(pbd)
+
+ if pbd_record["currently_attached"] == False:
+ num_pbds_not_attached = num_pbds_not_attached + 1
+
+ self.assertEqual(
+ num_pbds_not_attached,
+ 1,
+ "'num_pbds_not_attached' is not equal to 1."
+ )
+
+ host = Host.create(
+ self.apiClient,
+ self.cluster,
+ self.testdata[TestData.newHost],
+ hypervisor="XenServer"
+ )
+
+ self.assertTrue(
+ isinstance(host, Host),
+ "'host' is not a 'Host'."
+ )
+
+ pbds = self.xen_session.xenapi.SR.get_PBDs(xen_sr)
+
+ self.assertEqual(
+ len(pbds),
+ num_pbds,
+ "'len(pbds)' is not equal to 'num_pbds'."
+ )
+
+ self._verify_all_pbds_attached(pbds)
+
+ host_iscsi_iqns = self._get_host_iscsi_iqns()
+
+ sf_vag = self._get_sf_vag(sf_vag_id)
+
+ sf_vag_initiators = self._get_sf_vag_initiators(sf_vag)
+
+ self._verifyVag(host_iscsi_iqns, sf_vag_initiators)
+
+ sf_vag_initiators_len_new = len(sf_vag_initiators)
+
+ self.assertEqual(
+ sf_vag_initiators_len_new,
+ sf_vag_initiators_len_orig + 1,
+ "sf_vag_initiators_len_new' != sf_vag_initiators_len_orig + 1"
+ )
+
+ host.delete(self.apiClient)
+
+ pbds = self.xen_session.xenapi.SR.get_PBDs(xen_sr)
+
+ self.assertEqual(
+ len(pbds),
+ num_pbds,
+ "'len(pbds)' is not equal to 'num_pbds'."
+ )
+
+ self._verify_all_pbds_attached(pbds)
+
+ host_iscsi_iqns = self._get_host_iscsi_iqns()
+
+ sf_vag = self._get_sf_vag(sf_vag_id)
+
+ sf_vag_initiators = self._get_sf_vag_initiators(sf_vag)
+
+ self.assertEqual(
+ len(host_iscsi_iqns) - 1,
+ len(sf_vag_initiators),
+ "'len(host_iscsi_iqns) - 1' is not equal to 'len(sf_vag_initiators)'."
+ )
+
+ host_ref = self.xen_session.xenapi.host.get_by_name_label(self.testdata[TestData.newHostDisplayName])[0]
+
+ self.xen_session.xenapi.pool.eject(host_ref)
+
+ time.sleep(120)
+
+ pbds = self.xen_session.xenapi.SR.get_PBDs(xen_sr)
+
+ self.assertEqual(
+ len(pbds),
+ num_pbds - 1,
+ "'len(pbds)' is not equal to 'num_pbds - 1'."
+ )
+
+ self._verify_all_pbds_attached(pbds)
+
+ host_iscsi_iqns = self._get_host_iscsi_iqns()
+
+ sf_vag = self._get_sf_vag(sf_vag_id)
+
+ sf_vag_initiators = self._get_sf_vag_initiators(sf_vag)
+
+ self._verifyVag(host_iscsi_iqns, sf_vag_initiators)
+
+ sf_vag_initiators_len_new = len(sf_vag_initiators)
+
+ self.assertEqual(
+ sf_vag_initiators_len_new,
+ sf_vag_initiators_len_orig,
+ "sf_vag_initiators_len_new' != sf_vag_initiators_len_orig"
+ )
+
+ def _verify_all_pbds_attached(self, pbds):
+ for pbd in pbds:
+ pbd_record = self.xen_session.xenapi.PBD.get_record(pbd)
+
+ self.assertEqual(
+ pbd_record["currently_attached"],
+ True,
+ "Not all PBDs are currently attached."
+ )
+
+ def _get_root_volume(self, vm):
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ virtualmachineid=vm.id,
+ listall=True
+ )
+
+ self.assertNotEqual(
+ list_volumes_response,
+ None,
+ "'list_volumes_response' should not be equal to 'None'."
+ )
+
+ self.assertEqual(
+ len(list_volumes_response) > 0,
+ True,
+ "'len(list_volumes_response)' should be greater than 0."
+ )
+
+ for volume in list_volumes_response:
+ if volume.type.upper() == "ROOT":
+ return volume
+
+ self.assert_(False, "Unable to locate the ROOT volume of the VM with the following ID: " + str(vm.id))
+
+ def _get_iqn(self, volume):
+ # Get volume IQN
+ sf_iscsi_name_request = {'volumeid': volume.id}
+ # put this commented line back once PR 1403 is in
+ # sf_iscsi_name_result = self.cs_api.getVolumeiScsiName(sf_iscsi_name_request)
+ sf_iscsi_name_result = self.cs_api.getSolidFireVolumeIscsiName(sf_iscsi_name_request)
+ # sf_iscsi_name = sf_iscsi_name_result['apivolumeiscsiname']['volumeiScsiName']
+ sf_iscsi_name = sf_iscsi_name_result['apisolidfirevolumeiscsiname']['solidFireVolumeIscsiName']
+
+ self._check_iscsi_name(sf_iscsi_name)
+
+ return sf_iscsi_name
+
+ def _get_iqn_2(self, primary_storage):
+ sql_query = "Select path From storage_pool Where uuid = '" + str(primary_storage.id) + "'"
+
+ # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench
+ sql_result = self.dbConnection.execute(sql_query)
+
+ return sql_result[0][0]
+
+ def _check_iscsi_name(self, sf_iscsi_name):
+ self.assertEqual(
+ sf_iscsi_name[0],
+ "/",
+ "The iSCSI name needs to start with a forward slash."
+ )
+
+ def _get_host_iscsi_iqns(self):
+ hosts = self.xen_session.xenapi.host.get_all()
+
+ self.assertEqual(
+ isinstance(hosts, list),
+ True,
+ "'hosts' is not a list."
+ )
+
+ host_iscsi_iqns = []
+
+ for host in hosts:
+ host_iscsi_iqns.append(self._get_host_iscsi_iqn(host))
+
+ return host_iscsi_iqns
+
+ def _get_host_iscsi_iqn(self, host):
+ other_config = self.xen_session.xenapi.host.get_other_config(host)
+
+ return other_config["iscsi_iqn"]
+
+ def _get_sf_vag_id(self, cluster_id, primary_storage_id):
+ # Get SF Volume Access Group ID
+ sf_vag_id_request = {'clusterid': cluster_id, 'storageid': primary_storage_id}
+ sf_vag_id_result = self.cs_api.getSolidFireVolumeAccessGroupId(sf_vag_id_request)
+ sf_vag_id = sf_vag_id_result['apisolidfirevolumeaccessgroupid']['solidFireVolumeAccessGroupId']
+
+ self.assertEqual(
+ isinstance(sf_vag_id, int),
+ True,
+ TestAddRemoveHosts._vag_id_should_be_non_zero_int_err_msg
+ )
+
+ return sf_vag_id
+
+ def _get_sf_vag(self, sf_vag_id):
+ return self.sf_client.list_volume_access_groups(sf_vag_id, 1)["volumeAccessGroups"][0]
+
+ def _get_sf_vag_initiators(self, sf_vag):
+ return sf_vag["initiators"]
+
+ def _verifyVag(self, host_iscsi_iqns, sf_vag_initiators):
+ self.assertEqual(
+ isinstance(host_iscsi_iqns, list),
+ True,
+ "'host_iscsi_iqns' is not a list."
+ )
+
+ self.assertEqual(
+ isinstance(sf_vag_initiators, list),
+ True,
+ "'sf_vag_initiators' is not a list."
+ )
+
+ self.assertEqual(
+ len(host_iscsi_iqns),
+ len(sf_vag_initiators),
+ "Lists are not the same size."
+ )
+
+ for host_iscsi_iqn in host_iscsi_iqns:
+ # an error should occur if host_iscsi_iqn is not in sf_vag_initiators
+ sf_vag_initiators.index(host_iscsi_iqn)
+
+ def _check_list(self, in_list, expected_size_of_list, err_msg):
+ self.assertEqual(
+ isinstance(in_list, list),
+ True,
+ "'in_list' is not a list."
+ )
+
+ self.assertEqual(
+ len(in_list),
+ expected_size_of_list,
+ err_msg
+ )
+
+ @classmethod
+ def _purge_solidfire_volumes(cls):
+ deleted_volumes = cls.sf_client.list_deleted_volumes()
+
+ for deleted_volume in deleted_volumes:
+ cls.sf_client.purge_deleted_volume(deleted_volume['volumeID'])
+
diff --git a/test/integration/plugins/solidfire/TestSnapshots.py b/test/integration/plugins/solidfire/TestSnapshots.py
new file mode 100644
index 0000000..9c3d255
--- /dev/null
+++ b/test/integration/plugins/solidfire/TestSnapshots.py
@@ -0,0 +1,1472 @@
+# 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 logging
+import random
+import SignedAPICall
+import time
+import XenAPI
+
+# All tests inherit from cloudstackTestCase
+from marvin.cloudstackTestCase import cloudstackTestCase
+
+from nose.plugins.attrib import attr
+
+# Import Integration Libraries
+
+# base - contains all resources as entities and defines create, delete, list operations on them
+from marvin.lib.base import Account, DiskOffering, ServiceOffering, Snapshot, StoragePool, Template, User, VirtualMachine, Volume
+
+# common - commonly used methods for all tests are listed here
+from marvin.lib.common import get_domain, get_template, get_zone, list_clusters, list_hosts, list_volumes
+
+# utils - utility classes for common cleanup, external library wrappers, etc.
+from marvin.lib.utils import cleanup_resources
+
+from solidfire import solidfire_element_api as sf_api
+
+# on April 10, 2016: Ran 3 tests in 7742.481s with three hosts
+# on May 2, 2016: Ran 3 tests in 7409.770s with two hosts
+
+
+class TestData():
+ account = "account"
+ capacityBytes = "capacitybytes"
+ capacityIops = "capacityiops"
+ clusterId = "clusterId"
+ computeOffering = "computeoffering"
+ diskName = "diskname"
+ diskOffering = "diskoffering"
+ domainId = "domainId"
+ hypervisor = "hypervisor"
+ login = "login"
+ mvip = "mvip"
+ password = "password"
+ port = "port"
+ primaryStorage = "primarystorage"
+ provider = "provider"
+ scope = "scope"
+ solidFire = "solidfire"
+ storageTag = "SolidFire_SAN_1"
+ tags = "tags"
+ templateName = "templatename"
+ url = "url"
+ user = "user"
+ username = "username"
+ virtualMachine = "virtualmachine"
+ volume_1 = "volume_1"
+ volume_2 = "volume_2"
+ xenServer = "xenserver"
+ zoneId = "zoneId"
+
+ def __init__(self):
+ self.testdata = {
+ TestData.solidFire: {
+ TestData.mvip: "192.168.139.112",
+ TestData.login: "admin",
+ TestData.password: "admin",
+ TestData.port: 443,
+ TestData.url: "https://192.168.139.112:443"
+ },
+ TestData.xenServer: {
+ TestData.username: "root",
+ TestData.password: "solidfire"
+ },
+ TestData.account: {
+ "email": "test@test.com",
+ "firstname": "John",
+ "lastname": "Doe",
+ "username": "test",
+ "password": "test"
+ },
+ "testaccount": {
+ "email": "test2@test2.com",
+ "firstname": "Jane",
+ "lastname": "Doe",
+ TestData.username: "test2",
+ TestData.password: "test"
+ },
+ TestData.user: {
+ "email": "user@test.com",
+ "firstname": "Jane",
+ "lastname": "Doe",
+ TestData.username: "testuser",
+ TestData.password: "password"
+ },
+ TestData.primaryStorage: {
+ "name": "SolidFire-%d" % random.randint(0, 100),
+ TestData.scope: "ZONE",
+ "url": "MVIP=192.168.139.112;SVIP=10.10.8.112;" +
+ "clusterAdminUsername=admin;clusterAdminPassword=admin;" +
+ "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" +
+ "clusterDefaultBurstIopsPercentOfMaxIops=1.5;",
+ TestData.provider: "SolidFire",
+ TestData.tags: TestData.storageTag,
+ TestData.capacityIops: 4500000,
+ TestData.capacityBytes: 2251799813685248,
+ TestData.hypervisor: "Any"
+ },
+ TestData.virtualMachine: {
+ "name": "TestVM",
+ "displayname": "Test VM"
+ },
+ TestData.computeOffering: {
+ "name": "SF_CO_1",
+ "displaytext": "SF_CO_1 (Min IOPS = 10,000; Max IOPS = 15,000)",
+ "cpunumber": 1,
+ "cpuspeed": 100,
+ "memory": 128,
+ "storagetype": "shared",
+ "customizediops": False,
+ "miniops": "10000",
+ "maxiops": "15000",
+ "hypervisorsnapshotreserve": 200,
+ "tags": "SolidFire_SAN_1"
+ },
+ TestData.diskOffering: {
+ "name": "SF_DO_1",
+ "displaytext": "SF_DO_1 (Min IOPS = 300; Max IOPS = 500)",
+ "disksize": 128,
+ "customizediops": False,
+ "miniops": 300,
+ "maxiops": 500,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "testdiskofferings": {
+ "customiopsdo": {
+ "name": "SF_Custom_Iops_DO",
+ "displaytext": "Customized Iops DO",
+ "disksize": 128,
+ "customizediops": True,
+ "miniops": 500,
+ "maxiops": 1000,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "customsizedo": {
+ "name": "SF_Custom_Size_DO",
+ "displaytext": "Customized Size DO",
+ "disksize": 175,
+ "customizediops": False,
+ "miniops": 500,
+ "maxiops": 1000,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "customsizeandiopsdo": {
+ "name": "SF_Custom_Iops_Size_DO",
+ "displaytext": "Customized Size and Iops DO",
+ "disksize": 200,
+ "customizediops": True,
+ "miniops": 400,
+ "maxiops": 800,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "newiopsdo": {
+ "name": "SF_New_Iops_DO",
+ "displaytext": "New Iops (min=350, max = 700)",
+ "disksize": 128,
+ "miniops": 350,
+ "maxiops": 700,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "newsizedo": {
+ "name": "SF_New_Size_DO",
+ "displaytext": "New Size: 175",
+ "disksize": 175,
+ "miniops": 400,
+ "maxiops": 800,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "newsizeandiopsdo": {
+ "name": "SF_New_Size_Iops_DO",
+ "displaytext": "New Size and Iops",
+ "disksize": 200,
+ "miniops": 200,
+ "maxiops": 400,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ }
+ },
+ TestData.volume_1: {
+ TestData.diskName: "test-volume",
+ },
+ TestData.volume_2: {
+ TestData.diskName: "test-volume-2",
+ },
+ TestData.templateName: "CentOS 5.6(64-bit) no GUI (XenServer)",
+ TestData.zoneId: 1,
+ TestData.clusterId: 1,
+ TestData.domainId: 1,
+ TestData.url: "192.168.129.50"
+ }
+
+
+class TestSnapshots(cloudstackTestCase):
+ _should_be_zero_volume_access_groups_in_list_err_msg = "There shouldn't be any volume access groups in this list."
+ _should_be_zero_snapshots_in_list_err_msg = "There shouldn't be any snapshots in this list."
+ _should_only_be_one_snapshot_in_list_err_msg = "There should only be one snapshot in this list."
+ _should_be_two_snapshots_in_list_err_msg = "There should be two snapshots in this list."
+ _should_be_three_snapshots_in_list_err_msg = "There should be three snapshots in this list."
+ _should_be_zero_volumes_in_list_err_msg = "There shouldn't be any volumes in this list."
+ _should_only_be_one_volume_in_list_err_msg = "There should only be one volume in this list."
+ _should_be_two_volumes_in_list_err_msg = "There should be two volumes in this list."
+ _should_be_three_volumes_in_list_err_msg = "There should be three volumes in this list."
+ _should_be_four_volumes_in_list_err_msg = "There should be four volumes in this list."
+ _should_be_five_volumes_in_list_err_msg = "There should be five volumes in this list."
+ _should_be_six_volumes_in_list_err_msg = "There should be six volumes in this list."
+ _should_be_seven_volumes_in_list_err_msg = "There should be seven volumes in this list."
+ _should_be_five_items_in_list_err_msg = "There should be five items in this list."
+ _sf_account_id_should_be_non_zero_int_err_msg = "The SolidFire account ID should be a non-zero integer."
+
+ @classmethod
+ def setUpClass(cls):
+ # Set up API client
+ testclient = super(TestSnapshots, cls).getClsTestClient()
+ cls.apiClient = testclient.getApiClient()
+ cls.dbConnection = testclient.getDbConnection()
+
+ cls.testdata = TestData().testdata
+
+ # Set up xenAPI connection
+ host_ip = "https://" + \
+ list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress
+
+ # Set up XenAPI connection
+ cls.xen_session = XenAPI.Session(host_ip)
+
+ xenserver = cls.testdata[TestData.xenServer]
+
+ cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password])
+
+ # Set up SolidFire connection
+ cls.sf_client = sf_api.SolidFireAPI(endpoint_dict=cls.testdata[TestData.solidFire])
+
+ # Get Resources from Cloud Infrastructure
+ cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId])
+ cls.cluster = list_clusters(cls.apiClient)[0]
+ cls.template = get_template(cls.apiClient, cls.zone.id, template_name=cls.testdata[TestData.templateName])
+ cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId])
+
+ # Create test account
+ cls.account = Account.create(
+ cls.apiClient,
+ cls.testdata["account"],
+ admin=1
+ )
+
+ # Set up connection to make customized API calls
+ cls.user = User.create(
+ cls.apiClient,
+ cls.testdata["user"],
+ account=cls.account.name,
+ domainid=cls.domain.id
+ )
+
+ url = cls.testdata[TestData.url]
+
+ api_url = "http://" + url + ":8080/client/api"
+ userkeys = User.registerUserKeys(cls.apiClient, cls.user.id)
+
+ cls.cs_api = SignedAPICall.CloudStack(api_url, userkeys.apikey, userkeys.secretkey)
+
+ primarystorage = cls.testdata[TestData.primaryStorage]
+
+ cls.primary_storage = StoragePool.create(
+ cls.apiClient,
+ primarystorage,
+ scope=primarystorage[TestData.scope],
+ zoneid=cls.zone.id,
+ provider=primarystorage[TestData.provider],
+ tags=primarystorage[TestData.tags],
+ capacityiops=primarystorage[TestData.capacityIops],
+ capacitybytes=primarystorage[TestData.capacityBytes],
+ hypervisor=primarystorage[TestData.hypervisor]
+ )
+
+ cls.compute_offering = ServiceOffering.create(
+ cls.apiClient,
+ cls.testdata[TestData.computeOffering]
+ )
+
+ cls.disk_offering = DiskOffering.create(
+ cls.apiClient,
+ cls.testdata[TestData.diskOffering]
+ )
+
+ # Resources that are to be destroyed
+ cls._cleanup = [
+ cls.compute_offering,
+ cls.disk_offering,
+ cls.user,
+ cls.account
+ ]
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ cleanup_resources(cls.apiClient, cls._cleanup)
+
+ cls.primary_storage.delete(cls.apiClient)
+
+ cls._purge_solidfire_volumes()
+ except Exception as e:
+ logging.debug("Exception in tearDownClass(cls): %s" % e)
+
+ def setUp(self):
+ self.cleanup = []
+
+ def tearDown(self):
+ cleanup_resources(self.apiClient, self.cleanup)
+
+ @attr(hypervisor='XenServer')
+ def test_01_create_volume_snapshot_using_sf_snapshot(self):
+ self._set_supports_resign(True)
+
+ virtual_machine = VirtualMachine.create(
+ self.apiClient,
+ self.testdata[TestData.virtualMachine],
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=self.template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ virtualmachineid=virtual_machine.id,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vm_1_root_volume = list_volumes_response[0]
+ vm_1_root_volume_name = vm_1_root_volume.name
+
+ sf_account_id = self._get_sf_account_id(self.account.id, self.primary_storage.id)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name)
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume['volumeID'])
+
+ self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg)
+
+ primary_storage_db_id = self._get_cs_storage_pool_db_id(self.primary_storage)
+
+ vol_snap_1 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 1, TestSnapshots._should_only_be_one_snapshot_in_list_err_msg)
+
+ vol_snap_2 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 2, TestSnapshots._should_be_two_snapshots_in_list_err_msg)
+
+ vol_snap_3 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 3, TestSnapshots._should_be_three_snapshots_in_list_err_msg)
+
+ self._delete_and_test_snapshot(vol_snap_2)
+
+ self._delete_and_test_snapshot(vol_snap_1)
+
+ self._delete_and_test_snapshot(vol_snap_3)
+
+ vol_snap_1 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 1, TestSnapshots._should_only_be_one_snapshot_in_list_err_msg)
+
+ vol_snap_2 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 2, TestSnapshots._should_be_two_snapshots_in_list_err_msg)
+
+ virtual_machine.delete(self.apiClient, True)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name)
+
+ self._delete_and_test_snapshot(vol_snap_1)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name)
+
+ self._delete_and_test_snapshot(vol_snap_2)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg)
+
+ virtual_machine = VirtualMachine.create(
+ self.apiClient,
+ self.testdata[TestData.virtualMachine],
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=self.template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ virtualmachineid=virtual_machine.id,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vm_1_root_volume = list_volumes_response[0]
+ vm_1_root_volume_name = vm_1_root_volume.name
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name)
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume['volumeID'])
+
+ self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg)
+
+ vol_snap_1 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 1, TestSnapshots._should_only_be_one_snapshot_in_list_err_msg)
+
+ vol_snap_2 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 2, TestSnapshots._should_be_two_snapshots_in_list_err_msg)
+
+ vol_snap_3 = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 3, TestSnapshots._should_be_three_snapshots_in_list_err_msg)
+
+ services = {"displaytext": "Template-1", "name": "Template-1-name", "ostype": "CentOS 5.6 (64-bit)", "ispublic": "true"}
+
+ template = Template.create_from_snapshot(self.apiClient, vol_snap_2, services)
+
+ self.cleanup.append(template)
+
+ virtual_machine_dict = {"name": "TestVM2", "displayname": "Test VM 2"}
+
+ virtual_machine_2 = VirtualMachine.create(
+ self.apiClient,
+ virtual_machine_dict,
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ virtualmachineid=virtual_machine_2.id,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vm_2_root_volume = list_volumes_response[0]
+ vm_2_root_volume_name = vm_2_root_volume.name
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name)
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots_2 = self.sf_client.list_snapshots(volume_id=sf_volume_2['volumeID'])
+
+ self._check_list(sf_snapshots_2, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg)
+
+ vol_snap_a = self._create_and_test_snapshot(vm_2_root_volume.id, sf_volume_2, primary_storage_db_id, 1, TestSnapshots._should_only_be_one_snapshot_in_list_err_msg)
+
+ services = {"diskname": "Vol-1", "zoneid": self.testdata[TestData.zoneId], "size": 100, "ispublic": True}
+
+ volume_created_from_snapshot = Volume.create_from_snapshot(self.apiClient, vol_snap_a.id, services, account=self.account.name, domainid=self.domain.id)
+
+ volume_created_from_snapshot_name = volume_created_from_snapshot.name
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg)
+
+ sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name)
+ sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name)
+ sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name)
+
+ self._check_list(sf_volume_3['volumeAccessGroups'], 0, TestSnapshots._should_be_zero_volume_access_groups_in_list_err_msg)
+
+ volume_created_from_snapshot = virtual_machine.attach_volume(
+ self.apiClient,
+ volume_created_from_snapshot
+ )
+
+ self._delete_and_test_snapshot(vol_snap_a)
+
+ virtual_machine.delete(self.apiClient, True)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg)
+
+ sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name)
+ sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name)
+ sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name)
+
+ volume_created_from_snapshot = virtual_machine_2.attach_volume(
+ self.apiClient,
+ volume_created_from_snapshot
+ )
+
+ self._delete_and_test_snapshot(vol_snap_2)
+
+ self._delete_and_test_snapshot(vol_snap_3)
+
+ self._delete_and_test_snapshot(vol_snap_1)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name)
+ sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name)
+
+ virtual_machine_2.delete(self.apiClient, True)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name)
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ data_volume = list_volumes_response[0]
+
+ data_volume = Volume(data_volume.__dict__)
+
+ data_volume.delete(self.apiClient)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg)
+
+ @attr(hypervisor='XenServer')
+ def test_02_create_volume_snapshot_using_sf_volume(self):
+ self._set_supports_resign(False)
+
+ virtual_machine = VirtualMachine.create(
+ self.apiClient,
+ self.testdata[TestData.virtualMachine],
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=self.template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ virtualmachineid=virtual_machine.id,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vm_1_root_volume = list_volumes_response[0]
+ vm_1_root_volume_name = vm_1_root_volume.name
+
+ sf_account_id = self._get_sf_account_id(self.account.id, self.primary_storage.id)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name)
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume['volumeID'])
+
+ self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg)
+
+ primary_storage_db_id = self._get_cs_storage_pool_db_id(self.primary_storage)
+
+ sf_volume_id = sf_volume['volumeID']
+ sf_volume_size = sf_volume['totalSize']
+
+ vol_snap_1 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 1, primary_storage_db_id, sf_volume_size,
+ sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ vol_snap_2 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 2, primary_storage_db_id, sf_volume_size,
+ sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg)
+
+ vol_snap_3 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 3, primary_storage_db_id, sf_volume_size,
+ sf_account_id, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg)
+
+ self._delete_and_test_snapshot_2(vol_snap_2, sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg)
+
+ self._delete_and_test_snapshot_2(vol_snap_1, sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ self._delete_and_test_snapshot_2(vol_snap_3, sf_account_id, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vol_snap_1 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 4, primary_storage_db_id, sf_volume_size,
+ sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ vol_snap_2 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 5, primary_storage_db_id, sf_volume_size,
+ sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg)
+
+ virtual_machine.delete(self.apiClient, True)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ self._delete_and_test_snapshot_2(vol_snap_1, sf_account_id, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ self._delete_and_test_snapshot_2(vol_snap_2, sf_account_id, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg)
+
+ virtual_machine = VirtualMachine.create(
+ self.apiClient,
+ self.testdata[TestData.virtualMachine],
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=self.template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ virtualmachineid=virtual_machine.id,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vm_1_root_volume = list_volumes_response[0]
+ vm_1_root_volume_name = vm_1_root_volume.name
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name)
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume['volumeID'])
+
+ self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg)
+
+ sf_volume_id = sf_volume['volumeID']
+ sf_volume_size = sf_volume['totalSize']
+
+ vol_snap_1 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 1, primary_storage_db_id, sf_volume_size,
+ sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ vol_snap_2 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 2, primary_storage_db_id, sf_volume_size,
+ sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg)
+
+ vol_snap_3 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 3, primary_storage_db_id, sf_volume_size,
+ sf_account_id, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg)
+
+ services = {"displaytext": "Template-1", "name": "Template-1-name", "ostype": "CentOS 5.6 (64-bit)", "ispublic": "true"}
+
+ template = Template.create_from_snapshot(self.apiClient, vol_snap_2, services)
+
+ self.cleanup.append(template)
+
+ virtual_machine_dict = {"name": "TestVM2", "displayname": "Test VM 2"}
+
+ virtual_machine_2 = VirtualMachine.create(
+ self.apiClient,
+ virtual_machine_dict,
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ virtualmachineid=virtual_machine_2.id,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vm_2_root_volume = list_volumes_response[0]
+ vm_2_root_volume_name = vm_2_root_volume.name
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 5, TestSnapshots._should_be_five_volumes_in_list_err_msg)
+
+ sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name)
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots_2 = self.sf_client.list_snapshots(volume_id=sf_volume_2['volumeID'])
+
+ self._check_list(sf_snapshots_2, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg)
+
+ sf_volume_id_2 = sf_volume_2['volumeID']
+ sf_volume_size_2 = sf_volume_2['totalSize']
+
+ vol_snap_a = self._create_and_test_snapshot_2(vm_2_root_volume.id, sf_volume_id_2, sf_volume_id + 5, primary_storage_db_id, sf_volume_size_2,
+ sf_account_id, 6, TestSnapshots._should_be_six_volumes_in_list_err_msg)
+
+ services = {"diskname": "Vol-1", "zoneid": self.testdata[TestData.zoneId], "size": 100, "ispublic": True}
+
+ volume_created_from_snapshot = Volume.create_from_snapshot(self.apiClient, vol_snap_a.id, services, account=self.account.name, domainid=self.domain.id)
+
+ volume_created_from_snapshot_name = volume_created_from_snapshot.name
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 7, TestSnapshots._should_be_seven_volumes_in_list_err_msg)
+
+ sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name)
+ sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name)
+ sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name)
+
+ self._check_list(sf_volume_3['volumeAccessGroups'], 0, TestSnapshots._should_be_zero_volume_access_groups_in_list_err_msg)
+
+ volume_created_from_snapshot = virtual_machine.attach_volume(
+ self.apiClient,
+ volume_created_from_snapshot
+ )
+
+ self._delete_and_test_snapshot_2(vol_snap_a, sf_account_id, 6, TestSnapshots._should_be_six_volumes_in_list_err_msg)
+
+ virtual_machine.delete(self.apiClient, True)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 5, TestSnapshots._should_be_five_volumes_in_list_err_msg)
+
+ sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name)
+ sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name)
+
+ volume_created_from_snapshot = virtual_machine_2.attach_volume(
+ self.apiClient,
+ volume_created_from_snapshot
+ )
+
+ self._delete_and_test_snapshot_2(vol_snap_2, sf_account_id, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg)
+
+ self._delete_and_test_snapshot_2(vol_snap_3, sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg)
+
+ self._delete_and_test_snapshot_2(vol_snap_1, sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ virtual_machine_2.delete(self.apiClient, True)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ data_volume = list_volumes_response[0]
+
+ data_volume = Volume(data_volume.__dict__)
+
+ data_volume.delete(self.apiClient)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg)
+
+ virtual_machine = VirtualMachine.create(
+ self.apiClient,
+ self.testdata[TestData.virtualMachine],
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ virtualmachineid=virtual_machine.id,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vm_1_root_volume = list_volumes_response[0]
+ vm_1_root_volume_name = vm_1_root_volume.name
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ time.sleep(60)
+
+ virtual_machine.stop(self.apiClient, True)
+
+ sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name)
+
+ sf_volume_id = sf_volume['volumeID']
+ sf_volume_size = sf_volume['totalSize']
+
+ vol_snap_1 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 1, primary_storage_db_id, sf_volume_size,
+ sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ services = {"diskname": "Vol-1", "zoneid": self.testdata[TestData.zoneId], "size": 100, "ispublic": True}
+
+ volume_created_from_snapshot = Volume.create_from_snapshot(self.apiClient, vol_snap_1.id, services, account=self.account.name, domainid=self.domain.id)
+
+ volume_created_from_snapshot_name = volume_created_from_snapshot.name
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg)
+
+ sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, volume_created_from_snapshot_name)
+
+ self._check_list(sf_volume_2['volumeAccessGroups'], 0, TestSnapshots._should_be_zero_volume_access_groups_in_list_err_msg)
+
+ volume_created_from_snapshot = virtual_machine.attach_volume(
+ self.apiClient,
+ volume_created_from_snapshot
+ )
+
+ sf_volume_id_2 = sf_volume_2['volumeID']
+ sf_volume_size_2 = sf_volume_2['totalSize']
+
+ vol_snap_a = self._create_and_test_snapshot_2(volume_created_from_snapshot.id, sf_volume_id_2, sf_volume_id + 3, primary_storage_db_id, sf_volume_size_2,
+ sf_account_id, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg)
+
+ self._delete_and_test_snapshot_2(vol_snap_1, sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg)
+
+ self._delete_and_test_snapshot_2(vol_snap_a, sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ virtual_machine.delete(self.apiClient, True)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vol_snap_a = self._create_and_test_snapshot_2(volume_created_from_snapshot.id, sf_volume_id_2, sf_volume_id + 4, primary_storage_db_id, sf_volume_size_2,
+ sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ data_volume = list_volumes_response[0]
+
+ data_volume = Volume(data_volume.__dict__)
+
+ data_volume.delete(self.apiClient)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ listall=True
+ )
+
+ self.assertEqual(
+ list_volumes_response,
+ None,
+ "'list_volumes_response' should be equal to 'None'."
+ )
+
+ self._delete_and_test_snapshot_2(vol_snap_a, sf_account_id, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg)
+
+ @attr(hypervisor='XenServer')
+ def test_03_create_volume_snapshot_using_sf_volume_and_sf_snapshot(self):
+ self._set_supports_resign(False)
+
+ virtual_machine = VirtualMachine.create(
+ self.apiClient,
+ self.testdata[TestData.virtualMachine],
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=self.template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ virtualmachineid=virtual_machine.id,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vm_1_root_volume = list_volumes_response[0]
+ vm_1_root_volume_name = vm_1_root_volume.name
+
+ sf_account_id = self._get_sf_account_id(self.account.id, self.primary_storage.id)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ sf_volume = self._get_sf_volume_by_name(sf_volumes, vm_1_root_volume_name)
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume['volumeID'])
+
+ self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg)
+
+ primary_storage_db_id = self._get_cs_storage_pool_db_id(self.primary_storage)
+
+ sf_volume_id = sf_volume['volumeID']
+ sf_volume_size = sf_volume['totalSize']
+
+ vol_snap_1 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 1, primary_storage_db_id, sf_volume_size,
+ sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ vol_snap_2 = self._create_and_test_snapshot_2(vm_1_root_volume.id, sf_volume_id, sf_volume_id + 2, primary_storage_db_id, sf_volume_size,
+ sf_account_id, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg)
+
+ self._set_supports_resign(True)
+
+ vol_snap_a = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 1, TestSnapshots._should_only_be_one_snapshot_in_list_err_msg)
+
+ vol_snap_b = self._create_and_test_snapshot(vm_1_root_volume.id, sf_volume, primary_storage_db_id, 2, TestSnapshots._should_be_two_snapshots_in_list_err_msg)
+
+ services = {"displaytext": "Template-1", "name": "Template-1-name", "ostype": "CentOS 5.6 (64-bit)", "ispublic": "true"}
+
+ template_1 = Template.create_from_snapshot(self.apiClient, vol_snap_1, services)
+
+ self.cleanup.append(template_1)
+
+ virtual_machine_dict = {"name": "TestVM2", "displayname": "Test VM 2"}
+
+ virtual_machine_2 = VirtualMachine.create(
+ self.apiClient,
+ virtual_machine_dict,
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=template_1.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ virtualmachineid=virtual_machine_2.id,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vm_2_root_volume = list_volumes_response[0]
+ vm_2_root_volume_name = vm_2_root_volume.name
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg)
+
+ sf_volume_2 = self._get_sf_volume_by_name(sf_volumes, vm_2_root_volume_name)
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume_2['volumeID'])
+
+ self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg)
+
+ services = {"diskname": "Vol-1", "zoneid": self.testdata[TestData.zoneId], "size": 100, "ispublic": True}
+
+ volume_created_from_snapshot_1 = Volume.create_from_snapshot(self.apiClient, vol_snap_2.id, services, account=self.account.name, domainid=self.domain.id)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 5, TestSnapshots._should_be_five_volumes_in_list_err_msg)
+
+ volume_created_from_snapshot_1 = virtual_machine_2.attach_volume(
+ self.apiClient,
+ volume_created_from_snapshot_1
+ )
+
+ services = {"displaytext": "Template-A", "name": "Template-A-name", "ostype": "CentOS 5.6 (64-bit)", "ispublic": "true"}
+
+ template_a = Template.create_from_snapshot(self.apiClient, vol_snap_a, services)
+
+ self.cleanup.append(template_a)
+
+ virtual_machine_dict = {"name": "TestVM3", "displayname": "Test VM 3"}
+
+ virtual_machine_3 = VirtualMachine.create(
+ self.apiClient,
+ virtual_machine_dict,
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=template_a.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ virtualmachineid=virtual_machine_3.id,
+ listall=True
+ )
+
+ self._check_list(list_volumes_response, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ vm_3_root_volume = list_volumes_response[0]
+ vm_3_root_volume_name = vm_3_root_volume.name
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 6, TestSnapshots._should_be_six_volumes_in_list_err_msg)
+
+ sf_volume_3 = self._get_sf_volume_by_name(sf_volumes, vm_3_root_volume_name)
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume_3['volumeID'])
+
+ self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg)
+
+ services = {"diskname": "Vol-A", "zoneid": self.testdata[TestData.zoneId], "size": 100, "ispublic": True}
+
+ volume_created_from_snapshot_a = Volume.create_from_snapshot(self.apiClient, vol_snap_b.id, services, account=self.account.name, domainid=self.domain.id)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 7, TestSnapshots._should_be_seven_volumes_in_list_err_msg)
+
+ volume_created_from_snapshot_a = virtual_machine_3.attach_volume(
+ self.apiClient,
+ volume_created_from_snapshot_a
+ )
+
+ virtual_machine.delete(self.apiClient, True)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ # should still be 7 volumes because the SolidFire volume for the root disk of the VM just destroyed
+ # is still needed for the SolidFire snapshots
+ self._check_list(sf_volumes, 7, TestSnapshots._should_be_seven_volumes_in_list_err_msg)
+
+ virtual_machine_2.delete(self.apiClient, True)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 6, TestSnapshots._should_be_six_volumes_in_list_err_msg)
+
+ virtual_machine_3.delete(self.apiClient, True)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 5, TestSnapshots._should_be_five_volumes_in_list_err_msg)
+
+ data_volume = Volume(volume_created_from_snapshot_a.__dict__)
+
+ data_volume.delete(self.apiClient)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 4, TestSnapshots._should_be_four_volumes_in_list_err_msg)
+
+ data_volume = Volume(volume_created_from_snapshot_1.__dict__)
+
+ data_volume.delete(self.apiClient)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 3, TestSnapshots._should_be_three_volumes_in_list_err_msg)
+
+ self._delete_and_test_snapshot_2(vol_snap_1, sf_account_id, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ self._delete_and_test_snapshot(vol_snap_b)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ # should still be 2 volumes because the SolidFire volume for the root disk of the VM just destroyed
+ # is still needed for the SolidFire snapshots
+ self._check_list(sf_volumes, 2, TestSnapshots._should_be_two_volumes_in_list_err_msg)
+
+ self._delete_and_test_snapshot(vol_snap_a)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, 1, TestSnapshots._should_only_be_one_volume_in_list_err_msg)
+
+ self._delete_and_test_snapshot_2(vol_snap_2, sf_account_id, 0, TestSnapshots._should_be_zero_volumes_in_list_err_msg)
+
+ def _set_supports_resign(self, supports_resign):
+ supports_resign = str(supports_resign)
+
+ sql_query = "Update host_details Set value = '" + supports_resign + "' Where name = 'supportsResign'"
+
+ # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench
+ self.dbConnection.execute(sql_query)
+
+ def _check_list(self, in_list, expected_size_of_list, err_msg):
+ self.assertEqual(
+ isinstance(in_list, list),
+ True,
+ "'in_list' is not a list."
+ )
+
+ self.assertEqual(
+ len(in_list),
+ expected_size_of_list,
+ err_msg
+ )
+
+ def _check_list_not_empty(self, in_list):
+ self.assertEqual(
+ isinstance(in_list, list),
+ True,
+ "'in_list' is not a list."
+ )
+
+ self.assertGreater(
+ len(in_list),
+ 0,
+ "The size of 'in_list' must be greater than zero."
+ )
+
+ # used when SolidFire snapshots are being used for CloudStack volume snapshots
+ def _check_snapshot_details(self, sf_snapshot_details, cs_snapshot_id, sf_volume_id, sf_snapshot_id, storage_pool_id, sf_volume_size):
+ self._check_list(sf_snapshot_details, 5, TestSnapshots._should_be_five_items_in_list_err_msg)
+
+ self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "takeSnapshot", "true")
+ self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "volumeId", sf_volume_id)
+ self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "snapshotId", sf_snapshot_id)
+ self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "sfStoragePoolId", storage_pool_id)
+ self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "sfVolumeSize", sf_volume_size)
+
+ # used when SolidFire volumes are being used for CloudStack volume snapshots
+ def _check_snapshot_details_2(self, sf_snapshot_details, cs_snapshot_id, sf_volume_id, storage_pool_id, sf_volume_size):
+ self._check_list(sf_snapshot_details, 5, TestSnapshots._should_be_five_items_in_list_err_msg)
+
+ self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "volumeId", sf_volume_id)
+ self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "sfStoragePoolId", storage_pool_id)
+ self._check_snapshot_detail(sf_snapshot_details, cs_snapshot_id, "sfVolumeSize", sf_volume_size)
+ self._check_snapshot_detail_starts_with(sf_snapshot_details, cs_snapshot_id, "iqn", "/iqn.")
+ self._check_snapshot_detail_size(sf_snapshot_details, cs_snapshot_id, "path", 36)
+
+ def _check_snapshot_detail(self, sf_snapshot_details_list, cs_snapshot_id, snapshot_detail_key, snapshot_detail_value):
+ for sf_snapshot_detail_dict in sf_snapshot_details_list:
+ if sf_snapshot_detail_dict["volumeSnapshotId"] != cs_snapshot_id:
+ raise Exception("This snapshot detail does not apply to the expected CloudStack volume snapshot.")
+
+ if sf_snapshot_detail_dict["snapshotDetailsName"] == snapshot_detail_key:
+ if sf_snapshot_detail_dict["snapshotDetailsValue"] == str(snapshot_detail_value):
+ return
+
+ raise Exception("There is a problem with the snapshot details key '" + snapshot_detail_key + "' and value '" + str(snapshot_detail_value) + "'.")
+
+ def _check_snapshot_detail_starts_with(self, sf_snapshot_details_list, cs_snapshot_id, snapshot_detail_key, starts_with):
+ for sf_snapshot_detail_dict in sf_snapshot_details_list:
+ if sf_snapshot_detail_dict["volumeSnapshotId"] != cs_snapshot_id:
+ raise Exception("This snapshot detail does not apply to the expected CloudStack volume snapshot.")
+
+ if sf_snapshot_detail_dict["snapshotDetailsName"] == snapshot_detail_key:
+ if sf_snapshot_detail_dict["snapshotDetailsValue"].startswith(starts_with):
+ return
+
+ raise Exception("There is a problem with the snapshot details key '" + snapshot_detail_key + "' and 'starts with' value '" + starts_with + "'.")
+
+ def _check_snapshot_detail_size(self, sf_snapshot_details_list, cs_snapshot_id, snapshot_detail_key, length):
+ for sf_snapshot_detail_dict in sf_snapshot_details_list:
+ if sf_snapshot_detail_dict["volumeSnapshotId"] != cs_snapshot_id:
+ raise Exception("This snapshot detail does not apply to the expected CloudStack volume snapshot.")
+
+ if sf_snapshot_detail_dict["snapshotDetailsName"] == snapshot_detail_key:
+ if len(sf_snapshot_detail_dict["snapshotDetailsValue"]) == length:
+ return
+
+ raise Exception("There is a problem with the snapshot details key '" + snapshot_detail_key + "' and 'length' value '" + str(length) + "'.")
+
+ def _most_recent_sf_snapshot(self, sf_snapshots):
+ self._check_list_not_empty(sf_snapshots)
+
+ most_recent_id = 0
+ sf_snapshot_to_return = None
+
+ for sf_snapshot in sf_snapshots:
+ if (sf_snapshot['snapshotID'] > most_recent_id):
+ sf_snapshot_to_return = sf_snapshot
+
+ most_recent_id = sf_snapshot['snapshotID']
+
+ if (sf_snapshot_to_return == None):
+ raise Exception("Unable to find the most recent SolidFire snapshot in the provided list")
+
+ return sf_snapshot_to_return
+
+ def _get_cs_volume_snapshot_db_id(self, vol_snap):
+ return self._get_db_id("snapshots", vol_snap)
+
+ def _get_cs_storage_pool_db_id(self, storage_pool):
+ return self._get_db_id("storage_pool", storage_pool)
+
+ def _get_db_id(self, table, db_obj):
+ sql_query = "Select id From " + table + " Where uuid = '" + str(db_obj.id) + "'"
+
+ # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench
+ sql_result = self.dbConnection.execute(sql_query)
+
+ return sql_result[0][0]
+
+ def _get_sf_volume_by_name(self, sf_volumes, sf_volume_name):
+ self._check_list_not_empty(sf_volumes)
+
+ sf_volume = None
+
+ for volume in sf_volumes:
+ if volume['name'] == sf_volume_name:
+ sf_volume = volume
+
+ break
+
+ self.assertNotEqual(
+ sf_volume,
+ None,
+ "The SolidFire volume could not be found in the expected account."
+ )
+
+ return sf_volume
+
+ def _get_sf_volume_by_id(self, sf_volumes, sf_volume_id):
+ self._check_list_not_empty(sf_volumes)
+
+ sf_volume = None
+
+ for volume in sf_volumes:
+ if volume['volumeID'] == sf_volume_id:
+ sf_volume = volume
+
+ break
+
+ self.assertNotEqual(
+ sf_volume,
+ None,
+ "The SolidFire volume could not be found in the expected account."
+ )
+
+ return sf_volume
+
+ def _get_sf_account_id(self, cs_account_id, primary_storage_id):
+ sf_account_id_request = {'accountid': cs_account_id, 'storageid': primary_storage_id}
+ sf_account_id_result = self.cs_api.getSolidFireAccountId(sf_account_id_request)
+ sf_account_id = sf_account_id_result['apisolidfireaccountid']['solidFireAccountId']
+
+ self.assertEqual(
+ isinstance(sf_account_id, int),
+ True,
+ TestSnapshots._sf_account_id_should_be_non_zero_int_err_msg
+ )
+
+ return sf_account_id
+
+ def _get_snapshot_detail(self, sf_snapshot_details_list, key):
+ for sf_snapshot_detail_dict in sf_snapshot_details_list:
+ if sf_snapshot_detail_dict["snapshotDetailsName"] == key:
+ return sf_snapshot_detail_dict["snapshotDetailsValue"]
+
+ raise Exception("Unable to find the following snapshot details key: " + key)
+
+ def _check_sf_snapshot_does_not_exist(self, sf_snapshots, sf_snapshot_id):
+ for sf_snapshot in sf_snapshots:
+ if sf_snapshot["snapshotID"] == sf_snapshot:
+ raise Exception("The following SolidFire snapshot ID should not exist: " + sf_snapshot_id)
+
+ def _check_snapshot_details_do_not_exist(self, vol_snap_db_id):
+ sql_query = "Select count(*) From snapshot_details Where snapshot_id = " + str(vol_snap_db_id)
+
+ # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench
+ sql_result = self.dbConnection.execute(sql_query)
+
+ self.assertEqual(
+ sql_result[0][0],
+ 0,
+ "Snapshot details should not exist for the following CloudStack volume snapshot DB ID: " + str(vol_snap_db_id)
+ )
+
+ # used when SolidFire snapshots are being used for CloudStack volume snapshots
+ def _create_and_test_snapshot(self, volume_id_for_snapshot, sf_volume, primary_storage_db_id, expected_num_snapshots, snapshot_err_msg):
+ vol_snap = Snapshot.create(
+ self.apiClient,
+ volume_id=volume_id_for_snapshot
+ )
+
+ sf_volume_id = sf_volume['volumeID']
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume_id)
+
+ self._check_list(sf_snapshots, expected_num_snapshots, snapshot_err_msg)
+
+ sf_snapshot = self._most_recent_sf_snapshot(sf_snapshots)
+
+ sf_snapshot_details_request = {'snapshotid': vol_snap.id}
+ sf_snapshot_details_response = self.cs_api.getVolumeSnapshotDetails(sf_snapshot_details_request)
+ sf_snapshot_details = sf_snapshot_details_response['null'] # 'null' gets me the list that's in the dictionary
+
+ vol_snap_db_id = self._get_cs_volume_snapshot_db_id(vol_snap)
+
+ self._check_snapshot_details(sf_snapshot_details, vol_snap_db_id, sf_volume_id, sf_snapshot['snapshotID'], primary_storage_db_id, sf_volume['totalSize'])
+
+ return vol_snap
+
+ # used when SolidFire volumes are being used for CloudStack volume snapshots
+ def _create_and_test_snapshot_2(self, volume_id_for_snapshot, sf_volume_id, sf_volume_id_for_volume_snapshot, primary_storage_db_id, sf_volume_size,
+ sf_account_id, expected_num_volumes, volume_err_msg):
+ vol_snap = Snapshot.create(
+ self.apiClient,
+ volume_id=volume_id_for_snapshot
+ )
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume_id)
+
+ self._check_list(sf_snapshots, 0, TestSnapshots._should_be_zero_snapshots_in_list_err_msg)
+
+ sf_snapshot_details_request = {'snapshotid': vol_snap.id}
+ sf_snapshot_details_response = self.cs_api.getVolumeSnapshotDetails(sf_snapshot_details_request)
+ sf_snapshot_details = sf_snapshot_details_response['null'] # 'null' gets me the list that's in the dictionary
+
+ vol_snap_db_id = self._get_cs_volume_snapshot_db_id(vol_snap)
+
+ self._check_snapshot_details_2(sf_snapshot_details, vol_snap_db_id, sf_volume_id_for_volume_snapshot, primary_storage_db_id, sf_volume_size)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, expected_num_volumes, volume_err_msg)
+
+ sf_volume_for_snapshot = self._get_sf_volume_by_id(sf_volumes, sf_volume_id_for_volume_snapshot)
+
+ self._check_list(sf_volume_for_snapshot['volumeAccessGroups'], 0, TestSnapshots._should_be_zero_volume_access_groups_in_list_err_msg)
+
+ return vol_snap
+
+ # used when SolidFire snapshots are being used for CloudStack volume snapshots
+ def _delete_and_test_snapshot(self, vol_snap):
+ vol_snap_id = vol_snap.id
+ vol_snap_db_id = self._get_cs_volume_snapshot_db_id(vol_snap)
+
+ sf_snapshot_details_request = {'snapshotid': vol_snap_id}
+ sf_snapshot_details_response = self.cs_api.getVolumeSnapshotDetails(sf_snapshot_details_request)
+ sf_snapshot_details = sf_snapshot_details_response['null'] # 'null' gets me the list that's in the dictionary
+
+ sf_volume_id = self._get_snapshot_detail(sf_snapshot_details, "volumeId")
+ sf_snapshot_id = self._get_snapshot_detail(sf_snapshot_details, "snapshotId")
+
+ vol_snap.delete(self.apiClient)
+
+ # Get snapshot information for volume from SolidFire cluster
+ sf_snapshots = self.sf_client.list_snapshots(volume_id=sf_volume_id)
+
+ self._check_sf_snapshot_does_not_exist(sf_snapshots, sf_snapshot_id)
+
+ self._check_snapshot_details_do_not_exist(vol_snap_db_id)
+
+ # used when SolidFire volumes are being used for CloudStack volume snapshots
+ def _delete_and_test_snapshot_2(self, vol_snap, sf_account_id, expected_num_volumes, volume_err_msg):
+ vol_snap_db_id = self._get_cs_volume_snapshot_db_id(vol_snap)
+
+ vol_snap.delete(self.apiClient)
+
+ self._check_snapshot_details_do_not_exist(vol_snap_db_id)
+
+ # Get volume information from SolidFire cluster
+ sf_volumes = self.sf_client.list_volumes_for_account(account_id=sf_account_id)
+
+ self._check_list(sf_volumes, expected_num_volumes, volume_err_msg)
+
+ @classmethod
+ def _purge_solidfire_volumes(cls):
+ deleted_volumes = cls.sf_client.list_deleted_volumes()
+
+ for deleted_volume in deleted_volumes:
+ cls.sf_client.purge_deleted_volume(deleted_volume['volumeID'])
+
diff --git a/test/integration/plugins/solidfire/TestVMSnapshots.py b/test/integration/plugins/solidfire/TestVMSnapshots.py
new file mode 100644
index 0000000..8fba8f8
--- /dev/null
+++ b/test/integration/plugins/solidfire/TestVMSnapshots.py
@@ -0,0 +1,862 @@
+# 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 logging
+import random
+import SignedAPICall
+import XenAPI
+
+# All tests inherit from cloudstackTestCase
+from marvin.cloudstackTestCase import cloudstackTestCase
+
+# Import Integration Libraries
+
+# base - contains all resources as entities and defines create, delete, list operations on them
+from marvin.lib.base import Account, DiskOffering, ServiceOffering, StoragePool, User, VirtualMachine, VmSnapshot, Volume
+
+# common - commonly used methods for all tests are listed here
+from marvin.lib.common import get_domain, get_template, get_zone, list_hosts, list_volumes
+
+# utils - utility classes for common cleanup, external library wrappers, etc.
+from marvin.lib.utils import cleanup_resources
+
+from solidfire import solidfire_element_api as sf_api
+
+# on April 15, 2016: Ran 2 tests in 800.299s with three hosts
+# on May 2, 2016: Ran 2 tests in 789.729s with two hosts
+
+
+class TestData:
+ account = "account"
+ capacityBytes = "capacitybytes"
+ capacityIops = "capacityiops"
+ clusterId = "clusterId"
+ computeOffering = "computeoffering"
+ diskOffering = "diskoffering"
+ domainId = "domainId"
+ hypervisor = "hypervisor"
+ login = "login"
+ mvip = "mvip"
+ password = "password"
+ port = "port"
+ primaryStorage = "primarystorage"
+ provider = "provider"
+ scope = "scope"
+ solidFire = "solidfire"
+ storageTag = "SolidFire_SAN_1"
+ tags = "tags"
+ templateName = "templatename"
+ url = "url"
+ user = "user"
+ username = "username"
+ virtualMachine = "virtualmachine"
+ volume_1 = "volume_1"
+ xenServer = "xenserver"
+ zoneId = "zoneId"
+
+ def __init__(self):
+ self.testdata = {
+ TestData.solidFire: {
+ TestData.mvip: "192.168.139.112",
+ TestData.login: "admin",
+ TestData.password: "admin",
+ TestData.port: 443,
+ TestData.url: "https://192.168.139.112:443"
+ },
+ TestData.xenServer: {
+ TestData.username: "root",
+ TestData.password: "solidfire"
+ },
+ TestData.account: {
+ "email": "test@test.com",
+ "firstname": "John",
+ "lastname": "Doe",
+ TestData.username: "test",
+ TestData.password: "test"
+ },
+ TestData.user: {
+ "email": "user@test.com",
+ "firstname": "Jane",
+ "lastname": "Doe",
+ TestData.username: "testuser",
+ TestData.password: "password"
+ },
+ TestData.primaryStorage: {
+ "name": "SolidFire-%d" % random.randint(0, 100),
+ TestData.scope: "ZONE",
+ "url": "MVIP=192.168.139.112;SVIP=10.10.8.112;" +
+ "clusterAdminUsername=admin;clusterAdminPassword=admin;" +
+ "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" +
+ "clusterDefaultBurstIopsPercentOfMaxIops=1.5;",
+ TestData.provider: "SolidFire",
+ TestData.tags: TestData.storageTag,
+ TestData.capacityIops: 4500000,
+ TestData.capacityBytes: 2251799813685248,
+ TestData.hypervisor: "Any"
+ },
+ TestData.virtualMachine: {
+ "name": "TestVM",
+ "displayname": "Test VM"
+ },
+ TestData.computeOffering: {
+ "name": "SF_CO_1",
+ "displaytext": "SF_CO_1 (Min IOPS = 10,000; Max IOPS = 15,000)",
+ "cpunumber": 1,
+ "cpuspeed": 100,
+ "memory": 128,
+ "storagetype": "shared",
+ "customizediops": False,
+ "miniops": "10000",
+ "maxiops": "15000",
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag
+ },
+ TestData.diskOffering: {
+ "name": "SF_DO_1",
+ "displaytext": "SF_DO_1 (Min IOPS = 300; Max IOPS = 500)",
+ "disksize": 128,
+ "customizediops": False,
+ "miniops": 300,
+ "maxiops": 500,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "testdiskofferings": {
+ "customiopsdo": {
+ "name": "SF_Custom_IOPS_DO",
+ "displaytext": "Customized IOPS DO (Size = 128 GB; Min IOPS = 500; Max IOPS = 1000)",
+ "disksize": 128,
+ "customizediops": True,
+ "miniops": 500,
+ "maxiops": 1000,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "customsizedo": {
+ "name": "SF_Custom_Size_DO",
+ "displaytext": "Customized IOPS DO (Min IOPS = 500; Max IOPS = 1000)",
+ "disksize": 175,
+ "customizediops": False,
+ "miniops": 500,
+ "maxiops": 1000,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "customsizeandiopsdo": {
+ "name": "SF_Custom_Size_IOPS_DO",
+ "displaytext": "Customized Size and IOPS DO",
+ "disksize": 200,
+ "customizediops": True,
+ "miniops": 400,
+ "maxiops": 800,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "newiopsdo": {
+ "name": "SF_New_IOPS_DO",
+ "displaytext": "New IOPS (Size = 128 GB; Min IOPS = 350, Max IOPS = 700)",
+ "disksize": 128,
+ "miniops": 350,
+ "maxiops": 700,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "newsizedo": {
+ "name": "SF_New_Size_DO",
+ "displaytext": "New Size: 175",
+ "disksize": 175,
+ "miniops": 400,
+ "maxiops": 800,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "newsizeandiopsdo": {
+ "name": "SF_New_Size_IOPS_DO",
+ "displaytext": "New Size and IOPS",
+ "disksize": 200,
+ "miniops": 200,
+ "maxiops": 400,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ }
+ },
+ TestData.volume_1: {
+ "diskname": "testvolume",
+ },
+ "volume2": {
+ "diskname": "testvolume2",
+ },
+ TestData.templateName: "CentOS 5.6(64-bit) no GUI (XenServer)",
+ TestData.zoneId: 1,
+ TestData.clusterId: 1,
+ TestData.domainId: 1,
+ TestData.url: "192.168.129.50"
+ }
+
+
+class TestVMSnapshots(cloudstackTestCase):
+ _should_be_no_vm_snapshots_err_msg = "There should be no VM snapshots."
+ _should_only_be_one_vm_snapshot_err_msg = "There should only be one VM snapshot."
+ _should_only_be_one_root_volume_err_msg = "There should only be one root volume."
+ _path_should_have_changed_err_msg = "The 'path' in the 'DB' should have changed."
+ _path_should_not_have_changed_err_msg = "The 'path' in the 'DB' should not have changed."
+ _should_only_be_one_vdi_err_msg = "There should only be one VDI."
+ _should_be_three_vdis_err_msg = "There should be three VDIs."
+ _active_vdis_should_not_be_the_same_err_msg = "The active VDIs should not be the same."
+ _active_vdis_should_be_the_same_err_msg = "The active VDIs should be the same."
+ _snapshot_vdis_should_be_the_same_err_msg = "The snapshot VDIs should be the same."
+ _base_vdis_should_be_the_same_err_msg = "The base VDIs should be the same."
+ _snapshot_parent_not_correct_err_msg = "Snapshot's parent is not correct."
+
+ @classmethod
+ def setUpClass(cls):
+ # Set up API client
+ testclient = super(TestVMSnapshots, cls).getClsTestClient()
+ cls.apiClient = testclient.getApiClient()
+
+ cls.testdata = TestData().testdata
+
+ # Set up XenAPI connection
+ host_ip = "https://" + \
+ list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress
+
+ cls.xen_session = XenAPI.Session(host_ip)
+
+ xenserver = cls.testdata[TestData.xenServer]
+
+ cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password])
+
+ # Set up SolidFire connection
+ cls.sf_client = sf_api.SolidFireAPI(endpoint_dict=cls.testdata[TestData.solidFire])
+
+ # Get Resources from Cloud Infrastructure
+ cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId])
+ template = get_template(cls.apiClient, cls.zone.id, template_name=cls.testdata[TestData.templateName])
+ cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId])
+
+ # Create test account
+ cls.account = Account.create(
+ cls.apiClient,
+ cls.testdata[TestData.account],
+ admin=1
+ )
+
+ # Set up connection to make customized API calls
+ user = User.create(
+ cls.apiClient,
+ cls.testdata[TestData.user],
+ account=cls.account.name,
+ domainid=cls.domain.id
+ )
+
+ url = cls.testdata[TestData.url]
+
+ api_url = "http://" + url + ":8080/client/api"
+ userkeys = User.registerUserKeys(cls.apiClient, user.id)
+
+ cls.cs_api = SignedAPICall.CloudStack(api_url, userkeys.apikey, userkeys.secretkey)
+
+ primarystorage = cls.testdata[TestData.primaryStorage]
+
+ cls.primary_storage = StoragePool.create(
+ cls.apiClient,
+ primarystorage,
+ scope=primarystorage[TestData.scope],
+ zoneid=cls.zone.id,
+ provider=primarystorage[TestData.provider],
+ tags=primarystorage[TestData.tags],
+ capacityiops=primarystorage[TestData.capacityIops],
+ capacitybytes=primarystorage[TestData.capacityBytes],
+ hypervisor=primarystorage[TestData.hypervisor]
+ )
+
+ compute_offering = ServiceOffering.create(
+ cls.apiClient,
+ cls.testdata[TestData.computeOffering]
+ )
+
+ cls.disk_offering = DiskOffering.create(
+ cls.apiClient,
+ cls.testdata[TestData.diskOffering]
+ )
+
+ # Create VM and volume for tests
+ cls.virtual_machine = VirtualMachine.create(
+ cls.apiClient,
+ cls.testdata[TestData.virtualMachine],
+ accountid=cls.account.name,
+ zoneid=cls.zone.id,
+ serviceofferingid=compute_offering.id,
+ templateid=template.id,
+ domainid=cls.domain.id,
+ startvm=True
+ )
+
+ cls._cleanup = [
+ cls.virtual_machine,
+ compute_offering,
+ cls.disk_offering,
+ user,
+ cls.account
+ ]
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ cleanup_resources(cls.apiClient, cls._cleanup)
+
+ cls.primary_storage.delete(cls.apiClient)
+
+ cls._purge_solidfire_volumes()
+ except Exception as e:
+ logging.debug("Exception in tearDownClass(cls): %s" % e)
+
+ def setUp(self):
+ self.cleanup = []
+
+ def tearDown(self):
+ try:
+ cleanup_resources(self.apiClient, self.cleanup)
+ except Exception as e:
+ logging.debug("Exception in tearDown(self): %s" % e)
+
+ def test_01_take_VM_snapshot(self):
+ self.virtual_machine.start(self.apiClient)
+
+ root_volumes = list_volumes(self.apiClient, type="ROOT", listAll="true")
+
+ self._check_list(root_volumes, 1, TestVMSnapshots._should_only_be_one_root_volume_err_msg)
+
+ root_volume = root_volumes[0]
+
+ volume_id = {'volumeid': root_volume.id}
+
+ sf_iscsi_name_result = self.cs_api.getVolumeiScsiName(volume_id)
+ sf_iscsi_name = sf_iscsi_name_result['apivolumeiscsiname']['volumeiScsiName']
+
+ self._check_iscsi_name(sf_iscsi_name)
+
+ root_volume_path_1 = self._get_path(volume_id)
+
+ #######################################
+ #######################################
+ # STEP 1: Take snapshot of running VM #
+ #######################################
+ #######################################
+ vm_snapshot = VmSnapshot.create(
+ self.apiClient,
+ vmid=self.virtual_machine.id,
+ snapshotmemory="false",
+ name="Test Snapshot",
+ description="Test Snapshot Desc"
+ )
+
+ list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true")
+
+ self._verify_vm_snapshot(list_vm_snapshots, vm_snapshot)
+
+ root_volume_path_2 = self._get_path(volume_id)
+
+ self.assertEqual(
+ root_volume_path_1,
+ root_volume_path_2,
+ TestVMSnapshots._path_should_not_have_changed_err_msg
+ )
+
+ xen_sr = self.xen_session.xenapi.SR.get_by_name_label(sf_iscsi_name)[0]
+
+ xen_vdis = self.xen_session.xenapi.SR.get_VDIs(xen_sr)
+
+ self._check_list(xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg)
+
+ vdis_after_create = self._get_vdis(xen_vdis)
+
+ vdiSnapshotOf = self.xen_session.xenapi.VDI.get_record(vdis_after_create.snapshot_vdi["snapshot_of"])
+
+ self.assertEqual(
+ vdiSnapshotOf["uuid"],
+ vdis_after_create.active_vdi["uuid"],
+ TestVMSnapshots._snapshot_parent_not_correct_err_msg
+ )
+
+ #######################################
+ #######################################
+ ### STEP 2: Revert VM to Snapshot ###
+ #######################################
+ #######################################
+ self.virtual_machine.stop(self.apiClient)
+
+ VmSnapshot.revertToSnapshot(self.apiClient, vmsnapshotid=vm_snapshot.id)
+
+ list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true")
+
+ self._check_list(list_vm_snapshots, 1, TestVMSnapshots._should_only_be_one_vm_snapshot_err_msg)
+
+ root_volume_path_3 = self._get_path(volume_id)
+
+ self.assertNotEqual(
+ root_volume_path_1,
+ root_volume_path_3,
+ TestVMSnapshots._path_should_have_changed_err_msg
+ )
+
+ xen_vdis = self.xen_session.xenapi.SR.get_VDIs(xen_sr)
+
+ self._check_list(xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg)
+
+ vdis_after_revert = self._get_vdis(xen_vdis)
+
+ self.assertNotEqual(
+ vdis_after_create.active_vdi["uuid"],
+ vdis_after_revert.active_vdi["uuid"],
+ TestVMSnapshots._active_vdis_should_not_be_the_same_err_msg
+ )
+
+ self.assertEqual(
+ vdis_after_create.snapshot_vdi["uuid"],
+ vdis_after_revert.snapshot_vdi["uuid"],
+ TestVMSnapshots._snapshot_vdis_should_be_the_same_err_msg
+ )
+
+ self.assertEqual(
+ vdis_after_create.base_vdi["uuid"],
+ vdis_after_revert.base_vdi["uuid"],
+ TestVMSnapshots._base_vdis_should_be_the_same_err_msg
+ )
+
+ #######################################
+ #######################################
+ ##### STEP 3: Delete VM snapshot #####
+ #######################################
+ #######################################
+ VmSnapshot.deleteVMSnapshot(self.apiClient, vmsnapshotid=vm_snapshot.id)
+
+ list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true")
+
+ self.assertEqual(
+ list_vm_snapshots,
+ None,
+ TestVMSnapshots._should_be_no_vm_snapshots_err_msg
+ )
+
+ root_volume_path_4 = self._get_path(volume_id)
+
+ self.assertEqual(
+ root_volume_path_3,
+ root_volume_path_4,
+ TestVMSnapshots._path_should_not_have_changed_err_msg
+ )
+
+ xen_vdis = self.xen_session.xenapi.SR.get_VDIs(xen_sr)
+
+ self._check_list(xen_vdis, 1, TestVMSnapshots._should_only_be_one_vdi_err_msg)
+
+ vdis_after_delete = self._get_vdis(xen_vdis, True)
+
+ self.assertEqual(
+ vdis_after_revert.active_vdi["uuid"],
+ vdis_after_delete.active_vdi["uuid"],
+ TestVMSnapshots._active_vdis_should_be_the_same_err_msg
+ )
+
+ #######################################
+ #######################################
+ ##### STEP 4: Start VM #####
+ #######################################
+ #######################################
+ self.virtual_machine.start(self.apiClient)
+
+ def test_02_take_VM_snapshot_with_data_disk(self):
+ self.virtual_machine.start(self.apiClient)
+
+ data_volume = Volume.create(
+ self.apiClient,
+ self.testdata[TestData.volume_1],
+ account=self.account.name,
+ domainid=self.domain.id,
+ zoneid=self.zone.id,
+ diskofferingid=self.disk_offering.id
+ )
+
+ self.cleanup = [data_volume]
+
+ self.virtual_machine.attach_volume(self.apiClient, data_volume)
+
+ root_volumes = list_volumes(self.apiClient, type="ROOT", listAll="true")
+
+ self._check_list(root_volumes, 1, TestVMSnapshots._should_only_be_one_root_volume_err_msg)
+
+ root_volume = root_volumes[0]
+
+ root_volume_id = {'volumeid': root_volume.id}
+
+ sf_iscsi_name_result = self.cs_api.getVolumeiScsiName(root_volume_id)
+ sf_iscsi_root_volume_name = sf_iscsi_name_result['apivolumeiscsiname']['volumeiScsiName']
+
+ self._check_iscsi_name(sf_iscsi_root_volume_name)
+
+ root_volume_path_1 = self._get_path(root_volume_id)
+
+ data_volumes = list_volumes(self.apiClient, type="DATADISK", listAll="true")
+
+ self._check_list(data_volumes, 1, "There should only be one data volume.")
+
+ data_volume = data_volumes[0]
+
+ data_volume_id = {'volumeid': data_volume.id}
+
+ sf_iscsi_name_result = self.cs_api.getVolumeiScsiName(data_volume_id)
+ sf_iscsi_data_volume_name = sf_iscsi_name_result['apivolumeiscsiname']['volumeiScsiName']
+
+ self._check_iscsi_name(sf_iscsi_data_volume_name)
+
+ data_volume_path_1 = self._get_path(data_volume_id)
+
+ #######################################
+ #######################################
+ # STEP 1: Take snapshot of running VM #
+ #######################################
+ #######################################
+ vm_snapshot = VmSnapshot.create(
+ self.apiClient,
+ vmid=self.virtual_machine.id,
+ snapshotmemory="false",
+ name="Test Snapshot",
+ description="Test Snapshot Desc"
+ )
+
+ list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true")
+
+ self._verify_vm_snapshot(list_vm_snapshots, vm_snapshot)
+
+ root_volume_path_2 = self._get_path(root_volume_id)
+
+ self.assertEqual(
+ root_volume_path_1,
+ root_volume_path_2,
+ TestVMSnapshots._path_should_not_have_changed_err_msg
+ )
+
+ data_volume_path_2 = self._get_path(data_volume_id)
+
+ self.assertEqual(
+ data_volume_path_1,
+ data_volume_path_2,
+ TestVMSnapshots._path_should_not_have_changed_err_msg
+ )
+
+ root_volume_xen_sr = self.xen_session.xenapi.SR.get_by_name_label(sf_iscsi_root_volume_name)[0]
+
+ root_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(root_volume_xen_sr)
+
+ self._check_list(root_volume_xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg)
+
+ root_volume_vdis_after_create = self._get_vdis(root_volume_xen_vdis)
+
+ vdiSnapshotOf = self.xen_session.xenapi.VDI.get_record(root_volume_vdis_after_create.snapshot_vdi["snapshot_of"])
+
+ self.assertEqual(
+ vdiSnapshotOf["uuid"],
+ root_volume_vdis_after_create.active_vdi["uuid"],
+ TestVMSnapshots._snapshot_parent_not_correct_err_msg
+ )
+
+ data_volume_xen_sr = self.xen_session.xenapi.SR.get_by_name_label(sf_iscsi_data_volume_name)[0]
+
+ data_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(data_volume_xen_sr)
+
+ self._check_list(data_volume_xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg)
+
+ data_volume_vdis_after_create = self._get_vdis(data_volume_xen_vdis)
+
+ vdiSnapshotOf = self.xen_session.xenapi.VDI.get_record(data_volume_vdis_after_create.snapshot_vdi["snapshot_of"])
+
+ self.assertEqual(
+ vdiSnapshotOf["uuid"],
+ data_volume_vdis_after_create.active_vdi["uuid"],
+ TestVMSnapshots._snapshot_parent_not_correct_err_msg
+ )
+
+ #######################################
+ #######################################
+ ### STEP 2: Revert VM to Snapshot ###
+ #######################################
+ #######################################
+ self.virtual_machine.stop(self.apiClient)
+
+ VmSnapshot.revertToSnapshot(self.apiClient, vmsnapshotid=vm_snapshot.id)
+
+ list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true")
+
+ self._check_list(list_vm_snapshots, 1, TestVMSnapshots._should_only_be_one_vm_snapshot_err_msg)
+
+ root_volume_path_3 = self._get_path(root_volume_id)
+
+ self.assertNotEqual(
+ root_volume_path_1,
+ root_volume_path_3,
+ TestVMSnapshots._path_should_have_changed_err_msg
+ )
+
+ root_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(root_volume_xen_sr)
+
+ self._check_list(root_volume_xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg)
+
+ root_volume_vdis_after_revert = self._get_vdis(root_volume_xen_vdis)
+
+ self.assertNotEqual(
+ root_volume_vdis_after_create.active_vdi["uuid"],
+ root_volume_vdis_after_revert.active_vdi["uuid"],
+ TestVMSnapshots._active_vdis_should_not_be_the_same_err_msg
+ )
+
+ self.assertEqual(
+ root_volume_vdis_after_create.snapshot_vdi["uuid"],
+ root_volume_vdis_after_revert.snapshot_vdi["uuid"],
+ TestVMSnapshots._snapshot_vdis_should_be_the_same_err_msg
+ )
+
+ self.assertEqual(
+ root_volume_vdis_after_create.base_vdi["uuid"],
+ root_volume_vdis_after_revert.base_vdi["uuid"],
+ TestVMSnapshots._base_vdis_should_be_the_same_err_msg
+ )
+
+ data_volume_path_3 = self._get_path(data_volume_id)
+
+ self.assertNotEqual(
+ data_volume_path_1,
+ data_volume_path_3,
+ TestVMSnapshots._path_should_have_changed_err_msg
+ )
+
+ data_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(data_volume_xen_sr)
+
+ self._check_list(data_volume_xen_vdis, 3, TestVMSnapshots._should_be_three_vdis_err_msg)
+
+ data_volume_vdis_after_revert = self._get_vdis(data_volume_xen_vdis)
+
+ self.assertNotEqual(
+ data_volume_vdis_after_create.active_vdi["uuid"],
+ data_volume_vdis_after_revert.active_vdi["uuid"],
+ TestVMSnapshots._active_vdis_should_not_be_the_same_err_msg
+ )
+
+ self.assertEqual(
+ data_volume_vdis_after_create.snapshot_vdi["uuid"],
+ data_volume_vdis_after_revert.snapshot_vdi["uuid"],
+ TestVMSnapshots._snapshot_vdis_should_be_the_same_err_msg
+ )
+
+ self.assertEqual(
+ data_volume_vdis_after_create.base_vdi["uuid"],
+ data_volume_vdis_after_revert.base_vdi["uuid"],
+ TestVMSnapshots._base_vdis_should_be_the_same_err_msg
+ )
+
+ #######################################
+ #######################################
+ ##### STEP 3: Delete VM snapshot #####
+ #######################################
+ #######################################
+ VmSnapshot.deleteVMSnapshot(self.apiClient, vmsnapshotid=vm_snapshot.id)
+
+ list_vm_snapshots = VmSnapshot.list(self.apiClient, listAll="true")
+
+ self.assertEqual(
+ list_vm_snapshots,
+ None,
+ TestVMSnapshots._should_be_no_vm_snapshots_err_msg
+ )
+
+ root_volume_path_4 = self._get_path(root_volume_id)
+
+ self.assertEqual(
+ root_volume_path_3,
+ root_volume_path_4,
+ TestVMSnapshots._path_should_not_have_changed_err_msg
+ )
+
+ root_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(root_volume_xen_sr)
+
+ self._check_list(root_volume_xen_vdis, 1, TestVMSnapshots._should_only_be_one_vdi_err_msg)
+
+ root_volume_vdis_after_delete = self._get_vdis(root_volume_xen_vdis, True)
+
+ self.assertEqual(
+ root_volume_vdis_after_revert.active_vdi["uuid"],
+ root_volume_vdis_after_delete.active_vdi["uuid"],
+ TestVMSnapshots._active_vdis_should_be_the_same_err_msg
+ )
+
+ data_volume_path_4 = self._get_path(data_volume_id)
+
+ self.assertEqual(
+ data_volume_path_3,
+ data_volume_path_4,
+ TestVMSnapshots._path_should_not_have_changed_err_msg
+ )
+
+ data_volume_xen_vdis = self.xen_session.xenapi.SR.get_VDIs(data_volume_xen_sr)
+
+ self._check_list(data_volume_xen_vdis, 1, TestVMSnapshots._should_only_be_one_vdi_err_msg)
+
+ data_volume_vdis_after_delete = self._get_vdis(data_volume_xen_vdis, True)
+
+ self.assertEqual(
+ data_volume_vdis_after_revert.active_vdi["uuid"],
+ data_volume_vdis_after_delete.active_vdi["uuid"],
+ TestVMSnapshots._active_vdis_should_be_the_same_err_msg
+ )
+
+ #######################################
+ #######################################
+ ##### STEP 4: Start VM #####
+ #######################################
+ #######################################
+ self.virtual_machine.detach_volume(self.apiClient, data_volume)
+
+ self.virtual_machine.start(self.apiClient)
+
+ def _get_path(self, volume_id):
+ path_result = self.cs_api.getPathForVolume(volume_id)
+
+ return path_result['apipathforvolume']['path']
+
+ def _verify_vm_snapshot(self, list_vm_snapshots, vm_snapshot):
+ self._check_list(list_vm_snapshots, 1, TestVMSnapshots._should_only_be_one_vm_snapshot_err_msg)
+
+ vm_snapshot_from_list = list_vm_snapshots[0]
+
+ self.assertEqual(
+ vm_snapshot.id,
+ vm_snapshot_from_list.id,
+ "There is a problem with the VM snapshot ID."
+ )
+
+ self.assertEqual(
+ vm_snapshot.virtualmachineid,
+ self.virtual_machine.id,
+ "The ID of the snapshot's virtual machine does not match the expected virtual machine."
+ )
+
+ self.assertEqual(
+ vm_snapshot.state,
+ "Ready",
+ "The snapshot is not in the 'Ready' state."
+ )
+
+ def _check_iscsi_name(self, sf_iscsi_name):
+ self.assertEqual(
+ sf_iscsi_name[0],
+ "/",
+ "The iSCSI name needs to start with a forward slash."
+ )
+
+ def _check_list(self, in_list, expected_size_of_list, err_msg):
+ self.assertEqual(
+ isinstance(in_list, list),
+ True,
+ "'in_list' is not a list."
+ )
+
+ self.assertEqual(
+ len(in_list),
+ expected_size_of_list,
+ err_msg
+ )
+
+ def _get_vdis(self, xen_vdis, only_active_expected=False):
+ expected_number_of_vdis = 1 if only_active_expected else 3
+
+ self.assertEqual(
+ len(xen_vdis),
+ expected_number_of_vdis,
+ "The list had an unexpected number of items in it."
+ )
+
+ active_vdi = None
+ snapshot_vdi = None
+ base_vdi = None
+
+ for temp_vdi in xen_vdis:
+ temp = self.xen_session.xenapi.VDI.get_record(temp_vdi)
+
+ if temp["name_label"] == "base copy":
+ base_vdi = temp
+ else:
+ if temp["is_a_snapshot"] == True:
+ snapshot_vdi = temp
+ else:
+ active_vdi = temp
+
+ self.assertNotEqual(
+ active_vdi,
+ None,
+ "The active VDI could not be located."
+ )
+
+ if only_active_expected:
+ self.assertEqual(
+ snapshot_vdi,
+ None,
+ "The snapshot VDI should not be present."
+ )
+
+ self.assertEqual(
+ base_vdi,
+ None,
+ "The base VDI should not be present."
+ )
+ else:
+ self.assertNotEqual(
+ snapshot_vdi,
+ None,
+ "The snapshot VDI could not be located."
+ )
+
+ self.assertNotEqual(
+ base_vdi,
+ None,
+ "The base VDI could not be located."
+ )
+
+ class VdiCollection(object):
+ pass
+
+ vdis = VdiCollection()
+
+ vdis.active_vdi = active_vdi
+ vdis.snapshot_vdi = snapshot_vdi
+ vdis.base_vdi = base_vdi
+
+ return vdis
+
+ @classmethod
+ def _purge_solidfire_volumes(cls):
+ deleted_volumes = cls.sf_client.list_deleted_volumes()
+
+ for deleted_volume in deleted_volumes:
+ cls.sf_client.purge_deleted_volume(deleted_volume['volumeID'])
+
diff --git a/test/integration/plugins/solidfire/TestVolumes.py b/test/integration/plugins/solidfire/TestVolumes.py
new file mode 100644
index 0000000..ed7d42a
--- /dev/null
+++ b/test/integration/plugins/solidfire/TestVolumes.py
@@ -0,0 +1,1676 @@
+# 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 logging
+import random
+import SignedAPICall
+import XenAPI
+
+# All tests inherit from cloudstackTestCase
+from marvin.cloudstackTestCase import cloudstackTestCase
+
+from nose.plugins.attrib import attr
+
+# Import Integration Libraries
+
+# base - contains all resources as entities and defines create, delete, list operations on them
+from marvin.lib.base import Account, DiskOffering, ServiceOffering, StoragePool, User, VirtualMachine, Volume
+
+# common - commonly used methods for all tests are listed here
+from marvin.lib.common import get_domain, get_template, get_zone, list_clusters, list_hosts, list_virtual_machines, \
+ list_volumes
+
+# utils - utility classes for common cleanup, external library wrappers, etc.
+from marvin.lib.utils import cleanup_resources
+
+from solidfire import solidfire_element_api as sf_api
+
+# on April 14, 2016: Ran 11 tests in 2494.043s with three hosts (resign = True)
+# on April 14, 2016: Ran 11 tests in 2033.516s with three hosts (resign = False)
+
+# on May 2, 2016: Ran 11 tests in 2352.461s with two hosts (resign = True)
+# on May 2, 2016: Ran 11 tests in 1982.066s with two hosts (resign = False)
+
+
+class TestData():
+ account = "account"
+ capacityBytes = "capacitybytes"
+ capacityIops = "capacityiops"
+ clusterId = "clusterId"
+ computeOffering = "computeoffering"
+ diskName = "diskname"
+ diskOffering = "diskoffering"
+ domainId = "domainId"
+ hypervisor = "hypervisor"
+ login = "login"
+ mvip = "mvip"
+ password = "password"
+ port = "port"
+ primaryStorage = "primarystorage"
+ provider = "provider"
+ scope = "scope"
+ solidFire = "solidfire"
+ storageTag = "SolidFire_SAN_1"
+ tags = "tags"
+ templateCacheName = "centos56-x86-64-xen"
+ templateName = "templatename"
+ testAccount = "testaccount"
+ url = "url"
+ user = "user"
+ username = "username"
+ virtualMachine = "virtualmachine"
+ virtualMachine2 = "virtualmachine2"
+ volume_1 = "volume_1"
+ volume_2 = "volume_2"
+ xenServer = "xenserver"
+ zoneId = "zoneId"
+
+ def __init__(self):
+ self.testdata = {
+ TestData.solidFire: {
+ TestData.mvip: "192.168.139.112",
+ TestData.login: "admin",
+ TestData.password: "admin",
+ TestData.port: 443,
+ TestData.url: "https://192.168.139.112:443"
+ },
+ TestData.xenServer: {
+ TestData.username: "root",
+ TestData.password: "solidfire"
+ },
+ TestData.account: {
+ "email": "test@test.com",
+ "firstname": "John",
+ "lastname": "Doe",
+ "username": "test",
+ "password": "test"
+ },
+ TestData.testAccount: {
+ "email": "test2@test2.com",
+ "firstname": "Jane",
+ "lastname": "Doe",
+ "username": "test2",
+ "password": "test"
+ },
+ TestData.user: {
+ "email": "user@test.com",
+ "firstname": "Jane",
+ "lastname": "Doe",
+ "username": "testuser",
+ "password": "password"
+ },
+ TestData.primaryStorage: {
+ "name": "SolidFire-%d" % random.randint(0, 100),
+ TestData.scope: "ZONE",
+ "url": "MVIP=192.168.139.112;SVIP=10.10.8.112;" +
+ "clusterAdminUsername=admin;clusterAdminPassword=admin;" +
+ "clusterDefaultMinIops=10000;clusterDefaultMaxIops=15000;" +
+ "clusterDefaultBurstIopsPercentOfMaxIops=1.5;",
+ TestData.provider: "SolidFire",
+ TestData.tags: TestData.storageTag,
+ TestData.capacityIops: 4500000,
+ TestData.capacityBytes: 2251799813685248,
+ TestData.hypervisor: "Any"
+ },
+ TestData.virtualMachine: {
+ "name": "TestVM",
+ "displayname": "Test VM"
+ },
+ TestData.virtualMachine2: {
+ "name": "TestVM2",
+ "displayname": "Test VM 2"
+ },
+ TestData.computeOffering: {
+ "name": "SF_CO_1",
+ "displaytext": "SF_CO_1 (Min IOPS = 10,000; Max IOPS = 15,000)",
+ "cpunumber": 1,
+ "cpuspeed": 100,
+ "memory": 128,
+ "storagetype": "shared",
+ "customizediops": False,
+ "miniops": "10000",
+ "maxiops": "15000",
+ "hypervisorsnapshotreserve": 200,
+ "tags": "SolidFire_SAN_1"
+ },
+ TestData.diskOffering: {
+ "name": "SF_DO_1",
+ "displaytext": "SF_DO_1 (Min IOPS = 300; Max IOPS = 500)",
+ "disksize": 128,
+ "customizediops": False,
+ "miniops": 300,
+ "maxiops": 500,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "testdiskofferings": {
+ "customiopsdo": {
+ "name": "SF_Custom_Iops_DO",
+ "displaytext": "Customized Iops DO",
+ "disksize": 128,
+ "customizediops": True,
+ "miniops": 500,
+ "maxiops": 1000,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "customsizedo": {
+ "name": "SF_Custom_Size_DO",
+ "displaytext": "Customized Size DO",
+ "disksize": 175,
+ "customizediops": False,
+ "miniops": 500,
+ "maxiops": 1000,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "customsizeandiopsdo": {
+ "name": "SF_Custom_Iops_Size_DO",
+ "displaytext": "Customized Size and Iops DO",
+ "disksize": 200,
+ "customizediops": True,
+ "miniops": 400,
+ "maxiops": 800,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "newiopsdo": {
+ "name": "SF_New_Iops_DO",
+ "displaytext": "New Iops (min=350, max = 700)",
+ "disksize": 128,
+ "miniops": 350,
+ "maxiops": 700,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "newsizedo": {
+ "name": "SF_New_Size_DO",
+ "displaytext": "New Size: 175",
+ "disksize": 175,
+ "miniops": 400,
+ "maxiops": 800,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ },
+ "newsizeandiopsdo": {
+ "name": "SF_New_Size_Iops_DO",
+ "displaytext": "New Size and Iops",
+ "disksize": 200,
+ "miniops": 200,
+ "maxiops": 400,
+ "hypervisorsnapshotreserve": 200,
+ TestData.tags: TestData.storageTag,
+ "storagetype": "shared"
+ }
+ },
+ TestData.volume_1: {
+ TestData.diskName: "test-volume",
+ },
+ TestData.volume_2: {
+ TestData.diskName: "test-volume-2",
+ },
+ TestData.templateName: "CentOS 5.6(64-bit) no GUI (XenServer)",
+ TestData.zoneId: 1,
+ TestData.clusterId: 1,
+ TestData.domainId: 1,
+ TestData.url: "192.168.129.50"
+ }
+
+
+class TestVolumes(cloudstackTestCase):
+ _should_only_be_one_vm_in_list_err_msg = "There should only be one VM in this list."
+ _should_only_be_one_volume_in_list_err_msg = "There should only be one volume in this list."
+ _sf_account_id_should_be_non_zero_int_err_msg = "The SolidFire account ID should be a non-zero integer."
+ _vag_id_should_be_non_zero_int_err_msg = "The SolidFire VAG ID should be a non-zero integer."
+ _volume_size_should_be_non_zero_int_err_msg = "The SolidFire volume size should be a non-zero integer."
+ _volume_vm_id_and_vm_id_do_not_match_err_msg = "The volume's VM ID and the VM's ID do not match."
+ _vm_not_in_running_state_err_msg = "The VM is not in the 'Running' state."
+ _vm_not_in_stopped_state_err_msg = "The VM is not in the 'Stopped' state."
+ _sr_not_shared_err_msg = "The SR is not shared."
+ _volume_response_should_not_be_zero_err_msg = "The length of the response for the SolidFire-volume query should not be zero."
+ _list_should_be_empty = "The list should be empty."
+ _volume_should_not_be_in_a_vag = "The volume should not be in a volume access group."
+
+ @classmethod
+ def setUpClass(cls):
+ # Set up API client
+ testclient = super(TestVolumes, cls).getClsTestClient()
+ cls.apiClient = testclient.getApiClient()
+ cls.dbConnection = testclient.getDbConnection()
+
+ cls.testdata = TestData().testdata
+
+ cls.supports_resign = True
+
+ cls._set_supports_resign()
+
+ # Set up xenAPI connection
+ host_ip = "https://" + \
+ list_hosts(cls.apiClient, clusterid=cls.testdata[TestData.clusterId], name="XenServer-6.5-1")[0].ipaddress
+
+ # Set up XenAPI connection
+ cls.xen_session = XenAPI.Session(host_ip)
+
+ xenserver = cls.testdata[TestData.xenServer]
+
+ cls.xen_session.xenapi.login_with_password(xenserver[TestData.username], xenserver[TestData.password])
+
+ # Set up SolidFire connection
+ cls.sf_client = sf_api.SolidFireAPI(endpoint_dict=cls.testdata[TestData.solidFire])
+
+ # Get Resources from Cloud Infrastructure
+ cls.zone = get_zone(cls.apiClient, zone_id=cls.testdata[TestData.zoneId])
+ cls.cluster = list_clusters(cls.apiClient)[0]
+ cls.template = get_template(cls.apiClient, cls.zone.id, template_name=cls.testdata[TestData.templateName])
+ cls.domain = get_domain(cls.apiClient, cls.testdata[TestData.domainId])
+
+ # Create test account
+ cls.account = Account.create(
+ cls.apiClient,
+ cls.testdata["account"],
+ admin=1
+ )
+
+ # Set up connection to make customized API calls
+ cls.user = User.create(
+ cls.apiClient,
+ cls.testdata["user"],
+ account=cls.account.name,
+ domainid=cls.domain.id
+ )
+
+ url = cls.testdata[TestData.url]
+
+ api_url = "http://" + url + ":8080/client/api"
+ userkeys = User.registerUserKeys(cls.apiClient, cls.user.id)
+
+ cls.cs_api = SignedAPICall.CloudStack(api_url, userkeys.apikey, userkeys.secretkey)
+
+ primarystorage = cls.testdata[TestData.primaryStorage]
+
+ cls.primary_storage = StoragePool.create(
+ cls.apiClient,
+ primarystorage,
+ scope=primarystorage[TestData.scope],
+ zoneid=cls.zone.id,
+ provider=primarystorage[TestData.provider],
+ tags=primarystorage[TestData.tags],
+ capacityiops=primarystorage[TestData.capacityIops],
+ capacitybytes=primarystorage[TestData.capacityBytes],
+ hypervisor=primarystorage[TestData.hypervisor]
+ )
+
+ cls.compute_offering = ServiceOffering.create(
+ cls.apiClient,
+ cls.testdata[TestData.computeOffering]
+ )
+
+ cls.disk_offering = DiskOffering.create(
+ cls.apiClient,
+ cls.testdata[TestData.diskOffering]
+ )
+
+ # Create VM and volume for tests
+ cls.virtual_machine = VirtualMachine.create(
+ cls.apiClient,
+ cls.testdata[TestData.virtualMachine],
+ accountid=cls.account.name,
+ zoneid=cls.zone.id,
+ serviceofferingid=cls.compute_offering.id,
+ templateid=cls.template.id,
+ domainid=cls.domain.id,
+ startvm=True
+ )
+
+ cls.volume = Volume.create(
+ cls.apiClient,
+ cls.testdata[TestData.volume_1],
+ account=cls.account.name,
+ domainid=cls.domain.id,
+ zoneid=cls.zone.id,
+ diskofferingid=cls.disk_offering.id
+ )
+
+ # Resources that are to be destroyed
+ cls._cleanup = [
+ cls.volume,
+ cls.virtual_machine,
+ cls.compute_offering,
+ cls.disk_offering,
+ cls.user,
+ cls.account
+ ]
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ cleanup_resources(cls.apiClient, cls._cleanup)
+
+ cls.primary_storage.delete(cls.apiClient)
+
+ cls._purge_solidfire_volumes()
+ except Exception as e:
+ logging.debug("Exception in tearDownClass(cls): %s" % e)
+
+ def setUp(self):
+ self.attached = False
+ self.cleanup = []
+
+ def tearDown(self):
+ if self.attached:
+ self.virtual_machine.detach_volume(self.apiClient, self.volume)
+
+ cleanup_resources(self.apiClient, self.cleanup)
+
+ @attr(hypervisor='XenServer')
+ def test_00_check_template_cache(self):
+ if self.supports_resign == False:
+ return
+
+ sf_volumes = self._get_sf_volumes()
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, TestData.templateCacheName)
+
+ self.assertEqual(
+ len(sf_volume['volumeAccessGroups']),
+ 0,
+ "The volume should not be in a VAG."
+ )
+
+ sf_account_id = sf_volume["accountID"]
+
+ sf_account = self.sf_client.get_account_by_id(sf_account_id)["account"]
+
+ sf_account_name = sf_account["username"]
+
+ self.assertEqual(
+ sf_account_name.endswith("_1"),
+ True,
+ "The template cache volume's account does not end with '_1'."
+ )
+
+ @attr(hypervisor='XenServer')
+ def test_01_attach_new_volume_to_stopped_VM(self):
+ '''Attach a volume to a stopped virtual machine, then start VM'''
+
+ self.virtual_machine.stop(self.apiClient)
+
+ new_volume = Volume.create(
+ self.apiClient,
+ self.testdata[TestData.volume_2],
+ account=self.account.name,
+ domainid=self.domain.id,
+ zoneid=self.zone.id,
+ diskofferingid=self.disk_offering.id
+ )
+
+ self.cleanup.append(new_volume)
+
+ self._check_and_get_cs_volume(new_volume.id, self.testdata[TestData.volume_2][TestData.diskName])
+
+ new_volume = self.virtual_machine.attach_volume(
+ self.apiClient,
+ new_volume
+ )
+
+ newvolume = self._check_and_get_cs_volume(new_volume.id, self.testdata[TestData.volume_2][TestData.diskName])
+
+ self.virtual_machine.start(self.apiClient)
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ newvolume.virtualmachineid,
+ vm.id,
+ TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ "running",
+ TestVolumes._vm_not_in_running_state_err_msg
+ )
+
+ sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id)
+
+ sf_volume_size = self._get_volume_size_with_hsr(new_volume)
+
+ sf_vag_id = self._get_vag_id()
+
+ sf_iscsi_name = self._get_iqn(new_volume)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, newvolume.name)
+
+ self._check_size_and_iops(sf_volume, newvolume, sf_volume_size)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ # Detach volume
+ new_volume = self.virtual_machine.detach_volume(
+ self.apiClient,
+ new_volume
+ )
+
+ @attr(hypervisor='XenServer')
+ def test_02_attach_detach_attach_volume(self):
+ '''Attach, detach, and attach volume to a running VM'''
+
+ self.virtual_machine.start(self.apiClient)
+
+ sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id)
+
+ sf_vag_id = self._get_vag_id()
+
+ self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ #######################################
+ #######################################
+ # STEP 1: Attach volume to running VM #
+ #######################################
+ #######################################
+
+ self.volume = self.virtual_machine.attach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = True
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ vm.id,
+ TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ TestVolumes._vm_not_in_running_state_err_msg
+ )
+
+ sf_iscsi_name = self._get_iqn(self.volume)
+
+ sf_volume_size = self._get_volume_size_with_hsr(self.volume)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ #########################################
+ #########################################
+ # STEP 2: Detach volume from running VM #
+ #########################################
+ #########################################
+
+ self.volume = self.virtual_machine.detach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = False
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ None,
+ "The volume should not be attached to a VM."
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ str(vm.state)
+ )
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self.assertEqual(
+ len(sf_volume['volumeAccessGroups']),
+ 0,
+ "The volume should not be in a VAG."
+ )
+
+ self._check_xen_sr(sf_iscsi_name, False)
+
+ #######################################
+ #######################################
+ # STEP 3: Attach volume to running VM #
+ #######################################
+ #######################################
+
+ self.volume = self.virtual_machine.attach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = True
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ vm.id,
+ TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ TestVolumes._vm_not_in_running_state_err_msg
+ )
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ @attr(hypervisor='XenServer')
+ def test_03_attached_volume_reboot_VM(self):
+ '''Attach volume to running VM, then reboot.'''
+
+ self.virtual_machine.start(self.apiClient)
+
+ sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id)
+
+ sf_vag_id = self._get_vag_id()
+
+ self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ #######################################
+ #######################################
+ # STEP 1: Attach volume to running VM #
+ #######################################
+ #######################################
+
+ self.volume = self.virtual_machine.attach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = True
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ vm.id,
+ TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ TestVolumes._vm_not_in_running_state_err_msg
+ )
+
+ sf_iscsi_name = self._get_iqn(self.volume)
+
+ sf_volume_size = self._get_volume_size_with_hsr(self.volume)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ #######################################
+ #######################################
+ # STEP 2: Reboot VM with attached vol #
+ #######################################
+ #######################################
+ self.virtual_machine.reboot(self.apiClient)
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ sf_iscsi_name = self._get_iqn(self.volume)
+
+ sf_volume_size = self._get_volume_size_with_hsr(self.volume)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ @attr(hypervisor='XenServer')
+ def test_04_detach_volume_reboot(self):
+ '''Detach volume from a running VM, then reboot.'''
+
+ self.virtual_machine.start(self.apiClient)
+
+ sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id)
+
+ sf_vag_id = self._get_vag_id()
+
+ self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ #######################################
+ #######################################
+ # STEP 1: Attach volume to running VM #
+ #######################################
+ #######################################
+
+ self.volume = self.virtual_machine.attach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = True
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ vm.id,
+ TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ TestVolumes._vm_not_in_running_state_err_msg
+ )
+
+ sf_iscsi_name = self._get_iqn(self.volume)
+
+ sf_volume_size = self._get_volume_size_with_hsr(self.volume)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ #########################################
+ #########################################
+ # STEP 2: Detach volume from running VM #
+ #########################################
+ #########################################
+
+ self.volume = self.virtual_machine.detach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = False
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ None,
+ "The volume should not be attached to a VM."
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ TestVolumes._vm_not_in_running_state_err_msg
+ )
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self.assertEqual(
+ len(sf_volume['volumeAccessGroups']),
+ 0,
+ TestVolumes._volume_should_not_be_in_a_vag
+ )
+
+ self._check_xen_sr(sf_iscsi_name, False)
+
+ #######################################
+ #######################################
+ # STEP 3: Reboot VM with detached vol #
+ #######################################
+ #######################################
+
+ self.virtual_machine.reboot(self.apiClient)
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self.assertEqual(
+ len(sf_volume['volumeAccessGroups']),
+ 0,
+ TestVolumes._volume_should_not_be_in_a_vag
+ )
+
+ self._check_xen_sr(sf_iscsi_name, False)
+
+ @attr(hypervisor='XenServer')
+ def test_05_detach_vol_stopped_VM_start(self):
+ '''Detach volume from a stopped VM, then start.'''
+
+ self.virtual_machine.start(self.apiClient)
+
+ sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id)
+
+ sf_vag_id = self._get_vag_id()
+
+ self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ #######################################
+ #######################################
+ # STEP 1: Attach volume to running VM #
+ #######################################
+ #######################################
+
+ self.volume = self.virtual_machine.attach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = True
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ vm.id,
+ TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ TestVolumes._vm_not_in_running_state_err_msg
+ )
+
+ sf_iscsi_name = self._get_iqn(self.volume)
+
+ sf_volume_size = self._get_volume_size_with_hsr(self.volume)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ #########################################
+ #########################################
+ # STEP 2: Detach volume from stopped VM #
+ #########################################
+ #########################################
+
+ self.virtual_machine.stop(self.apiClient)
+
+ self.volume = self.virtual_machine.detach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = False
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ None,
+ "The volume should not be attached to a VM."
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'stopped',
+ TestVolumes._vm_not_in_stopped_state_err_msg
+ )
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self.assertEqual(
+ len(sf_volume['volumeAccessGroups']),
+ 0,
+ TestVolumes._volume_should_not_be_in_a_vag
+ )
+
+ self._check_xen_sr(sf_iscsi_name, False)
+
+ #######################################
+ #######################################
+ # STEP 3: Start VM with detached vol #
+ #######################################
+ #######################################
+
+ self.virtual_machine.start(self.apiClient)
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self.assertEqual(
+ len(sf_volume['volumeAccessGroups']),
+ 0,
+ TestVolumes._volume_should_not_be_in_a_vag
+ )
+
+ self._check_xen_sr(sf_iscsi_name, False)
+
+ @attr(hypervisor='XenServer')
+ def test_06_attach_volume_to_stopped_VM(self):
+ '''Attach a volume to a stopped virtual machine, then start VM'''
+
+ self.virtual_machine.stop(self.apiClient)
+
+ sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id)
+
+ sf_vag_id = self._get_vag_id()
+
+ self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ #######################################
+ #######################################
+ # STEP 1: Attach volume to stopped VM #
+ #######################################
+ #######################################
+
+ self.volume = self.virtual_machine.attach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = True
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ vm.id,
+ TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'stopped',
+ TestVolumes._vm_not_in_stopped_state_err_msg
+ )
+
+ sf_iscsi_name = self._get_iqn(self.volume)
+
+ sf_volume_size = self._get_volume_size_with_hsr(self.volume)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ self.virtual_machine.start(self.apiClient)
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ vm.id,
+ TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ TestVolumes._vm_not_in_running_state_err_msg
+ )
+
+ sf_iscsi_name = self._get_iqn(self.volume)
+
+ sf_volume_size = self._get_volume_size_with_hsr(self.volume)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ @attr(hypervisor='XenServer')
+ def test_07_destroy_expunge_VM_with_volume(self):
+ '''Destroy and expunge VM with attached volume'''
+
+ #######################################
+ #######################################
+ # STEP 1: Create VM and attach volume #
+ #######################################
+ #######################################
+
+ test_virtual_machine = VirtualMachine.create(
+ self.apiClient,
+ self.testdata[TestData.virtualMachine2],
+ accountid=self.account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=self.template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ self.volume = test_virtual_machine.attach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = True
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(test_virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ vm.id,
+ TestVolumes._volume_vm_id_and_vm_id_do_not_match_err_msg
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ TestVolumes._vm_not_in_running_state_err_msg
+ )
+
+ sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id)
+
+ sf_volume_size = self._get_volume_size_with_hsr(self.volume)
+
+ sf_vag_id = self._get_vag_id()
+
+ sf_iscsi_name = self._get_iqn(self.volume)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ #######################################
+ #######################################
+ # STEP 2: Destroy and Expunge VM #
+ #######################################
+ #######################################
+
+ test_virtual_machine.delete(self.apiClient, True)
+
+ self.attached = False
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ None,
+ "Check if attached to virtual machine"
+ )
+
+ self.assertEqual(
+ vol.vmname,
+ None,
+ "Check if VM was expunged"
+ )
+
+ list_virtual_machine_response = list_virtual_machines(
+ self.apiClient,
+ id=test_virtual_machine.id
+ )
+
+ self.assertEqual(
+ list_virtual_machine_response,
+ None,
+ "Check if VM was actually expunged"
+ )
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ self.assertEqual(
+ len(sf_volume['volumeAccessGroups']),
+ 0,
+ TestVolumes._volume_should_not_be_in_a_vag
+ )
+
+ self._check_xen_sr(sf_iscsi_name, False)
+
+ @attr(hypervisor='XenServer')
+ def test_08_delete_volume_was_attached(self):
+ '''Delete volume that was attached to a VM and is detached now'''
+
+ self.virtual_machine.start(self.apiClient)
+
+ #######################################
+ #######################################
+ # STEP 1: Create vol and attach to VM #
+ #######################################
+ #######################################
+
+ new_volume = Volume.create(
+ self.apiClient,
+ self.testdata[TestData.volume_2],
+ account=self.account.name,
+ domainid=self.domain.id,
+ zoneid=self.zone.id,
+ diskofferingid=self.disk_offering.id
+ )
+
+ volume_to_delete_later = new_volume
+
+ self._check_and_get_cs_volume(new_volume.id, self.testdata[TestData.volume_2][TestData.diskName])
+
+ new_volume = self.virtual_machine.attach_volume(
+ self.apiClient,
+ new_volume
+ )
+
+ vol = self._check_and_get_cs_volume(new_volume.id, self.testdata[TestData.volume_2][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ vm.id,
+ "Check if attached to virtual machine"
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ str(vm.state)
+ )
+
+ sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id)
+
+ sf_volume_size = self._get_volume_size_with_hsr(new_volume)
+
+ sf_vag_id = self._get_vag_id()
+
+ sf_iscsi_name = self._get_iqn(new_volume)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ #######################################
+ #######################################
+ # STEP 2: Detach and delete volume #
+ #######################################
+ #######################################
+
+ new_volume = self.virtual_machine.detach_volume(
+ self.apiClient,
+ new_volume
+ )
+
+ vol = self._check_and_get_cs_volume(new_volume.id, self.testdata[TestData.volume_2][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ None,
+ "Check if attached to virtual machine"
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ str(vm.state)
+ )
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ self.assertEqual(
+ len(sf_volume['volumeAccessGroups']),
+ 0,
+ TestVolumes._volume_should_not_be_in_a_vag
+ )
+
+ self._check_xen_sr(sf_iscsi_name, False)
+
+ volume_to_delete_later.delete(self.apiClient)
+
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ id=new_volume.id
+ )
+
+ self.assertEqual(
+ list_volumes_response,
+ None,
+ "Check volume was deleted"
+ )
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ self._check_and_get_sf_volume(sf_volumes, vol.name, False)
+
+ @attr(hypervisor='XenServer')
+ def test_09_attach_volumes_multiple_accounts(self):
+ '''Attach a data disk to a VM in one account and attach another data disk to a VM in another account'''
+
+ self.virtual_machine.start(self.apiClient)
+
+ #######################################
+ #######################################
+ # STEP 1: Create account, VM, and vol #
+ #######################################
+ #######################################
+
+ test_account = Account.create(
+ self.apiClient,
+ self.testdata[TestData.testAccount],
+ admin=1
+ )
+
+ self.cleanup.append(test_account)
+
+ test_virtual_machine = VirtualMachine.create(
+ self.apiClient,
+ self.testdata[TestData.virtualMachine2],
+ accountid=test_account.name,
+ zoneid=self.zone.id,
+ serviceofferingid=self.compute_offering.id,
+ templateid=self.template.id,
+ domainid=self.domain.id,
+ startvm=True
+ )
+
+ test_volume = Volume.create(
+ self.apiClient,
+ self.testdata[TestData.volume_2],
+ zoneid=self.zone.id,
+ account=test_account.name,
+ domainid=self.domain.id,
+ diskofferingid=self.disk_offering.id
+ )
+
+ self._check_and_get_cs_volume(test_volume.id, self.testdata[TestData.volume_2][TestData.diskName])
+
+ #######################################
+ #######################################
+ # STEP 2: Attach volumes to VMs #
+ #######################################
+ #######################################
+
+ self.volume = self.virtual_machine.attach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = True
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ vm = self._get_vm(self.virtual_machine.id)
+
+ self.assertEqual(
+ vol.virtualmachineid,
+ vm.id,
+ "Check if attached to virtual machine"
+ )
+
+ self.assertEqual(
+ vm.state.lower(),
+ 'running',
+ str(vm.state)
+ )
+
+ test_volume = test_virtual_machine.attach_volume(
+ self.apiClient,
+ test_volume
+ )
+
+ test_vol = self._check_and_get_cs_volume(test_volume.id, self.testdata[TestData.volume_2][TestData.diskName])
+
+ test_vm = self._get_vm(test_virtual_machine.id)
+
+ self.assertEqual(
+ test_vol.virtualmachineid,
+ test_vm.id,
+ "Check if attached to virtual machine of other acct"
+ )
+
+ self.assertEqual(
+ test_vm.state.lower(),
+ 'running',
+ str(test_vm.state)
+ )
+
+ sf_vag_id = self._get_vag_id()
+
+ sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id)
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ sf_volume_size = self._get_volume_size_with_hsr(vol)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ sf_iscsi_name = self._get_iqn(self.volume)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ sf_test_account_id = self._get_sf_account_id(self.primary_storage.id, test_account.id)
+
+ sf_test_volumes = self._get_sf_volumes(sf_test_account_id)
+
+ sf_test_volume = self._check_and_get_sf_volume(sf_test_volumes, test_vol.name)
+
+ sf_test_volume_size = self._get_volume_size_with_hsr(test_vol)
+
+ self._check_size_and_iops(sf_test_volume, test_vol, sf_test_volume_size)
+
+ sf_test_iscsi_name = self._get_iqn(test_volume)
+
+ self._check_xen_sr(sf_test_iscsi_name)
+
+ self._check_vag(sf_test_volume, sf_vag_id)
+
+ @attr(hypervisor='XenServer')
+ def test_10_attach_more_than_one_disk_to_VM(self):
+ '''Attach more than one disk to a VM'''
+
+ self.virtual_machine.start(self.apiClient)
+
+ volume_2 = Volume.create(
+ self.apiClient,
+ self.testdata[TestData.volume_2],
+ zoneid=self.zone.id,
+ account=self.account.name,
+ domainid=self.domain.id,
+ diskofferingid=self.disk_offering.id
+ )
+
+ self.cleanup.append(volume_2)
+
+ self._check_and_get_cs_volume(volume_2.id, self.testdata[TestData.volume_2][TestData.diskName])
+
+ #######################################
+ #######################################
+ # Step 1: Attach volumes to VM #
+ #######################################
+ #######################################
+
+ self.virtual_machine.attach_volume(
+ self.apiClient,
+ self.volume
+ )
+
+ self.attached = True
+
+ vol = self._check_and_get_cs_volume(self.volume.id, self.testdata[TestData.volume_1][TestData.diskName])
+
+ self.virtual_machine.attach_volume(
+ self.apiClient,
+ volume_2
+ )
+
+ vol_2 = self._check_and_get_cs_volume(volume_2.id, self.testdata[TestData.volume_2][TestData.diskName])
+
+ sf_account_id = self._get_sf_account_id(self.primary_storage.id, self.account.id)
+
+ sf_volume_size = self._get_volume_size_with_hsr(self.volume)
+
+ sf_volume_2_size = self._get_volume_size_with_hsr(volume_2)
+
+ sf_vag_id = self._get_vag_id()
+
+ sf_volumes = self._get_sf_volumes(sf_account_id)
+
+ sf_volume = self._check_and_get_sf_volume(sf_volumes, vol.name)
+
+ self._check_size_and_iops(sf_volume, vol, sf_volume_size)
+
+ sf_iscsi_name = self._get_iqn(self.volume)
+
+ self._check_xen_sr(sf_iscsi_name)
+
+ self._check_vag(sf_volume, sf_vag_id)
+
+ sf_volume_2 = self._check_and_get_sf_volume(sf_volumes, vol_2.name)
+
+ self._check_size_and_iops(sf_volume_2, vol_2, sf_volume_2_size)
+
+ sf_iscsi_name_2 = self._get_iqn(volume_2)
+
+ self._check_xen_sr(sf_iscsi_name_2)
+
+ self._check_vag(sf_volume_2, sf_vag_id)
+
+ self.virtual_machine.detach_volume(self.apiClient, volume_2)
+
+ '''
+ @attr(hypervisor = 'XenServer')
+ def _test_11_attach_disk_to_running_vm_change_iops(self):
+ Attach a disk to a running VM, then change iops
+ self.custom_iops_disk_offering = DiskOffering.create(
+
+ )'''
+
+ def _check_list(self, in_list, expected_size_of_list, err_msg):
+ self.assertEqual(
+ isinstance(in_list, list),
+ True,
+ "'in_list' is not a list."
+ )
+
+ self.assertEqual(
+ len(in_list),
+ expected_size_of_list,
+ err_msg
+ )
+
+ def _check_iscsi_name(self, sf_iscsi_name):
+ self.assertEqual(
+ sf_iscsi_name[0],
+ "/",
+ "The iSCSI name needs to start with a forward slash."
+ )
+
+ def _check_volume(self, volume, volume_name):
+ self.assertTrue(
+ volume.name.startswith(volume_name),
+ "The volume name is incorrect."
+ )
+
+ self.assertEqual(
+ volume.diskofferingid,
+ self.disk_offering.id,
+ "The disk offering is incorrect."
+ )
+
+ self.assertEqual(
+ volume.zoneid,
+ self.zone.id,
+ "The zone is incorrect."
+ )
+
+ self.assertEqual(
+ volume.storagetype,
+ self.disk_offering.storagetype,
+ "The storage type is incorrect."
+ )
+
+ def _check_size_and_iops(self, sf_volume, volume, size):
+ self.assertEqual(
+ sf_volume['qos']['minIOPS'],
+ volume.miniops,
+ "Check QOS - Min IOPS: " + str(sf_volume['qos']['minIOPS'])
+ )
+
+ self.assertEqual(
+ sf_volume['qos']['maxIOPS'],
+ volume.maxiops,
+ "Check QOS - Max IOPS: " + str(sf_volume['qos']['maxIOPS'])
+ )
+
+ self.assertEqual(
+ sf_volume['totalSize'],
+ size,
+ "Check SF volume size: " + str(sf_volume['totalSize'])
+ )
+
+ def _check_vag(self, sf_volume, sf_vag_id):
+ self.assertEqual(
+ len(sf_volume['volumeAccessGroups']),
+ 1,
+ "The volume should only be in one VAG."
+ )
+
+ self.assertEqual(
+ sf_volume['volumeAccessGroups'][0],
+ sf_vag_id,
+ "The volume is not in the VAG with the following ID: " + str(sf_vag_id) + "."
+ )
+
+ def _check_and_get_cs_volume(self, volume_id, volume_name):
+ list_volumes_response = list_volumes(
+ self.apiClient,
+ id=volume_id
+ )
+
+ self._check_list(list_volumes_response, 1, TestVolumes._should_only_be_one_volume_in_list_err_msg)
+
+ cs_volume = list_volumes_response[0]
+
+ self._check_volume(cs_volume, volume_name)
+
+ return cs_volume
+
+ def _get_sf_account_id(self, primary_storage_id, account_id):
+ sf_account_id_request = {'storageid': primary_storage_id, 'accountid': account_id}
+ sf_account_id_result = self.cs_api.getSolidFireAccountId(sf_account_id_request)
+ sf_account_id = sf_account_id_result['apisolidfireaccountid']['solidFireAccountId']
+
+ self.assertEqual(
+ isinstance(sf_account_id, int),
+ True,
+ TestVolumes._sf_account_id_should_be_non_zero_int_err_msg
+ )
+
+ return sf_account_id
+
+ def _get_volume_size_with_hsr(self, cs_volume):
+ # Get underlying SF volume size with hypervisor snapshot reserve
+ sf_volume_size_request = {'volumeid': cs_volume.id}
+ sf_volume_size_result = self.cs_api.getSolidFireVolumeSize(sf_volume_size_request)
+ sf_volume_size = sf_volume_size_result['apisolidfirevolumesize']['solidFireVolumeSize']
+
+ self.assertEqual(
+ isinstance(sf_volume_size, int),
+ True,
+ "The SolidFire volume size should be a non-zero integer."
+ )
+
+ return sf_volume_size
+
+ def _get_vag_id(self):
+ # Get SF Volume Access Group ID
+ sf_vag_id_request = {'clusterid': self.cluster.id, 'storageid': self.primary_storage.id}
+ sf_vag_id_result = self.cs_api.getSolidFireVolumeAccessGroupId(sf_vag_id_request)
+ sf_vag_id = sf_vag_id_result['apisolidfirevolumeaccessgroupid']['solidFireVolumeAccessGroupId']
+
+ self.assertEqual(
+ isinstance(sf_vag_id, int),
+ True,
+ TestVolumes._vag_id_should_be_non_zero_int_err_msg
+ )
+
+ return sf_vag_id
+
+ def _get_iqn(self, volume):
+ # Get volume IQN
+ sf_iscsi_name_request = {'volumeid': volume.id}
+ sf_iscsi_name_result = self.cs_api.getVolumeiScsiName(sf_iscsi_name_request)
+ sf_iscsi_name = sf_iscsi_name_result['apivolumeiscsiname']['volumeiScsiName']
+
+ self._check_iscsi_name(sf_iscsi_name)
+
+ return sf_iscsi_name
+
+ def _get_vm(self, vm_id):
+ list_vms_response = list_virtual_machines(self.apiClient, id=vm_id)
+
+ self._check_list(list_vms_response, 1, TestVolumes._should_only_be_one_vm_in_list_err_msg)
+
+ return list_vms_response[0]
+
+ def _check_and_get_sf_volume(self, sf_volumes, sf_volume_name, should_exist=True):
+ sf_volume = None
+
+ for volume in sf_volumes:
+ if volume['name'] == sf_volume_name:
+ sf_volume = volume
+ break
+
+ if should_exist:
+ self.assertNotEqual(
+ sf_volume,
+ None,
+ "Check if SF volume was created in correct account: " + str(sf_volumes)
+ )
+ else:
+ self.assertEqual(
+ sf_volume,
+ None,
+ "Check if SF volume was deleted: " + str(sf_volumes)
+ )
+
+ return sf_volume
+
+ def _check_xen_sr(self, xen_sr_name, should_exist=True):
+ if should_exist:
+ xen_sr = self.xen_session.xenapi.SR.get_by_name_label(xen_sr_name)[0]
+
+ self.sr_shared = self.xen_session.xenapi.SR.get_shared(xen_sr)
+
+ self.assertEqual(
+ self.sr_shared,
+ True,
+ TestVolumes._sr_not_shared_err_msg
+ )
+ else:
+ xen_sr = self.xen_session.xenapi.SR.get_by_name_label(xen_sr_name)
+
+ self._check_list(xen_sr, 0, TestVolumes._list_should_be_empty)
+
+ def _get_sf_volumes(self, sf_account_id=None):
+ if sf_account_id is not None:
+ sf_volumes = self.sf_client.list_volumes_for_account(sf_account_id)
+ else:
+ sf_volumes = self.sf_client.list_active_volumes()
+
+ self.assertNotEqual(
+ len(sf_volumes),
+ 0,
+ TestVolumes._volume_response_should_not_be_zero_err_msg
+ )
+
+ return sf_volumes
+
+ @classmethod
+ def _set_supports_resign(cls):
+ supports_resign = str(cls.supports_resign)
+
+ sql_query = "Update host_details Set value = '" + supports_resign + "' Where name = 'supportsResign'"
+
+ # make sure you can connect to MySQL: https://teamtreehouse.com/community/cant-connect-remotely-to-mysql-server-with-mysql-workbench
+ cls.dbConnection.execute(sql_query)
+
+ @classmethod
+ def _purge_solidfire_volumes(cls):
+ deleted_volumes = cls.sf_client.list_deleted_volumes()
+
+ for deleted_volume in deleted_volumes:
+ cls.sf_client.purge_deleted_volume(deleted_volume['volumeID'])
+
diff --git a/test/integration/plugins/test_quota.py b/test/integration/plugins/test_quota.py
index d4e4323..1ae6790 100644
--- a/test/integration/plugins/test_quota.py
+++ b/test/integration/plugins/test_quota.py
@@ -30,10 +30,30 @@
#Import System modules
import time
-#ENABLE THE QUOTA PLUGIN AND RESTART THE MANAGEMENT SERVER TO RUN QUOTA TESTS
-
class TestQuota(cloudstackTestCase):
+ @classmethod
+ def setUpClass(cls):
+ # Create Account
+ testClient = super(TestQuota, cls).getClsTestClient()
+ cls.apiclient = testClient.getApiClient()
+ cls.services = testClient.getParsedTestDataConfig()
+
+ # Get Zone, Domain
+ cls.domain = get_domain(cls.apiclient)
+ cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
+
+ # Create Account
+ cls.account = Account.create(
+ cls.apiclient,
+ cls.services["account"],
+ domainid=cls.domain.id
+ )
+ cls._cleanup = [
+ cls.account,
+ ]
+ return
+
def setUp(self):
self.apiclient = self.testClient.getApiClient()
self.hypervisor = self.testClient.getHypervisorInfo()
@@ -55,6 +75,12 @@
#Check quotaTariffList API returning 22 items
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_01_quota(self):
+ if not is_config_suitable(
+ apiclient=self.apiclient,
+ name='quota.enable.service',
+ value='true'):
+ self.skipTest('quota.enable.service should be true. skipping')
+
cmd = quotaTariffList.quotaTariffListCmd()
response = self.apiclient.quotaTariffList(cmd)
@@ -75,6 +101,12 @@
#Check quota tariff on a particualr day
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_02_quota(self):
+ if not is_config_suitable(
+ apiclient=self.apiclient,
+ name='quota.enable.service',
+ value='true'):
+ self.skipTest('quota.enable.service should be true. skipping')
+
cmd = quotaTariffList.quotaTariffListCmd()
cmd.startdate='2015-07-06'
response = self.apiclient.quotaTariffList(cmd)
@@ -89,6 +121,12 @@
#check quota tariff of a particular item
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_03_quota(self):
+ if not is_config_suitable(
+ apiclient=self.apiclient,
+ name='quota.enable.service',
+ value='true'):
+ self.skipTest('quota.enable.service should be true. skipping')
+
cmd = quotaTariffList.quotaTariffListCmd()
cmd.startdate='2015-07-06'
cmd.usagetype='10'
@@ -107,6 +145,12 @@
#check the old tariff it should be same
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_04_quota(self):
+ if not is_config_suitable(
+ apiclient=self.apiclient,
+ name='quota.enable.service',
+ value='true'):
+ self.skipTest('quota.enable.service should be true. skipping')
+
cmd = quotaTariffList.quotaTariffListCmd()
cmd.startdate='2015-07-06'
cmd.usagetype='10'
@@ -157,9 +201,15 @@
#Make credit deposit
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_05_quota(self):
+ if not is_config_suitable(
+ apiclient=self.apiclient,
+ name='quota.enable.service',
+ value='true'):
+ self.skipTest('quota.enable.service should be true. skipping')
+
cmd = quotaCredits.quotaCreditsCmd()
- cmd.domainid = '1'
- cmd.account = 'admin'
+ cmd.domainid = self.account.domainid
+ cmd.account = self.account.name
cmd.value = '10'
cmd.quota_enforce = '1'
cmd.min_balance = '9'
@@ -173,32 +223,45 @@
#Make credit deposit and check today balance
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_06_quota(self):
+ if not is_config_suitable(
+ apiclient=self.apiclient,
+ name='quota.enable.service',
+ value='true'):
+ self.skipTest('quota.enable.service should be true. skipping')
+
cmd = quotaBalance.quotaBalanceCmd()
today = datetime.date.today()
- cmd.domainid = '1'
- cmd.account = 'admin'
+ cmd.domainid = self.account.domainid
+ cmd.account = self.account.name
cmd.startdate = today
response = self.apiclient.quotaBalance(cmd)
self.debug("Quota Balance on: %s" % response.startdate)
self.debug("is: %s" % response.startquota)
- self.assertGreater( response.startquota, 9)
+ self.assertEqual( response.startquota, 10)
return
#make credit deposit and check start and end date balances
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_07_quota(self):
+ if not is_config_suitable(
+ apiclient=self.apiclient,
+ name='quota.enable.service',
+ value='true'):
+ self.skipTest('quota.enable.service should be true. skipping')
+
cmd = quotaBalance.quotaBalanceCmd()
today = datetime.date.today()
- cmd.domainid = '1'
- cmd.account = 'admin'
+ cmd.domainid = self.account.domainid
+ cmd.account = self.account.name
cmd.startdate = today - datetime.timedelta(days=2)
- cmd.enddate = today
+ cmd.enddate = today
response = self.apiclient.quotaBalance(cmd)
self.debug("Quota Balance on: %s" % response.startdate)
self.debug("is: %s" % response.startquota)
- self.assertGreater( response.endquota, 9)
+ self.assertEqual( response.startquota, 0)
+ self.assertEqual( response.endquota, 10)
return
diff --git a/test/integration/smoke/test_dynamicroles.py b/test/integration/smoke/test_dynamicroles.py
new file mode 100644
index 0000000..9961437
--- /dev/null
+++ b/test/integration/smoke/test_dynamicroles.py
@@ -0,0 +1,537 @@
+# 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.
+
+from marvin.cloudstackAPI import *
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.base import Account, Role, RolePermission
+from marvin.lib.utils import cleanup_resources
+from nose.plugins.attrib import attr
+from random import shuffle
+
+import copy
+import random
+import re
+
+
+class TestData(object):
+ """Test data object that is required to create resources
+ """
+ def __init__(self):
+ self.testdata = {
+ "account": {
+ "email": "mtu@test.cloud",
+ "firstname": "Marvin",
+ "lastname": "TestUser",
+ "username": "roletest",
+ "password": "password",
+ },
+ "role": {
+ "name": "MarvinFake Role ",
+ "type": "User",
+ "description": "Fake Role created by Marvin test"
+ },
+ "roleadmin": {
+ "name": "MarvinFake Admin Role ",
+ "type": "Admin",
+ "description": "Fake Admin Role created by Marvin test"
+ },
+ "roledomainadmin": {
+ "name": "MarvinFake DomainAdmin Role ",
+ "type": "DomainAdmin",
+ "description": "Fake Domain-Admin Role created by Marvin test"
+ },
+ "rolepermission": {
+ "roleid": 1,
+ "rule": "listVirtualMachines",
+ "permission": "allow",
+ "description": "Fake role permission created by Marvin test"
+ },
+ "apiConfig": {
+ "listApis": "allow",
+ "listAccounts": "allow",
+ "listClusters": "deny",
+ "*VM*": "allow",
+ "*Host*": "deny"
+ }
+ }
+
+
+class TestDynamicRoles(cloudstackTestCase):
+ """Tests dynamic role and role permission management in CloudStack
+ """
+
+ def setUp(self):
+ self.apiclient = self.testClient.getApiClient()
+ self.dbclient = self.testClient.getDbConnection()
+ self.testdata = TestData().testdata
+
+ feature_enabled = self.apiclient.listCapabilities(listCapabilities.listCapabilitiesCmd()).dynamicrolesenabled
+ if not feature_enabled:
+ self.skipTest("Dynamic Role-Based API checker not enabled, skipping test")
+
+ self.testdata["role"]["name"] += self.getRandomString()
+ self.role = Role.create(
+ self.apiclient,
+ self.testdata["role"]
+ )
+
+ self.testdata["rolepermission"]["roleid"] = self.role.id
+ self.rolepermission = RolePermission.create(
+ self.apiclient,
+ self.testdata["rolepermission"]
+ )
+
+ self.account = Account.create(
+ self.apiclient,
+ self.testdata["account"],
+ roleid=self.role.id
+ )
+ self.cleanup = [
+ self.account,
+ self.rolepermission,
+ self.role
+ ]
+
+
+ def tearDown(self):
+ try:
+ cleanup_resources(self.apiclient, self.cleanup)
+ except Exception as e:
+ self.debug("Warning! Exception in tearDown: %s" % e)
+
+
+ def translateRoleToAccountType(self, role_type):
+ if role_type == "User":
+ return 0
+ elif role_type == "Admin":
+ return 1
+ elif role_type == "DomainAdmin":
+ return 2
+ elif role_type == "ResourceAdmin":
+ return 3
+ return -1
+
+
+ def getUserApiClient(self, username, domain='ROOT', role_type='User'):
+ self.user_apiclient = self.testClient.getUserApiClient(UserName=username, DomainName='ROOT', type=self.translateRoleToAccountType(role_type))
+ return self.user_apiclient
+
+
+ def getRandomString(self):
+ return "".join(random.choice("abcdefghijklmnopqrstuvwxyz0123456789") for _ in range(10))
+
+
+ def getRandomRoleName(self):
+ return "MarvinFakeRoleNewName-" + self.getRandomString()
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_role_lifecycle_list(self):
+ """
+ Tests that default four roles exist
+ """
+ roleTypes = {1: "Admin", 2: "ResourceAdmin", 3: "DomainAdmin", 4: "User"}
+ for idx in range(1,5):
+ list_roles = Role.list(self.apiclient, id=idx)
+ self.assertEqual(
+ isinstance(list_roles, list),
+ True,
+ "List Roles response was not a valid list"
+ )
+ self.assertEqual(
+ len(list_roles),
+ 1,
+ "List Roles response size was not 1"
+ )
+ self.assertEqual(
+ list_roles[0].type,
+ roleTypes[idx],
+ msg="Default role type differs from expectation"
+ )
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_role_lifecycle_create(self):
+ """
+ Tests normal lifecycle operations for roles
+ """
+ # Reuse self.role created in setUp()
+ try:
+ role = Role.create(
+ self.apiclient,
+ self.testdata["role"]
+ )
+ self.fail("An exception was expected when creating duplicate roles")
+ except CloudstackAPIException: pass
+
+ list_roles = Role.list(self.apiclient, id=self.role.id)
+ self.assertEqual(
+ isinstance(list_roles, list),
+ True,
+ "List Roles response was not a valid list"
+ )
+ self.assertEqual(
+ len(list_roles),
+ 1,
+ "List Roles response size was not 1"
+ )
+ self.assertEqual(
+ list_roles[0].name,
+ self.testdata["role"]["name"],
+ msg="Role name does not match the test data"
+ )
+ self.assertEqual(
+ list_roles[0].type,
+ self.testdata["role"]["type"],
+ msg="Role type does not match the test data"
+ )
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_role_lifecycle_update(self):
+ """
+ Tests role update
+ """
+ self.account.delete(self.apiclient)
+ new_role_name = self.getRandomRoleName()
+ self.role.update(self.apiclient, name=new_role_name, type='Admin')
+ update_role = Role.list(self.apiclient, id=self.role.id)[0]
+ self.assertEqual(
+ update_role.name,
+ new_role_name,
+ msg="Role name does not match updated role name"
+ )
+ self.assertEqual(
+ update_role.type,
+ 'Admin',
+ msg="Role type does not match updated role type"
+ )
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_role_lifecycle_update_role_inuse(self):
+ """
+ Tests role update when role is in use by an account
+ """
+ new_role_name = self.getRandomRoleName()
+ try:
+ self.role.update(self.apiclient, name=new_role_name, type='Admin')
+ self.fail("Updation of role type is not allowed when role is in use")
+ except CloudstackAPIException: pass
+
+ self.role.update(self.apiclient, name=new_role_name)
+ update_role = Role.list(self.apiclient, id=self.role.id)[0]
+ self.assertEqual(
+ update_role.name,
+ new_role_name,
+ msg="Role name does not match updated role name"
+ )
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_role_lifecycle_delete(self):
+ """
+ Tests role update
+ """
+ self.account.delete(self.apiclient)
+ self.role.delete(self.apiclient)
+ list_roles = Role.list(self.apiclient, id=self.role.id)
+ self.assertEqual(
+ list_roles,
+ None,
+ "List Roles response should be empty"
+ )
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_role_inuse_deletion(self):
+ """
+ Test to ensure role in use cannot be deleted
+ """
+ try:
+ self.role.delete(self.apiclient)
+ self.fail("Role with any account should not be allowed to be deleted")
+ except CloudstackAPIException: pass
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_default_role_deletion(self):
+ """
+ Test to ensure 4 default roles cannot be deleted
+ """
+ for idx in range(1,5):
+ cmd = deleteRole.deleteRoleCmd()
+ cmd.id = idx
+ try:
+ self.apiclient.deleteRole(cmd)
+ self.fail("Default role got deleted with id: " + idx)
+ except CloudstackAPIException: pass
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_rolepermission_lifecycle_list(self):
+ """
+ Tests listing of default role's permission
+ """
+ for idx in range(1,5):
+ list_rolepermissions = RolePermission.list(self.apiclient, roleid=idx)
+ self.assertEqual(
+ isinstance(list_rolepermissions, list),
+ True,
+ "List rolepermissions response was not a valid list"
+ )
+ self.assertTrue(
+ len(list_rolepermissions) > 0,
+ "List rolepermissions response was empty"
+ )
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_rolepermission_lifecycle_create(self):
+ """
+ Tests creation of role permission
+ """
+ # Reuse self.rolepermission created in setUp()
+ try:
+ rolepermission = RolePermission.create(
+ self.apiclient,
+ self.testdata["rolepermission"]
+ )
+ self.fail("An exception was expected when creating duplicate role permissions")
+ except CloudstackAPIException: pass
+
+ list_rolepermissions = RolePermission.list(self.apiclient, roleid=self.role.id)
+ self.assertEqual(
+ isinstance(list_rolepermissions, list),
+ True,
+ "List rolepermissions response was not a valid list"
+ )
+ self.assertNotEqual(
+ len(list_rolepermissions),
+ 0,
+ "List rolepermissions response was empty"
+ )
+ self.assertEqual(
+ list_rolepermissions[0].rule,
+ self.testdata["rolepermission"]["rule"],
+ msg="Role permission rule does not match the test data"
+ )
+ self.assertEqual(
+ list_rolepermissions[0].permission,
+ self.testdata["rolepermission"]["permission"],
+ msg="Role permission permission-type does not match the test data"
+ )
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_rolepermission_lifecycle_update(self):
+ """
+ Tests order updation of role permission
+ """
+ permissions = [self.rolepermission]
+ rules = ['list*', '*Vol*', 'listCapabilities']
+ for rule in rules:
+ data = copy.deepcopy(self.testdata["rolepermission"])
+ data['rule'] = rule
+ permission = RolePermission.create(
+ self.apiclient,
+ data
+ )
+ self.cleanup.append(permission)
+ permissions.append(permission)
+
+
+ def validate_permissions_list(permissions):
+ list_rolepermissions = RolePermission.list(self.apiclient, roleid=self.role.id)
+ self.assertEqual(
+ len(list_rolepermissions),
+ len(permissions),
+ msg="List of role permissions do not match created list of permissions"
+ )
+
+ for idx, rolepermission in enumerate(list_rolepermissions):
+ self.assertEqual(
+ rolepermission.rule,
+ permissions[idx].rule,
+ msg="Rule permission don't match with expected item at the index"
+ )
+ self.assertEqual(
+ rolepermission.permission,
+ permissions[idx].permission,
+ msg="Rule permission don't match with expected item at the index"
+ )
+
+ # Move last item to the top
+ rule = permissions.pop(len(permissions)-1)
+ permissions = [rule] + permissions
+ rule.update(self.apiclient, ruleorder=",".join(map(lambda x: x.id, permissions)))
+ validate_permissions_list(permissions)
+
+ # Move to the bottom
+ rule = permissions.pop(0)
+ permissions = permissions + [rule]
+ rule.update(self.apiclient, ruleorder=",".join(map(lambda x: x.id, permissions)))
+ validate_permissions_list(permissions)
+
+ # Random shuffles
+ for _ in range(3):
+ shuffle(permissions)
+ rule.update(self.apiclient, ruleorder=",".join(map(lambda x: x.id, permissions)))
+ validate_permissions_list(permissions)
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_rolepermission_lifecycle_concurrent_updates(self):
+ """
+ Tests concurrent order updation of role permission
+ """
+ permissions = [self.rolepermission]
+ rules = ['list*', '*Vol*', 'listCapabilities']
+ for rule in rules:
+ data = copy.deepcopy(self.testdata["rolepermission"])
+ data['rule'] = rule
+ permission = RolePermission.create(
+ self.apiclient,
+ data
+ )
+ self.cleanup.append(permission)
+ permissions.append(permission)
+
+
+ # The following rule is considered to be created by another mgmt server
+ data = copy.deepcopy(self.testdata["rolepermission"])
+ data['rule'] = "someRule*"
+ permission = RolePermission.create(
+ self.apiclient,
+ data
+ )
+ self.cleanup.append(permission)
+
+ shuffle(permissions)
+ try:
+ permission.update(self.apiclient, ruleorder=",".join(map(lambda x: x.id, permissions)))
+ self.fail("Reordering should fail in case of concurrent updates by other user")
+ except CloudstackAPIException: pass
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_rolepermission_lifecycle_delete(self):
+ """
+ Tests deletion of role permission
+ """
+ permission = self.cleanup.pop(1)
+ permission.delete(self.apiclient)
+ list_rolepermissions = RolePermission.list(self.apiclient, roleid=self.role.id)
+ self.assertEqual(
+ list_rolepermissions,
+ None,
+ "List rolepermissions response should be empty"
+ )
+
+
+ def checkApiAvailability(self, apiConfig, userApiClient):
+ """
+ Checks available APIs based on api map
+ """
+ response = userApiClient.listApis(listApis.listApisCmd())
+ allowedApis = map(lambda x: x.name, response)
+ for api in allowedApis:
+ for rule, perm in apiConfig.items():
+ if re.match(rule.replace('*', '.*'), api):
+ if perm.lower() == 'allow':
+ break
+ else:
+ self.fail('Denied API found to be allowed: ' + api)
+
+
+ def checkApiCall(self, apiConfig, userApiClient):
+ """
+ Performs actual API calls to verify API ACLs
+ """
+ list_accounts = userApiClient.listAccounts(listAccounts.listAccountsCmd())
+ self.assertEqual(
+ isinstance(list_accounts, list),
+ True,
+ "List accounts response was not a valid list"
+ )
+ self.assertNotEqual(
+ len(list_accounts),
+ 0,
+ "List accounts response was empty"
+ )
+
+ # Perform actual API call for deny API
+ try:
+ userApiClient.listHosts(listHosts.listHostsCmd())
+ self.fail("API call succeeded which is denied for the role")
+ except CloudstackAPIException: pass
+
+ # Perform actual API call for API with no allow/deny rule
+ try:
+ userApiClient.listZones(listZones.listZonesCmd())
+ self.fail("API call succeeded which has no allow/deny rule for the role")
+ except CloudstackAPIException: pass
+
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_role_account_acls(self):
+ """
+ Test to check role, role permissions and account life cycles
+ """
+ apiConfig = self.testdata['apiConfig']
+ for api, perm in apiConfig.items():
+ testdata = self.testdata['rolepermission']
+ testdata['roleid'] = self.role.id
+ testdata['rule'] = api
+ testdata['permission'] = perm.lower()
+
+ RolePermission.create(
+ self.apiclient,
+ testdata
+ )
+
+ userApiClient = self.getUserApiClient(self.account.name, domain=self.account.domain, role_type=self.account.roletype)
+
+ # Perform listApis check
+ self.checkApiAvailability(apiConfig, userApiClient)
+
+ # Perform actual API call for allow API
+ self.checkApiCall(apiConfig, userApiClient)
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_role_account_acls_multiple_mgmt_servers(self):
+ """
+ Test for role-rule enforcement in case of multiple mgmt servers
+ Inserts rule directly in DB and checks expected behaviour
+ """
+ apiConfig = self.testdata["apiConfig"]
+ roleId = self.dbclient.execute("select id from roles where uuid='%s'" % self.role.id)[0][0]
+ sortOrder = 1
+ for rule, perm in apiConfig.items():
+ self.dbclient.execute("insert into role_permissions (uuid, role_id, rule, permission, sort_order) values (UUID(), %d, '%s', '%s', %d)" % (roleId, rule, perm.upper(), sortOrder))
+ sortOrder += 1
+
+ userApiClient = self.getUserApiClient(self.account.name, domain=self.account.domain, role_type=self.account.roletype)
+
+ # Perform listApis check
+ self.checkApiAvailability(apiConfig, userApiClient)
+
+ # Perform actual API call for allow API
+ self.checkApiCall(apiConfig, userApiClient)
diff --git a/test/integration/smoke/test_list_ids_parameter.py b/test/integration/smoke/test_list_ids_parameter.py
new file mode 100755
index 0000000..f679aed
--- /dev/null
+++ b/test/integration/smoke/test_list_ids_parameter.py
@@ -0,0 +1,295 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+""" Tests for API listing methods using 'ids' parameter
+"""
+#Import Local Modules
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.utils import (cleanup_resources,
+ validateList)
+from marvin.lib.base import (Account,
+ Volume,
+ DiskOffering,
+ Template,
+ ServiceOffering,
+ Snapshot,
+ VmSnapshot,
+ VirtualMachine)
+from marvin.lib.common import (get_domain,
+ get_zone, get_template)
+from marvin.codes import FAILED, PASS
+from nose.plugins.attrib import attr
+#Import System modules
+import time
+
+_multiprocess_shared_ = True
+class TestListIdsParams(cloudstackTestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ testClient = super(TestListIdsParams, cls).getClsTestClient()
+ cls.apiclient = testClient.getApiClient()
+ cls.services = testClient.getParsedTestDataConfig()
+ cls.hypervisor = testClient.getHypervisorInfo()
+ cls.domain = get_domain(cls.apiclient)
+ cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+
+ cls.disk_offering = DiskOffering.create(
+ cls.apiclient,
+ cls.services["disk_offering"]
+ )
+
+ cls.account = Account.create(
+ cls.apiclient,
+ cls.services["account"],
+ domainid=cls.domain.id
+ )
+ cls.service_offering = ServiceOffering.create(
+ cls.apiclient,
+ cls.services["service_offerings"]["tiny"]
+ )
+
+ template = get_template(
+ cls.apiclient,
+ cls.zone.id,
+ cls.services["ostype"]
+ )
+ if template == FAILED:
+ assert False, "get_template() failed to return template with description %s" % cls.services["ostype"]
+
+ cls.services["template"]["ostypeid"] = template.ostypeid
+ cls.services["template_2"]["ostypeid"] = template.ostypeid
+ cls.services["ostypeid"] = template.ostypeid
+ cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+ cls.services["mode"] = cls.zone.networktype
+
+ #Create 3 VMs
+ cls.virtual_machine_1 = VirtualMachine.create(
+ cls.apiclient,
+ cls.services["virtual_machine"],
+ templateid=template.id,
+ accountid=cls.account.name,
+ domainid=cls.account.domainid,
+ serviceofferingid=cls.service_offering.id,
+ mode=cls.services["mode"]
+ )
+ cls.virtual_machine_2 = VirtualMachine.create(
+ cls.apiclient,
+ cls.services["virtual_machine"],
+ templateid=template.id,
+ accountid=cls.account.name,
+ domainid=cls.account.domainid,
+ serviceofferingid=cls.service_offering.id,
+ mode=cls.services["mode"]
+ )
+ cls.virtual_machine_3 = VirtualMachine.create(
+ cls.apiclient,
+ cls.services["virtual_machine"],
+ templateid=template.id,
+ accountid=cls.account.name,
+ domainid=cls.account.domainid,
+ serviceofferingid=cls.service_offering.id,
+ mode=cls.services["mode"]
+ )
+
+ #Take 3 VM1 Snapshots
+ #PLEASE UNCOMMENT ONCE VM SNAPSHOT DELAY BUG AFTER VM CREATION IS FIXED
+ """cls.vmsnapshot_1 = VmSnapshot.create(
+ cls.apiclient,
+ cls.virtual_machine_1.id
+ )
+ cls.vmsnapshot_2 = VmSnapshot.create(
+ cls.apiclient,
+ cls.virtual_machine_1.id
+ )
+ cls.vmsnapshot_3 = VmSnapshot.create(
+ cls.apiclient,
+ cls.virtual_machine_1.id
+ )"""
+
+ #Stop VMs
+ cls.virtual_machine_1.stop(cls.apiclient)
+ cls.virtual_machine_2.stop(cls.apiclient)
+ cls.virtual_machine_3.stop(cls.apiclient)
+
+ #Get ROOT volumes of 3 VMs
+ vm1RootVolumeResponse = Volume.list(
+ cls.apiclient,
+ virtualmachineid=cls.virtual_machine_1.id,
+ type='ROOT',
+ listall=True
+ )
+ vm2RootVolumeResponse = Volume.list(
+ cls.apiclient,
+ virtualmachineid=cls.virtual_machine_2.id,
+ type='ROOT',
+ listall=True
+ )
+ vm3RootVolumeResponse = Volume.list(
+ cls.apiclient,
+ virtualmachineid=cls.virtual_machine_3.id,
+ type='ROOT',
+ listall=True
+ )
+ cls.vm1_root_volume = vm1RootVolumeResponse[0]
+ cls.vm2_root_volume = vm2RootVolumeResponse[0]
+ cls.vm3_root_volume = vm3RootVolumeResponse[0]
+
+ #Take 3 snapshots of VM2's ROOT volume
+ cls.snapshot_1 = Snapshot.create(
+ cls.apiclient,
+ cls.vm2_root_volume.id,
+ account=cls.account.name,
+ domainid=cls.account.domainid
+ )
+ cls.snapshot_2 = Snapshot.create(
+ cls.apiclient,
+ cls.vm2_root_volume.id,
+ account=cls.account.name,
+ domainid=cls.account.domainid
+ )
+ cls.snapshot_3 = Snapshot.create(
+ cls.apiclient,
+ cls.vm2_root_volume.id,
+ account=cls.account.name,
+ domainid=cls.account.domainid
+ )
+
+ #Create 3 templates
+ cls.template_1 = Template.create(
+ cls.apiclient,
+ cls.services["template"],
+ cls.vm3_root_volume.id,
+ account=cls.account.name,
+ domainid=cls.account.domainid
+ )
+ cls.template_2 = Template.create(
+ cls.apiclient,
+ cls.services["template_2"],
+ cls.vm3_root_volume.id,
+ account=cls.account.name,
+ domainid=cls.account.domainid
+ )
+ cls.template_3 = Template.create(
+ cls.apiclient,
+ cls.services["template_2"],
+ cls.vm3_root_volume.id,
+ account=cls.account.name,
+ domainid=cls.account.domainid
+ )
+
+ cls._cleanup = [
+ cls.snapshot_1,
+ cls.snapshot_2,
+ cls.snapshot_3,
+ cls.account,
+ cls.disk_offering,
+ cls.service_offering
+ ]
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.apiclient = super(TestListIdsParams, cls).getClsTestClient().getApiClient()
+ try:
+ cleanup_resources(cls.apiclient, cls._cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+ return
+
+ @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false")
+ def test_01_list_volumes(self):
+ """Test listing Volumes using 'ids' parameter
+ """
+ list_volume_response = Volume.list(
+ self.apiclient,
+ ids=[self.vm1_root_volume.id, self.vm2_root_volume.id, self.vm3_root_volume.id],
+ type='ROOT',
+ listAll=True
+ )
+ self.assertEqual(
+ isinstance(list_volume_response, list),
+ True,
+ "List Volume response was not a valid list"
+ )
+ self.assertEqual(
+ len(list_volume_response),
+ 3,
+ "ListVolumes response expected 3 Volumes, received %s" % len(list_volume_response)
+ )
+
+ @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false")
+ def test_02_list_templates(self):
+ """Test listing Templates using 'ids' parameter
+ """
+ list_template_response = Template.list(
+ self.apiclient,
+ templatefilter='all',
+ ids=[self.template_1.id, self.template_2.id, self.template_3.id],
+ account=self.account.name,
+ domainid=self.account.domainid,
+ listAll=True
+ )
+ self.assertEqual(
+ isinstance(list_template_response, list),
+ True,
+ "ListTemplates response was not a valid list"
+ )
+ self.assertEqual(
+ len(list_template_response),
+ 3,
+ "ListTemplates response expected 3 Templates, received %s" % len(list_template_response)
+ )
+
+ @attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false")
+ def test_03_list_snapshots(self):
+ """Test listing Snapshots using 'ids' parameter
+ """
+ list_snapshot_response = Snapshot.list(
+ self.apiclient,
+ ids=[self.snapshot_1.id, self.snapshot_2.id, self.snapshot_3.id],
+ listAll=True
+ )
+ self.assertEqual(
+ isinstance(list_snapshot_response, list),
+ True,
+ "ListSnapshots response was not a valid list"
+ )
+ self.assertEqual(
+ len(list_snapshot_response),
+ 3,
+ "ListSnapshots response expected 3 Snapshots, received %s" % len(list_snapshot_response)
+ )
+
+ #PLEASE UNCOMMENT ONCE VM SNAPSHOT DELAY BUG AFTER VM CREATION IS FIXED
+ #@attr(tags = ["advanced", "advancedns", "smoke", "basic"], required_hardware="false")
+ #def test_04_list_vm_snapshots(self):
+ """Test listing VMSnapshots using 'vmsnapshotids' parameter
+ """
+ """list_vm_snapshot_response = VmSnapshot.list(
+ self.apiclient,
+ vmsnapshotids=[self.vmsnapshot_1.id, self.vmsnapshot_2.id, self.vmsnapshot_3.id],
+ listall=True
+ )
+ self.assertEqual(
+ isinstance(list_vm_snapshot_response, list),
+ True,
+ "ListVMSnapshots response was not a valid list"
+ )
+ self.assertEqual(
+ len(list_vm_snapshot_response),
+ 3,
+ "ListVMSnapshots response expected 3 VMSnapshots, received %s" % len(list_vm_snapshot_response)
+ )"""
diff --git a/test/integration/smoke/test_outofbandmanagement.py b/test/integration/smoke/test_outofbandmanagement.py
new file mode 100644
index 0000000..122fcfc
--- /dev/null
+++ b/test/integration/smoke/test_outofbandmanagement.py
@@ -0,0 +1,592 @@
+# 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 marvin
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from marvin.lib.utils import *
+from marvin.lib.base import *
+from marvin.lib.common import *
+from marvin.lib.utils import (random_gen)
+from nose.plugins.attrib import attr
+
+from ipmisim.ipmisim import IpmiServerContext, IpmiServer, ThreadedIpmiServer
+
+import random
+import socket
+import sys
+import thread
+import time
+
+
+class TestOutOfBandManagement(cloudstackTestCase):
+ """ Test cases for out of band management
+ """
+
+ def setUp(self):
+ self.apiclient = self.testClient.getApiClient()
+ self.hypervisor = self.testClient.getHypervisorInfo()
+ self.dbclient = self.testClient.getDbConnection()
+ self.services = self.testClient.getParsedTestDataConfig()
+ self.mgtSvrDetails = self.config.__dict__["mgtSvr"][0].__dict__
+ self.fakeMsId = random.randint(10000, 99999) * random.randint(10, 20)
+
+ self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests())
+ self.host = None
+ self.server = None
+
+ # use random port for ipmisim
+ s = socket.socket()
+ s.bind(('', 0))
+ self.serverPort = s.getsockname()[1]
+ s.close()
+
+ self.cleanup = []
+
+
+ def tearDown(self):
+ try:
+ self.dbclient.execute("delete from oobm where port=%d" % self.getIpmiServerPort())
+ self.dbclient.execute("delete from mshost_peer where peer_runid=%s" % self.getFakeMsRunId())
+ self.dbclient.execute("delete from mshost where runid=%s" % self.getFakeMsRunId())
+ self.dbclient.execute("delete from cluster_details where name='outOfBandManagementEnabled'")
+ self.dbclient.execute("delete from data_center_details where name='outOfBandManagementEnabled'")
+ cleanup_resources(self.apiclient, self.cleanup)
+ if self.server:
+ self.server.shutdown()
+ self.server.server_close()
+ IpmiServerContext('reset')
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+
+
+ def getFakeMsId(self):
+ return self.fakeMsId
+
+
+ def getFakeMsRunId(self):
+ return self.fakeMsId * 1000
+
+
+ def getHost(self, hostId=None):
+ if self.host and hostId is None:
+ return self.host
+
+ response = list_hosts(
+ self.apiclient,
+ zoneid=self.zone.id,
+ type='Routing',
+ id=hostId
+ )
+ if len(response) > 0:
+ self.host = response[0]
+ return self.host
+ raise self.skipTest("No hosts found, skipping out-of-band management test")
+
+
+ def getIpmiServerIp(self):
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ s.connect((self.mgtSvrDetails["mgtSvrIp"], self.mgtSvrDetails["port"]))
+ return s.getsockname()[0]
+
+
+ def getIpmiServerPort(self):
+ return self.serverPort
+
+
+ def getOobmConfigCmd(self):
+ cmd = configureOutOfBandManagement.configureOutOfBandManagementCmd()
+ cmd.driver = 'ipmitool' # The default available driver
+ cmd.address = self.getIpmiServerIp()
+ cmd.port = self.getIpmiServerPort()
+ cmd.username = 'admin'
+ cmd.password = 'password'
+ cmd.hostid = self.getHost().id
+ return cmd
+
+
+ def getOobmEnableCmd(self):
+ cmd = enableOutOfBandManagementForHost.enableOutOfBandManagementForHostCmd()
+ cmd.hostid = self.getHost().id
+ return cmd
+
+
+ def getOobmDisableCmd(self):
+ cmd = disableOutOfBandManagementForHost.disableOutOfBandManagementForHostCmd()
+ cmd.hostid = self.getHost().id
+ return cmd
+
+
+ def getOobmIssueActionCmd(self):
+ cmd = issueOutOfBandManagementPowerAction.issueOutOfBandManagementPowerActionCmd()
+ cmd.hostid = self.getHost().id
+ cmd.action = 'STATUS'
+ return cmd
+
+
+ def issuePowerActionCmd(self, action, timeout=None):
+ cmd = self.getOobmIssueActionCmd()
+ cmd.action = action
+ if timeout:
+ cmd.timeout = timeout
+
+ try:
+ return self.apiclient.issueOutOfBandManagementPowerAction(cmd)
+ except Exception as e:
+ if "packet session id 0x0 does not match active session" in str(e):
+ raise self.skipTest("Known ipmitool issue hit, skipping test")
+ raise e
+
+
+ def configureAndEnableOobm(self):
+ self.apiclient.configureOutOfBandManagement(self.getOobmConfigCmd())
+ response = self.apiclient.enableOutOfBandManagementForHost(self.getOobmEnableCmd())
+ self.assertEqual(response.enabled, True)
+
+
+ def startIpmiServer(self):
+ def startIpmiServer(tname, server):
+ self.debug("Starting ipmisim server")
+ try:
+ server.serve_forever()
+ except Exception: pass
+ IpmiServerContext('reset')
+ ThreadedIpmiServer.allow_reuse_address = False
+ server = ThreadedIpmiServer(('0.0.0.0', self.getIpmiServerPort()), IpmiServer)
+ thread.start_new_thread(startIpmiServer, ("ipmi-server", server,))
+ self.server = server
+
+
+ def checkSyncToState(self, state, interval):
+ def checkForStateSync(expectedState):
+ response = self.getHost(hostId=self.getHost().id).outofbandmanagement
+ return response.powerstate == expectedState, None
+
+ sync_interval = 1 + int(interval)/1000
+ res, _ = wait_until(sync_interval, 10, checkForStateSync, state)
+ if not res:
+ self.fail("Failed to get host.powerstate synced to expected state:" + state)
+ response = self.getHost(hostId=self.getHost().id).outofbandmanagement
+ self.assertEqual(response.powerstate, state)
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_configure_invalid_driver(self):
+ """
+ Tests out-of-band management configuration with invalid driver
+ """
+ cmd = self.getOobmConfigCmd()
+ cmd.driver = 'randomDriverThatDoesNotExist'
+ try:
+ response = self.apiclient.configureOutOfBandManagement(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_configure_default_driver(self):
+ """
+ Tests out-of-band management configuration with valid data
+ """
+ cmd = self.getOobmConfigCmd()
+ response = self.apiclient.configureOutOfBandManagement(cmd)
+ self.assertEqual(response.hostid, cmd.hostid)
+ self.assertEqual(response.driver, cmd.driver)
+ self.assertEqual(response.address, cmd.address)
+ self.assertEqual(response.port, str(cmd.port))
+ self.assertEqual(response.username, cmd.username)
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_enable_feature_invalid(self):
+ """
+ Tests out-of-band management host enable feature with
+ invalid options
+ """
+ cmd = self.getOobmEnableCmd()
+ cmd.hostid = -1
+ try:
+ response = self.apiclient.enableOutOfBandManagementForHost(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+ try:
+ cmd = enableOutOfBandManagementForCluster.enableOutOfBandManagementForClusterCmd()
+ response = self.apiclient.enableOutOfBandManagementForCluster(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+ try:
+ cmd = enableOutOfBandManagementForZone.enableOutOfBandManagementForZoneCmd()
+ response = self.apiclient.enableOutOfBandManagementForZone(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_disable_feature_invalid(self):
+ """
+ Tests out-of-band management host disable feature with
+ invalid options
+ """
+ cmd = self.getOobmDisableCmd()
+ cmd.hostid = -1
+ try:
+ response = self.apiclient.disableOutOfBandManagementForHost(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+ try:
+ cmd = disableOutOfBandManagementForCluster.disableOutOfBandManagementForClusterCmd()
+ response = self.apiclient.disableOutOfBandManagementForCluster(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+ try:
+ cmd = disableOutOfBandManagementForZone.disableOutOfBandManagementForZoneCmd()
+ response = self.apiclient.disableOutOfBandManagementForZone(cmd)
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_enable_feature_valid(self):
+ """
+ Tests out-of-band management host enable feature with
+ valid options
+ """
+ self.apiclient.configureOutOfBandManagement(self.getOobmConfigCmd())
+ cmd = self.getOobmEnableCmd()
+ response = self.apiclient.enableOutOfBandManagementForHost(cmd)
+ self.assertEqual(response.hostid, cmd.hostid)
+ self.assertEqual(response.enabled, True)
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_disable_feature_valid(self):
+ """
+ Tests out-of-band management host disable feature with
+ valid options
+ """
+
+ self.apiclient.configureOutOfBandManagement(self.getOobmConfigCmd())
+ cmd = self.getOobmDisableCmd()
+ response = self.apiclient.disableOutOfBandManagementForHost(cmd)
+ self.assertEqual(response.hostid, cmd.hostid)
+ self.assertEqual(response.enabled, False)
+
+ response = self.getHost(hostId=cmd.hostid).outofbandmanagement
+ self.assertEqual(response.powerstate, 'Disabled')
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_enabledisable_across_clusterzones(self):
+ """
+ Tests out-of-band management enable/disable feature at cluster
+ and zone level sequentially Zone > Cluster > Host
+ """
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+ bmc = IpmiServerContext().bmc
+ bmc.powerstate = 'off'
+
+ host = self.getHost()
+
+ # Disable at zone level
+ cmd = disableOutOfBandManagementForZone.disableOutOfBandManagementForZoneCmd()
+ cmd.zoneid = host.zoneid
+ response = self.apiclient.disableOutOfBandManagementForZone(cmd)
+
+ # Disable at cluster level
+ cmd = disableOutOfBandManagementForCluster.disableOutOfBandManagementForClusterCmd()
+ cmd.clusterid = host.clusterid
+ response = self.apiclient.disableOutOfBandManagementForCluster(cmd)
+
+ # Disable at host level
+ cmd = disableOutOfBandManagementForHost.disableOutOfBandManagementForHostCmd()
+ cmd.hostid = host.id
+ response = self.apiclient.disableOutOfBandManagementForHost(cmd)
+
+ try:
+ self.issuePowerActionCmd('STATUS')
+ self.fail("Exception was expected, oobm is disabled at zone level")
+ except Exception: pass
+
+ # Enable at zone level
+ cmd = enableOutOfBandManagementForZone.enableOutOfBandManagementForZoneCmd()
+ cmd.zoneid = host.zoneid
+ response = self.apiclient.enableOutOfBandManagementForZone(cmd)
+
+ try:
+ self.issuePowerActionCmd('STATUS')
+ self.fail("Exception was expected, oobm is disabled at cluster level")
+ except Exception: pass
+
+ # Check background thread syncs state to Disabled
+ response = self.getHost(hostId=host.id).outofbandmanagement
+ self.assertEqual(response.powerstate, 'Disabled')
+ self.dbclient.execute("update oobm set power_state='On' where port=%d" % self.getIpmiServerPort())
+ interval = list_configurations(
+ self.apiclient,
+ name='outofbandmanagement.sync.interval'
+ )[0].value
+ self.checkSyncToState('Disabled', interval)
+
+ # Enable at cluster level
+ cmd = enableOutOfBandManagementForCluster.enableOutOfBandManagementForClusterCmd()
+ cmd.clusterid = host.clusterid
+ response = self.apiclient.enableOutOfBandManagementForCluster(cmd)
+
+ try:
+ self.issuePowerActionCmd('STATUS')
+ self.fail("Exception was expected, oobm is disabled at host level")
+ except Exception: pass
+
+ # Enable at host level
+ cmd = enableOutOfBandManagementForHost.enableOutOfBandManagementForHostCmd()
+ cmd.hostid = host.id
+ response = self.apiclient.enableOutOfBandManagementForHost(cmd)
+
+ response = self.issuePowerActionCmd('STATUS')
+ self.assertEqual(response.powerstate, 'Off')
+
+
+ def configureAndStartIpmiServer(self, power_state=None):
+ """
+ Setup ipmisim and enable out-of-band management for host
+ """
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+ if power_state:
+ bmc = IpmiServerContext().bmc
+ bmc.powerstate = power_state
+
+
+ def assertIssueCommandState(self, command, expected):
+ """
+ Asserts power action result for a given power command
+ """
+ if command != 'STATUS':
+ self.issuePowerActionCmd(command)
+ response = self.issuePowerActionCmd('STATUS')
+ self.assertEqual(response.powerstate, expected)
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_issue_power_status(self):
+ """
+ Tests out-of-band management issue power action
+ """
+ self.configureAndStartIpmiServer(power_state='on')
+ self.assertIssueCommandState('STATUS', 'On')
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_issue_power_on(self):
+ """
+ Tests out-of-band management issue power on action
+ """
+ self.configureAndStartIpmiServer()
+ self.assertIssueCommandState('ON', 'On')
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_issue_power_off(self):
+ """
+ Tests out-of-band management issue power off action
+ """
+ self.configureAndStartIpmiServer()
+ self.assertIssueCommandState('OFF', 'Off')
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_issue_power_cycle(self):
+ """
+ Tests out-of-band management issue power cycle action
+ """
+ self.configureAndStartIpmiServer()
+ self.assertIssueCommandState('CYCLE', 'On')
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_issue_power_reset(self):
+ """
+ Tests out-of-band management issue power reset action
+ """
+ self.configureAndStartIpmiServer()
+ self.assertIssueCommandState('RESET', 'On')
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_issue_power_soft(self):
+ """
+ Tests out-of-band management issue power soft action
+ """
+ self.configureAndStartIpmiServer()
+ self.assertIssueCommandState('SOFT', 'Off')
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_background_powerstate_sync(self):
+ """
+ Tests out-of-band management background powerstate sync
+ """
+ self.debug("Testing oobm background sync")
+ interval = list_configurations(
+ self.apiclient,
+ name='outofbandmanagement.sync.interval'
+ )[0].value
+
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+ bmc = IpmiServerContext().bmc
+
+ bmc.powerstate = 'on'
+ self.checkSyncToState('On', interval)
+
+ bmc.powerstate = 'off'
+ self.checkSyncToState('Off', interval)
+
+ self.server.shutdown()
+ self.server.server_close()
+
+ # Check for unknown state (ipmi server not reachable)
+ self.checkSyncToState('Unknown', interval)
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_multiple_mgmt_server_ownership(self):
+ """
+ Tests out-of-band management ownership expiry across multi-mgmt server
+ """
+ self.configureAndEnableOobm()
+
+ cloudstackVersion = Configurations.listCapabilities(self.apiclient).cloudstackversion
+
+ currentMsHosts = []
+ mshosts = self.dbclient.execute("select msid from mshost where version='%s' and removed is NULL and state='Up'" % (cloudstackVersion))
+ if len(mshosts) > 0:
+ currentMsHosts = map(lambda row: row[0], mshosts)
+
+ # Inject fake ms host
+ self.dbclient.execute("insert into mshost (msid,runid,name,state,version,service_ip,service_port,last_update) values (%s,%s,'oobm-marvin-fakebox', 'Down', '%s', '127.0.0.1', '22', NOW())" % (self.getFakeMsId(), self.getFakeMsRunId(), cloudstackVersion))
+
+ # Pass ownership to the fake ms id
+ self.dbclient.execute("update oobm set mgmt_server_id=%d where port=%d" % (self.getFakeMsId(), self.getIpmiServerPort()))
+
+ self.debug("Testing oobm background sync")
+ pingInterval = float(list_configurations(
+ self.apiclient,
+ name='ping.interval'
+ )[0].value)
+
+ pingTimeout = float(list_configurations(
+ self.apiclient,
+ name='ping.timeout'
+ )[0].value)
+
+
+ def removeFakeMgmtServer(fakeMsRunId):
+ rows = self.dbclient.execute("select * from mshost_peer where peer_runid=%s" % fakeMsRunId)
+ if len(rows) > 0:
+ self.debug("Mgmt server is now trying to contact the fake mgmt server")
+ self.dbclient.execute("update mshost set removed=now() where runid=%s" % fakeMsRunId)
+ self.dbclient.execute("update mshost_peer set peer_state='Down' where peer_runid=%s" % fakeMsRunId)
+ return True, None
+ return False, None
+
+ def checkOobmOwnershipExpiry(serverPort, fakeMsId):
+ rows = self.dbclient.execute("select mgmt_server_id from oobm where port=%d" % (serverPort))
+ if len(rows) > 0 and rows[0][0] != fakeMsId:
+ self.debug("Out-of-band management ownership expired as node was detected to be gone")
+ return True, None
+ return False, None
+
+ retry_interval = 1 + (pingInterval * pingTimeout / 10)
+
+ res, _ = wait_until(retry_interval, 10, removeFakeMgmtServer, self.getFakeMsRunId())
+ if not res:
+ self.fail("Management server failed to turn down or remove fake mgmt server")
+
+ res, _ = wait_until(retry_interval, 100, checkOobmOwnershipExpiry, self.getIpmiServerPort(), self.getFakeMsId())
+ if not res:
+ self.fail("Management server failed to expire ownership of fenced peer")
+
+ self.debug("Testing oobm background sync should claim new ownership")
+ interval = list_configurations(
+ self.apiclient,
+ name='outofbandmanagement.sync.interval'
+ )[0].value
+
+ self.startIpmiServer()
+ bmc = IpmiServerContext().bmc
+ bmc.powerstate = 'on'
+
+ self.checkSyncToState('On', interval)
+
+ result = self.dbclient.execute("select mgmt_server_id from oobm where port=%d" % (self.getIpmiServerPort()))
+ newOwnerId = result[0][0]
+ self.assertTrue(newOwnerId in currentMsHosts)
+
+
+ @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+ def test_oobm_zchange_password(self):
+ """
+ Tests out-of-band management change password feature
+ """
+ self.configureAndEnableOobm()
+ self.startIpmiServer()
+
+ self.debug("Testing oobm change password")
+
+ alerts = Alert.list(self.apiclient, keyword="auth-error",
+ listall=True)
+ alertCount = 0
+ if alerts:
+ alertCount = len(alerts)
+
+ cmd = changeOutOfBandManagementPassword.changeOutOfBandManagementPasswordCmd()
+ cmd.hostid = self.getHost().id
+ cmd.password = "Password12345"
+ try:
+ response = self.apiclient.changeOutOfBandManagementPassword(cmd)
+ self.assertEqual(response.status, True)
+ except Exception as e:
+ if "packet session id 0x0 does not match active session" in str(e):
+ raise self.skipTest("Known ipmitool issue hit, skipping test")
+ raise e
+
+ bmc = IpmiServerContext().bmc
+ bmc.powerstate = 'on'
+ response = self.issuePowerActionCmd('STATUS')
+ self.assertEqual(response.status, True)
+ self.assertEqual(response.powerstate, 'On')
+
+ # Reset configuration, resets password
+ self.apiclient.configureOutOfBandManagement(self.getOobmConfigCmd())
+ self.assertEqual(response.status, True)
+
+ try:
+ response = self.issuePowerActionCmd('STATUS')
+ self.fail("Expected an exception to be thrown, failing")
+ except Exception: pass
+
+ alerts = Alert.list(self.apiclient, keyword="auth-error",
+ listall=True)
+
+ self.assertTrue((len(alerts) - alertCount) >= 0)
diff --git a/test/integration/smoke/test_privategw_acl.py b/test/integration/smoke/test_privategw_acl.py
index 1a86175..03a99d1 100644
--- a/test/integration/smoke/test_privategw_acl.py
+++ b/test/integration/smoke/test_privategw_acl.py
@@ -24,6 +24,7 @@
from marvin.lib.base import *
from marvin.lib.common import *
from nose.plugins.attrib import attr
+from marvin.codes import PASS
import time
import logging
@@ -244,6 +245,10 @@
"select vnet from op_dc_vnet_alloc where physical_network_id=\
(select id from physical_network where uuid='%s' ) and taken is NULL and reservation_id is NULL and account_id is NULL ORDER BY id DESC;" % physical_network.id
)
+ self.assertEqual(validateList(qresultset)[0],
+ PASS,
+ "Invalid sql query response"
+ )
vlans = qresultset
vlan_1 = int(vlans[0][0])
@@ -316,6 +321,10 @@
"select vnet from op_dc_vnet_alloc where physical_network_id=\
(select id from physical_network where uuid='%s' ) and taken is NULL and reservation_id is NULL and account_id is NULL ORDER BY id DESC;" % physical_network.id
)
+ self.assertEqual(validateList(qresultset)[0],
+ PASS,
+ "Invalid sql query response"
+ )
vlans = qresultset
vlan_1 = int(vlans[0][0])
diff --git a/test/integration/smoke/test_router_dns.py b/test/integration/smoke/test_router_dns.py
new file mode 100644
index 0000000..ef77224
--- /dev/null
+++ b/test/integration/smoke/test_router_dns.py
@@ -0,0 +1,268 @@
+# 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 logging
+import dns.resolver
+
+from nose.plugins.attrib import attr
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.utils import cleanup_resources
+from marvin.lib.base import (ServiceOffering,
+ VirtualMachine,
+ Account,
+ NATRule,
+ FireWallRule,
+ NetworkOffering,
+ Network)
+from marvin.lib.common import (get_zone,
+ get_template,
+ get_domain,
+ list_routers,
+ list_nat_rules,
+ list_publicIP)
+
+
+class TestRouterDns(cloudstackTestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.logger = logging.getLogger('TestRouterDns')
+ cls.stream_handler = logging.StreamHandler()
+ cls.logger.setLevel(logging.DEBUG)
+ cls.logger.addHandler(cls.stream_handler)
+
+ cls.testClient = super(TestRouterDns, cls).getClsTestClient()
+ cls.api_client = cls.testClient.getApiClient()
+ cls.services = cls.testClient.getParsedTestDataConfig()
+
+ cls.domain = get_domain(cls.api_client)
+ cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+ cls.services['mode'] = cls.zone.networktype
+ cls.template = get_template(
+ cls.api_client,
+ cls.zone.id,
+ cls.services["ostype"]
+ )
+ cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+
+ cls.logger.debug("Creating Admin Account for domain %s on zone %s" % (cls.domain.id, cls.zone.id))
+ cls.account = Account.create(
+ cls.api_client,
+ cls.services["account"],
+ admin=True,
+ domainid=cls.domain.id
+ )
+
+ cls.logger.debug("Creating Service Offering on zone %s" % (cls.zone.id))
+ cls.service_offering = ServiceOffering.create(
+ cls.api_client,
+ cls.services["service_offering"]
+ )
+
+ cls.logger.debug("Creating Network Offering on zone %s" % (cls.zone.id))
+ cls.services["isolated_network_offering"]["egress_policy"] = "true"
+ cls.network_offering = NetworkOffering.create(cls.api_client,
+ cls.services["isolated_network_offering"],
+ conservemode=True)
+ cls.network_offering.update(cls.api_client, state='Enabled')
+
+ cls.logger.debug("Creating Network for Account %s using offering %s" % (cls.account.name, cls.network_offering.id))
+ cls.network = Network.create(cls.api_client,
+ cls.services["network"],
+ accountid=cls.account.name,
+ domainid=cls.account.domainid,
+ networkofferingid=cls.network_offering.id,
+ zoneid=cls.zone.id)
+
+ cls.logger.debug("Creating guest VM for Account %s using offering %s" % (cls.account.name, cls.service_offering.id))
+ cls.vm = VirtualMachine.create(cls.api_client,
+ cls.services["virtual_machine"],
+ templateid=cls.template.id,
+ accountid=cls.account.name,
+ domainid=cls.domain.id,
+ serviceofferingid=cls.service_offering.id,
+ networkids=[str(cls.network.id)])
+ cls.vm.password = "password"
+
+ cls.services["natrule1"] = {
+ "privateport": 22,
+ "publicport": 22,
+ "protocol": "TCP"
+ }
+
+ cls.services["configurableData"] = {
+ "host": {
+ "password": "password",
+ "username": "root",
+ "port": 22
+ },
+ "input": "INPUT",
+ "forward": "FORWARD"
+ }
+
+ cls._cleanup = [
+ cls.vm,
+ cls.network,
+ cls.network_offering,
+ cls.service_offering,
+ cls.account
+ ]
+
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ cleanup_resources(cls.api_client, cls._cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+
+
+ def setUp(self):
+ self.apiclient = self.testClient.getApiClient()
+ self.cleanup = []
+
+
+ def tearDown(self):
+ try:
+ cleanup_resources(self.apiclient, self.cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+
+
+ def test_router_common(self):
+ """Performs common router tests and returns router public_ips"""
+
+ routers = list_routers(
+ self.apiclient,
+ account=self.account.name,
+ domainid=self.account.domainid
+ )
+
+ self.assertEqual(
+ isinstance(routers, list),
+ True,
+ "Check for list routers response return valid data"
+ )
+
+ self.assertTrue(
+ len(routers) >= 1,
+ "Check list router response"
+ )
+
+ router = routers[0]
+
+ self.assertEqual(
+ router.state,
+ 'Running',
+ "Check list router response for router state"
+ )
+
+ public_ips = list_publicIP(
+ self.apiclient,
+ account=self.account.name,
+ domainid=self.account.domainid,
+ zoneid=self.zone.id
+ )
+
+ self.assertEqual(
+ isinstance(public_ips, list),
+ True,
+ "Check for list public IPs response return valid data"
+ )
+
+ self.assertTrue(
+ len(public_ips) >= 1,
+ "Check public IP list has at least one IP"
+ )
+
+ return public_ips
+
+
+ @attr(tags=["advanced", "advancedns", "ssh"], required_hardware="true")
+ def test_router_dns_externalipquery(self):
+ """Checks that non-guest network IPs cannot access VR DNS"""
+
+ self.logger.debug("Starting test_router_dns_externalips...")
+
+ public_ip = self.test_router_common()[0]
+
+ self.logger.debug("Querying VR DNS IP: " + public_ip.ipaddress)
+ resolver = dns.resolver.Resolver()
+ resolver.namerservers = [public_ip.ipaddress]
+ try:
+ resolver.query('google.com', 'A')
+ self.fail("Non-guest network IPs are able to access VR DNS, failing.")
+ except:
+ self.logger.debug("VR DNS query failed from non-guest network IP as expected")
+
+
+ @attr(tags=["advanced", "advancedns", "ssh"], required_hardware="true")
+ def test_router_dns_guestipquery(self):
+ """Checks that guest VM can query VR DNS"""
+
+ self.logger.debug("Starting test_router_dns_guestipquery...")
+ public_ip = self.test_router_common()[0]
+
+ self.logger.debug("Creating Firewall rule for VM ID: %s" % self.vm.id)
+ FireWallRule.create(
+ self.apiclient,
+ ipaddressid=public_ip.id,
+ protocol=self.services["natrule1"]["protocol"],
+ cidrlist=['0.0.0.0/0'],
+ startport=self.services["natrule1"]["publicport"],
+ endport=self.services["natrule1"]["publicport"]
+ )
+
+ self.logger.debug("Creating NAT rule for VM ID: %s" % self.vm.id)
+ nat_rule1 = NATRule.create(
+ self.apiclient,
+ self.vm,
+ self.services["natrule1"],
+ public_ip.id
+ )
+ nat_rules = list_nat_rules(
+ self.apiclient,
+ id=nat_rule1.id
+ )
+ self.assertEqual(
+ isinstance(nat_rules, list),
+ True,
+ "Check for list NAT rules response return valid data"
+ )
+ self.assertTrue(
+ len(nat_rules) >= 1,
+ "Check for list NAT rules to have at least one rule"
+ )
+ self.assertEqual(
+ nat_rules[0].state,
+ 'Active',
+ "Check list port forwarding rules"
+ )
+
+ result = None
+ try:
+ self.logger.debug("SSH into guest VM with IP: %s" % nat_rule1.ipaddress)
+ ssh = self.vm.get_ssh_client(ipaddress=nat_rule1.ipaddress, port=self.services['natrule1']["publicport"], retries=8)
+ result = str(ssh.execute("nslookup google.com"))
+ except Exception as e:
+ self.fail("Failed to SSH into VM - %s due to exception: %s" % (nat_rule1.ipaddress, e))
+
+ if not result:
+ self.fail("Did not to receive any response from the guest VM, failing.")
+
+ self.assertTrue("google.com" in result and "#53" in result,
+ "VR DNS should serve requests from guest network, unable to get valid nslookup result from guest VM.")
diff --git a/test/integration/smoke/test_routers.py b/test/integration/smoke/test_routers.py
index 4478c7b..c6aa496 100644
--- a/test/integration/smoke/test_routers.py
+++ b/test/integration/smoke/test_routers.py
@@ -313,7 +313,14 @@
self.debug("Haproxy process status: %s" % res)
return
- @attr(tags=["advanced", "advancedns", "smoke", "dvs"], required_hardware="false")
+ @attr(
+ tags=[
+ "advanced",
+ "basic",
+ "advancedns",
+ "smoke",
+ "dvs"],
+ required_hardware="false")
def test_03_restart_network_cleanup(self):
"""Test restart network
"""
@@ -323,20 +330,30 @@
# 2. New router should have the same public IP
# Find router associated with user account
- list_router_response = list_routers(
- self.apiclient,
- account=self.account.name,
- domainid=self.account.domainid
- )
+ if self.zone.networktype.lower() == "basic":
+ list_router_response = list_routers(
+ self.apiclient,
+ listall="true"
+ )
+ else:
+ list_router_response = list_routers(
+ self.apiclient,
+ account=self.account.name,
+ domainid=self.account.domainid
+ )
self.assertEqual(
isinstance(list_router_response, list),
True,
"Check list response returns a valid list"
)
+
router = list_router_response[0]
# Store old values before restart
- old_publicip = router.publicip
+ if self.zone.networktype.lower == "basic":
+ old_publicip = router.guestipaddress
+ else:
+ old_publicip = router.publicip
timeout = 10
# Network should be in Implemented or Setup stage before restart
@@ -371,11 +388,17 @@
self.apiclient.restartNetwork(cmd)
# Get router details after restart
- list_router_response = list_routers(
- self.apiclient,
- account=self.account.name,
- domainid=self.account.domainid
- )
+ if self.zone.networktype.lower() == "basic":
+ list_router_response = list_routers(
+ self.apiclient,
+ listall="true"
+ )
+ else:
+ list_router_response = list_routers(
+ self.apiclient,
+ account=self.account.name,
+ domainid=self.account.domainid
+ )
self.assertEqual(
isinstance(list_router_response, list),
True,
@@ -383,8 +406,12 @@
)
router = list_router_response[0]
+ if self.zone.networktype.lower() == "basic":
+ new_publicip = router.guestipaddress
+ else:
+ new_publicip = router.publicip
self.assertEqual(
- router.publicip,
+ new_publicip,
old_publicip,
"Public IP of the router should remain same after network restart"
)
diff --git a/test/integration/smoke/test_staticroles.py b/test/integration/smoke/test_staticroles.py
new file mode 100644
index 0000000..5421f6b
--- /dev/null
+++ b/test/integration/smoke/test_staticroles.py
@@ -0,0 +1,134 @@
+# 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.
+
+from marvin.cloudstackAPI import *
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.base import Account
+from marvin.lib.utils import cleanup_resources
+from marvin.sshClient import SshClient
+from nose.plugins.attrib import attr
+
+import inspect
+import logging
+import os
+import re
+
+
+class TestStaticRoles(cloudstackTestCase):
+ """Tests static role api-checker
+ """
+
+ def setUp(self):
+ self.apiclient = self.testClient.getApiClient()
+ self.dbclient = self.testClient.getDbConnection()
+ self.mgtSvrDetails = self.config.__dict__["mgtSvr"][0].__dict__
+ self.cleanup = []
+ self.testdata = {
+ "account": {
+ "email": "mtu@test.cloud",
+ "firstname": "Marvin",
+ "lastname": "TestUser",
+ "username": "staticrole_acctest-",
+ "password": "password",
+ }
+ }
+
+ feature_enabled = self.apiclient.listCapabilities(listCapabilities.listCapabilitiesCmd()).dynamicrolesenabled
+ if feature_enabled:
+ self.skipTest("Dynamic role-based API checker is enabled, skipping tests for static role-base API checker")
+
+ commandsProperties = []
+ try:
+ sshClient = SshClient(
+ self.mgtSvrDetails["mgtSvrIp"],
+ 22,
+ self.mgtSvrDetails["user"],
+ self.mgtSvrDetails["passwd"],
+ retries=1,
+ log_lvl=logging.INFO
+ )
+ result = sshClient.runCommand("cat /etc/cloudstack/management/commands.properties")
+ if 'status' in result and result['status'] == 'SUCCESS' and 'stdout' in result and len(result['stdout']) > 0:
+ commandsProperties = result['stdout']
+ except Exception:
+ self.debug("Failed to ssh into mgmt server host and grab commands.properties file")
+ testDir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+ localFileName = os.path.abspath(testDir + "/../../../client/tomcatconf/commands.properties.in")
+ if os.path.isfile(localFileName):
+ self.info("Detected that we're running in developer mode with maven, using file at:" + localFileName)
+ with open(localFileName) as f:
+ commandsProperties = f.readlines()
+
+ if len(commandsProperties) < 1:
+ self.skipTest("Unable to find commands.properties, skipping this test")
+
+ apiMap = {}
+ for line in commandsProperties:
+ if not line or line == '' or line == '\n' or line.startswith('#'):
+ continue
+ name, value = line.split('=')
+ apiMap[name.strip()] = value.strip()
+
+ self.roleApiMap = {} # role to list of apis allowed
+ octetKey = {'Admin':1, 'DomainAdmin':4, 'User':8}
+ for role in octetKey.keys():
+ for api in sorted(apiMap.keys()):
+ if (octetKey[role] & int(apiMap[api])) > 0:
+ if role not in self.roleApiMap:
+ self.roleApiMap[role] = []
+ self.roleApiMap[role].append(api)
+
+
+ def tearDown(self):
+ try:
+ cleanup_resources(self.apiclient, self.cleanup)
+ except Exception as e:
+ self.debug("Warning! Exception in tearDown: %s" % e)
+
+
+ def translateRoleToAccountType(self, role_type):
+ if role_type == 'User':
+ return 0
+ elif role_type == 'Admin':
+ return 1
+ elif role_type == 'DomainAdmin':
+ return 2
+ return -1
+
+
+ @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+ def test_static_role_account_acls(self):
+ """
+ Tests allowed APIs for common account types
+ """
+ for role in ['Admin', 'DomainAdmin', 'User']:
+ accountType = self.translateRoleToAccountType(role)
+ account = Account.create(
+ self.apiclient,
+ self.testdata['account'],
+ admin=accountType
+ )
+ self.cleanup.append(account)
+ userApiClient = self.testClient.getUserApiClient(UserName=account.name, DomainName=account.domain, type=accountType)
+ allowedApis = map(lambda x: x.name, userApiClient.listApis(listApis.listApisCmd()))
+ allApis = map(lambda x: x.name, self.apiclient.listApis(listApis.listApisCmd()))
+ for api in self.roleApiMap[role]:
+ if api not in allApis:
+ continue
+ if api not in allowedApis:
+ self.fail("API configured in commands.properties not returned by listApis: " + api + " for role: " + role)
diff --git a/test/integration/testpaths/testpath_attach_disk_zwps.py b/test/integration/testpaths/testpath_attach_disk_zwps.py
index d386438..1f1e073 100644
--- a/test/integration/testpaths/testpath_attach_disk_zwps.py
+++ b/test/integration/testpaths/testpath_attach_disk_zwps.py
@@ -34,7 +34,8 @@
)
from marvin.codes import (PASS,
- ZONETAG1)
+ ZONETAG1,
+ CLUSTERTAG1)
class TestAttachDataDisk(cloudstackTestCase):
@@ -207,3 +208,188 @@
"Check: Data if Disk is attached to VM")
return
+
+
+class TestAttachDataDiskOnCWPS(cloudstackTestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ testClient = super(TestAttachDataDiskOnCWPS, cls).getClsTestClient()
+ cls.apiclient = testClient.getApiClient()
+ cls.testdata = testClient.getParsedTestDataConfig()
+ cls.hypervisor = cls.testClient.getHypervisorInfo()
+
+ # Get Zone, Domain and templates
+ cls.domain = get_domain(cls.apiclient)
+ cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+ cls._cleanup = []
+ cls.template = get_template(
+ cls.apiclient,
+ cls.zone.id,
+ cls.testdata["ostype"])
+ cls.skiptest = False
+
+ try:
+ cls.pools = StoragePool.list(
+ cls.apiclient,
+ zoneid=cls.zone.id,
+ scope="CLUSTER")
+ except Exception as e:
+ cls.skiptest = True
+ return
+ try:
+
+ # Create an account
+ cls.account = Account.create(
+ cls.apiclient,
+ cls.testdata["account"],
+ domainid=cls.domain.id
+ )
+ cls._cleanup.append(cls.account)
+
+ # Create user api client of the account
+ cls.userapiclient = testClient.getUserApiClient(
+ UserName=cls.account.name,
+ DomainName=cls.account.domain
+ )
+ # Create Service offering
+ cls.service_offering = ServiceOffering.create(
+ cls.apiclient,
+ cls.testdata["service_offering"],
+ )
+ cls._cleanup.append(cls.service_offering)
+
+ # Create Disk offering
+ cls.disk_offering = DiskOffering.create(
+ cls.apiclient,
+ cls.testdata["disk_offering"],
+ custom=True,
+ tags=CLUSTERTAG1,
+ )
+
+ cls._cleanup.append(cls.disk_offering)
+
+ except Exception as e:
+ cls.tearDownClass()
+ raise e
+ return
+
+ @classmethod
+ def tearDownClass(cls):
+ try:
+ cleanup_resources(cls.apiclient, cls._cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+
+ def setUp(self):
+ self.apiclient = self.testClient.getApiClient()
+ self.dbclient = self.testClient.getDbConnection()
+ self.cleanup = []
+
+ def tearDown(self):
+ try:
+ for storagePool in self.pools:
+ StoragePool.update(self.apiclient, id=storagePool.id, tags="")
+
+ if hasattr(self, "data_volume_created"):
+ data_volumes_list = Volume.list(
+ self.userapiclient,
+ id=self.data_volume_created.id,
+ virtualmachineid=self.vm.id
+ )
+ if data_volumes_list:
+ self.vm.detach_volume(
+ self.userapiclient,
+ data_volumes_list[0]
+ )
+
+ status = validateList(data_volumes_list)
+ self.assertEqual(
+ status[0],
+ PASS,
+ "DATA Volume List Validation Failed")
+
+ cleanup_resources(self.apiclient, self.cleanup)
+ except Exception as e:
+ raise Exception("Warning: Exception during cleanup : %s" % e)
+ return
+
+ @attr(tags=["basic", "advanced"], required_hardware="true")
+ def test_01_attach_datadisk_to_vm_on_zwps(self):
+ """ Attach Data Disk on CWPS To VM
+ 1. Check if zwps storage pool exists.
+ 2. Adding tag to zone wide primary storage
+ 3. Launch a VM
+ 4. Attach data disk to vm.
+ 5. Verify disk is attached and in correct storage pool.
+ """
+
+ # Step 1
+ if len(list(self.pools)) < 1:
+ self.skipTest("There must be at least one zone wide \
+ storage pools available in the setup")
+
+ # Step 2
+ # Adding tags to Storage Pools
+ StoragePool.update(
+ self.apiclient,
+ id=self.pools[0].id,
+ tags=[CLUSTERTAG1])
+
+ # Launch VM
+ self.vm = VirtualMachine.create(
+ self.apiclient,
+ self.testdata["small"],
+ templateid=self.template.id,
+ accountid=self.account.name,
+ domainid=self.account.domainid,
+ serviceofferingid=self.service_offering_zone1.id,
+ zoneid=self.zone.id
+ )
+
+ self.testdata["volume"]["zoneid"] = self.zone.id
+ self.testdata["volume"]["customdisksize"] = 1
+ self.data_volume_created = Volume.create_custom_disk(
+ self.userapiclient,
+ self.testdata["volume"],
+ account=self.account.name,
+ domainid=self.account.domainid,
+ diskofferingid=self.disk_offering.id,
+ )
+
+ self.cleanup.append(self.data_volume_created)
+
+ # Step 4
+ self.vm.attach_volume(
+ self.userapiclient,
+ self.data_volume_created
+ )
+
+ data_volumes_list = Volume.list(
+ self.userapiclient,
+ virtualmachineid=self.vm.id,
+ type="DATA",
+ listall=True
+ )
+
+ self.debug("list volumes using vm id %s" % dir(data_volumes_list[0]))
+
+ data_volumes_list = Volume.list(self.apiclient,
+ id=self.data_volume_created.id,
+ listall=True)
+ data_volume = data_volumes_list[0]
+ status = validateList(data_volume)
+ # Step 5
+ self.assertEqual(
+ status[0],
+ PASS,
+ "Check: volume list is valid")
+
+ self.assertEqual(
+ data_volume.state,
+ "Ready",
+ "Check: Data volume is attached to VM")
+
+ if data_volume.storage != self.pools[0].name:
+ self.fail("check if volume is created in correct storage pool")
+ return
diff --git a/test/integration/testpaths/testpath_revert_snap.py b/test/integration/testpaths/testpath_revert_snap.py
index 8026f34..5934400 100644
--- a/test/integration/testpaths/testpath_revert_snap.py
+++ b/test/integration/testpaths/testpath_revert_snap.py
@@ -150,7 +150,12 @@
vm_snap = VmSnapshot.create(self.apiclient,
vm.id)
- volume_list_validation = validateList(vm_snap)
+ self.assertEqual(
+ vm_snap.state,
+ "Ready",
+ "Check the snapshot of vm is ready!"
+ )
+
#Step 3
with self.assertRaises(Exception):
diff --git a/test/integration/testpaths/testpath_snapshot_hadrning.py b/test/integration/testpaths/testpath_snapshot_hadrning.py
index 0b72a6a..cb31f0f 100755
--- a/test/integration/testpaths/testpath_snapshot_hadrning.py
+++ b/test/integration/testpaths/testpath_snapshot_hadrning.py
@@ -262,7 +262,6 @@
cls.testdata["account"],
domainid=cls.domain.id
)
- cls._cleanup.append(cls.account)
# Create user api client of the account
cls.userapiclient = testClient.getUserApiClient(
@@ -327,6 +326,8 @@
mode=cls.zone.networktype
)
cls._cleanup.append(cls.vm_ha)
+
+ cls._cleanup.append(cls.account)
cls.root_volume_ha = list_volumes(
cls.userapiclient,
virtualmachineid=cls.vm_ha.id,
diff --git a/test/integration/testpaths/testpath_snapshot_limits.py b/test/integration/testpaths/testpath_snapshot_limits.py
index 855d3a2..7a27feb 100644
--- a/test/integration/testpaths/testpath_snapshot_limits.py
+++ b/test/integration/testpaths/testpath_snapshot_limits.py
@@ -31,10 +31,13 @@
)
from marvin.lib.common import (get_domain,
get_zone,
- get_template
+ get_template,
+ createChecksum,
+ list_volumes
)
-from marvin.codes import (BACKED_UP, PASS, FAIL)
+from marvin.codes import (BACKED_UP, PASS, FAIL, ROOT)
+import time
class TestStorageSnapshotsLimits(cloudstackTestCase):
@@ -99,6 +102,7 @@
domainid=cls.account.domainid,
serviceofferingid=cls.service_offering.id,
zoneid=cls.zone.id,
+ mode=cls.zone.networktype
)
except Exception as e:
@@ -137,7 +141,6 @@
PASS,
"DATA Volume List Validation Failed")
- if data_volumes_list:
self.vm.detach_volume(
self.userapiclient,
data_volumes_list[0]
@@ -359,3 +362,129 @@
)
return
+
+ @attr(tags=["advanced", "basic"], required_hardware="true")
+ def test_02_snapshot_size_check(self):
+ """ Check Snapshots size in database
+ 1. Create file on ROOT disk of deployed VM.
+ 2. Create Snapshot of ROOT disk.
+ 3. Check if physiacal_size parameter of snapshot_store_ref table
+ has physical size of snapshot
+ """
+ if self.hypervisor.lower() not in ["xenserver", "vmware"]:
+ self.skipTest("Test not to be run on %s" % self.hypervisor)
+
+ root_volumes_list = list_volumes(
+ self.apiclient,
+ virtualmachineid=self.vm.id,
+ type=ROOT,
+ listall=True
+ )
+
+ status = validateList(root_volumes_list)
+ self.assertEqual(
+ status[0],
+ PASS,
+ "Check listVolumes response for ROOT Disk")
+
+ root_volume = root_volumes_list[0]
+
+ # Get Secondary Storage Value from Database
+ qryresult_before_snapshot = self.dbclient.execute(
+ " select id, account_name, secondaryStorageTotal\
+ from account_view where account_name = '%s';" %
+ self.account.name)
+
+ self.assertNotEqual(
+ len(qryresult_before_snapshot),
+ 0,
+ "Check sql query to return SecondaryStorageTotal of account")
+
+ storage_qry_result_old = qryresult_before_snapshot[0]
+ secondary_storage_old = storage_qry_result_old[2]
+
+ createChecksum(
+ self.testdata,
+ self.vm,
+ root_volume,
+ "rootdiskdevice")
+
+ time.sleep(30)
+
+ root_vol_snapshot = Snapshot.create(
+ self.apiclient,
+ root_volume.id)
+
+ snapshots_list = Snapshot.list(self.apiclient,
+ id=root_vol_snapshot.id)
+
+ status = validateList(snapshots_list)
+ self.assertEqual(status[0], PASS, "Check listSnapshots response")
+ # Verify Snapshot state
+ self.assertEqual(
+ snapshots_list[0].state.lower() in [
+ BACKED_UP,
+ ],
+ True,
+ "Snapshot state is not as expected. It is %s" %
+ snapshots_list[0].state
+ )
+
+ self.assertEqual(
+ snapshots_list[0].volumeid,
+ root_volume.id,
+ "Snapshot volume id is not matching with the vm's volume id")
+
+ qryresult_snp_id = self.dbclient.execute(
+ "select id\
+ from snapshots where uuid = '%s';" %
+ snapshots_list[0].id)
+
+ self.assertNotEqual(
+ len(qryresult_snp_id),
+ 0,
+ "Check sql query to return physical size of the snapshot")
+
+ snp_id_result = qryresult_snp_id[0]
+ snp_id = snp_id_result[0]
+
+ qryresult_physical_size = self.dbclient.execute(
+ " select id, store_id, physical_size\
+ from snapshot_store_ref where snapshot_id = '%s' \
+ and store_role='Image';" %
+ snp_id)
+
+ self.assertNotEqual(
+ len(qryresult_physical_size),
+ 0,
+ "Check sql query to return SecondaryStorageTotal of account")
+
+ snapshot_physical_size_result = qryresult_physical_size[0]
+ snapshot_physical_size = snapshot_physical_size_result[
+ 2]
+
+ # Step 3
+ qryresult_after_snapshot = self.dbclient.execute(
+ " select id, account_name, secondaryStorageTotal\
+ from account_view where account_name = '%s';" %
+ self.account.name)
+ self.assertNotEqual(
+ len(qryresult_after_snapshot),
+ 0,
+ "Check sql query to return SecondaryStorageTotal of account")
+
+ storage_qry_result_from_database = qryresult_after_snapshot[0]
+ secondary_storage_new = storage_qry_result_from_database[
+ 2]
+
+ secondary_storage_after_snapshot = secondary_storage_new - \
+ secondary_storage_old
+
+ self.assertEqual(
+ snapshot_physical_size,
+ secondary_storage_after_snapshot,
+ "Check if physical_size attribute of snapshot_store_ref table \
+ stores correct value"
+ )
+
+ return
diff --git a/test/integration/testpaths/testpath_storage_migration.py b/test/integration/testpaths/testpath_storage_migration.py
index 3ef31f0..848594d 100644
--- a/test/integration/testpaths/testpath_storage_migration.py
+++ b/test/integration/testpaths/testpath_storage_migration.py
@@ -248,6 +248,13 @@
DomainName=cls.account.domain
)
# Create Service offering
+ cls.service_offering = ServiceOffering.create(
+ cls.apiclient,
+ cls.testdata["service_offering"]
+ )
+
+ cls._cleanup.append(cls.service_offering)
+
cls.service_offering_zone1 = ServiceOffering.create(
cls.apiclient,
cls.testdata["service_offering"],
diff --git a/test/integration/testpaths/testpath_volume_snapshot.py b/test/integration/testpaths/testpath_volume_snapshot.py
index 87c5fe4..c0e609a 100644
--- a/test/integration/testpaths/testpath_volume_snapshot.py
+++ b/test/integration/testpaths/testpath_volume_snapshot.py
@@ -805,13 +805,13 @@
event_list_validation_result[2])
self.debug("Events list contains event SNAPSHOT.CREATE")
+ self.testdata["volume"]["zoneid"] = self.zone.id
volumeFromSnap = Volume.create_from_snapshot(
self.apiclient,
data_vol_snap.id,
self.testdata["volume"],
account=self.account.name,
domainid=self.account.domainid,
- zoneid=self.zone.id
)
self.assertTrue(
@@ -926,13 +926,13 @@
"Check resource id in list resources call"
)
+ self.testdata["volume"]["zoneid"] = self.zone.id
volumeFromSnap_2 = Volume.create_from_snapshot(
self.apiclient,
data_vol_snap_2.id,
self.testdata["volume"],
account=self.account.name,
domainid=self.account.domainid,
- zoneid=self.zone.id
)
self.vm_2.attach_volume(
diff --git a/test/pom.xml b/test/pom.xml
index a1ce4eeaf..6d0f284 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
diff --git a/tools/apidoc/XmlToHtmlConverter.java b/tools/apidoc/XmlToHtmlConverter.java
index d15877c..63eb68e 100644
--- a/tools/apidoc/XmlToHtmlConverter.java
+++ b/tools/apidoc/XmlToHtmlConverter.java
@@ -23,9 +23,7 @@
// To turn off generation of API docs for certain roles, comment out
public static void main(String[] args) {
XmlToHtmlConverter x = new XmlToHtmlConverter();
- x.populateForRootAdmin();
- x.populateForDomainAdmin();
- x.populateForUser();
+ x.populateForApi();
x.generateToc();
x.generateIndividualCommandPages();
}
@@ -33,26 +31,12 @@
public void generateToc() {
try {
TransformerFactory tFactory = TransformerFactory.newInstance();
- // Generate the TOC for the API reference for User role
- Transformer transformer = tFactory.newTransformer(new javax.xml.transform.stream.StreamSource("generatetocforuser.xsl"));
- // Modify this path to match your own setup.
- transformer.transform(new javax.xml.transform.stream.StreamSource("regular_user/regularUserSummary.xml"), new javax.xml.transform.stream.StreamResult(
- new FileOutputStream("html/TOC_User.html")));
// Generate the TOC for root administrator role
- Transformer transformer1 = tFactory.newTransformer(new javax.xml.transform.stream.StreamSource("generatetocforadmin.xsl"));
+ Transformer transformer1 = tFactory.newTransformer(new javax.xml.transform.stream.StreamSource("generatetoc.xsl"));
// Modify this path to match your own setup.
- transformer1.transform(new javax.xml.transform.stream.StreamSource("root_admin/rootAdminSummary.xml"),
+ transformer1.transform(new javax.xml.transform.stream.StreamSource("apis/apiSummarySorted.xml"),
// Modify this path to your own desired output location.
- new javax.xml.transform.stream.StreamResult(new FileOutputStream("html/TOC_Root_Admin.html")));
- // Generate the TOC for domain admin role
- Transformer transformer2 = tFactory.newTransformer(new javax.xml.transform.stream.StreamSource("generatetocfordomainadmin.xsl"));
-
- // The XML to be transformed must be at the location below.
- // Modify this path to match your own setup.
- transformer2.transform(new javax.xml.transform.stream.StreamSource("domain_admin/domainAdminSummary.xml"),
- // Modify this path to your own desired output location.
- new javax.xml.transform.stream.StreamResult(new FileOutputStream("html/TOC_Domain_Admin.html")));
-
+ new javax.xml.transform.stream.StreamResult(new FileOutputStream("html/index.html")));
} catch (Exception e) {
e.printStackTrace();
}
@@ -60,50 +44,18 @@
// Create man pages
public void generateIndividualCommandPages() {
- for (String commandName : rootAdminCommandNames) {
+ for (String commandName : allCommandNames) {
try {
TransformerFactory tFactory = TransformerFactory.newInstance();
- Transformer transformer = tFactory.newTransformer(new javax.xml.transform.stream.StreamSource("generateadmincommands.xsl"));
+ Transformer transformer = tFactory.newTransformer(new javax.xml.transform.stream.StreamSource("generatecommands.xsl"));
transformer.transform
// Modify this path to the location of the input files on your system.
- (new javax.xml.transform.stream.StreamSource("root_admin/" + commandName + ".xml"),
+ (new javax.xml.transform.stream.StreamSource("apis/" + commandName + ".xml"),
// Modify this path with the desired output location.
- new javax.xml.transform.stream.StreamResult(new FileOutputStream("html/root_admin/" + commandName + ".html")));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- for (String commandName : domainAdminCommandNames) {
-
- try {
-
- TransformerFactory tFactory = TransformerFactory.newInstance();
- Transformer transformer = tFactory.newTransformer(new javax.xml.transform.stream.StreamSource("generatedomainadmincommands.xsl"));
-
- transformer.transform
- // Modify this path with the location of the input files on your system.
- (new javax.xml.transform.stream.StreamSource("domain_admin/" + commandName + ".xml"),
- // Modify this path to the desired output location.
- new javax.xml.transform.stream.StreamResult(new FileOutputStream("html/domain_admin/" + commandName + ".html")));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- for (String commandName : userCommandNames) {
-
- try {
-
- TransformerFactory tFactory = TransformerFactory.newInstance();
-
- Transformer transformer = tFactory.newTransformer(new javax.xml.transform.stream.StreamSource("generateusercommands.xsl"));
-
- transformer.transform(new javax.xml.transform.stream.StreamSource("regular_user/" + commandName + ".xml"), new javax.xml.transform.stream.StreamResult(
- new FileOutputStream("html/user/" + commandName + ".html")));
+ new javax.xml.transform.stream.StreamResult(new FileOutputStream("html/apis/" + commandName + ".html")));
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/tools/apidoc/build-apidoc.sh b/tools/apidoc/build-apidoc.sh
index dc3751c..8ab69c8 100755
--- a/tools/apidoc/build-apidoc.sh
+++ b/tools/apidoc/build-apidoc.sh
@@ -58,9 +58,7 @@
(cd "$DISTDIR/xmldoc"
cp "$thisdir"/*.java .
cp "$thisdir"/*.xsl .
- sed -e 's,%API_HEADER%,User API,g' "$thisdir/generatetoc_header.xsl" >generatetocforuser.xsl
- sed -e 's,%API_HEADER%,Root Admin API,g' "$thisdir/generatetoc_header.xsl" >generatetocforadmin.xsl
- sed -e 's,%API_HEADER%,Domain Admin API,g' "$thisdir/generatetoc_header.xsl" >generatetocfordomainadmin.xsl
+ sed -e 's,%API_HEADER%,All APIs,g' "$thisdir/generatetoc_header.xsl" >generatetoc.xsl
PLATFORM=`uname -s`
if [[ "$PLATFORM" =~ .*WIN.* ]]
@@ -74,15 +72,10 @@
python "$thisdir/gen_toc.py" $(find . -type f)
fi
- cat generatetocforuser_include.xsl >>generatetocforuser.xsl
- cat generatetocforadmin_include.xsl >>generatetocforadmin.xsl
- cat generatetocfordomainadmin_include.xsl >>generatetocfordomainadmin.xsl
+ cat generatetoc_include.xsl >> generatetoc.xsl
+ cat "$thisdir/generatetoc_footer.xsl" >>generatetoc.xsl
- cat "$thisdir/generatetoc_footer.xsl" >>generatetocforuser.xsl
- cat "$thisdir/generatetoc_footer.xsl" >>generatetocforadmin.xsl
- cat "$thisdir/generatetoc_footer.xsl" >>generatetocfordomainadmin.xsl
-
- mkdir -p html/user html/domain_admin html/root_admin
+ mkdir -p html/apis
cp -r "$thisdir/includes" html
cp -r "$thisdir/images" html
diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py
index 6974fd7..e6ef674 100644
--- a/tools/apidoc/gen_toc.py
+++ b/tools/apidoc/gen_toc.py
@@ -23,35 +23,25 @@
from xml.parsers.expat import ExpatError
-REGULAR_USER = 'u'
-DOMAIN_ADMIN = 'd'
ROOT_ADMIN = 'r'
user_to_func = {
- REGULAR_USER: 'populateForUser',
- DOMAIN_ADMIN: 'populateForDomainAdmin',
- ROOT_ADMIN: 'populateForRootAdmin',
+ ROOT_ADMIN: 'populateForApi',
}
user_to_cns = {
- REGULAR_USER: 'userCommandNames',
- DOMAIN_ADMIN: 'domainAdminCommandNames',
- ROOT_ADMIN: 'rootAdminCommandNames',
+ ROOT_ADMIN: 'allCommandNames',
}
dirname_to_user = {
- 'regular_user': REGULAR_USER,
- 'domain_admin': DOMAIN_ADMIN,
- 'root_admin': ROOT_ADMIN,
+ 'apis': ROOT_ADMIN,
}
dirname_to_dirname = {
- 'regular_user': 'user',
- 'domain_admin': 'domain_admin',
- 'root_admin': 'root_admin',
+ 'apis': 'apis',
}
@@ -71,8 +61,10 @@
'StaticNat': 'NAT',
'IpForwarding': 'NAT',
'Host': 'Host',
+ 'OutOfBand': 'Out-of-band Management',
'Cluster': 'Cluster',
'Account': 'Account',
+ 'Role': 'Role',
'Snapshot': 'Snapshot',
'User': 'User',
'Os': 'Guest OS',
@@ -130,6 +122,7 @@
'Product': 'Product',
'LB': 'Load Balancer',
'ldap': 'LDAP',
+ 'Ldap': 'LDAP',
'Swift': 'Swift',
'S3' : 'S3',
'SecondaryStorage': 'Host',
@@ -301,15 +294,9 @@
import java.util.Set;
public class XmlToHtmlConverterData {
-
- Set<String> rootAdminCommandNames = new HashSet<String>();
- Set<String> domainAdminCommandNames = new HashSet<String>();
- Set<String> userCommandNames = new HashSet<String>();
-
+ Set<String> allCommandNames = new HashSet<String>();
''')
- f.write(java_for_user(REGULAR_USER) + "\n");
f.write(java_for_user(ROOT_ADMIN) + "\n")
- f.write(java_for_user(DOMAIN_ADMIN) + "\n")
f.write('''
}
@@ -317,7 +304,5 @@
''')
-write_xml('generatetocforuser_include.xsl', REGULAR_USER)
-write_xml('generatetocforadmin_include.xsl', ROOT_ADMIN)
-write_xml('generatetocfordomainadmin_include.xsl', DOMAIN_ADMIN)
+write_xml('generatetoc_include.xsl', ROOT_ADMIN)
write_java('XmlToHtmlConverterData.java')
diff --git a/tools/apidoc/generateadmincommands.xsl b/tools/apidoc/generateadmincommands.xsl
deleted file mode 100644
index 4ad2faf..0000000
--- a/tools/apidoc/generateadmincommands.xsl
+++ /dev/null
@@ -1,164 +0,0 @@
-<?xml version="1.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.
--->
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-version="1.0">
-<xsl:output method="html" doctype-public="-//W3C//DTD HTML 1.0 Transitional//EN"/>
-<xsl:template match="/">
-<html xmlns="http://www.w3.org/1999/xhtml"><head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel= "stylesheet" href="../includes/main.css" type="text/css" />
-<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" />
-
-<title>Apache CloudStack | The Power Behind Your Cloud</title>
-</head>
-
-<body>
-<div id="insidetopbg">
-<div id="inside_wrapper">
- <div class="uppermenu_panel">
- <div class="uppermenu_box">
-</div>
- </div>
-
- <div id="main_master">
- <div id="inside_header">
-
- <div class="header_top">
- <a class="cloud_logo" href="http://cloudstack.org"></a>
- <div class="mainemenu_panel">
-
- </div>
- </div>
- </div>
-
- <div id="main_content">
-
- <div class="inside_apileftpanel">
- <div class="inside_contentpanel" style="width:930px;">
- <div class="api_titlebox">
- <div class="api_titlebox_left">
- <xsl:for-each select="command/command">
- <!-- Modify this line for the release version -->
- <span>
- Apache CloudStack v4.6.0 Root Admin API Reference
- </span>
- <p></p>
- <h1><xsl:value-of select="name"/></h1>
- <p><xsl:value-of select="description"/></p>
- </xsl:for-each>
- </div>
-
-
- <div class="api_titlebox_right">
- <a class="api_backbutton" href="../TOC_Root_Admin.html"></a>
- </div>
- </div>
- <div class="api_tablepanel">
- <h2>Request parameters</h2>
- <table class="apitable">
- <tr class="hed">
- <td style="width:200px;"><strong>Parameter Name</strong></td>
-
- <td style="width:500px;">Description</td>
- <td style="width:180px;">Required</td>
- </tr>
- <xsl:for-each select="command/command/request/arg">
- <tr>
- <xsl:if test="required='true'">
- <td style="width:200px;"><strong><xsl:value-of select="name"/></strong></td>
- <td style="width:500px;"><strong><xsl:value-of select="description"/></strong></td>
- <td style="width:180px;"><strong><xsl:value-of select="required"/></strong></td>
- </xsl:if>
- <xsl:if test="required='false'">
- <td style="width:200px;"><i><xsl:value-of select="name"/></i></td>
- <td style="width:500px;"><i><xsl:value-of select="description"/></i></td>
- <td style="width:180px;"><i><xsl:value-of select="required"/></i></td>
- </xsl:if>
- </tr>
- </xsl:for-each>
- </table>
- </div>
-
-
- <div class="api_tablepanel">
- <h2>Response Tags</h2>
- <table class="apitable">
- <tr class="hed">
- <td style="width:200px;"><strong>Response Name</strong></td>
- <td style="width:500px;">Description</td>
- </tr>
-
- <xsl:for-each select="command/command/response/arg">
- <tr>
- <td style="width:200px;"><strong><xsl:value-of select="name"/></strong></td>
- <td style="width:500px;"><xsl:value-of select="description"/></td>
- <xsl:for-each select="./arguments/arg">
- <tr>
- <td style="width:180px; padding-left:25px;"><strong><xsl:value-of select="name"/></strong></td>
- <td style="width:500px;"><xsl:value-of select="description"/></td>
- </tr>
- <xsl:for-each select="./arguments/arg">
- <tr>
- <td style="width:165px; padding-left:40px;"><xsl:value-of select="name"/></td>
- <td style="width:500px;"><xsl:value-of select="description"/></td>
- </tr>
- </xsl:for-each>
- </xsl:for-each>
- </tr>
- </xsl:for-each>
-
-
-
-
-
- </table>
-
- </div>
-
-
- </div>
- </div>
-
-
- </div>
-
- </div><!-- #BeginLibraryItem "/libraries/footer.lbi" -->
-<div id="footer">
-<div id="comments_thread">
- <script type="text/javascript" src="https://comments.apache.org/show_comments.lua?site=test" async="true">
- </script>
- <noscript>
- <iframe width="930" height="500" src="https://comments.apache.org/iframe.lua?site=test&page=4.2.0/rootadmin"></iframe>
- </noscript>
- </div>
-
- <div id="footer_mainmaster">
- <p>Copyright © 2015 The Apache Software Foundation, Licensed under the
- <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0.</a> <br />
- Apache, CloudStack, Apache CloudStack, the Apache CloudStack logo, the CloudMonkey logo and the Apache feather logo are trademarks of The Apache Software Foundation.</p>
- </div>
- </div>
- </div>
- </div>
-</body>
-</html>
-</xsl:template>
-</xsl:stylesheet>
-
diff --git a/tools/apidoc/generatedomainadmincommands.xsl b/tools/apidoc/generatecommands.xsl
similarity index 71%
rename from tools/apidoc/generatedomainadmincommands.xsl
rename to tools/apidoc/generatecommands.xsl
index e260b4f..7e8ef78 100644
--- a/tools/apidoc/generatedomainadmincommands.xsl
+++ b/tools/apidoc/generatecommands.xsl
@@ -34,33 +34,30 @@
<div id="inside_wrapper">
<div class="uppermenu_panel">
<div class="uppermenu_box">
-
</div>
</div>
-
+
<div id="main_master">
<div id="inside_header">
<div class="header_top">
<a class="cloud_logo" href="http://cloudstack.org"></a>
<div class="mainemenu_panel">
-
+
</div>
</div>
-
-
</div>
<div id="main_content">
-
+
<div class="inside_apileftpanel">
- <div class="inside_contentpanel" style="width:930px;">
- <div class="api_titlebox">
- <div class="api_titlebox_left">
+ <div class="inside_contentpanel" style="width:930px;">
+ <div class="api_titlebox">
+ <div class="api_titlebox_left">
<xsl:for-each select="command/command">
- <!-- Modify this line for the release version -->
- <span>
- Apache CloudStack v4.6.0 Domain Admin API Reference
+ <!-- Modify this line for the release version -->
+ <span>
+ Apache CloudStack v4.9.0 Root Admin API Reference
</span>
<p></p>
<h1><xsl:value-of select="name"/></h1>
@@ -68,16 +65,16 @@
</xsl:for-each>
</div>
-
+
<div class="api_titlebox_right">
- <a class="api_backbutton" href="../TOC_Domain_Admin.html"></a>
+ <a class="api_backbutton" href="../index.html"></a>
</div>
</div>
- <div class="api_tablepanel">
- <h2>Request parameters</h2>
- <table class="apitable">
- <tr class="hed">
- <td style="width:200px;"><strong>Parameter Name</strong></td>
+ <div class="api_tablepanel">
+ <h2>Request parameters</h2>
+ <table class="apitable">
+ <tr class="hed">
+ <td style="width:200px;"><strong>Parameter Name</strong></td>
<td style="width:500px;">Description</td>
<td style="width:180px;">Required</td>
@@ -90,7 +87,7 @@
<td style="width:180px;"><strong><xsl:value-of select="required"/></strong></td>
</xsl:if>
<xsl:if test="required='false'">
- <td style="width:200px;"><i><xsl:value-of select="name"/></i></td>
+ <td style="width:200px;"><i><xsl:value-of select="name"/></i></td>
<td style="width:500px;"><i><xsl:value-of select="description"/></i></td>
<td style="width:180px;"><i><xsl:value-of select="required"/></i></td>
</xsl:if>
@@ -98,16 +95,16 @@
</xsl:for-each>
</table>
</div>
-
-
- <div class="api_tablepanel">
- <h2>Response Tags</h2>
- <table class="apitable">
- <tr class="hed">
- <td style="width:200px;"><strong>Response Name</strong></td>
+
+
+ <div class="api_tablepanel">
+ <h2>Response Tags</h2>
+ <table class="apitable">
+ <tr class="hed">
+ <td style="width:200px;"><strong>Response Name</strong></td>
<td style="width:500px;">Description</td>
</tr>
-
+
<xsl:for-each select="command/command/response/arg">
<tr>
<td style="width:200px;"><strong><xsl:value-of select="name"/></strong></td>
@@ -115,45 +112,52 @@
<xsl:for-each select="./arguments/arg">
<tr>
<td style="width:180px; padding-left:25px;"><strong><xsl:value-of select="name"/></strong></td>
- <td style="width:500px;"><xsl:value-of select="description"/></td>
+ <td style="width:500px;"><xsl:value-of select="description"/></td>
</tr>
<xsl:for-each select="./arguments/arg">
<tr>
<td style="width:165px; padding-left:40px;"><xsl:value-of select="name"/></td>
- <td style="width:500px;"><xsl:value-of select="description"/></td>
+ <td style="width:500px;"><xsl:value-of select="description"/></td>
</tr>
- </xsl:for-each>
- </xsl:for-each>
+ </xsl:for-each>
+ </xsl:for-each>
</tr>
</xsl:for-each>
-
-
-
-
-
+
+
+
+
+
</table>
</div>
-
-
- </div>
+
+
</div>
-
-
+ </div>
+
+
</div>
- </div>
+
+ </div><!-- #BeginLibraryItem "/libraries/footer.lbi" -->
<div id="footer">
- <div id="footer_mainmaster">
+<div id="comments_thread">
+ <script type="text/javascript" src="https://comments.apache.org/show_comments.lua?site=test" async="true">
+ </script>
+ <noscript>
+ <iframe width="930" height="500" src="https://comments.apache.org/iframe.lua?site=test&page=4.2.0/rootadmin"></iframe>
+ </noscript>
+ </div>
+
+ <div id="footer_mainmaster">
<p>Copyright © 2015 The Apache Software Foundation, Licensed under the
<a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0.</a> <br />
Apache, CloudStack, Apache CloudStack, the Apache CloudStack logo, the CloudMonkey logo and the Apache feather logo are trademarks of The Apache Software Foundation.</p>
- </div>
+ </div>
</div>
-
</div>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
-
diff --git a/tools/apidoc/generatetoc.xsl b/tools/apidoc/generatetoc.xsl
index 2cd1b00..687e626 100644
--- a/tools/apidoc/generatetoc.xsl
+++ b/tools/apidoc/generatetoc.xsl
@@ -25,7 +25,7 @@
<body>
<table border="1" cellpadding="1" cellspacing="0.5">
<tr>
-<h1 ALIGN='CENTER'>Cloudstack API Version 4.6.0</h1>
+<h1 ALIGN='CENTER'>Cloudstack API Version 4.9.0</h1>
<br/>
<h2 ALIGN='CENTER'>Table of Contents</h2>
<th><h3>Name</h3></th>
diff --git a/tools/apidoc/generatetoc_header.xsl b/tools/apidoc/generatetoc_header.xsl
index f760430..6362ab8 100644
--- a/tools/apidoc/generatetoc_header.xsl
+++ b/tools/apidoc/generatetoc_header.xsl
@@ -52,7 +52,7 @@
<div class="inside_apileftpanel">
<div class="inside_contentpanel" style="width:930px;">
<!-- Modify this line for the release version -->
- <h1>Apache CloudStack API Documentation (v4.6.0)</h1>
+ <h1>Apache CloudStack API Documentation (v4.9.0)</h1>
<a class="api_backbutton" href="http://cloudstack.apache.org/docs/api/"></a>
<div class="apiannouncement_box">
<div class="apiannouncement_contentarea">
diff --git a/tools/apidoc/generateusercommands.xsl b/tools/apidoc/generateusercommands.xsl
deleted file mode 100644
index c9ec857..0000000
--- a/tools/apidoc/generateusercommands.xsl
+++ /dev/null
@@ -1,157 +0,0 @@
-<?xml version="1.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.
--->
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
-version="1.0">
-<xsl:output method="html" doctype-public="-//W3C//DTD HTML 1.0 Transitional//EN"/>
-<xsl:template match="/">
-<html xmlns="http://www.w3.org/1999/xhtml"><head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel= "stylesheet" href="../includes/main.css" type="text/css" />
-<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" />
-
-<title>Apache CloudStack | The Power Behind Your Cloud</title>
-</head>
-
-<body>
-<div id="insidetopbg">
-<div id="inside_wrapper">
- <div class="uppermenu_panel">
- <div class="uppermenu_box"></div>
- </div>
-
- <div id="main_master">
- <div id="inside_header">
-
- <div class="header_top">
- <a class="cloud_logo" href="http://cloudstack.org"></a>
- <div class="mainemenu_panel">
-
- </div>
- </div>
-
- </div>
-
- <div id="main_content">
-
- <div class="inside_apileftpanel">
- <div class="inside_contentpanel" style="width:930px;">
- <div class="api_titlebox">
- <div class="api_titlebox_left">
- <xsl:for-each select="command/command">
- <!-- Modify this line for the release version -->
- <span>
- Apache CloudStack v4.6.0 User API Reference
- </span>
- <p></p>
- <h1><xsl:value-of select="name"/></h1>
- <p><xsl:value-of select="description"/></p>
- </xsl:for-each>
- </div>
-
-
- <div class="api_titlebox_right">
- <a class="api_backbutton" href="../TOC_User.html"></a>
- </div>
- </div>
- <div class="api_tablepanel">
- <h2>Request parameters</h2>
- <table class="apitable">
- <tr class="hed">
- <td style="width:200px;"><strong>Parameter Name</strong></td>
-
- <td style="width:500px;">Description</td>
- <td style="width:180px;">Required</td>
- </tr>
- <xsl:for-each select="command/command/request/arg">
- <tr>
- <xsl:if test="required='true'">
- <td style="width:200px;"><strong><xsl:value-of select="name"/></strong></td>
- <td style="width:500px;"><strong><xsl:value-of select="description"/></strong></td>
- <td style="width:180px;"><strong><xsl:value-of select="required"/></strong></td>
- </xsl:if>
- <xsl:if test="required='false'">
- <td style="width:200px;"><i><xsl:value-of select="name"/></i></td>
- <td style="width:500px;"><i><xsl:value-of select="description"/></i></td>
- <td style="width:180px;"><i><xsl:value-of select="required"/></i></td>
- </xsl:if>
- </tr>
- </xsl:for-each>
- </table>
- </div>
-
-
- <div class="api_tablepanel">
- <h2>Response Tags</h2>
- <table class="apitable">
- <tr class="hed">
- <td style="width:200px;"><strong>Response Name</strong></td>
- <td style="width:500px;">Description</td>
- </tr>
-
- <xsl:for-each select="command/command/response/arg">
- <tr>
- <td style="width:200px;"><strong><xsl:value-of select="name"/></strong></td>
- <td style="width:500px;"><xsl:value-of select="description"/></td>
- <xsl:for-each select="./arguments/arg">
- <tr>
- <td style="width:180px; padding-left:25px;"><strong><xsl:value-of select="name"/></strong></td>
- <td style="width:500px;"><xsl:value-of select="description"/></td>
- </tr>
- <xsl:for-each select="./arguments/arg">
- <tr>
- <td style="width:165px; padding-left:40px;"><xsl:value-of select="name"/></td>
- <td style="width:500px;"><xsl:value-of select="description"/></td>
- </tr>
- </xsl:for-each>
- </xsl:for-each>
- </tr>
- </xsl:for-each>
-
-
-
-
-
- </table>
-
- </div>
-
-
- </div>
- </div>
-
-
- </div>
- </div>
-<div id="footer">
-
- <div id="footer_mainmaster">
- <p>Copyright © 2015 The Apache Software Foundation, Licensed under the
- <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0.</a> <br />
- Apache, CloudStack, Apache CloudStack, the Apache CloudStack logo, the CloudMonkey logo and the Apache feather logo are trademarks of The Apache Software Foundation.</p>
- </div>
- </div>
-
- </div>
- </div>
-</body>
-</html>
-</xsl:template>
-</xsl:stylesheet>
-
diff --git a/tools/apidoc/pom.xml b/tools/apidoc/pom.xml
index ebdceac..440d807 100644
--- a/tools/apidoc/pom.xml
+++ b/tools/apidoc/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-tools</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
@@ -61,8 +61,6 @@
<argument>${client.config.jars}</argument>
<argument>${client.config.jars}</argument>
<argument>./target</argument>
- <argument>-f</argument>
- <argument>${client.config.conf}/commands.properties</argument>
</arguments>
</configuration>
</execution>
diff --git a/tools/appliance/.ruby-version b/tools/appliance/.ruby-version
index 7a895c2..bc9bac6 100644
--- a/tools/appliance/.ruby-version
+++ b/tools/appliance/.ruby-version
@@ -1 +1 @@
-1.9.3-p484
+2.3.0p0
diff --git a/tools/appliance/.rvmrc b/tools/appliance/.rvmrc
index 3c8c66c..573ecb7 100644
--- a/tools/appliance/.rvmrc
+++ b/tools/appliance/.rvmrc
@@ -15,7 +15,7 @@
# specific language governing permissions and limitations
# under the License.
-rvm use ruby-1.9.3@vagrant-release-cloudstack --create
+rvm use ruby-2.3.0@vagrant-release-cloudstack --create
export VAGRANT_HOME=$HOME/.vagrant.d-release-cloudstack
bundle check > /dev/null 2>&1
RETVAL=$?
diff --git a/tools/appliance/Gemfile b/tools/appliance/Gemfile
index 386601c..acd771b 100644
--- a/tools/appliance/Gemfile
+++ b/tools/appliance/Gemfile
@@ -16,7 +16,9 @@
# under the License.
source 'https://rubygems.org'
-# gem 'veewee', :git => 'https://github.com/jedi4ever/veewee.git'
+
gem 'veewee', '~> 0.4.5.1'
gem 'em-winrm'
gem 'sys-proctable'
+gem 'net-scp'
+gem 'net-ssh'
diff --git a/tools/appliance/README.md b/tools/appliance/README.md
index 82b0488..403eb45 100644
--- a/tools/appliance/README.md
+++ b/tools/appliance/README.md
@@ -19,17 +19,17 @@
# Setting up Tools and Environment
- - Install latest VirtualBox (at least 4.2)
- - Install tools for exporting appliances: qemu-img, vboxmanage, vhd-util
+ - Install latest VirtualBox (5.0+)
+ - Install tools for exporting appliances: qemu-img, vboxmanage, vhd-util, ovftool
- Install [RVM](https://rvm.io/rvm/install)
- - Install shar
- yum install sharutils
+ - Install dependencies (tested on Ubuntu 16.04):
+ apt-get install sharutils libxslt1-dev libxml2-dev zlib1g-dev build-essential ruby ruby-bundler ruby-dev qemu-utils blktap-utils faketime
- Setup paths:
export PATH=~/.rvm/bin:$PATH
- - Install Ruby 1.9.3, if it installed some other version:
- rvm install 1.9.3
- - Set rvm to use that 1.9.3
- rvm use ruby-1.9.3
+ - Install Ruby 2.3.0, if it installed some other version:
+ rvm install 2.3.0
+ - Set rvm to use that 2.3.0
+ rvm use ruby-2.3.0
- Install bundler: (if you get any openssl issue see https://rvm.io/packages/openssl)
gem install bundler
@@ -38,10 +38,6 @@
To save some time if you've downloaded iso of your distro, put the isos in:
tools/appliance/iso/
-Note, gem may require gcc-4.2, make sure link exists:
-
- sudo ln -s /usr/bin/gcc /usr/bin/gcc-4.2
-
# Setting up jenkins (CI) builds
All the tools listed above are expected to be available. If you follow
@@ -69,9 +65,10 @@
# How to build SystemVMs automatically
Just run build.sh, it will export archived appliances for KVM, XenServer,
-VMWare and HyperV in `dist`:
+VMWare and HyperV in `dist` directory:
- bash build.sh [systemvmtemplate|systemvmtemplate64]
+ bundle install
+ bash build.sh systemvm64template
# Building SystemVM template appliance manually
@@ -103,7 +100,7 @@
Troubleshooting
===============
-If you see following line in the screen, then veewee is failing
+If you see following line in the screen, then veewee is failing
extracting vboxmanage version.
Downloading vbox guest additions iso v - http://download.virtualbox.org/vi
diff --git a/tools/appliance/build.sh b/tools/appliance/build.sh
index 96fe6df..9ac4388 100755
--- a/tools/appliance/build.sh
+++ b/tools/appliance/build.sh
@@ -64,8 +64,13 @@
# make
# sudo make install
# * vhd-util
+# Install on yum-based:
# sudo yum -y install python-devel dev86 iasl iasl-devel libuuid libuuid-devel \
# glib-devel glib2 glib2-devel yajl yajl-devel
+# Install on apt-based:
+# sudo apt-get install -y python python-dev bcc bin86 iasl uuid-dev \
+# libglib2.0-dev libyajl-dev build-essential libc6-dev zlib1g-dev libncurses5-dev \
+# patch iasl libbz2-dev e2fslibs-dev xz-utils gettext
# wget -q http://bits.xensource.com/oss-xen/release/4.2.0/xen-4.2.0.tar.gz
# tar xzvf xen-4.2.0.tar.gz
# cd xen-4.2.0/tools/
@@ -77,7 +82,7 @@
# sudo ldconfig
# sudo cp blktap2/vhd/vhd-util /usr/lib64/cloud/common/scripts/vm/hypervisor/xenserver
# faketime 2010-01-01 vhd-util convert
-
+#
set -e
###
@@ -529,8 +534,6 @@
stage_vmx ${appliance_build_name}-vmware ${appliance_build_name}-vmware.vmdk
ovftool ${appliance_build_name}-vmware.vmx ${appliance_build_name}-vmware.ova
fi
- bzip2 "${appliance_build_name}-vmware.vmdk"
- mv "${appliance_build_name}-vmware.vmdk.bz2" dist/
mv ${appliance_build_name}-vmware.ova dist/
log INFO "${appliance} exported for VMWare: dist/${appliance_build_name}-vmware.ova"
}
diff --git a/tools/appliance/definitions/systemvmtemplate/configure_systemvm_services.sh b/tools/appliance/definitions/systemvmtemplate/configure_systemvm_services.sh
index 4f65543..57fa2a7 100644
--- a/tools/appliance/definitions/systemvmtemplate/configure_systemvm_services.sh
+++ b/tools/appliance/definitions/systemvmtemplate/configure_systemvm_services.sh
@@ -37,7 +37,6 @@
chmod +x /opt/cloud/bin/* \
/root/{clearUsageRules.sh,reconfigLB.sh,monitorServices.py} \
/etc/init.d/{cloud,cloud-early-config,cloud-passwd-srvr,postinit} \
- /etc/cron.daily/cloud-cleanup \
/etc/profile.d/cloud.sh
chkconfig --add cloud-early-config
diff --git a/tools/appliance/definitions/systemvmtemplate/definition.rb b/tools/appliance/definitions/systemvmtemplate/definition.rb
index 3d9da81..db6fce8 100644
--- a/tools/appliance/definitions/systemvmtemplate/definition.rb
+++ b/tools/appliance/definitions/systemvmtemplate/definition.rb
@@ -27,15 +27,15 @@
architectures = {
:i386 => {
:os_type_id => 'Debian',
- :iso_file => 'debian-7.9.0-i386-netinst.iso',
- :iso_src => 'http://cdimage.debian.org/cdimage/archive/7.9.0/i386/iso-cd/debian-7.9.0-i386-netinst.iso',
- :iso_md5 => 'e101a11ddb31f85acef542df1a49bf57',
+ :iso_file => 'debian-7.11.0-i386-netinst.iso',
+ :iso_src => 'http://cdimage.debian.org/cdimage/archive/7.11.0/i386/iso-cd/debian-7.11.0-i386-netinst.iso',
+ :iso_md5 => '75055a694508f5b891038ec12d703c9e',
},
:amd64 => {
:os_type_id => 'Debian_64',
- :iso_file => 'debian-7.9.0-amd64-netinst.iso',
- :iso_src => 'http://cdimage.debian.org/cdimage/archive/7.9.0/amd64/iso-cd/debian-7.9.0-amd64-netinst.iso',
- :iso_md5 => '774d1fc8c5364e63b22242c33a89c1a3'
+ :iso_file => 'debian-7.11.0-amd64-netinst.iso',
+ :iso_src => 'http://cdimage.debian.org/cdimage/archive/7.11.0/amd64/iso-cd/debian-7.11.0-amd64-netinst.iso',
+ :iso_md5 => '096c1c18b44c269808bd815d58c53c8f'
}
}
diff --git a/tools/appliance/definitions/systemvmtemplate/install_systemvm_packages.sh b/tools/appliance/definitions/systemvmtemplate/install_systemvm_packages.sh
index c8b7b91..f5f871b 100644
--- a/tools/appliance/definitions/systemvmtemplate/install_systemvm_packages.sh
+++ b/tools/appliance/definitions/systemvmtemplate/install_systemvm_packages.sh
@@ -63,7 +63,7 @@
nfs-common \
samba-common cifs-utils \
xl2tpd bcrelay ppp ipsec-tools tdb-tools \
- openswan=1:2.6.37-3 \
+ openswan=1:2.6.37-3+deb7u1 \
xenstore-utils libxenstore3.0 \
conntrackd ipvsadm libnetfilter-conntrack3 libnl-3-200 libnl-genl-3-200 \
ipcalc \
diff --git a/tools/checkstyle/pom.xml b/tools/checkstyle/pom.xml
index 5140fd8..a93fad0 100644
--- a/tools/checkstyle/pom.xml
+++ b/tools/checkstyle/pom.xml
@@ -24,13 +24,8 @@
<name>Apache CloudStack Developer Tools - Checkstyle Configuration</name>
<groupId>org.apache.cloudstack</groupId>
<artifactId>checkstyle</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
-
-
- <prerequisites>
- <maven>3.0.4</maven>
- </prerequisites>
-
+ <version>4.9.1.0-SNAPSHOT</version>
+
<build>
<plugins>
<plugin>
diff --git a/tools/devcloud-kvm/pom.xml b/tools/devcloud-kvm/pom.xml
index dd4a789..6fdd90e 100644
--- a/tools/devcloud-kvm/pom.xml
+++ b/tools/devcloud-kvm/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-tools</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
@@ -83,7 +83,7 @@
</dependencies>
<configuration>
<driver>org.gjt.mm.mysql.Driver</driver>
- <url>jdbc:mysql://${db.cloud.host}:${db.cloud.port}/cloud</url>
+ <url>${db.cloud.driver}://${db.cloud.host}:${db.cloud.port}/cloud</url>
<username>${db.cloud.username}</username>
<password>${db.cloud.password}</password>
<!--all executions are ignored if -Dmaven.test.skip=true -->
diff --git a/tools/devcloud/pom.xml b/tools/devcloud/pom.xml
index 4d62927..b2277da 100644
--- a/tools/devcloud/pom.xml
+++ b/tools/devcloud/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-tools</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
@@ -83,7 +83,7 @@
</dependencies>
<configuration>
<driver>org.gjt.mm.mysql.Driver</driver>
- <url>jdbc:mysql://${db.cloud.host}:${db.cloud.port}/cloud</url>
+ <url>${db.cloud.driver}://${db.cloud.host}:${db.cloud.port}/cloud</url>
<username>${db.cloud.username}</username>
<password>${db.cloud.password}</password>
<!--all executions are ignored if -Dmaven.test.skip=true -->
diff --git a/tools/devcloud4/pom.xml b/tools/devcloud4/pom.xml
index 9f3baa8..b13c743 100644
--- a/tools/devcloud4/pom.xml
+++ b/tools/devcloud4/pom.xml
@@ -17,7 +17,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-tools</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
@@ -83,7 +83,7 @@
</dependencies>
<configuration>
<driver>org.gjt.mm.mysql.Driver</driver>
- <url>jdbc:mysql://${db.cloud.host}:${db.cloud.port}/cloud</url>
+ <url>${db.cloud.driver}://${db.cloud.host}:${db.cloud.port}/cloud</url>
<username>${db.cloud.username}</username>
<password>${db.cloud.password}</password>
<!--all executions are ignored if -Dmaven.test.skip=true -->
diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py
index aa7b18f..d044fdd 100644
--- a/tools/marvin/marvin/cloudstackConnection.py
+++ b/tools/marvin/marvin/cloudstackConnection.py
@@ -143,7 +143,7 @@
["=".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 c81e7e9..e23069b 100644
--- a/tools/marvin/marvin/codes.py
+++ b/tools/marvin/marvin/codes.py
@@ -116,6 +116,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
'''
ZONETAG1 = "zwps1"
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 0000000..a382e33
--- /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 23981f0..f694bba 100644
--- a/tools/marvin/marvin/config/setup.cfg
+++ b/tools/marvin/marvin/config/setup.cfg
@@ -143,6 +143,10 @@
},
"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 3d4745d..c9bb7c6 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 91b30a6..2413328 100644
--- a/tools/marvin/marvin/deployDataCenter.py
+++ b/tools/marvin/marvin/deployDataCenter.py
@@ -133,6 +133,12 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 3b81b97..681619b 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 @@
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 @@
if domainid:
cmd.domainid = domainid
+
+ if roleid:
+ cmd.roleid = roleid
+
account = apiclient.createAccount(cmd)
return Account(account.__dict__)
@@ -1205,8 +1293,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
@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 @@
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 97b80ac..68fb336 100644
--- a/tools/marvin/marvin/lib/utils.py
+++ b/tools/marvin/marvin/lib/utils.py
@@ -520,4 +520,24 @@
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/marvin/sshClient.py b/tools/marvin/marvin/sshClient.py
index e481109..e872256 100644
--- a/tools/marvin/marvin/sshClient.py
+++ b/tools/marvin/marvin/sshClient.py
@@ -118,7 +118,8 @@
port=self.port,
username=self.user,
password=self.passwd,
- timeout=self.timeout)
+ timeout=self.timeout,
+ allow_agent=False)
else:
self.ssh.connect(hostname=self.host,
port=self.port,
diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml
index 3d8aea4..50257dc 100644
--- a/tools/marvin/pom.xml
+++ b/tools/marvin/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-tools</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
diff --git a/tools/marvin/setup.py b/tools/marvin/setup.py
index 8bfbf17..46d9628 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.2.0-SNAPSHOT"
+VERSION = "4.9.1.0-SNAPSHOT"
setup(name="Marvin",
version=VERSION,
@@ -52,7 +52,9 @@
"nose >= 1.3.3",
"ddt >= 0.4.0",
"pyvmomi >= 5.5.0",
- "netaddr >= 0.7.14"
+ "netaddr >= 0.7.14",
+ "dnspython",
+ "ipmisim >= 0.7"
],
py_modules=['marvin.marvinPlugin'],
zip_safe=False,
diff --git a/tools/pom.xml b/tools/pom.xml
index 09311cb..e6d5447 100644
--- a/tools/pom.xml
+++ b/tools/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<build>
diff --git a/tools/transifex/.tx/config b/tools/transifex/.tx/config
index 9804e76..fa4bc1f 100644
--- a/tools/transifex/.tx/config
+++ b/tools/transifex/.tx/config
@@ -108,3 +108,22 @@
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 b90a099..99195c2 100755
--- a/tools/travis/before_install.sh
+++ b/tools/travis/before_install.sh
@@ -49,12 +49,21 @@
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 @@
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 "<settings>
<mirrors>
<mirror>
@@ -94,9 +112,11 @@
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 40e6700..beb8acc 100755
--- a/tools/travis/before_script.sh
+++ b/tools/travis/before_script.sh
@@ -41,4 +41,4 @@
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 28f4ed4..bbea550 100755
--- a/tools/travis/install.sh
+++ b/tools/travis/install.sh
@@ -34,24 +34,19 @@
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 7e7c497..dc955b0 100755
--- a/tools/travis/script.sh
+++ b/tools/travis/script.sh
@@ -37,10 +37,11 @@
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 c492c01..80e228b 100755
--- a/tools/travis/xunit-reader.py
+++ b/tools/travis/xunit-reader.py
@@ -61,6 +61,8 @@
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 parse_reports(file_path_list):
table = texttable.Texttable()
- table.header(['Test', 'Result'])
+ table.header(['Test', 'Result', 'Time'])
exit_code = 0
@@ -80,16 +82,24 @@
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 61ebc50..d14a974 100644
--- a/tools/whisker/LICENSE
+++ b/tools/whisker/LICENSE
@@ -2771,10 +2771,7 @@
Copyright (c) 2012 The Apache Software Foundation
from The Apache Software Foundation http://www.apache.org/
httpd.conf
- ports.conf
- sites-available/default
- sites-available/default-ssl
- vhostexample.conf
+ vhost.template
Within the patches/systemvm/debian/config/etc/ssh/ directory
licensed under the BSD (2-clause) http://www.opensource.org/licenses/BSD-2-Clause (as follows)
@@ -2896,7 +2893,7 @@
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 1a68a0d..579e9d7 100644
--- a/tools/whisker/descriptor-for-packaging.xml
+++ b/tools/whisker/descriptor-for-packaging.xml
@@ -2459,10 +2459,7 @@
</copyright-notice>
<by-organisation id='apache.org.2'>
<resource name='httpd.conf' />
- <resource name='ports.conf' />
- <resource name='vhostexample.conf' />
- <resource name='sites-available/default' />
- <resource name='sites-available/default-ssl' />
+ <resource name='vhost.template' />
</by-organisation>
</with-license>
</within>
@@ -2673,7 +2670,7 @@
2009-2011 Bryan Kearney <bkearney@redhat.com>
</copyright-notice>
<by-organisation id='libvirt.org'>
- <resource name='libvirt-java-0.4.9' />
+ <resource name='libvirt-java-0.5.1' />
</by-organisation>
</with-license>
<with-license id="ApacheLicenseVersion2">
@@ -2683,7 +2680,7 @@
<by-organisation id="apache.org.2">
<resource name="cloud-axis.jar" source="http://axis.apache.org/axis/" notice='axis2.notice'/>
<resource name="cloud-commons-codec-1.5.jar" source="http://commons.apache.org/codec/" notice="codec" />
- <resource name="cloud-commons-collections-3.2.1.jar" source="http://commons.apache.org/collections/"/>
+ <resource name="cloud-commons-collections-3.2.2.jar" source="http://commons.apache.org/collections/"/>
<resource name="cloud-commons-configuration-1.8.jar" source="http://commons.apache.org/configuration/"/>
<resource name="cloud-commons-dbcp-1.4.jar" source="http://commons.apache.org/dbcp/" />
<resource name="cloud-commons-httpclient-3.1.jar" source="http://hc.apache.org/httpclient-3.x/" />
diff --git a/tools/whisker/descriptor.xml b/tools/whisker/descriptor.xml
index da38b18..0b6ded5 100644
--- a/tools/whisker/descriptor.xml
+++ b/tools/whisker/descriptor.xml
@@ -2443,10 +2443,7 @@
</copyright-notice>
<by-organisation id='apache.org.2'>
<resource name='httpd.conf' />
- <resource name='ports.conf' />
- <resource name='vhostexample.conf' />
- <resource name='sites-available/default' />
- <resource name='sites-available/default-ssl' />
+ <resource name='vhost.template' />
</by-organisation>
</with-license>
</within>
diff --git a/tools/wix-cloudstack-maven-plugin/pom.xml b/tools/wix-cloudstack-maven-plugin/pom.xml
index a4c71d8..57fcd0b 100644
--- a/tools/wix-cloudstack-maven-plugin/pom.xml
+++ b/tools/wix-cloudstack-maven-plugin/pom.xml
@@ -16,7 +16,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css
index a211a6e..16ee0b7 100644
--- a/ui/css/cloudstack3.css
+++ b/ui/css/cloudstack3.css
@@ -2904,6 +2904,15 @@
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 @@
/*Breadcrumbs*/
div.toolbar div.filters {
margin: 5px 0px 0 12px;
- width: 168px;
+ width: 200px;
float: left;
}
@@ -12694,6 +12703,54 @@
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 @@
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 b97141c..c15dae2 100644
--- a/ui/dictionary.jsp
+++ b/ui/dictionary.jsp
@@ -871,6 +871,7 @@
'label.metrics.property': '<fmt:message key="label.metrics.property" />',
'label.metrics.scope': '<fmt:message key="label.metrics.scope" />',
'label.metrics.state': '<fmt:message key="label.metrics.state" />',
+'label.metrics.outofbandmanagementpowerstate': '<fmt:message key="label.metrics.outofbandmanagementpowerstate" />',
'label.metrics.storagepool': '<fmt:message key="label.metrics.storagepool" />',
'label.metrics.vm.name': '<fmt:message key="label.metrics.vm.name" />',
'label.migrate.instance.to': '<fmt:message key="label.migrate.instance.to" />',
@@ -987,6 +988,27 @@
'label.port.forwarding': '<fmt:message key="label.port.forwarding" />',
'label.port.forwarding.policies': '<fmt:message key="label.port.forwarding.policies" />',
'label.port.range': '<fmt:message key="label.port.range" />',
+'label.powerstate': '<fmt:message key="label.powerstate" />',
+'label.outofbandmanagement': '<fmt:message key="label.outofbandmanagement" />',
+'label.outofbandmanagement.action.issue': '<fmt:message key="label.outofbandmanagement.action.issue" />',
+'label.outofbandmanagement.action': '<fmt:message key="label.outofbandmanagement.action" />',
+'label.outofbandmanagement.address': '<fmt:message key="label.outofbandmanagement.address" />',
+'label.outofbandmanagement.changepassword': '<fmt:message key="label.outofbandmanagement.changepassword" />',
+'label.outofbandmanagement.configure': '<fmt:message key="label.outofbandmanagement.configure" />',
+'label.outofbandmanagement.driver': '<fmt:message key="label.outofbandmanagement.driver" />',
+'label.outofbandmanagement.disable': '<fmt:message key="label.outofbandmanagement.disable" />',
+'label.outofbandmanagement.enable': '<fmt:message key="label.outofbandmanagement.enable" />',
+'label.outofbandmanagement.password': '<fmt:message key="label.outofbandmanagement.password" />',
+'label.outofbandmanagement.reenterpassword': '<fmt:message key="label.outofbandmanagement.reenterpassword" />',
+'label.outofbandmanagement.port': '<fmt:message key="label.outofbandmanagement.port" />',
+'label.outofbandmanagement.timeout': '<fmt:message key="label.outofbandmanagement.timeout" />',
+'label.outofbandmanagement.username': '<fmt:message key="label.outofbandmanagement.username" />',
+'message.outofbandmanagement.changepassword': '<fmt:message key="message.outofbandmanagement.changepassword" />',
+'message.outofbandmanagement.configure': '<fmt:message key="message.outofbandmanagement.configure" />',
+'message.outofbandmanagement.disable': '<fmt:message key="message.outofbandmanagement.disable" />',
+'message.outofbandmanagement.enable': '<fmt:message key="message.outofbandmanagement.enable" />',
+'message.outofbandmanagement.issue': '<fmt:message key="message.outofbandmanagement.issue" />',
+'message.outofbandmanagement.action.maintenance': '<fmt:message key="message.outofbandmanagement.action.maintenance" />',
'label.PreSetup': '<fmt:message key="label.PreSetup" />',
'label.prev': '<fmt:message key="label.prev" />',
'label.previous': '<fmt:message key="label.previous" />',
@@ -1120,7 +1142,14 @@
'label.retry.interval': '<fmt:message key="label.retry.interval" />',
'label.review': '<fmt:message key="label.review" />',
'label.revoke.project.invite': '<fmt:message key="label.revoke.project.invite" />',
+'label.permission': '<fmt:message key="label.permission" />',
'label.role': '<fmt:message key="label.role" />',
+'label.roles': '<fmt:message key="label.roles" />',
+'label.roletype': '<fmt:message key="label.roletype" />',
+'label.add.role': '<fmt:message key="label.add.role" />',
+'label.edit.role': '<fmt:message key="label.edit.role" />',
+'label.delete.role': '<fmt:message key="label.delete.role" />',
+'message.role.ordering.fail': '<fmt:message key="message.role.ordering.fail" />',
'label.root.disk.controller': '<fmt:message key="label.root.disk.controller" />',
'label.root.disk.offering': '<fmt:message key="label.root.disk.offering" />',
'message.configure.firewall.rules.allow.traffic': '<fmt:message key="message.configure.firewall.rules.allow.traffic" />',
diff --git a/ui/dictionary2.jsp b/ui/dictionary2.jsp
index 4268104..f919b15 100644
--- a/ui/dictionary2.jsp
+++ b/ui/dictionary2.jsp
@@ -26,6 +26,7 @@
<script type="text/javascript">
$.extend(dictionary, {
'label.add.ldap.account': '<fmt:message key="label.add.ldap.account" />',
+'label.rule': '<fmt:message key="label.rule" />',
'label.rules': '<fmt:message key="label.rules" />',
'label.running.vms': '<fmt:message key="label.running.vms" />',
'label.s3.access_key': '<fmt:message key="label.s3.access_key" />',
diff --git a/ui/images/icons.png b/ui/images/icons.png
index fd1049d..f676969 100644
--- a/ui/images/icons.png
+++ b/ui/images/icons.png
Binary files differ
diff --git a/ui/index.jsp b/ui/index.jsp
index 703507f..34f6310 100644
--- a/ui/index.jsp
+++ b/ui/index.jsp
@@ -1823,6 +1823,7 @@
<script type="text/javascript" src="scripts/ui-custom/uploadVolume.js"></script>
<script type="text/javascript" src="scripts/storage.js"></script>
<script type="text/javascript" src="scripts/templates.js"></script>
+ <script type="text/javascript" src="scripts/roles.js"></script>
<script type="text/javascript" src="scripts/accountsWizard.js"></script>
<script type="text/javascript" src="scripts/ui-custom/accountsWizard.js"></script>
<script type="text/javascript" src="scripts/accounts.js"></script>
diff --git a/ui/plugins/plugins.js b/ui/plugins/plugins.js
index b629e30..21da7a0 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 94a8730..4505b96 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 db0ab3f..913f81f 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 633821e..7fc4014 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 6e41607..b712d6c 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 14b0e15..4f7947a 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 f2b5682..bd32863 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 a367f46..19db257 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 e9a947d..554aab7 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);
@@ -425,7 +425,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);
@@ -556,7 +556,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
},
@@ -568,7 +581,7 @@
collapsible: true,
columns: {
cores: {
- label: 'label.metrics.num.cpu.cores',
+ label: 'label.metrics.num.cpu.cores'
},
cputotal: {
label: 'label.metrics.cpu.total'
@@ -663,6 +676,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) {
@@ -808,7 +824,7 @@
'Stopping': 'transition',
'Starting': 'transition',
'Migrating': 'transition',
- 'Shutdowned': 'warning',
+ 'Shutdowned': 'warning'
},
compact: true
},
@@ -823,13 +839,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'
}
}
},
@@ -958,7 +974,7 @@
'Expunging': 'off',
'Migrating': 'warning',
'UploadOp': 'transition',
- 'Snapshotting': 'warning',
+ 'Snapshotting': 'warning'
},
compact: true
},
@@ -973,7 +989,7 @@
},
storagepool: {
label: 'label.metrics.storagepool'
- },
+ }
},
dataProvider: function(args) {
var data = {listAll: true};
@@ -1046,7 +1062,7 @@
'ErrorInMaintenance': 'off',
'PrepareForMaintenance': 'transition',
'CancelMaintenance': 'warning',
- 'Maintenance': 'warning',
+ 'Maintenance': 'warning'
},
compact: true
},
@@ -1055,7 +1071,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 0000000..eae088f
--- /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 $('<div>').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 7b4b26a..88d728e 100644
--- a/ui/scripts/sharedFunctions.js
+++ b/ui/scripts/sharedFunctions.js
@@ -1112,6 +1112,17 @@
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 39dfccf..b26e60b 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();
}
@@ -2363,10 +2365,8 @@
}
}
- if (jsonObj.hypervisor == "KVM" || jsonObj.hypervisor == "XenServer" || jsonObj.hypervisor == "VMware") {
- if (jsonObj.state == "Ready" || jsonObj.state == "Allocated") {
- allowedActions.push("resize");
- }
+ if (jsonObj.state == "Ready" || jsonObj.state == "Allocated") {
+ allowedActions.push("resize");
}
if (jsonObj.state != "Allocated") {
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index 7e4200a..4ae7d67 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, {
@@ -7124,7 +7124,7 @@
},
apiversion: {
label: 'label.api.version',
- defaultValue: 'v1_0',
+ defaultValue: 'v3_2',
validation: {
required: true
},
@@ -7887,7 +7887,7 @@
return 'label.metrics';
}
}
- },
+ }
},
detailView: {
@@ -8256,6 +8256,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: {
@@ -9073,8 +9149,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) {
@@ -13120,7 +13205,7 @@
},
apiversion: {
label: 'label.api.version',
- defaultValue: 'v1_0'
+ defaultValue: 'v3_2'
},
retrycount: {
label: 'label.numretries',
@@ -13191,7 +13276,7 @@
dataType: "json",
async: false,
success: function(json) {
- var items = json.listnuagevspdeviceresponse.nuagevspdevice;
+ var items = json.listnuagevspdevicesresponse.nuagevspdevice;
args.response.success({
data: items
});
@@ -13260,7 +13345,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
});
@@ -14990,7 +15075,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: {
@@ -15348,7 +15511,15 @@
'Alert': 'off',
'Error': 'off'
}
- }
+ },
+ powerstate: {
+ label: 'label.powerstate',
+ indicator: {
+ 'On': 'on',
+ 'Off': 'off',
+ 'Unknown': 'warning'
+ },
+ },
},
dataProvider: function (args) {
@@ -15375,13 +15546,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
@@ -16018,6 +16196,7 @@
}
},
+
dedicate: {
label: 'label.dedicate.host',
messages: {
@@ -16356,8 +16535,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.") })
}
}
});
@@ -16367,13 +16549,342 @@
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
+ },
+ },
+ reenterpassword: {
+ label: 'label.outofbandmanagement.reenterpassword',
+ isPassword: true,
+ validation: {
+ required: false
+ }
+ },
+ }
+ },
+ action: function (args) {
+ var data = args.data;
+ if (data.password != data.reenterpassword) {
+ args.response.error("Passwords do not match");
+ return;
+ }
+ 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: {
@@ -16410,6 +16921,9 @@
state: {
label: 'label.state'
},
+ powerstate: {
+ label: 'label.powerstate'
+ },
type: {
label: 'label.type'
},
@@ -16521,6 +17035,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",
@@ -16552,6 +17070,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: {
@@ -20827,6 +21383,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;
}
@@ -20912,6 +21475,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;
}
@@ -20948,6 +21517,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 ddd7265..2ce72a2 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 0dd49ed..35a40de 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 ecc67a6..e0c3a8f 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -15,7 +15,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
@@ -53,17 +53,17 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
- <version>1.7.7</version>
+ <version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
- <version>1.7.7</version>
+ <version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
- <version>2.4.9</version>
+ <version>2.5.2</version>
<scope>test</scope>
</dependency>
</dependencies>
diff --git a/usage/test/resources/db.properties b/usage/test/resources/db.properties
index a458b23..e8e9412 100644
--- a/usage/test/resources/db.properties
+++ b/usage/test/resources/db.properties
@@ -26,6 +26,7 @@
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.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.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 49fd68a..c7aeaad 100644
--- a/utils/conf/db.properties
+++ b/utils/conf/db.properties
@@ -29,6 +29,7 @@
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.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.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 6c49207..ae1bf23 100755
--- a/utils/pom.xml
+++ b/utils/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
@@ -69,7 +69,7 @@
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
- <artifactId>bcprov-jdk16</artifactId>
+ <artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
@@ -157,7 +157,7 @@
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
- <version>3.3</version>
+ <version>3.4</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
diff --git a/api/src/com/cloud/exception/MissingParameterValueException.java b/utils/src/main/java/com/cloud/utils/ListUtils.java
similarity index 70%
copy from api/src/com/cloud/exception/MissingParameterValueException.java
copy to utils/src/main/java/com/cloud/utils/ListUtils.java
index 4bcaa56..fa9332f 100644
--- a/api/src/com/cloud/exception/MissingParameterValueException.java
+++ b/utils/src/main/java/com/cloud/utils/ListUtils.java
@@ -14,13 +14,18 @@
// 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 com.cloud.utils;
-public class MissingParameterValueException extends CloudRuntimeException {
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
- public MissingParameterValueException(String message) {
- super(message);
+public class ListUtils {
+ public static <T> List<T> toListOfInterface(final List<? extends T> items) {
+ if (items != null) {
+ return new ArrayList<>(items);
+ }
+ return Collections.emptyList();
}
-}
\ No newline at end of file
+}
diff --git a/utils/src/main/java/com/cloud/utils/Profiler.java b/utils/src/main/java/com/cloud/utils/Profiler.java
index f8e44bd..addee2d 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 @@
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 getDuration() {
if (startTickNanoSeconds != null && stopTickNanoSeconds != null) {
- final long timeInNanoSeconds = stopTickNanoSeconds - startTickNanoSeconds;
- return timeInNanoSeconds;
+ return stopTickNanoSeconds - startTickNanoSeconds;
}
return -1;
@@ -61,8 +59,7 @@
*/
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 4cb89f7..c0da87a 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 0683c8c..b45e028 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 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/api/src/org/apache/cloudstack/api/response/StatusResponse.java b/utils/src/main/java/com/cloud/utils/Utils.java
similarity index 60%
copy from api/src/org/apache/cloudstack/api/response/StatusResponse.java
copy to utils/src/main/java/com/cloud/utils/Utils.java
index fa2b4b2..53f0a80 100644
--- a/api/src/org/apache/cloudstack/api/response/StatusResponse.java
+++ b/utils/src/main/java/com/cloud/utils/Utils.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,21 +15,24 @@
// 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;
+package com.cloud.utils;
-import org.apache.cloudstack.api.BaseResponse;
+import java.util.Map;
-public class StatusResponse extends BaseResponse {
- @SerializedName("status")
- private Boolean status;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
- public Boolean getStatus() {
- return status;
- }
+public class Utils {
+ public static <K, V> Map getImmutableMap(Map<K, V> map) {
+ Map<K, V> filteredMap = Maps.filterValues(map, new Predicate<V>() {
+ public boolean apply(final V input) {
+ return input != null;
+ }
+ });
- public void setStatus(Boolean status) {
- this.status = status;
+ return ImmutableMap.<K, V>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 431d961..f03974a 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 void addInitialTransition(E event, S toState) {
+ addTransition(null, event, toState);
+ }
+
public void addTransition(S currentState, E event, S toState) {
addTransition(new Transition<S, E>(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<S, E> 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 6d6306a..02ffaab 100644
--- a/utils/src/main/java/com/cloud/utils/nio/Link.java
+++ b/utils/src/main/java/com/cloud/utils/nio/Link.java
@@ -19,36 +19,32 @@
package com.cloud.utils.nio;
-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 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 org.apache.cloudstack.utils.security.SSLUtils;
-import org.apache.log4j.Logger;
-
-import com.cloud.utils.PropertiesUtil;
-import com.cloud.utils.db.DbProperties;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.util.concurrent.ConcurrentLinkedQueue;
/**
*/
@@ -453,115 +449,188 @@
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?");
- }
+ 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;
}
- } 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) {
+ default:
+ throw new IllegalStateException("Invalid SSL status: " + result.getStatus());
+ }
+ return true;
+ }
+
+ 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);
+ }
+ 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);
+ }
+ // 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.");
+ }
+ 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;
+ }
+ 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("Handshake reading time out! Cut the connection");
+ s_logger.trace("SSL: Running delegated task!");
}
- count = -1;
+ task.run();
}
- if (count == -1) {
- throw new IOException("Connection closed with -1 on reading size.");
- }
- in_pkgBuf.flip();
- }
- 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();
-
- in_appBuf.clear();
- engResult = sslEngine.unwrap(in_pkgBuf, in_appBuf);
- loop_count++;
- }
- } 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!");
- }
- run.run();
- }
- } else if (hsStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
- throw new IOException("NOT a handshaking!");
+ break;
+ case FINISHED:
+ break;
+ case NOT_HANDSHAKING:
+ break;
+ default:
+ throw new IllegalStateException("Invalid SSL status: " + handshakeStatus);
}
- if (engResult != null && engResult.getStatus() != SSLEngineResult.Status.OK) {
- throw new IOException("Fail to handshake! " + engResult.getStatus());
- }
- 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 d989f30..dc4f670 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 @@
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 @@
_host = host;
}
- public void setBindAddress(final String ipAddress) {
- _bindAddress = ipAddress;
- }
-
@Override
protected void init() throws IOException {
_selector = Selector.open();
@@ -55,33 +50,25 @@
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);
- }
-
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 249f512..630b2dd 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 @@
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 @@
_port = port;
_factory = factory;
_executor = new ThreadPoolExecutor(workers, 5 * workers, 1, TimeUnit.DAYS, new LinkedBlockingQueue<Runnable>(), new NamedThreadFactory(name + "-Handler"));
+ _sslHandshakeExecutor = Executors.newCachedThreadPool(new NamedThreadFactory(name + "-SSLHandshakeHandler"));
}
public void start() throws NioConnectionException {
@@ -125,7 +125,7 @@
public Boolean call() throws NioConnectionException {
while (_isRunning) {
try {
- _selector.select();
+ _selector.select(100);
// Someone is ready for I/O, get the ready keys
final Set<SelectionKey> readyKeys = _selector.selectedKeys();
@@ -185,8 +185,9 @@
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 @@
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 539c2bb..b655f18 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 @@
_links = new WeakHashMap<InetSocketAddress, Link>(1024);
}
+ public int getPort() {
+ return _serverSocket.socket().getLocalPort();
+ }
+
@Override
protected void init() throws IOException {
_selector = SelectorProvider.provider().openSelector();
@@ -55,7 +59,7 @@
_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 d3c88c8..1f6d30c 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,30 @@
package com.cloud.utils.ssh;
import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
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<Boolean, String> sshExecute(String host, int port, String user, File pemKeyFile, String password, String command) throws Exception {
@@ -40,19 +52,19 @@
}
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 +100,7 @@
}
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 +135,8 @@
}
public static Pair<Boolean, String> 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 +157,7 @@
throw new Exception(msg);
}
}
- sess = conn.openSession();
+ sess = openConnectionSession(conn);
sess.execCommand(command);
@@ -156,22 +169,22 @@
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) {
@@ -187,13 +200,24 @@
String result = sbResult.toString();
+ if (StringUtils.isBlank(result)) {
+ try {
+ result = IOUtils.toString(stdout, StandardCharsets.UTF_8);
+ }
+ catch (IOException e) {
+ s_logger.error("Couldn't get content of input stream due to: " + e.getMessage());
+ return new Pair<Boolean, String>(false, result);
+ }
+ }
+
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<Boolean, String>(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<Boolean, String>(false, result);
}
@@ -206,4 +230,66 @@
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 0000000..b50a7ab
--- /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 0000000..c8ea6bf
--- /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<String> 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<String> 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<Integer> processFuture = executor.submit(new Callable<Integer>() {
+ @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 55f7a34..20c1623 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 @@
@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 f0e163e..0e68175 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();
- pf.start();
- try {
- Thread.sleep(20);
- } catch (final InterruptedException e) {
- }
+ //Given
+ final long expectedAnswer = -1;
- Assert.assertTrue(pf.getDurationInMillis() == -1);
+ //When
+ pf.start();
+
+ //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 0000000..355a514
--- /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 d8510cf..894aa1a 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 s_logger = Logger.getLogger(NioTest.class);
+ private static final Logger LOGGER = Logger.getLogger(NioTest.class);
- private NioServer _server;
- private NioClient _client;
+ // Test should fail in due time instead of looping forever
+ private static final int TESTTIMEOUT = 60000;
- private Link _clientLink;
+ final private int totalTestCount = 2;
+ private int completedTestCount = 0;
- private int _testCount;
- private int _completedCount;
+ private NioServer server;
+ private List<NioClient> clients = new ArrayList<>();
+ private List<NioClient> maliciousClients = new ArrayList<>();
+
+ 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() {
- while (!isTestsDone()) {
- try {
- s_logger.debug(_completedCount + "/" + _testCount + " tests done. Waiting for completion");
- Thread.sleep(1000);
- } catch (final InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
stopClient();
stopServer();
}
protected void stopClient() {
- _client.stop();
- s_logger.info("Client stopped.");
+ for (NioClient client : clients) {
+ client.stop();
+ }
+ for (NioClient maliciousClient : maliciousClients) {
+ maliciousClient.stop();
+ }
+ LOGGER.info("Clients stopped.");
}
protected void stopServer() {
- _server.stop();
- s_logger.info("Server stopped.");
+ server.stop();
+ LOGGER.info("Server stopped.");
}
- protected void setClientLink(final Link link) {
- _clientLink = link;
- }
-
- Random randomGenerator = new Random();
-
- byte[] _testBytes;
-
+ @Test(timeout=TESTTIMEOUT)
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();
+ while (!isTestsDone()) {
+ try {
+ LOGGER.debug(completedTestCount + "/" + totalTestCount + " tests done. Waiting for completion");
+ Thread.sleep(1000);
+ } catch (final InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
}
+ LOGGER.debug(completedTestCount + "/" + totalTestCount + " tests done.");
}
protected void doServerProcess(final byte[] data) {
oneMoreTestDone();
- Assert.assertArrayEquals(_testBytes, data);
- s_logger.info("Verify done.");
+ Assert.assertArrayEquals(testBytes, data);
+ LOGGER.info("Verify data received by server done.");
+ }
+
+ public byte[] getTestBytes() {
+ return testBytes;
+ }
+
+ 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());
+ }
+ }
+ }
+
+ public class NioMaliciousClient extends NioClient {
+
+ public NioMaliciousClient(String name, String host, int port, int workers, HandlerFactory factory) {
+ super(name, host, port, workers, factory);
+ }
+
+ @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());
+ }
+ }
+ }
+
+ 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 @@
@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 @@
@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 54d002f..f687767 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 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 0000000..2c158c8
--- /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 d2a2859..b2341dd 100644
--- a/vmware-base/pom.xml
+++ b/vmware-base/pom.xml
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack</artifactId>
- <version>4.8.2.0-SNAPSHOT</version>
+ <version>4.9.1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>