From 94de31ebada689a766809e0b73faf567a079c79a Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Fri, 29 Mar 2013 11:44:40 +0530 Subject: [PATCH 01/90] api: Fix ListNicsCmd's s_name, it should have a response suffix Signed-off-by: Rohit Yadav --- .../org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java index 9af044ebb70..4c4e1f71441 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/ListNicsCmd.java @@ -44,7 +44,7 @@ import com.cloud.vm.NicSecondaryIp; @APICommand(name = "listNics", description = "list the vm nics IP to NIC", responseObject = NicResponse.class) public class ListNicsCmd extends BaseListCmd { public static final Logger s_logger = Logger.getLogger(ListNicsCmd.class.getName()); - private static final String s_name = "listnics"; + private static final String s_name = "listnicsresponse"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// From d13c18516a30d035e2251d187979e805670aab81 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Fri, 29 Mar 2013 13:25:20 +0530 Subject: [PATCH 02/90] CLOUDSTACK-1841: Missing `cloud`.`configuration` stmts in upgrade Following global configurations introduced b/w 3.0.2 and 4.1 were missed. concurrent.snapshots.threshold.perhost | NULL network.ipv6.search.retry.max | 10000 traffic.sentinel.exclude.zones | traffic.sentinel.include.zones | EXTERNAL Signed-off-by: Prasanna Santhanam --- setup/db/db/schema-40to410.sql | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/setup/db/db/schema-40to410.sql b/setup/db/db/schema-40to410.sql index 3dae1cc50fe..e333810cb06 100644 --- a/setup/db/db/schema-40to410.sql +++ b/setup/db/db/schema-40to410.sql @@ -1652,3 +1652,10 @@ CREATE TABLE `cloud`.`ucs_manager` ( SET foreign_key_checks = 1; + +UPDATE `cloud`.`configuration` SET value='KVM,XenServer,VMware,Ovm' WHERE name='hypervisor.list'; + +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'concurrent.snapshots.threshold.perhost' , NULL, 'Limit number of snapshots that can be handled concurrently; default is NULL - unlimited.'); +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Network', 'DEFAULT', 'management-server', 'network.ipv6.search.retry.max' , 10000, 'The maximum number of retrying times to search for an available IPv6 address in the table'); +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Usage', 'DEFAULT', 'management-server', 'traffic.sentinel.exclude.zones' , '', 'Traffic going into specified list of zones is not metered'); +INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Usage', 'DEFAULT', 'management-server', 'traffic.sentinel.include.zones' , 'EXTERNAL', 'Traffic going into specified list of zones is metered. For metering all traffic leave this parameter empty'); From 2c176ab9ea6216b7c9da25ce0b0d2b34cbc2a776 Mon Sep 17 00:00:00 2001 From: Sanjay Tripathi Date: Fri, 29 Mar 2013 14:18:14 +0530 Subject: [PATCH 03/90] CLOUDSTACK-1592:[UI] Add support to limit newly added resourcetypes --- .../classes/resources/messages.properties | 8 + ui/dictionary.jsp | 8 + ui/scripts/accounts.js | 137 ++++++++++++++++-- ui/scripts/domains.js | 92 ++++++++++++ ui/scripts/projects.js | 20 ++- 5 files changed, 254 insertions(+), 11 deletions(-) diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 66b32acfc6c..da224eb3a7a 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -19,6 +19,14 @@ #new labels (begin) ********************************************************************************************** message.redirecting.region=Redirecting to region... label.use.vm.ip=Use VM IP: +label.cpu.limits=CPU limits +label.memory.limits=Memory limits (MiB) +label.primary.storage.limits=Primary Storage limits (GiB) +label.secondary.storage.limits=Secondary Storage limits (GiB) +label.max.cpus=Max. CPU cores +label.max.memory=Max. memory (MiB) +label.max.primary.storage=Max. primary (GiB) +label.max.secondary.storage=Max. secondary (GiB) label.menu.regions=Regions label.region=Region label.add.region=Add Region diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp index cd8d7323300..d4f9078907b 100644 --- a/ui/dictionary.jsp +++ b/ui/dictionary.jsp @@ -27,6 +27,14 @@ under the License. dictionary = { 'message.redirecting.region': '', 'label.use.vm.ip': '', +'label.cpu.limits': '', +'label.memory.limits': '', +'label.primary.storage.limits': '', +'label.secondary.storage.limits': '', +'label.max.cpus': '', +'label.max.memory': '', +'label.max.primary.storage': '', +'label.max.secondary.storage': '', 'label.add.region': '', 'label.remove.region': '', 'message.remove.region': '', diff --git a/ui/scripts/accounts.js b/ui/scripts/accounts.js index 3403337a834..8353d70536e 100644 --- a/ui/scripts/accounts.js +++ b/ui/scripts/accounts.js @@ -409,6 +409,77 @@ }); } + if(args.data.cpuLimit != null) { + var data = { + resourceType: 8, + max: args.data.cpuLimit, + domainid: accountObj.domainid, + account: accountObj.name + }; + + $.ajax({ + url: createURL('updateResourceLimit'), + data: data, + async: false, + success: function(json) { + accountObj["cpuLimit"] = args.data.cpuLimit; + } + }); + } + + if(args.data.memoryLimit != null) { + var data = { + resourceType: 9, + max: args.data.memoryLimit, + domainid: accountObj.domainid, + account: accountObj.name + }; + + $.ajax({ + url: createURL('updateResourceLimit'), + data: data, + async: false, + success: function(json) { + accountObj["memoryLimit"] = args.data.memoryLimit; + } + }); + } + + if(args.data.primaryStorageLimit != null) { + var data = { + resourceType: 10, + max: args.data.primaryStorageLimit, + domainid: accountObj.domainid, + account: accountObj.name + }; + + $.ajax({ + url: createURL('updateResourceLimit'), + data: data, + async: false, + success: function(json) { + accountObj["primaryStorageLimit"] = args.data.primaryStorageLimit; + } + }); + } + + if(args.data.secondaryStorageLimit != null) { + var data = { + resourceType: 11, + max: args.data.secondaryStorageLimit, + domainid: accountObj.domainid, + account: accountObj.name + }; + + $.ajax({ + url: createURL('updateResourceLimit'), + data: data, + async: false, + success: function(json) { + accountObj["secondaryStorageLimit"] = args.data.secondaryStorageLimit; + } + }); + } args.response.success({data: accountObj}); } }, @@ -698,6 +769,42 @@ return false; } }, + cpuLimit: { + label: 'label.cpu.limits', + isEditable: function(context) { + if (context.accounts[0].accounttype == roleTypeUser || context.accounts[0].accounttype == roleTypeDomainAdmin) //updateResourceLimits is only allowed on account whose type is user or domain-admin + return true; + else + return false; + } + }, + memoryLimit: { + label: 'label.memory.limits', + isEditable: function(context) { + if (context.accounts[0].accounttype == roleTypeUser || context.accounts[0].accounttype == roleTypeDomainAdmin) //updateResourceLimits is only allowed on account whose type is user or domain-admin + return true; + else + return false; + } + }, + primaryStorageLimit: { + label: 'label.primary.storage.limits', + isEditable: function(context) { + if (context.accounts[0].accounttype == roleTypeUser || context.accounts[0].accounttype == roleTypeDomainAdmin) //updateResourceLimits is only allowed on account whose type is user or domain-admin + return true; + else + return false; + } + }, + secondaryStorageLimit: { + label: 'label.secondary.storage.limits', + isEditable: function(context) { + if (context.accounts[0].accounttype == roleTypeUser || context.accounts[0].accounttype == roleTypeDomainAdmin) //updateResourceLimits is only allowed on account whose type is user or domain-admin + return true; + else + return false; + } + }, vmtotal: { label: 'label.total.of.vm' }, iptotal: { label: 'label.total.of.ip' }, @@ -725,11 +832,11 @@ dataProvider: function(args) { var data = { id: args.context.accounts[0].id - }; + }; $.ajax({ url: createURL('listAccounts'), - data: data, - success: function(json) { + data: data, + success: function(json) { var accountObj = json.listaccountsresponse.account[0]; var data = { domainid: accountObj.domainid, @@ -737,7 +844,7 @@ }; $.ajax({ url: createURL('listResourceLimits'), - data: data, + data: data, success: function(json) { var limits = json.listresourcelimitsresponse.resourcelimit; if (limits != null) { @@ -759,22 +866,34 @@ case "4": accountObj["templateLimit"] = limit.max; break; - case "7": + case "7": accountObj["vpcLimit"] = limit.max; break; + case "8": + accountObj["cpuLimit"] = limit.max; + break; + case "9": + accountObj["memoryLimit"] = limit.max; + break; + case "10": + accountObj["primaryStorageLimit"] = limit.max; + break; + case "11": + accountObj["secondaryStorageLimit"] = limit.max; + break; } } - } + } args.response.success( { actionFilter: accountActionfilter, data: accountObj } - ); + ); } - }); + }); } - }); + }); } } } diff --git a/ui/scripts/domains.js b/ui/scripts/domains.js index 991e37d7324..8ee0ee6816a 100644 --- a/ui/scripts/domains.js +++ b/ui/scripts/domains.js @@ -184,6 +184,50 @@ }); } + if(args.data.cpuLimit != null) { + $.ajax({ + url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=8&max=" + args.data.cpuLimit), + dataType: "json", + async: false, + success: function(json) { + domainObj["cpuLimit"] = args.data.cpuLimit; + } + }); + } + + if(args.data.memoryLimit != null) { + $.ajax({ + url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=9&max=" + args.data.memoryLimit), + dataType: "json", + async: false, + success: function(json) { + domainObj["memoryLimit"] = args.data.memoryLimit; + } + }); + } + + if(args.data.primaryStorageLimit != null) { + $.ajax({ + url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=10&max=" + args.data.primaryStorageLimit), + dataType: "json", + async: false, + success: function(json) { + domainObj["primaryStorageLimit"] = args.data.primaryStorageLimit; + } + }); + } + + if(args.data.secondaryStorageLimit != null) { + $.ajax({ + url: createURL("updateResourceLimit&domainid=" + args.context.domains[0].id + "&resourceType=11&max=" + args.data.secondaryStorageLimit), + dataType: "json", + async: false, + success: function(json) { + domainObj["secondaryStorageLimit"] = args.data.secondaryStorageLimit; + } + }); + } + args.response.success({data: domainObj}); } }, @@ -348,6 +392,42 @@ return false; } }, + cpuLimit: { + label: 'label.cpu.limits', + isEditable: function(context) { + if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits + return true; + else + return false; + } + }, + memoryLimit: { + label: 'label.memory.limits', + isEditable: function(context) { + if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits + return true; + else + return false; + } + }, + primaryStorageLimit: { + label: 'label.primary.storage.limits', + isEditable: function(context) { + if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits + return true; + else + return false; + } + }, + secondaryStorageLimit: { + label: 'label.secondary.storage.limits', + isEditable: function(context) { + if(context.domains[0].level != 0) //ROOT domain (whose level is 0) is not allowed to updateResourceLimits + return true; + else + return false; + } + }, accountTotal: { label: 'label.accounts' }, vmTotal: { label: 'label.instances' }, volumeTotal: { label: 'label.volumes' } @@ -441,6 +521,18 @@ case "7": domainObj["vpcLimit"] = limit.max; break; + case "8": + domainObj["cpuLimit"] = limit.max; + break; + case "9": + domainObj["memoryLimit"] = limit.max; + break; + case "10": + domainObj["primaryStorageLimit"] = limit.max; + break; + case "7": + domainObj["secondaryStorageLimit"] = limit.max; + break; } } } diff --git a/ui/scripts/projects.js b/ui/scripts/projects.js index b62dcb4c6a2..4004709a75d 100644 --- a/ui/scripts/projects.js +++ b/ui/scripts/projects.js @@ -71,7 +71,7 @@ var resourceLimits = $.grep( json.listresourcelimitsresponse.resourcelimit, function(resourceLimit) { - return resourceLimit.resourcetype != 5 && resourceLimit.resourcetype != 8; + return resourceLimit.resourcetype != 5 && resourceLimit.resourcetype != 12; } ); @@ -111,7 +111,23 @@ 7: { id: 'vpc', label: 'label.max.vpcs' - } + }, + 8: { + id: 'cpu', + label: 'label.max.cpus' + }, + 9: { + id: 'memory', + label: 'label.max.memory' + }, + 10: { + id: 'primary_storage', + label: 'label.max.primary.storage' + }, + 11: { + id: 'secondary_storage', + label: 'label.max.secondary.storage' + } }; return { From 6a7156ad9af6ca173c0b685d69d5724d91d0a401 Mon Sep 17 00:00:00 2001 From: Anshul Gangwar Date: Wed, 6 Mar 2013 14:11:47 +0530 Subject: [PATCH 04/90] CLOUDSTACK-712: Feature Syslog Enhancements Signed-off-by: Anshul Gangwar Signed-off-by: Sateesh Chodapuneedi --- client/pom.xml | 5 + client/tomcatconf/log4j-cloud.xml.in | 15 + plugins/alert-handlers/syslog-alerts/pom.xml | 40 +++ .../syslog/AlertsSyslogAppender.java | 336 ++++++++++++++++++ .../syslog/AlertsSyslogAppenderTest.java | 61 ++++ plugins/pom.xml | 1 + 6 files changed, 458 insertions(+) create mode 100644 plugins/alert-handlers/syslog-alerts/pom.xml create mode 100644 plugins/alert-handlers/syslog-alerts/src/org/apache/cloudstack/syslog/AlertsSyslogAppender.java create mode 100644 plugins/alert-handlers/syslog-alerts/test/org/apache/cloudstack/syslog/AlertsSyslogAppenderTest.java diff --git a/client/pom.xml b/client/pom.xml index 23892e14091..61cda76aa2e 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -65,6 +65,11 @@ cloud-plugin-network-nvp ${project.version} + + org.apache.cloudstack + cloud-plugin-syslog-alerts + ${project.version} + org.apache.cloudstack cloud-plugin-snmp-alerts diff --git a/client/tomcatconf/log4j-cloud.xml.in b/client/tomcatconf/log4j-cloud.xml.in index ce4079f9c96..0e7f004eb80 100755 --- a/client/tomcatconf/log4j-cloud.xml.in +++ b/client/tomcatconf/log4j-cloud.xml.in @@ -74,6 +74,20 @@ under the License. + + + + + + + + + + + + + + @@ -166,6 +180,7 @@ under the License. + diff --git a/plugins/alert-handlers/syslog-alerts/pom.xml b/plugins/alert-handlers/syslog-alerts/pom.xml new file mode 100644 index 00000000000..21aa54a7be2 --- /dev/null +++ b/plugins/alert-handlers/syslog-alerts/pom.xml @@ -0,0 +1,40 @@ + + + + cloudstack-plugins + org.apache.cloudstack + 4.2.0-SNAPSHOT + ../../pom.xml + + 4.0.0 + Apache CloudStack Plugin - Syslog Alerts + cloud-plugin-syslog-alerts + + + + log4j + log4j + ${cs.log4j.version} + + + + \ No newline at end of file diff --git a/plugins/alert-handlers/syslog-alerts/src/org/apache/cloudstack/syslog/AlertsSyslogAppender.java b/plugins/alert-handlers/syslog-alerts/src/org/apache/cloudstack/syslog/AlertsSyslogAppender.java new file mode 100644 index 00000000000..d2f25654c7a --- /dev/null +++ b/plugins/alert-handlers/syslog-alerts/src/org/apache/cloudstack/syslog/AlertsSyslogAppender.java @@ -0,0 +1,336 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT 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.syslog; + +import com.cloud.utils.net.NetUtils; +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.net.SyslogAppender; +import org.apache.log4j.spi.LoggingEvent; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +public class AlertsSyslogAppender extends AppenderSkeleton { + String _syslogHosts = null; + String _delimiter = ","; + List _syslogHostsList = null; + List _syslogAppenders = null; + private String _facility; + private String _pairDelimiter = "//"; + private String _keyValueDelimiter = "::"; + private int alertType = -1; + private long dataCenterId = 0; + private long podId = 0; + private long clusterId = 0; + private String sysMessage = null; + public static final int LENGTH_OF_STRING_MESSAGE_AND_KEY_VALUE_DELIMITER = 9; + public static final int LENGTH_OF_STRING_MESSAGE = 8; + public static final String MESSAGE_DELIMITER_STRING = " "; + //add the alertType in this array it its level needs to be set to critical + private static final int[] criticalAlerts = {7, 8, 9, 10, 11, 12, 13, 15, 16, 19, 20}; + private static final Map alertsMap; + + static { + Map aMap = new HashMap(27); + aMap.put(0, "availableMemory"); + aMap.put(1, "availableCpu"); + aMap.put(2, "availableStorage"); + aMap.put(3, "remainingStorageAllocated"); + aMap.put(4, "unallocatedVirtualNetworkpublicIp"); + aMap.put(5, "unallocatedPrivateIp"); + aMap.put(6, "availableSecondaryStorage"); + aMap.put(7, "host"); + aMap.put(8, "userVmState"); + aMap.put(9, "domainRouterVmState "); + aMap.put(10, "consoleProxyVmState"); + aMap.put(11, "routingConnection"); + aMap.put(12, "storageIssueSystemVms"); + aMap.put(13, "usageServerStatus"); + aMap.put(14, "managementNode"); + aMap.put(15, "domainRouterMigrate"); + aMap.put(16, "consoleProxyMigrate"); + aMap.put(17, "userVmMigrate"); + aMap.put(18, "unallocatedVlan"); + aMap.put(19, "ssvmStopped"); + aMap.put(20, "usageServerResult"); + aMap.put(21, "storageDelete"); + aMap.put(22, "updateResourceCount"); + aMap.put(23, "usageSanityResult"); + aMap.put(24, "unallocatedDirectAttachedPublicIp"); + aMap.put(25, "unallocatedLocalStorage"); + aMap.put(26, "resourceLimitExceeded"); + + alertsMap = Collections.unmodifiableMap(aMap); + } + + @Override + protected void append(LoggingEvent event) { + if (!isAsSevereAsThreshold(event.getLevel())) { + return; + } + + if (_syslogAppenders != null && !_syslogAppenders.isEmpty()) { + try { + String logMessage = event.getRenderedMessage(); + if (logMessage.contains("alertType") && logMessage.contains("message")) { + parseMessage(logMessage); + String syslogMessage = createSyslogMessage(); + + LoggingEvent syslogEvent = new LoggingEvent(event.getFQNOfLoggerClass(), event.getLogger(), + event.getLevel(), syslogMessage, null); + + for (SyslogAppender syslogAppender : _syslogAppenders) { + syslogAppender.append(syslogEvent); + } + } + } catch (Exception e) { + errorHandler.error(e.getMessage()); + } + } + } + + @Override + synchronized public void close() { + for (SyslogAppender syslogAppender : _syslogAppenders) { + syslogAppender.close(); + } + } + + @Override + public boolean requiresLayout() { + return true; + } + + void setSyslogAppenders() { + if (_syslogAppenders == null) { + _syslogAppenders = new ArrayList(); + } + + if (_syslogHosts == null || _syslogHosts.trim().isEmpty()) { + reset(); + return; + } + + _syslogHostsList = parseSyslogHosts(_syslogHosts); + + if (!validateIpAddresses()) { + reset(); + errorHandler.error(" Invalid format for the IP Addresses parameter "); + return; + } + + for (String syslogHost : _syslogHostsList) { + _syslogAppenders.add(new SyslogAppender(getLayout(), syslogHost, SyslogAppender.getFacility(_facility))); + } + } + + private List parseSyslogHosts(String syslogHosts) { + List result = new ArrayList(); + + final StringTokenizer tokenizer = new StringTokenizer(syslogHosts, _delimiter); + while (tokenizer.hasMoreTokens()) { + result.add(tokenizer.nextToken().trim()); + } + return result; + } + + private boolean validateIpAddresses() { + for (String ipAddress : _syslogHostsList) { + if (ipAddress.trim().equalsIgnoreCase("localhost")) { + continue; + } + if (!NetUtils.isValidIp(ipAddress)) { + return false; + } + } + return true; + } + + void parseMessage(String logMessage) { + final StringTokenizer messageSplitter = new StringTokenizer(logMessage, _pairDelimiter); + while (messageSplitter.hasMoreTokens()) { + final String pairToken = messageSplitter.nextToken(); + final StringTokenizer pairSplitter = new StringTokenizer(pairToken, _keyValueDelimiter); + String keyToken; + String valueToken; + + if (pairSplitter.hasMoreTokens()) { + keyToken = pairSplitter.nextToken().trim(); + } else { + break; + } + + if (pairSplitter.hasMoreTokens()) { + valueToken = pairSplitter.nextToken().trim(); + } else { + break; + } + + if (keyToken.equalsIgnoreCase("alertType") && !valueToken.equalsIgnoreCase("null")) { + alertType = Short.parseShort(valueToken); + } else if (keyToken.equalsIgnoreCase("dataCenterId") && !valueToken.equalsIgnoreCase("null")) { + dataCenterId = Long.parseLong(valueToken); + } else if (keyToken.equalsIgnoreCase("podId") && !valueToken.equalsIgnoreCase("null")) { + podId = Long.parseLong(valueToken); + } else if (keyToken.equalsIgnoreCase("clusterId") && !valueToken.equalsIgnoreCase("null")) { + clusterId = Long.parseLong(valueToken); + } else if (keyToken.equalsIgnoreCase("message") && !valueToken.equalsIgnoreCase("null")) { + sysMessage = getSyslogMessage(logMessage); + } + } + } + + String createSyslogMessage() { + StringBuilder message = new StringBuilder(); + message.append(severityOfAlert(alertType)).append(MESSAGE_DELIMITER_STRING); + InetAddress ip; + try { + ip = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + ip = null; + } + + if (ip != null) { + message.append(ip.getHostName()).append(MESSAGE_DELIMITER_STRING); + } else { + message.append("unknown" + MESSAGE_DELIMITER_STRING); + } + + if (alertType > 0) { + message.append("alertType").append(_keyValueDelimiter).append(" ").append(alertsMap.get(alertType)) + .append(MESSAGE_DELIMITER_STRING); + if (dataCenterId != 0) { + message.append("dataCenterId").append(_keyValueDelimiter).append(" ").append(dataCenterId) + .append(MESSAGE_DELIMITER_STRING); + } + + if (podId != 0) { + message.append("podId").append(_keyValueDelimiter).append(" ").append(podId) + .append(MESSAGE_DELIMITER_STRING); + } + + if (clusterId != 0) { + message.append("clusterId").append(_keyValueDelimiter).append(" ").append(clusterId) + .append(MESSAGE_DELIMITER_STRING); + } + + if (sysMessage != null) { + message.append("message").append(_keyValueDelimiter).append(" ").append(sysMessage); + } else { + errorHandler.error(" What is the use of alert without message "); + } + } else { + errorHandler.error(" Invalid alert Type "); + } + + return message.toString(); + } + + private String getSyslogMessage(String message) { + int lastIndexOfKeyValueDelimiter = message.lastIndexOf(_keyValueDelimiter); + int lastIndexOfMessageInString = message.lastIndexOf("message"); + + if (lastIndexOfKeyValueDelimiter - lastIndexOfMessageInString <= + LENGTH_OF_STRING_MESSAGE_AND_KEY_VALUE_DELIMITER) { + return message.substring(lastIndexOfKeyValueDelimiter + _keyValueDelimiter.length()).trim(); + } else if (lastIndexOfMessageInString < lastIndexOfKeyValueDelimiter) { + return message.substring( + lastIndexOfMessageInString + _keyValueDelimiter.length() + LENGTH_OF_STRING_MESSAGE).trim(); + } + + return message.substring(message.lastIndexOf("message" + _keyValueDelimiter) + + LENGTH_OF_STRING_MESSAGE_AND_KEY_VALUE_DELIMITER).trim(); + } + + private void reset() { + _syslogAppenders.clear(); + } + + public void setFacility(String facility) { + if (facility == null) { + return; + } + + this._facility = facility; + if (_syslogAppenders != null && !_syslogAppenders.isEmpty()) { + for (SyslogAppender syslogAppender : _syslogAppenders) { + syslogAppender.setFacility(facility); + } + } + } + + private String severityOfAlert(int alertType) { + if (isCritical(alertType)) { + return "CRITICAL"; + } else { + return "WARN"; + } + } + + private boolean isCritical(int alertType) { + for (int type : criticalAlerts) { + if (type == alertType) { + return true; + } + } + return false; + } + + public String getFacility() { + return _facility; + } + + public String getSyslogHosts() { + return _syslogHosts; + } + + public void setSyslogHosts(String syslogHosts) { + this._syslogHosts = syslogHosts; + this.setSyslogAppenders(); + } + + public String getDelimiter() { + return _delimiter; + } + + public void setDelimiter(String delimiter) { + this._delimiter = delimiter; + } + + public String getPairDelimiter() { + return _pairDelimiter; + } + + public void setPairDelimiter(String pairDelimiter) { + this._pairDelimiter = pairDelimiter; + } + + public String getKeyValueDelimiter() { + return _keyValueDelimiter; + } + + public void setKeyValueDelimiter(String keyValueDelimiter) { + this._keyValueDelimiter = keyValueDelimiter; + } +} \ No newline at end of file diff --git a/plugins/alert-handlers/syslog-alerts/test/org/apache/cloudstack/syslog/AlertsSyslogAppenderTest.java b/plugins/alert-handlers/syslog-alerts/test/org/apache/cloudstack/syslog/AlertsSyslogAppenderTest.java new file mode 100644 index 00000000000..68585ee6055 --- /dev/null +++ b/plugins/alert-handlers/syslog-alerts/test/org/apache/cloudstack/syslog/AlertsSyslogAppenderTest.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.syslog; + +import org.apache.log4j.PatternLayout; +import org.junit.Before; +import org.junit.Test; + +import javax.naming.ConfigurationException; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +public class AlertsSyslogAppenderTest { + AlertsSyslogAppender _appender = new AlertsSyslogAppender(); + + @Before + public void setUp() throws ConfigurationException { + _appender.setLayout(new PatternLayout("%-5p [%c{3}] (%t:%x) %m%n")); + _appender.setFacility("LOCAL6"); + } + + @Test + public void setSyslogAppendersTest() { + _appender.setSyslogHosts("10.1.1.1,10.1.1.2"); + assertEquals(" error Syslog Appenders list size not as expected ", 2, _appender._syslogAppenders.size()); + } + + @Test + public void setSyslogAppendersNegativeTest() { + //setting invalid IP for Syslog Hosts + _appender.setSyslogHosts("10.1.1."); + assertTrue(" list was expected to be empty", _appender._syslogAppenders.isEmpty()); + } + + @Test + public void appendTest() { + String message = "alertType:: 14 // dataCenterId:: 0 // podId:: 0 // clusterId:: null // message:: Management" + + " server node 127.0.0.1 is up"; + _appender.parseMessage(message); + String createdMessage = _appender.createSyslogMessage(); + assertTrue(" message is not as expected ", createdMessage.contains("alertType:: managementNode" + + AlertsSyslogAppender.MESSAGE_DELIMITER_STRING + "message:: Management server node 127.0.0.1 is up")); + assertTrue("severity level not as expected ", createdMessage.contains("WARN")); + } +} \ No newline at end of file diff --git a/plugins/pom.xml b/plugins/pom.xml index 39d99073f09..d7e8debbf02 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -59,6 +59,7 @@ storage/volume/solidfire storage/volume/default alert-handlers/snmp-alerts + alert-handlers/syslog-alerts From b585fa11c13bb7d548b2c16ba1ed1057a1b55f3f Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Fri, 29 Mar 2013 14:02:57 +0530 Subject: [PATCH 05/90] removing @Autowired, which is not JSR complaint. initializing the bean 'GlobalLoadBalancingRulesServiceImpl' through the componentContext.xml --- client/tomcatconf/componentContext.xml.in | 2 ++ client/tomcatconf/nonossComponentContext.xml.in | 5 +++++ .../region/gslb/GlobalLoadBalancingRulesServiceImpl.java | 9 ++++----- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index a98a41ffd5a..3f8277a2222 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -333,4 +333,6 @@ + + diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 1cc1722cff5..97a4f28e244 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -47,6 +47,11 @@ + + + + + diff --git a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java b/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java index 9cc10aa044e..696e6e9aa48 100644 --- a/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java +++ b/server/src/org/apache/cloudstack/region/gslb/GlobalLoadBalancingRulesServiceImpl.java @@ -44,8 +44,6 @@ import org.apache.cloudstack.api.command.user.region.ha.gslb.*; import org.apache.cloudstack.region.Region; import org.apache.cloudstack.region.dao.RegionDao; import org.apache.log4j.Logger; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; import javax.ejb.Local; import javax.inject.Inject; @@ -54,7 +52,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -@Component @Local(value = {GlobalLoadBalancingRulesService.class}) public class GlobalLoadBalancingRulesServiceImpl implements GlobalLoadBalancingRulesService { @@ -80,9 +77,11 @@ public class GlobalLoadBalancingRulesServiceImpl implements GlobalLoadBalancingR IPAddressDao _ipAddressDao; @Inject AgentManager _agentMgr; - @Autowired(required=false) - protected GslbServiceProvider _gslbProvider; + protected GslbServiceProvider _gslbProvider=null; + public void setGslbServiceProvider(GslbServiceProvider provider) { + this._gslbProvider = provider; + } @Override @DB From 48311363d600264cb3542992a615706cb92f90ad Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Fri, 29 Mar 2013 15:53:21 +0530 Subject: [PATCH 06/90] CLOUDSTACK-1834: Events are not generated for registerUserKeys(), Enabling account and Editing account. --- api/src/com/cloud/event/EventTypes.java | 5 +++++ server/src/com/cloud/server/ManagementServerImpl.java | 1 + server/src/com/cloud/user/AccountManagerImpl.java | 2 ++ 3 files changed, 8 insertions(+) diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 2e961e5b390..704a1bfc02c 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -122,9 +122,11 @@ public class EventTypes { public static final String EVENT_GLOBAL_LOAD_BALANCER_DELETE = "GLOBAL.LB.DELETE"; // Account events + public static final String EVENT_ACCOUNT_ENABLE = "ACCOUNT.ENABLE"; public static final String EVENT_ACCOUNT_DISABLE = "ACCOUNT.DISABLE"; public static final String EVENT_ACCOUNT_CREATE = "ACCOUNT.CREATE"; public static final String EVENT_ACCOUNT_DELETE = "ACCOUNT.DELETE"; + public static final String EVENT_ACCOUNT_UPDATE = "ACCOUNT.UPDATE"; public static final String EVENT_ACCOUNT_MARK_DEFAULT_ZONE = "ACCOUNT.MARK.DEFAULT.ZONE"; // UserVO Events @@ -137,6 +139,9 @@ public class EventTypes { public static final String EVENT_USER_ENABLE = "USER.ENABLE"; public static final String EVENT_USER_LOCK = "USER.LOCK"; + //registering SSH keypair events + public static final String EVENT_REGISTER_SSH_KEYPAIR = "REGISTER.SSH.KEYPAIR"; + // Template Events public static final String EVENT_TEMPLATE_CREATE = "TEMPLATE.CREATE"; public static final String EVENT_TEMPLATE_DELETE = "TEMPLATE.DELETE"; diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index ecd7751553d..26bc18d986a 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -3005,6 +3005,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } @Override + @ActionEvent(eventType = EventTypes.EVENT_REGISTER_SSH_KEYPAIR, eventDescription = "registering ssh keypair", async = true) public SSHKeyPair registerSSHKeyPair(RegisterSSHKeyPairCmd cmd) { Account caller = UserContext.current().getCaller(); diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index b69f31464ba..77864fdfb8e 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -1172,6 +1172,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M } @Override + @ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_ENABLE, eventDescription = "enabling account", async = true) public AccountVO enableAccount(String accountName, Long domainId, Long accountId) { // Check if account exists @@ -1262,6 +1263,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Override @DB + @ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_UPDATE, eventDescription = "updating account", async = true) public AccountVO updateAccount(UpdateAccountCmd cmd) { Long accountId = cmd.getId(); Long domainId = cmd.getDomainId(); From 95fce112157526b0727821e145ec53d0e8f3e824 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Fri, 29 Mar 2013 11:53:49 +0100 Subject: [PATCH 07/90] CLOUDSTACK-1156 Fix small typo --- .../src/com/cloud/configuration/Config.java | 4 +- .../ResourceLimitManagerImpl.java | 51 ++++++++++--------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index 5b2616f2d70..8ec5a41708e 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -323,7 +323,7 @@ public enum Config { DefaultMaxAccountVpcs("Account Defaults", ManagementServer.class, Long.class, "max.account.vpcs", "20", "The default maximum number of vpcs that can be created for an account", null), DefaultMaxAccountCpus("Account Defaults", ManagementServer.class, Long.class, "max.account.cpus", "40", "The default maximum number of cpu cores that can be used for an account", null), DefaultMaxAccountMemory("Account Defaults", ManagementServer.class, Long.class, "max.account.memory", "40960", "The default maximum memory (in MB) that can be used for an account", null), - DefaultMaxAccountPrimayStorage("Account Defaults", ManagementServer.class, Long.class, "max.account.primary.storage", "200", "The default maximum primary storage space (in GiB) that can be used for an account", null), + DefaultMaxAccountPrimaryStorage("Account Defaults", ManagementServer.class, Long.class, "max.account.primary.storage", "200", "The default maximum primary storage space (in GiB) that can be used for an account", null), DefaultMaxAccountSecondaryStorage("Account Defaults", ManagementServer.class, Long.class, "max.account.secondary.storage", "400", "The default maximum secondary storage space (in GiB) that can be used for an account", null), ResourceCountCheckInterval("Advanced", ManagementServer.class, Long.class, "resourcecount.check.interval", "0", "Time (in seconds) to wait before retrying resource count check task. Default is 0 which is to never run the task", "Seconds"), @@ -350,7 +350,7 @@ public enum Config { DefaultMaxProjectVpcs("Project Defaults", ManagementServer.class, Long.class, "max.project.vpcs", "20", "The default maximum number of vpcs that can be created for a project", null), DefaultMaxProjectCpus("Project Defaults", ManagementServer.class, Long.class, "max.project.cpus", "40", "The default maximum number of cpu cores that can be used for a project", null), DefaultMaxProjectMemory("Project Defaults", ManagementServer.class, Long.class, "max.project.memory", "40960", "The default maximum memory (in MB) that can be used for a project", null), - DefaultMaxProjectPrimayStorage("Project Defaults", ManagementServer.class, Long.class, "max.project.primary.storage", "200", "The default maximum primary storage space (in GiB) that can be used for an project", null), + DefaultMaxProjectPrimaryStorage("Project Defaults", ManagementServer.class, Long.class, "max.project.primary.storage", "200", "The default maximum primary storage space (in GiB) that can be used for an project", null), DefaultMaxProjectSecondaryStorage("Project Defaults", ManagementServer.class, Long.class, "max.project.secondary.storage", "400", "The default maximum secondary storage space (in GiB) that can be used for an project", null), ProjectInviteRequired("Project Defaults", ManagementServer.class, Boolean.class, "project.invite.required", "false", "If invitation confirmation is required when add account to project. Default value is false", null), diff --git a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java index bbe0190e3ae..e8805ae8910 100755 --- a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java +++ b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java @@ -186,29 +186,34 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim _rcExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("ResourceCountChecker")); } - projectResourceLimitMap.put(Resource.ResourceType.public_ip, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectPublicIPs.key()))); - projectResourceLimitMap.put(Resource.ResourceType.snapshot, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectSnapshots.key()))); - projectResourceLimitMap.put(Resource.ResourceType.template, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectTemplates.key()))); - projectResourceLimitMap.put(Resource.ResourceType.user_vm, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectUserVms.key()))); - projectResourceLimitMap.put(Resource.ResourceType.volume, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectVolumes.key()))); - projectResourceLimitMap.put(Resource.ResourceType.network, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectNetworks.key()))); - projectResourceLimitMap.put(Resource.ResourceType.vpc, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectVpcs.key()))); - projectResourceLimitMap.put(Resource.ResourceType.cpu, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectCpus.key()))); - projectResourceLimitMap.put(Resource.ResourceType.memory, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectMemory.key()))); - projectResourceLimitMap.put(Resource.ResourceType.primary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectPrimayStorage.key()))); - projectResourceLimitMap.put(Resource.ResourceType.secondary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectSecondaryStorage.key()))); - - accountResourceLimitMap.put(Resource.ResourceType.public_ip, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountPublicIPs.key()))); - accountResourceLimitMap.put(Resource.ResourceType.snapshot, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountSnapshots.key()))); - accountResourceLimitMap.put(Resource.ResourceType.template, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountTemplates.key()))); - accountResourceLimitMap.put(Resource.ResourceType.user_vm, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountUserVms.key()))); - accountResourceLimitMap.put(Resource.ResourceType.volume, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountVolumes.key()))); - accountResourceLimitMap.put(Resource.ResourceType.network, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountNetworks.key()))); - accountResourceLimitMap.put(Resource.ResourceType.vpc, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountVpcs.key()))); - accountResourceLimitMap.put(Resource.ResourceType.cpu, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountCpus.key()))); - accountResourceLimitMap.put(Resource.ResourceType.memory, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountMemory.key()))); - accountResourceLimitMap.put(Resource.ResourceType.primary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountPrimayStorage.key()))); - accountResourceLimitMap.put(Resource.ResourceType.secondary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountSecondaryStorage.key()))); + try { + projectResourceLimitMap.put(Resource.ResourceType.public_ip, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectPublicIPs.key()))); + projectResourceLimitMap.put(Resource.ResourceType.snapshot, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectSnapshots.key()))); + projectResourceLimitMap.put(Resource.ResourceType.template, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectTemplates.key()))); + projectResourceLimitMap.put(Resource.ResourceType.user_vm, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectUserVms.key()))); + projectResourceLimitMap.put(Resource.ResourceType.volume, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectVolumes.key()))); + projectResourceLimitMap.put(Resource.ResourceType.network, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectNetworks.key()))); + projectResourceLimitMap.put(Resource.ResourceType.vpc, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectVpcs.key()))); + projectResourceLimitMap.put(Resource.ResourceType.cpu, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectCpus.key()))); + projectResourceLimitMap.put(Resource.ResourceType.memory, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectMemory.key()))); + projectResourceLimitMap.put(Resource.ResourceType.primary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectPrimaryStorage.key()))); + projectResourceLimitMap.put(Resource.ResourceType.secondary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectSecondaryStorage.key()))); + + accountResourceLimitMap.put(Resource.ResourceType.public_ip, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountPublicIPs.key()))); + accountResourceLimitMap.put(Resource.ResourceType.snapshot, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountSnapshots.key()))); + accountResourceLimitMap.put(Resource.ResourceType.template, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountTemplates.key()))); + accountResourceLimitMap.put(Resource.ResourceType.user_vm, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountUserVms.key()))); + accountResourceLimitMap.put(Resource.ResourceType.volume, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountVolumes.key()))); + accountResourceLimitMap.put(Resource.ResourceType.network, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountNetworks.key()))); + accountResourceLimitMap.put(Resource.ResourceType.vpc, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountVpcs.key()))); + accountResourceLimitMap.put(Resource.ResourceType.cpu, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountCpus.key()))); + accountResourceLimitMap.put(Resource.ResourceType.memory, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountMemory.key()))); + accountResourceLimitMap.put(Resource.ResourceType.primary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountPrimaryStorage.key()))); + accountResourceLimitMap.put(Resource.ResourceType.secondary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountSecondaryStorage.key()))); + } catch (NumberFormatException e) { + s_logger.error("NumberFormatException during configuration", e); + throw new ConfigurationException("Configuration failed due to NumberFormatException, see log for the stacktrace"); + } return true; } From 9a5bf78c3ee156daf5527a4faf70375fc3a5fa47 Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Fri, 29 Mar 2013 11:55:00 +0100 Subject: [PATCH 08/90] Better error handling for some corner cases Make the exceptions more descriptive so admins can pinpoint the issue easier. --- .../cloud/agent/manager/ClusteredAgentAttache.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/server/src/com/cloud/agent/manager/ClusteredAgentAttache.java b/server/src/com/cloud/agent/manager/ClusteredAgentAttache.java index a6487402942..058a90475fd 100755 --- a/server/src/com/cloud/agent/manager/ClusteredAgentAttache.java +++ b/server/src/com/cloud/agent/manager/ClusteredAgentAttache.java @@ -95,8 +95,13 @@ public class ClusteredAgentAttache extends ConnectedAgentAttache implements Rout SynchronousListener synchronous = (SynchronousListener)listener; String peerName = synchronous.getPeer(); if (peerName != null) { - s_logger.debug(log(seq, "Forwarding to peer to cancel due to timeout")); - s_clusteredAgentMgr.cancel(peerName, _id, seq, "Timed Out"); + if (s_clusteredAgentMgr != null) { + s_logger.debug(log(seq, "Forwarding to peer to cancel due to timeout")); + s_clusteredAgentMgr.cancel(peerName, _id, seq, "Timed Out"); + } else { + s_logger.error("Unable to forward cancel, ClusteredAgentAttache is not properly initialized"); + } + } } } @@ -159,6 +164,10 @@ public class ClusteredAgentAttache extends ConnectedAgentAttache implements Rout } } + if (s_clusteredAgentMgr == null) { + throw new AgentUnavailableException("ClusteredAgentAttache not properly initialized", _id); + } + int i = 0; SocketChannel ch = null; boolean error = true; From 5a66ec35ad08ff3313e72b54eba7e1754868eee4 Mon Sep 17 00:00:00 2001 From: Pradeep Date: Fri, 29 Mar 2013 15:54:09 +0530 Subject: [PATCH 09/90] CLOUDSTACK-1689: KVM agent install.sh should install ipset command Added ipset in cloud.spec as part of agent install. Signed-off-by: Pradeep Signed-off-by: Prasanna Santhanam --- packaging/centos63/cloud.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index f8e31338005..7d6e63880b1 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -114,6 +114,7 @@ Requires: %{name}-common = %{_ver} Requires: libvirt Requires: bridge-utils Requires: ebtables +Requires: ipset Requires: jsvc Requires: jakarta-commons-daemon Requires: jakarta-commons-daemon-jsvc From 690c31290bcbd138c1cf49a7f8ca72fbe8c33c24 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Fri, 29 Mar 2013 18:00:42 +0530 Subject: [PATCH 10/90] CLOUDSTACK-767:nTier Apps 2.0 : Allow more than one Private GW to a VPC --- ui/scripts/vpc.js | 87 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index 4281ca283fa..a4834f26c72 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -616,6 +616,7 @@ } }, gateways: { + add: { preCheck: function(args) { if(isAdmin()) { //root-admin @@ -732,6 +733,92 @@ netmask: { label: 'label.netmask', validation: { required: true }}, vlan: { label: 'label.vlan', validation: { required: true }} }, + + actions:{ + add:{ + label:'Add Private Gateway', + createForm:{ + title: 'label.add.new.gateway', + desc: 'message.add.new.gateway.to.vpc', + fields: { + physicalnetworkid: { + docID: 'helpVPCGatewayPhysicalNetwork', + label: 'label.physical.network', + select: function(args) { + $.ajax({ + url: createURL("listPhysicalNetworks"), + data: { + zoneid: args.context.vpc[0].zoneid + }, + success: function(json) { + var objs = json.listphysicalnetworksresponse.physicalnetwork; + var items = []; + $(objs).each(function() { + items.push({id: this.id, description: this.name}); + }); + args.response.success({data: items}); + } + }); + } + }, + vlan: { + label: 'label.vlan', validation: { required: true }, + docID: 'helpVPCGatewayVLAN' + }, + ipaddress: { + label: 'label.ip.address', validation: { required: true }, + docID: 'helpVPCGatewayIP' + }, + gateway: { + label: 'label.gateway', validation: { required: true }, + docID: 'helpVPCGatewayGateway' + }, + netmask: { + label: 'label.netmask', validation: { required: true }, + docID: 'helpVPCGatewayNetmask' + } + } + + + + }, + action:function(args){ + $.ajax({ + url: createURL('createPrivateGateway'), + data: { + physicalnetworkid: args.data.physicalnetworkid, + vpcid: args.context.vpc[0].id, + ipaddress: args.data.ipaddress, + gateway: args.data.gateway, + netmask: args.data.netmask, + vlan: args.data.vlan + }, + success: function(json) { + var jid = json.createprivategatewayresponse.jobid; + args.response.success( + {_custom: + {jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.privategateway; + } + } + } + ); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + + notification: { + poll: pollAsyncJobResult + } + + + } + }, + dataProvider: function(args) { $.ajax({ url: createURL('listPrivateGateways'), From ee3fd1843533528eb3872951730fee6e5802c348 Mon Sep 17 00:00:00 2001 From: Kanzhe Jiang Date: Fri, 29 Mar 2013 18:48:50 +0530 Subject: [PATCH 11/90] BigSwitch networking plugin update Update BigSwitch Plugin: . UI support for adding BigSwitch controller as a network service provider . Correct the message format between the plugin and the controller . Add Health check API Test to add a BigSwitch controller as a network service provider and view. Test to implementation of guest network on the controller Test to associate VM to its guest network --- .../classes/resources/messages.properties | 4 + client/tomcatconf/componentContext.xml.in | 13 +- .../tomcatconf/nonossComponentContext.xml.in | 6 + .../commands/DeleteBigSwitchVnsDeviceCmd.java | 4 +- .../commands/ListBigSwitchVnsDevicesCmd.java | 8 +- .../response/BigSwitchVnsDeviceResponse.java | 4 + .../cloud/network/BigSwitchVnsDeviceVO.java | 4 +- .../{Attachment.java => AttachmentData.java} | 42 +- .../network/bigswitch/BigSwitchVnsApi.java | 39 +- .../bigswitch/ControlClusterStatus.java | 4 + .../com/cloud/network/bigswitch/Network.java | 74 ---- .../cloud/network/bigswitch/NetworkData.java | 86 ++++ .../bigswitch/{Port.java => PortData.java} | 70 ++-- .../network/element/BigSwitchVnsElement.java | 14 +- .../guru/BigSwitchVnsGuestNetworkGuru.java | 4 +- .../resource/BigSwitchVnsResource.java | 40 +- .../network/bigswitch/BigSwitchApiTest.java | 18 +- .../resource/BigSwitchVnsResourceTest.java | 44 ++- ui/dictionary.jsp | 5 +- ui/scripts/system.js | 373 +++++++++++++++++- 20 files changed, 648 insertions(+), 208 deletions(-) rename plugins/network-elements/bigswitch-vns/src/com/cloud/network/bigswitch/{Attachment.java => AttachmentData.java} (61%) delete mode 100644 plugins/network-elements/bigswitch-vns/src/com/cloud/network/bigswitch/Network.java create mode 100644 plugins/network-elements/bigswitch-vns/src/com/cloud/network/bigswitch/NetworkData.java rename plugins/network-elements/bigswitch-vns/src/com/cloud/network/bigswitch/{Port.java => PortData.java} (50%) diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index da224eb3a7a..d62cbaeb99b 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -1582,6 +1582,10 @@ label.nicira.controller.address=Controller Address label.nicira.transportzoneuuid=Transport Zone Uuid label.nicira.l3gatewayserviceuuid=L3 Gateway Service Uuid +label.add.BigSwitchVns.device=Add BigSwitch Vns Controller +label.delete.BigSwitchVns=Remove BigSwitch Vns Controller +label.bigswitch.controller.address=BigSwitch Vns Controller Address + #resizeVolumes label.resize.new.size=New Size(GB) label.action.resize.volume=Resize Volume diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 3f8277a2222..0b81016d184 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -107,12 +107,6 @@ --> - - @@ -91,9 +89,6 @@ - - - @@ -165,5 +160,586 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 0b81016d184..159bf851f9e 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -30,298 +30,172 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> - + - - + - + + - - - - + + + + + + + + + - - + + - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - + + + + + + + + + + + - - + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 6659e21b292..13bb3f536a5 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -33,315 +33,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -351,4 +48,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index c219cfccaf2..0cbf72f2d7a 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -103,12 +103,24 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { @Inject DataStoreManager dataStoreMgr; @Inject protected ClusterDetailsDao _clusterDetailsDao; - //@com.cloud.utils.component.Inject(adapter=StoragePoolAllocator.class) - @Inject protected List _storagePoolAllocators; + protected List _storagePoolAllocators; + public List getStoragePoolAllocators() { + return _storagePoolAllocators; + } + public void setStoragePoolAllocators( + List _storagePoolAllocators) { + this._storagePoolAllocators = _storagePoolAllocators; + } - //@com.cloud.utils.component.Inject(adapter=HostAllocator.class) - @Inject protected List _hostAllocators; - protected String _allocationAlgorithm = "random"; + protected List _hostAllocators; + public List getHostAllocators() { + return _hostAllocators; + } + public void setHostAllocators(List _hostAllocators) { + this._hostAllocators = _hostAllocators; + } + + protected String _allocationAlgorithm = "random"; @Override diff --git a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java index bba8be5c649..25c5a043b6c 100755 --- a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java +++ b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java @@ -116,11 +116,23 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai ClusterDetailsDao _clusterDetailsDao; long _serverId; - @Inject List _investigators; - @Inject - List _fenceBuilders; - @Inject + public List getInvestigators() { + return _investigators; + } + public void setInvestigators(List _investigators) { + this._investigators = _investigators; + } + + List _fenceBuilders; + public List getFenceBuilders() { + return _fenceBuilders; + } + public void setFenceBuilders(List _fenceBuilders) { + this._fenceBuilders = _fenceBuilders; + } + + @Inject AgentManager _agentMgr; @Inject AlertManager _alertMgr; diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index b2ceb46d1ab..a4eac3687ad 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -243,16 +243,41 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L @Inject PodVlanMapDao _podVlanMapDao; - @Inject List _networkGurus; + public List getNetworkGurus() { + return _networkGurus; + } + public void setNetworkGurus(List _networkGurus) { + this._networkGurus = _networkGurus; + } - @Inject protected List _networkElements; + List _networkElements; + public List getNetworkElements() { + return _networkElements; + } + public void setNetworkElements(List _networkElements) { + this._networkElements = _networkElements; + } - @Inject NetworkDomainDao _networkDomainDao; - @Inject List _ipDeployers; - @Inject List _dhcpProviders; - - @Inject + @Inject NetworkDomainDao _networkDomainDao; + + List _ipDeployers; + public List getIpDeployers() { + return _ipDeployers; + } + public void setIpDeployers(List _ipDeployers) { + this._ipDeployers = _ipDeployers; + } + + List _dhcpProviders; + public List getDhcpProviders() { + return _dhcpProviders; + } + public void setDhcpProviders(List _dhcpProviders) { + this._dhcpProviders = _dhcpProviders; + } + + @Inject VMInstanceDao _vmDao; @Inject FirewallManager _firewallMgr; diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index 41ce103b360..788e031d4a6 100644 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -143,9 +143,15 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { @Inject PodVlanMapDao _podVlanMapDao; - @Inject List _networkElements; - - @Inject + List _networkElements; + public List getNetworkElements() { + return _networkElements; + } + public void setNetworkElements(List _networkElements) { + this._networkElements = _networkElements; + } + + @Inject NetworkDomainDao _networkDomainDao; @Inject VMInstanceDao _vmDao; diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 15d32e0640d..82bca5194bf 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -206,19 +206,29 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, protected HighAvailabilityManager _haMgr; @Inject protected StorageService _storageSvr; - // @com.cloud.utils.component.Inject(adapter = Discoverer.class) + + protected List _discoverers; + public List getDiscoverers() { + return _discoverers; + } + public void setDiscoverers(List _discoverers) { + this._discoverers = _discoverers; + } + @Inject - protected List _discoverers; - @Inject protected ClusterManager _clusterMgr; @Inject protected StoragePoolHostDao _storagePoolHostDao; - // @com.cloud.utils.component.Inject(adapter = PodAllocator.class) - @Inject - protected List _podAllocators = null; + protected List _podAllocators; + public List getPodAllocators() { + return _podAllocators; + } + public void setPodAllocators(List _podAllocators) { + this._podAllocators = _podAllocators; + } - @Inject + @Inject protected VMTemplateDao _templateDao; @Inject protected ConfigurationManager _configMgr; diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 26bc18d986a..d0904e1049c 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -16,6 +16,98 @@ // under the License. package com.cloud.server; +import java.lang.reflect.Field; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import javax.annotation.PostConstruct; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import javax.inject.Inject; +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanRegistrationException; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.naming.ConfigurationException; + +import com.cloud.storage.dao.*; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.api.ApiConstants; + +import com.cloud.event.ActionEventUtils; +import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd; +import org.apache.cloudstack.api.command.admin.account.*; +import org.apache.cloudstack.api.command.admin.autoscale.*; +import org.apache.cloudstack.api.command.admin.cluster.*; +import org.apache.cloudstack.api.command.admin.config.*; +import org.apache.cloudstack.api.command.admin.domain.*; +import org.apache.cloudstack.api.command.admin.host.*; +import org.apache.cloudstack.api.command.admin.ldap.*; +import org.apache.cloudstack.api.command.admin.network.*; +import org.apache.cloudstack.api.command.admin.offering.*; +import org.apache.cloudstack.api.command.admin.pod.*; +import org.apache.cloudstack.api.command.admin.region.*; +import org.apache.cloudstack.api.command.admin.resource.*; +import org.apache.cloudstack.api.command.admin.router.*; +import org.apache.cloudstack.api.command.admin.storage.*; +import org.apache.cloudstack.api.command.admin.swift.*; +import org.apache.cloudstack.api.command.admin.systemvm.*; +import org.apache.cloudstack.api.command.admin.template.*; +import org.apache.cloudstack.api.command.admin.usage.*; +import org.apache.cloudstack.api.command.admin.user.*; +import org.apache.cloudstack.api.command.admin.vlan.*; +import org.apache.cloudstack.api.command.admin.vm.*; +import org.apache.cloudstack.api.command.admin.vpc.*; +import org.apache.cloudstack.api.command.admin.zone.*; +import org.apache.cloudstack.api.command.user.account.*; +import org.apache.cloudstack.api.command.user.address.*; +import org.apache.cloudstack.api.command.user.autoscale.*; +import org.apache.cloudstack.api.command.user.config.*; +import org.apache.cloudstack.api.command.user.event.*; +import org.apache.cloudstack.api.command.user.firewall.*; +import org.apache.cloudstack.api.command.user.guest.*; +import org.apache.cloudstack.api.command.user.iso.*; +import org.apache.cloudstack.api.command.user.job.*; +import org.apache.cloudstack.api.command.user.loadbalancer.*; +import org.apache.cloudstack.api.command.user.nat.*; +import org.apache.cloudstack.api.command.user.network.*; +import org.apache.cloudstack.api.command.user.offering.*; +import org.apache.cloudstack.api.command.user.project.*; +import org.apache.cloudstack.api.command.user.region.*; +import org.apache.cloudstack.api.command.user.resource.*; +import org.apache.cloudstack.api.command.user.securitygroup.*; +import org.apache.cloudstack.api.command.user.snapshot.*; +import org.apache.cloudstack.api.command.user.ssh.*; +import org.apache.cloudstack.api.command.user.tag.*; +import org.apache.cloudstack.api.command.user.template.*; +import org.apache.cloudstack.api.command.user.vm.*; +import org.apache.cloudstack.api.command.user.vmgroup.*; +import org.apache.cloudstack.api.command.user.volume.*; +import org.apache.cloudstack.api.command.user.vpc.*; +import org.apache.cloudstack.api.command.user.vpn.*; +import org.apache.cloudstack.api.command.user.zone.*; +import org.apache.cloudstack.api.response.ExtractResponse; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + import com.cloud.agent.AgentManager; import com.cloud.agent.api.GetVncPortAnswer; import com.cloud.agent.api.GetVncPortCommand; @@ -97,7 +189,15 @@ import com.cloud.user.*; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.SSHKeyPairDao; import com.cloud.user.dao.UserDao; -import com.cloud.utils.*; +import com.cloud.utils.EnumUtils; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.PasswordGenerator; +import com.cloud.utils.ReflectUtil; +import com.cloud.utils.Ternary; +import com.cloud.utils.component.Adapter; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ComponentLifecycle; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -324,9 +424,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Inject private HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; - @Inject private List _hostAllocators; - @Inject + + @Inject private ConfigurationManager _configMgr; @Inject private ResourceTagDao _resourceTagDao; @@ -373,6 +473,14 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe public void setUserAuthenticators(List authenticators) { _userAuthenticators = authenticators; } + + public List getHostAllocators() { + return _hostAllocators; + } + + public void setHostAllocators(List _hostAllocators) { + this._hostAllocators = _hostAllocators; + } @Override public boolean configure(String name, Map params) @@ -406,7 +514,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe return true; } - @Override + @Override public boolean start() { s_logger.info("Startup CloudStack management server..."); diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index f37654bb317..a33d524d8ea 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -276,8 +276,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Inject protected SecondaryStorageVmManager _ssvmMgr; @Inject - protected List _storagePoolAllocators; - @Inject ConfigurationDao _configDao; @Inject ManagementServer _msServer; @@ -296,12 +294,26 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Inject protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; - // TODO : we don't have any instantiated pool discover, disable injection - // temporarily - // @Inject - protected List _discoverers; + @Inject protected ResourceTagDao _resourceTagDao; - protected SearchBuilder HostTemplateStatesSearch; + protected List _storagePoolAllocators; + public List getStoragePoolAllocators() { + return _storagePoolAllocators; + } + public void setStoragePoolAllocators( + List _storagePoolAllocators) { + this._storagePoolAllocators = _storagePoolAllocators; + } + + protected List _discoverers; + public List getDiscoverers() { + return _discoverers; + } + public void setDiscoverers(List _discoverers) { + this._discoverers = _discoverers; + } + + protected SearchBuilder HostTemplateStatesSearch; protected GenericSearchBuilder UpHostsInPoolSearch; protected SearchBuilder StoragePoolSearch; protected SearchBuilder LocalStorageSearch; diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 77864fdfb8e..40db4ed2f86 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -230,9 +230,9 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M UserVO _systemUser; AccountVO _systemAccount; - @Inject List _securityCheckers; - int _cleanupInterval; + + int _cleanupInterval; public List getUserAuthenticators() { return _userAuthenticators; @@ -242,6 +242,14 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M _userAuthenticators = authenticators; } + public List getSecurityCheckers() { + return _securityCheckers; + } + + public void setSecurityCheckers(List securityCheckers) { + this._securityCheckers = securityCheckers; + } + @Override public boolean configure(final String name, final Map params) throws ConfigurationException { _systemAccount = _accountDao.findById(AccountVO.ACCOUNT_ID_SYSTEM); diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index a6d0b1b5d11..23746ae64f9 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -208,13 +208,23 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Inject protected VMSnapshotDao _vmSnapshotDao; - @Inject protected List _planners; + public List getPlanners() { + return _planners; + } + public void setPlanners(List _planners) { + this._planners = _planners; + } - @Inject protected List _hostAllocators; + public List getHostAllocators() { + return _hostAllocators; + } + public void setHostAllocators(List _hostAllocators) { + this._hostAllocators = _hostAllocators; + } - @Inject + @Inject protected ResourceManager _resourceMgr; @Inject From 8bb09901442d79a7dddf33465bedaccb62190952 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Tue, 26 Mar 2013 14:25:52 -0700 Subject: [PATCH 16/90] CLOUDSTACK-1795: implement custom AOP to fully support legacy CloudStack AOP semantcis (rebase fixups) --- client/tomcatconf/applicationContext.xml.in | 78 ++++++++++--------- client/tomcatconf/componentContext.xml.in | 15 +++- .../tomcatconf/nonossComponentContext.xml.in | 11 +++ .../com/cloud/network/NetworkServiceImpl.java | 4 + 4 files changed, 72 insertions(+), 36 deletions(-) diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 608ffc43356..3c93b8a6801 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -177,8 +177,6 @@ - - @@ -382,15 +380,6 @@ - - - - - - - - - @@ -455,7 +444,6 @@ - @@ -509,10 +497,6 @@ - - - - @@ -536,10 +520,6 @@ - - - - @@ -590,14 +570,6 @@ - - - - - - - - @@ -619,12 +591,6 @@ - - - - - - @@ -672,6 +638,49 @@ + + + @@ -686,7 +695,6 @@ - diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 159bf851f9e..a6bd42032de 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -33,7 +33,6 @@ - @@ -103,7 +102,11 @@ + + + @@ -138,7 +141,11 @@ + + + @@ -163,9 +170,11 @@ + @@ -179,7 +188,9 @@ + @@ -191,9 +202,11 @@ + diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 13bb3f536a5..55a8f06592c 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -170,6 +170,7 @@ + @@ -194,7 +195,9 @@ + @@ -232,7 +235,9 @@ + @@ -262,9 +267,11 @@ + @@ -278,7 +285,9 @@ + @@ -295,9 +304,11 @@ + diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 130cb1b87bd..846d79e93cf 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -3081,9 +3081,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { PhysicalNetworkVO pvo = _physicalNetworkDao.findById(physicalNetworkId); DataCenterVO dvo = _dcDao.findById(pvo.getDataCenterId()); if (dvo.getNetworkType() == NetworkType.Basic) { + + // Baremetal is currently disabled +/* addProviderToPhysicalNetwork(physicalNetworkId, "BaremetalDhcpProvider", null, null); addProviderToPhysicalNetwork(physicalNetworkId, "BaremetalPxeProvider", null, null); addProviderToPhysicalNetwork(physicalNetworkId, "BaremetaUserdataProvider", null, null); +*/ } return null; } From 95011d6bf365dcc9335fb6edf37fe43c10371f10 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Tue, 26 Mar 2013 18:47:05 -0700 Subject: [PATCH 17/90] CLOUDSTACK-1818: add a missing file that is missed in previous patch --- .../cloud/upgrade/databaseCreatorContext.xml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 server/resources/com/cloud/upgrade/databaseCreatorContext.xml diff --git a/server/resources/com/cloud/upgrade/databaseCreatorContext.xml b/server/resources/com/cloud/upgrade/databaseCreatorContext.xml new file mode 100644 index 00000000000..d2ed26f426b --- /dev/null +++ b/server/resources/com/cloud/upgrade/databaseCreatorContext.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + From 3ab744d1009ded8b937edf102d881df3e8208691 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Wed, 27 Mar 2013 13:06:49 +0000 Subject: [PATCH 18/90] CLOUDSTACK-1795: implement custom AOP to fully support legacy CloudStack AOP semantcis Signed-off-by: Chip Childers --- client/tomcatconf/applicationContext.xml.in | 27 ++-- server/src/com/cloud/api/ApiDispatcher.java | 5 +- server/src/com/cloud/api/ApiServer.java | 39 +++-- .../com/cloud/cluster/ClusterManagerImpl.java | 4 +- .../cloud/event/ActionEventInterceptor.java | 52 ++---- ...ExternalLoadBalancerDeviceManagerImpl.java | 2 +- .../com/cloud/network/NetworkManagerImpl.java | 16 +- .../com/cloud/network/NetworkModelImpl.java | 6 +- .../src/com/cloud/server/StatsCollector.java | 3 +- .../cloud/utils/component/AdapterBase.java | 4 +- .../utils/component/ComponentContext.java | 32 ++-- .../ComponentInstantiationPostProcessor.java | 152 ++++++++++++++++++ .../ComponentMethodInterceptable.java | 24 +++ .../component/ComponentMethodInterceptor.java | 27 ++++ .../component/ComponentNamingPolicy.java | 63 ++++++++ .../cloud/utils/component/ManagerBase.java | 2 +- .../com/cloud/utils/db/GenericDaoBase.java | 29 +--- .../utils/db/TransactionContextBuilder.java | 70 +++----- .../utils/log/CglibThrowableRendererTest.java | 2 +- utils/test/resources/testContext.xml | 20 +-- 20 files changed, 383 insertions(+), 196 deletions(-) create mode 100644 utils/src/com/cloud/utils/component/ComponentInstantiationPostProcessor.java create mode 100644 utils/src/com/cloud/utils/component/ComponentMethodInterceptable.java create mode 100644 utils/src/com/cloud/utils/component/ComponentMethodInterceptor.java create mode 100644 utils/src/com/cloud/utils/component/ComponentNamingPolicy.java diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 3c93b8a6801..6bab4fdea25 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -35,27 +35,18 @@ - - - - - - - - - - - - - - + + + + + + + + + diff --git a/server/src/com/cloud/api/ApiDispatcher.java b/server/src/com/cloud/api/ApiDispatcher.java index f7a32364cf8..925d90a697d 100755 --- a/server/src/com/cloud/api/ApiDispatcher.java +++ b/server/src/com/cloud/api/ApiDispatcher.java @@ -138,8 +138,7 @@ public class ApiDispatcher { UserContext ctx = UserContext.current(); ctx.setAccountId(cmd.getEntityOwnerId()); - BaseCmd realCmdObj = ComponentContext.getTargetObject(cmd); - if (realCmdObj instanceof BaseAsyncCmd) { + if (cmd instanceof BaseAsyncCmd) { BaseAsyncCmd asyncCmd = (BaseAsyncCmd) cmd; String startEventId = params.get("ctxStartEventId"); @@ -171,8 +170,6 @@ public class ApiDispatcher { Map entitiesToAccess = new HashMap(); Map unpackedParams = cmd.unpackParams(params); - cmd = ComponentContext.getTargetObject(cmd); - if (cmd instanceof BaseListCmd) { Object pageSizeObj = unpackedParams.get(ApiConstants.PAGE_SIZE); Long pageSize = null; diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index 3c0857568b4..d842819ee48 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -388,16 +388,15 @@ public class ApiServer implements HttpRequestHandler, ApiServerService { Long callerUserId = ctx.getCallerUserId(); Account caller = ctx.getCaller(); - BaseCmd realCmdObj = ComponentContext.getTargetObject(cmdObj); // Queue command based on Cmd super class: // BaseCmd: cmd is dispatched to ApiDispatcher, executed, serialized and returned. // BaseAsyncCreateCmd: cmd params are processed and create() is called, then same workflow as BaseAsyncCmd. // BaseAsyncCmd: cmd is processed and submitted as an AsyncJob, job related info is serialized and returned. - if (realCmdObj instanceof BaseAsyncCmd) { + if (cmdObj instanceof BaseAsyncCmd) { Long objectId = null; String objectUuid = null; - if (realCmdObj instanceof BaseAsyncCreateCmd) { + if (cmdObj instanceof BaseAsyncCreateCmd) { BaseAsyncCreateCmd createCmd = (BaseAsyncCreateCmd) cmdObj; _dispatcher.dispatchCreateCmd(createCmd, params); objectId = createCmd.getEntityId(); @@ -433,7 +432,7 @@ public class ApiServer implements HttpRequestHandler, ApiServerService { ctx.setAccountId(asyncCmd.getEntityOwnerId()); Long instanceId = (objectId == null) ? asyncCmd.getInstanceId() : objectId; - AsyncJobVO job = new AsyncJobVO(callerUserId, caller.getId(), realCmdObj.getClass().getName(), + AsyncJobVO job = new AsyncJobVO(callerUserId, caller.getId(), cmdObj.getClass().getName(), ApiGsonHelper.getBuilder().create().toJson(params), instanceId, asyncCmd.getInstanceType()); long jobId = _asyncMgr.submitAsyncJob(job); @@ -457,22 +456,22 @@ public class ApiServer implements HttpRequestHandler, ApiServerService { // if the command is of the listXXXCommand, we will need to also return the // the job id and status if possible // For those listXXXCommand which we have already created DB views, this step is not needed since async job is joined in their db views. - if (realCmdObj instanceof BaseListCmd && !(realCmdObj instanceof ListVMsCmd) && !(realCmdObj instanceof ListRoutersCmd) - && !(realCmdObj instanceof ListSecurityGroupsCmd) - && !(realCmdObj instanceof ListTagsCmd) - && !(realCmdObj instanceof ListEventsCmd) - && !(realCmdObj instanceof ListVMGroupsCmd) - && !(realCmdObj instanceof ListProjectsCmd) - && !(realCmdObj instanceof ListProjectAccountsCmd) - && !(realCmdObj instanceof ListProjectInvitationsCmd) - && !(realCmdObj instanceof ListHostsCmd) - && !(realCmdObj instanceof ListVolumesCmd) - && !(realCmdObj instanceof ListUsersCmd) - && !(realCmdObj instanceof ListAccountsCmd) - && !(realCmdObj instanceof ListStoragePoolsCmd) - && !(realCmdObj instanceof ListDiskOfferingsCmd) - && !(realCmdObj instanceof ListServiceOfferingsCmd) - && !(realCmdObj instanceof ListZonesByCmd) + if (cmdObj instanceof BaseListCmd && !(cmdObj instanceof ListVMsCmd) && !(cmdObj instanceof ListRoutersCmd) + && !(cmdObj instanceof ListSecurityGroupsCmd) + && !(cmdObj instanceof ListTagsCmd) + && !(cmdObj instanceof ListEventsCmd) + && !(cmdObj instanceof ListVMGroupsCmd) + && !(cmdObj instanceof ListProjectsCmd) + && !(cmdObj instanceof ListProjectAccountsCmd) + && !(cmdObj instanceof ListProjectInvitationsCmd) + && !(cmdObj instanceof ListHostsCmd) + && !(cmdObj instanceof ListVolumesCmd) + && !(cmdObj instanceof ListUsersCmd) + && !(cmdObj instanceof ListAccountsCmd) + && !(cmdObj instanceof ListStoragePoolsCmd) + && !(cmdObj instanceof ListDiskOfferingsCmd) + && !(cmdObj instanceof ListServiceOfferingsCmd) + && !(cmdObj instanceof ListZonesByCmd) ) { buildAsyncListResponse((BaseListCmd) cmdObj, caller); } diff --git a/server/src/com/cloud/cluster/ClusterManagerImpl.java b/server/src/com/cloud/cluster/ClusterManagerImpl.java index 27e0e0381d2..118de41b738 100755 --- a/server/src/com/cloud/cluster/ClusterManagerImpl.java +++ b/server/src/com/cloud/cluster/ClusterManagerImpl.java @@ -365,11 +365,11 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager { try { // schedule a scan task immediately - if (ComponentContext.getTargetObject(_agentMgr) instanceof ClusteredAgentManagerImpl) { + if (_agentMgr instanceof ClusteredAgentManagerImpl) { if (s_logger.isDebugEnabled()) { s_logger.debug("Received notification as part of addHost command to start a host scan task"); } - ClusteredAgentManagerImpl clusteredAgentMgr = (ClusteredAgentManagerImpl)ComponentContext.getTargetObject(_agentMgr); + ClusteredAgentManagerImpl clusteredAgentMgr = (ClusteredAgentManagerImpl)_agentMgr; clusteredAgentMgr.scheduleHostScanTask(); } } catch (Exception e) { diff --git a/server/src/com/cloud/event/ActionEventInterceptor.java b/server/src/com/cloud/event/ActionEventInterceptor.java index a6c2565510e..01eefcd72b7 100644 --- a/server/src/com/cloud/event/ActionEventInterceptor.java +++ b/server/src/com/cloud/event/ActionEventInterceptor.java @@ -16,55 +16,22 @@ // under the License. package com.cloud.event; -import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; import org.apache.log4j.Logger; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.reflect.MethodSignature; import com.cloud.user.UserContext; -import com.cloud.utils.component.ComponentMethodProxyCache; +import com.cloud.utils.component.ComponentMethodInterceptor; -public class ActionEventInterceptor { +public class ActionEventInterceptor implements ComponentMethodInterceptor { private static final Logger s_logger = Logger.getLogger(ActionEventInterceptor.class); public ActionEventInterceptor() { } - public Object AroundAnyMethod(ProceedingJoinPoint call) throws Throwable { - MethodSignature methodSignature = (MethodSignature)call.getSignature(); - - // Note: AOP for ActionEvent is triggered annotation, no need to check the annotation on method again - Method targetMethod = ComponentMethodProxyCache.getTargetMethod( - methodSignature.getMethod(), call.getTarget()); - - if(targetMethod != null) { - EventVO event = interceptStart(targetMethod); - - boolean success = true; - Object ret = null; - try { - ret = call.proceed(); - } catch (Throwable e) { - success = false; - interceptException(targetMethod, event); - throw e; - } finally { - if(success){ - interceptComplete(targetMethod, event); - } - } - return ret; - } else { - s_logger.error("Unable to find the proxied method behind. Method: " + methodSignature.getMethod().getName()); - } - return call.proceed(); - } - - public EventVO interceptStart(AnnotatedElement element) { + @Override + public Object interceptStart(Method method, Object target) { EventVO event = null; - Method method = (Method)element; ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); if (actionEvent != null) { boolean async = actionEvent.async(); @@ -83,8 +50,8 @@ public class ActionEventInterceptor { return event; } - public void interceptComplete(AnnotatedElement element, EventVO event) { - Method method = (Method)element; + @Override + public void interceptComplete(Method method, Object target, Object event) { ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); if (actionEvent != null) { UserContext ctx = UserContext.current(); @@ -105,8 +72,8 @@ public class ActionEventInterceptor { } } - public void interceptException(AnnotatedElement element, EventVO event) { - Method method = (Method)element; + @Override + public void interceptException(Method method, Object target, Object event) { ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); if (actionEvent != null) { UserContext ctx = UserContext.current(); @@ -126,7 +93,8 @@ public class ActionEventInterceptor { } } - private boolean needToIntercept(Method method) { + @Override + public boolean needToIntercept(Method method) { ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); if (actionEvent != null) { return true; diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index cafe95aeb87..4853256db72 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -1113,7 +1113,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } NetworkElement element = _networkModel.getElementImplementingProvider(providers.get(0).getName()); - if (!(ComponentContext.getTargetObject(element) instanceof IpDeployer)) { + if (!(element instanceof IpDeployer)) { s_logger.error("The firewall provider for network " + network.getName() + " don't have ability to deploy IP address!"); return null; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index a4eac3687ad..42544ae1240 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -611,10 +611,10 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } IpDeployer deployer = null; NetworkElement element = _networkModel.getElementImplementingProvider(provider.getName()); - if (!(ComponentContext.getTargetObject(element) instanceof IpDeployingRequester)) { + if (!(element instanceof IpDeployingRequester)) { throw new CloudRuntimeException("Element " + element + " is not a IpDeployingRequester!"); } - deployer = ((IpDeployingRequester)ComponentContext.getTargetObject(element)).getIpDeployer(network); + deployer = ((IpDeployingRequester)element).getIpDeployer(network); if (deployer == null) { throw new CloudRuntimeException("Fail to get ip deployer for element: " + element); } @@ -1594,13 +1594,13 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L if (vmProfile.getType() == Type.User && element.getProvider() != null) { if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dhcp) && _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, element.getProvider()) && - (ComponentContext.getTargetObject(element) instanceof DhcpServiceProvider)) { + element instanceof DhcpServiceProvider) { DhcpServiceProvider sp = (DhcpServiceProvider) element; sp.addDhcpEntry(network, profile, vmProfile, dest, context); } if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.UserData) && _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.UserData, element.getProvider()) && - (ComponentContext.getTargetObject(element) instanceof UserDataServiceProvider)) { + element instanceof UserDataServiceProvider) { UserDataServiceProvider sp = (UserDataServiceProvider) element; sp.addPasswordAndUserdata(network, profile, vmProfile, dest, context); } @@ -3678,15 +3678,15 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L @Override public StaticNatServiceProvider getStaticNatProviderForNetwork(Network network) { NetworkElement element = getElementForServiceInNetwork(network, Service.StaticNat); - assert ComponentContext.getTargetObject(element) instanceof StaticNatServiceProvider; - return (StaticNatServiceProvider)ComponentContext.getTargetObject(element); + assert element instanceof StaticNatServiceProvider; + return (StaticNatServiceProvider)element; } @Override public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(Network network) { NetworkElement element = getElementForServiceInNetwork(network, Service.Lb); - assert ComponentContext.getTargetObject(element) instanceof LoadBalancingServiceProvider; - return ( LoadBalancingServiceProvider)ComponentContext.getTargetObject(element); + assert element instanceof LoadBalancingServiceProvider; + return (LoadBalancingServiceProvider)element; } @Override public boolean isNetworkInlineMode(Network network) { diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index 788e031d4a6..e7bdbca27c8 100644 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -404,9 +404,9 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { Network network = _networksDao.findById(networkId); NetworkElement oldElement = getElementImplementingProvider(oldProvider.getName()); NetworkElement newElement = getElementImplementingProvider(newProvider.getName()); - if (ComponentContext.getTargetObject(oldElement) instanceof IpDeployingRequester && ComponentContext.getTargetObject(newElement) instanceof IpDeployingRequester) { - IpDeployer oldIpDeployer = ((IpDeployingRequester)ComponentContext.getTargetObject(oldElement)).getIpDeployer(network); - IpDeployer newIpDeployer = ((IpDeployingRequester)ComponentContext.getTargetObject(newElement)).getIpDeployer(network); + if (oldElement instanceof IpDeployingRequester && newElement instanceof IpDeployingRequester) { + IpDeployer oldIpDeployer = ((IpDeployingRequester)oldElement).getIpDeployer(network); + IpDeployer newIpDeployer = ((IpDeployingRequester)newElement).getIpDeployer(network); if (!oldIpDeployer.getProvider().getName().equals(newIpDeployer.getProvider().getName())) { throw new InvalidParameterException("There would be multiple providers for IP " + publicIp.getAddress() + "!"); } diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index 7dcf091f3e3..b1f4a570f48 100755 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -65,6 +65,7 @@ import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.utils.NumbersUtil; +import com.cloud.utils.component.ComponentMethodInterceptable; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.SearchCriteria; import com.cloud.vm.UserVmManager; @@ -77,7 +78,7 @@ import com.cloud.vm.dao.UserVmDao; * */ @Component -public class StatsCollector { +public class StatsCollector implements ComponentMethodInterceptable { public static final Logger s_logger = Logger.getLogger(StatsCollector.class.getName()); private static StatsCollector s_instance = null; diff --git a/utils/src/com/cloud/utils/component/AdapterBase.java b/utils/src/com/cloud/utils/component/AdapterBase.java index ea5e9611ab6..8353cee967a 100644 --- a/utils/src/com/cloud/utils/component/AdapterBase.java +++ b/utils/src/com/cloud/utils/component/AdapterBase.java @@ -19,7 +19,7 @@ package com.cloud.utils.component; import java.util.List; // Typical Adapter implementation. -public class AdapterBase extends ComponentLifecycleBase implements Adapter { +public class AdapterBase extends ComponentLifecycleBase implements Adapter, ComponentMethodInterceptable { public AdapterBase() { // set default run level for adapter components @@ -29,7 +29,7 @@ public class AdapterBase extends ComponentLifecycleBase implements Adapter { public static T getAdapterByName(List adapters, String name) { for(T adapter : adapters) { if(adapter.getName() != null && adapter.getName().equalsIgnoreCase(name)) - return ComponentContext.getTargetObject(adapter); + return adapter; } return null; } diff --git a/utils/src/com/cloud/utils/component/ComponentContext.java b/utils/src/com/cloud/utils/component/ComponentContext.java index ca7ad5c7b4b..d11d3542e7f 100644 --- a/utils/src/com/cloud/utils/component/ComponentContext.java +++ b/utils/src/com/cloud/utils/component/ComponentContext.java @@ -59,16 +59,18 @@ public class ComponentContext implements ApplicationContextAware { public static ApplicationContext getApplicationContext() { return s_appContext; - } - + } + public static void initComponentsLifeCycle() { - // Run the SystemIntegrityCheckers first - Map integrityCheckers = getApplicationContext().getBeansOfType(SystemIntegrityChecker.class); - for (Entry entry : integrityCheckers.entrySet() ){ - s_logger.info ("Running SystemIntegrityChecker " + entry.getKey()); - entry.getValue().check(); - } - + AutowireCapableBeanFactory beanFactory = s_appContext.getAutowireCapableBeanFactory(); + + Map interceptableComponents = getApplicationContext().getBeansOfType( + ComponentMethodInterceptable.class); + for(Map.Entry entry : interceptableComponents.entrySet()) { + Object bean = getTargetObject(entry.getValue()); + beanFactory.configureBean(bean, entry.getKey()); + } + Map lifecyleComponents = getApplicationContext().getBeansOfType(ComponentLifecycle.class); Map[] classifiedComponents = new Map[ComponentLifecycle.MAX_RUN_LEVELS]; @@ -103,6 +105,18 @@ public class ComponentContext implements ApplicationContextAware { avoidMap.put(implClassName, implClassName); } } + + // Run the SystemIntegrityCheckers first + Map integrityCheckers = getApplicationContext().getBeansOfType(SystemIntegrityChecker.class); + for (Entry entry : integrityCheckers.entrySet() ){ + s_logger.info ("Running SystemIntegrityChecker " + entry.getKey()); + try { + entry.getValue().check(); + } catch(Throwable e) { + s_logger.error("System integrity check failed. Refuse to startup"); + System.exit(1); + } + } // starting phase avoidMap.clear(); diff --git a/utils/src/com/cloud/utils/component/ComponentInstantiationPostProcessor.java b/utils/src/com/cloud/utils/component/ComponentInstantiationPostProcessor.java new file mode 100644 index 00000000000..cb64975d585 --- /dev/null +++ b/utils/src/com/cloud/utils/component/ComponentInstantiationPostProcessor.java @@ -0,0 +1,152 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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.component; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import net.sf.cglib.proxy.Callback; +import net.sf.cglib.proxy.CallbackFilter; +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.MethodProxy; +import net.sf.cglib.proxy.NoOp; + +import org.apache.log4j.Logger; +import org.springframework.beans.BeansException; +import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor; + +import com.cloud.utils.Pair; + +public class ComponentInstantiationPostProcessor implements InstantiationAwareBeanPostProcessor { + private static final Logger s_logger = Logger.getLogger(ComponentInstantiationPostProcessor.class); + + private List _interceptors = new ArrayList(); + private Callback[] _callbacks; + private CallbackFilter _callbackFilter; + + public ComponentInstantiationPostProcessor() { + _callbacks = new Callback[2]; + _callbacks[0] = NoOp.INSTANCE; + _callbacks[1] = new InterceptorDispatcher(); + + _callbackFilter = new InterceptorFilter(); + } + + public List getInterceptors() { + return _interceptors; + } + + public void setInterceptors(List interceptors) { + _interceptors = interceptors; + } + + private Callback[] getCallbacks() { + return _callbacks; + } + + private CallbackFilter getCallbackFilter() { + return _callbackFilter; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + @Override + public Object postProcessBeforeInstantiation(Class beanClass, + String beanName) throws BeansException { + if(_interceptors != null && _interceptors.size() > 0) { + if(ComponentMethodInterceptable.class.isAssignableFrom(beanClass)) { + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(beanClass); + enhancer.setCallbacks(getCallbacks()); + enhancer.setCallbackFilter(getCallbackFilter()); + enhancer.setNamingPolicy(ComponentNamingPolicy.INSTANCE); + + Object bean = enhancer.create(); + return bean; + } + } + return null; + } + + @Override + public boolean postProcessAfterInstantiation(Object bean, String beanName) + throws BeansException { + return true; + } + + @Override + public PropertyValues postProcessPropertyValues(PropertyValues pvs, + PropertyDescriptor[] pds, Object bean, String beanName) + throws BeansException { + return pvs; + } + + protected class InterceptorDispatcher implements MethodInterceptor { + @Override + public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { + ArrayList> interceptors = new ArrayList>(); + + for (ComponentMethodInterceptor interceptor : getInterceptors()) { + if (interceptor.needToIntercept(method)) { + Object objReturnedInInterceptStart = interceptor.interceptStart(method, target); + interceptors.add(new Pair(interceptor, objReturnedInInterceptStart)); + } + } + boolean success = false; + try { + Object obj = methodProxy.invokeSuper(target, args); + success = true; + return obj; + } finally { + for (Pair interceptor : interceptors) { + if (success) { + interceptor.first().interceptComplete(method, target, interceptor.second()); + } else { + interceptor.first().interceptException(method, target, interceptor.second()); + } + } + } + } + } + + protected class InterceptorFilter implements CallbackFilter { + @Override + public int accept(Method method) { + for(ComponentMethodInterceptor interceptor : getInterceptors()) { + + if (interceptor.needToIntercept(method)) { + return 1; + } + } + return 0; + } + } +} diff --git a/utils/src/com/cloud/utils/component/ComponentMethodInterceptable.java b/utils/src/com/cloud/utils/component/ComponentMethodInterceptable.java new file mode 100644 index 00000000000..5a95c43ea93 --- /dev/null +++ b/utils/src/com/cloud/utils/component/ComponentMethodInterceptable.java @@ -0,0 +1,24 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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.component; + +/** + * Marker interface to work with CGLIB based CloudStack legacy AOP + * + */ +public interface ComponentMethodInterceptable { +} diff --git a/utils/src/com/cloud/utils/component/ComponentMethodInterceptor.java b/utils/src/com/cloud/utils/component/ComponentMethodInterceptor.java new file mode 100644 index 00000000000..39a81d0349c --- /dev/null +++ b/utils/src/com/cloud/utils/component/ComponentMethodInterceptor.java @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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.component; + +import java.lang.reflect.Method; + +public interface ComponentMethodInterceptor { + boolean needToIntercept(Method method); + + Object interceptStart(Method method, Object target); + void interceptComplete(Method method, Object target, Object objReturnedInInterceptStart); + void interceptException(Method method, Object target, Object objReturnedInInterceptStart); +} diff --git a/utils/src/com/cloud/utils/component/ComponentNamingPolicy.java b/utils/src/com/cloud/utils/component/ComponentNamingPolicy.java new file mode 100644 index 00000000000..5659a487395 --- /dev/null +++ b/utils/src/com/cloud/utils/component/ComponentNamingPolicy.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 +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT 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.component; + +import net.sf.cglib.core.NamingPolicy; +import net.sf.cglib.core.Predicate; + +/** + * Copied/Modified from Spring source + * + */ +public class ComponentNamingPolicy implements NamingPolicy { + + public static final ComponentNamingPolicy INSTANCE = new ComponentNamingPolicy(); + + public String getClassName(String prefix, String source, Object key, Predicate names) { + if (prefix == null) { + prefix = "net.sf.cglib.empty.Object"; + } else if (prefix.startsWith("java")) { + prefix = "_" + prefix; + } + String base = + prefix + "_" + + source.substring(source.lastIndexOf('.') + 1) + + getTag() + "_" + + Integer.toHexString(key.hashCode()); + String attempt = base; + int index = 2; + while (names.evaluate(attempt)) + attempt = base + "_" + index++; + return attempt; + } + + /** + * Returns a string which is incorporated into every generated class name. + * By default returns "ByCloudStack" + */ + protected String getTag() { + return "ByCloudStack"; + } + + public int hashCode() { + return getTag().hashCode(); + } + + public boolean equals(Object o) { + return (o instanceof ComponentNamingPolicy) && ((ComponentNamingPolicy) o).getTag().equals(getTag()); + } +} diff --git a/utils/src/com/cloud/utils/component/ManagerBase.java b/utils/src/com/cloud/utils/component/ManagerBase.java index 529ef629201..1908f4e1051 100644 --- a/utils/src/com/cloud/utils/component/ManagerBase.java +++ b/utils/src/com/cloud/utils/component/ManagerBase.java @@ -16,7 +16,7 @@ // under the License. package com.cloud.utils.component; -public class ManagerBase extends ComponentLifecycleBase { +public class ManagerBase extends ComponentLifecycleBase implements ComponentMethodInterceptable { public ManagerBase() { // set default run level for manager components setRunLevel(ComponentLifecycle.RUN_LEVEL_COMPONENT_BOOTSTRAP); diff --git a/utils/src/com/cloud/utils/db/GenericDaoBase.java b/utils/src/com/cloud/utils/db/GenericDaoBase.java index afb12471da7..f0fc7006003 100755 --- a/utils/src/com/cloud/utils/db/GenericDaoBase.java +++ b/utils/src/com/cloud/utils/db/GenericDaoBase.java @@ -71,6 +71,7 @@ import com.cloud.utils.Ternary; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ComponentLifecycle; import com.cloud.utils.component.ComponentLifecycleBase; +import com.cloud.utils.component.ComponentMethodInterceptable; import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.db.SearchCriteria.SelectType; import com.cloud.utils.exception.CloudRuntimeException; @@ -114,7 +115,7 @@ import edu.emory.mathcs.backport.java.util.Collections; * **/ @DB -public abstract class GenericDaoBase extends ComponentLifecycleBase implements GenericDao { +public abstract class GenericDaoBase extends ComponentLifecycleBase implements GenericDao, ComponentMethodInterceptable { private final static Logger s_logger = Logger.getLogger(GenericDaoBase.class); protected final static TimeZone s_gmtTimeZone = TimeZone.getTimeZone("GMT"); @@ -193,15 +194,14 @@ public abstract class GenericDaoBase extends Compone ( (Class)((Class)t).getGenericSuperclass()).getGenericSuperclass()).getActualTypeArguments()[0]; } -/* - s_daoMaps.put(_entityBeanType, ComponentContext.getComponent(this.getClass())); + s_daoMaps.put(_entityBeanType, this); Class[] interphaces = _entityBeanType.getInterfaces(); if (interphaces != null) { for (Class interphace : interphaces) { - s_daoMaps.put(interphace, ComponentContext.getComponent(this.getClass())); + s_daoMaps.put(interphace, this); } } -*/ + _table = DbUtil.getTableName(_entityBeanType); final SqlGenerator generator = new SqlGenerator(_entityBeanType); @@ -1750,25 +1750,6 @@ public abstract class GenericDaoBase extends Compone public boolean configure(final String name, final Map params) throws ConfigurationException { _name = name; - Class daoInterface = null; - for(Class intf : this.getClass().getInterfaces()) { - if(GenericDao.class.isAssignableFrom(intf)) { - daoInterface = intf; - break; - } - } - - if(daoInterface != null) { - s_logger.info("Register dao interface in GenericDaoBase entity-DAO map. " + daoInterface.getName()); - s_daoMaps.put(_entityBeanType, (GenericDao) ComponentContext.getComponent(daoInterface)); - Class[] interphaces = _entityBeanType.getInterfaces(); - if (interphaces != null) { - for (Class interphace : interphaces) { - s_daoMaps.put(interphace, (GenericDao) ComponentContext.getComponent(daoInterface)); - } - } - } - final String value = (String)params.get("lock.timeout"); _timeoutSeconds = NumbersUtil.parseInt(value, 300); diff --git a/utils/src/com/cloud/utils/db/TransactionContextBuilder.java b/utils/src/com/cloud/utils/db/TransactionContextBuilder.java index 7ca33ab5f5d..40fcbbf5593 100644 --- a/utils/src/com/cloud/utils/db/TransactionContextBuilder.java +++ b/utils/src/com/cloud/utils/db/TransactionContextBuilder.java @@ -18,65 +18,20 @@ package com.cloud.utils.db; import java.lang.reflect.Method; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.log4j.Logger; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.reflect.MethodSignature; +import com.cloud.utils.component.ComponentMethodInterceptor; -import com.cloud.utils.component.ComponentMethodProxyCache; - -public class TransactionContextBuilder implements MethodInterceptor { - private static final Logger s_logger = Logger.getLogger(TransactionContextBuilder.class); +public class TransactionContextBuilder implements ComponentMethodInterceptor { public TransactionContextBuilder() { } - public Object AroundAnyMethod(ProceedingJoinPoint call) throws Throwable { - MethodSignature methodSignature = (MethodSignature)call.getSignature(); - Method targetMethod = methodSignature.getMethod(); - if(needToIntercept(targetMethod, call.getTarget())) { - Transaction txn = Transaction.open(call.getSignature().getName()); - Object ret = null; - try { - ret = call.proceed(); - } finally { - txn.close(); - } - return ret; - } - return call.proceed(); - } - @Override - public Object invoke(MethodInvocation method) throws Throwable { - Method targetMethod = method.getMethod(); - - if(needToIntercept(targetMethod, method.getThis())) { - Transaction txn = Transaction.open(targetMethod.getName()); - Object ret = null; - try { - ret = method.proceed(); - } finally { - txn.close(); - } - return ret; - } - return method.proceed(); - } - - private boolean needToIntercept(Method method, Object target) { + public boolean needToIntercept(Method method) { DB db = method.getAnnotation(DB.class); if (db != null) { return true; } Class clazz = method.getDeclaringClass(); - if(clazz.isInterface()) { - clazz = target.getClass(); - Method targetMethod = ComponentMethodProxyCache.getTargetMethod(method, target); - if(targetMethod != null && targetMethod.getAnnotation(DB.class) != null) - return true; - } do { db = clazz.getAnnotation(DB.class); @@ -88,4 +43,23 @@ public class TransactionContextBuilder implements MethodInterceptor { return false; } + + @Override + public Object interceptStart(Method method, Object target) { + return Transaction.open(method.getName()); + } + + @Override + public void interceptComplete(Method method, Object target, Object objReturnedInInterceptStart) { + Transaction txn = (Transaction)objReturnedInInterceptStart; + if(txn != null) + txn.close(); + } + + @Override + public void interceptException(Method method, Object target, Object objReturnedInInterceptStart) { + Transaction txn = (Transaction)objReturnedInInterceptStart; + if(txn != null) + txn.close(); + } } diff --git a/utils/test/com/cloud/utils/log/CglibThrowableRendererTest.java b/utils/test/com/cloud/utils/log/CglibThrowableRendererTest.java index ae50f5b786b..5e3571a8984 100644 --- a/utils/test/com/cloud/utils/log/CglibThrowableRendererTest.java +++ b/utils/test/com/cloud/utils/log/CglibThrowableRendererTest.java @@ -80,7 +80,7 @@ public class CglibThrowableRendererTest extends TestCase { Writer w = new CharArrayWriter(); Logger alt = getAlternateLogger(w, null); - TestClass test = ComponentContext.inject(TestClass.class); + TestClass test = new TestClass(); try { test.exception(); } catch (Exception e) { diff --git a/utils/test/resources/testContext.xml b/utils/test/resources/testContext.xml index 26cdaaed32f..5cccfcdd745 100644 --- a/utils/test/resources/testContext.xml +++ b/utils/test/resources/testContext.xml @@ -33,22 +33,18 @@ - + - - - - - - - - - + + + + + + + From 85971b51948e33435957e653f39f9aac82824452 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Wed, 27 Mar 2013 13:08:03 +0000 Subject: [PATCH 19/90] CLOUDSTACK-1818: make DababaseCreator ready to invoke DatabaseUpgradeChecker, adjust Component startup sequence for integrity checkers Signed-off-by: Chip Childers --- client/tomcatconf/applicationContext.xml.in | 2 +- server/pom.xml | 8 +++++++ .../com/cloud/upgrade/DatabaseCreator.java | 7 ++++++ .../utils/component/ComponentContext.java | 24 +++++++++---------- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 6bab4fdea25..17725f0761c 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -35,6 +35,7 @@ + @@ -688,7 +689,6 @@ - diff --git a/server/pom.xml b/server/pom.xml index b39f731b4c9..1bc0f6958d7 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -103,6 +103,14 @@ install src test + + + resources + + **/*.xml + + + test/resources diff --git a/server/src/com/cloud/upgrade/DatabaseCreator.java b/server/src/com/cloud/upgrade/DatabaseCreator.java index 9841faeb94b..9b1be6bc6b6 100755 --- a/server/src/com/cloud/upgrade/DatabaseCreator.java +++ b/server/src/com/cloud/upgrade/DatabaseCreator.java @@ -27,6 +27,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; +import org.springframework.context.support.ClassPathXmlApplicationContext; + import com.cloud.utils.PropertiesUtil; import com.cloud.utils.component.ComponentContext; @@ -117,6 +119,11 @@ public class DatabaseCreator { } public static void main(String[] args) { + + ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext( + new String[] {"/com/cloud/upgrade/databaseCreatorContext.xml"}); + appContext.getBean(ComponentContext.class); + String dbPropsFile = ""; List sqlFiles = new ArrayList(); List upgradeClasses = new ArrayList(); diff --git a/utils/src/com/cloud/utils/component/ComponentContext.java b/utils/src/com/cloud/utils/component/ComponentContext.java index d11d3542e7f..796d4ec0282 100644 --- a/utils/src/com/cloud/utils/component/ComponentContext.java +++ b/utils/src/com/cloud/utils/component/ComponentContext.java @@ -81,6 +81,18 @@ public class ComponentContext implements ApplicationContextAware { for(Map.Entry entry : lifecyleComponents.entrySet()) { classifiedComponents[entry.getValue().getRunLevel()].put(entry.getKey(), entry.getValue()); } + + // Run the SystemIntegrityCheckers first + Map integrityCheckers = getApplicationContext().getBeansOfType(SystemIntegrityChecker.class); + for (Entry entry : integrityCheckers.entrySet() ){ + s_logger.info ("Running SystemIntegrityChecker " + entry.getKey()); + try { + entry.getValue().check(); + } catch(Throwable e) { + s_logger.error("System integrity check failed. Refuse to startup"); + System.exit(1); + } + } // configuration phase Map avoidMap = new HashMap(); @@ -105,18 +117,6 @@ public class ComponentContext implements ApplicationContextAware { avoidMap.put(implClassName, implClassName); } } - - // Run the SystemIntegrityCheckers first - Map integrityCheckers = getApplicationContext().getBeansOfType(SystemIntegrityChecker.class); - for (Entry entry : integrityCheckers.entrySet() ){ - s_logger.info ("Running SystemIntegrityChecker " + entry.getKey()); - try { - entry.getValue().check(); - } catch(Throwable e) { - s_logger.error("System integrity check failed. Refuse to startup"); - System.exit(1); - } - } // starting phase avoidMap.clear(); From c3c7e7e57086dc4cdbca2dcb4ce0fe4a67d5ad62 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Wed, 27 Mar 2013 14:31:05 -0700 Subject: [PATCH 20/90] CLOUDSTACK-1746: update usage server startup configuration --- usage/resources/usageApplicationContext.xml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/usage/resources/usageApplicationContext.xml b/usage/resources/usageApplicationContext.xml index 0340038a06a..fc67e0ad32a 100644 --- a/usage/resources/usageApplicationContext.xml +++ b/usage/resources/usageApplicationContext.xml @@ -38,17 +38,16 @@ - - - - - - - - + + + + + + + + + From 9dcaf508c9bea022d1704ba545f935df84af782c Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Wed, 27 Mar 2013 14:51:58 -0700 Subject: [PATCH 21/90] CLOUDSTACK-1825: Update AWSAPI server's XML configuration --- awsapi/conf/applicationContext.xml.in | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/awsapi/conf/applicationContext.xml.in b/awsapi/conf/applicationContext.xml.in index 0a24df214af..8b3a0222262 100644 --- a/awsapi/conf/applicationContext.xml.in +++ b/awsapi/conf/applicationContext.xml.in @@ -37,17 +37,19 @@ - - - - - - - - + + - + + + + + + + + + From 2654e645c7f9f185ae212a721f333a342866ff7d Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Thu, 28 Mar 2013 17:34:15 -0700 Subject: [PATCH 22/90] Fixup after merging 4.1 fixes to master --- client/tomcatconf/applicationContext.xml.in | 76 ++++++++++++------- client/tomcatconf/componentContext.xml.in | 8 +- .../tomcatconf/nonossComponentContext.xml.in | 8 +- 3 files changed, 61 insertions(+), 31 deletions(-) diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 17725f0761c..ca6b4020364 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -169,10 +169,13 @@ + + + @@ -200,12 +203,14 @@ + + - + @@ -213,7 +218,6 @@ - @@ -221,12 +225,20 @@ + + + + + + + + @@ -238,6 +250,7 @@ + @@ -249,6 +262,7 @@ + @@ -286,7 +300,6 @@ - @@ -314,6 +327,8 @@ + + @@ -322,6 +337,7 @@ + @@ -340,10 +356,8 @@ + - - - - + - - + + + + - - - - - - - + @@ -436,7 +446,7 @@ - + @@ -591,8 +601,6 @@ - - @@ -676,17 +684,19 @@ - - + + + + @@ -696,12 +706,9 @@ - - - - + @@ -710,7 +717,6 @@ - @@ -725,20 +731,36 @@ + + + - + + + + + + + + + + + + + + diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index a6bd42032de..9d95e150129 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -71,7 +71,9 @@ - + + + @@ -81,7 +83,9 @@ - + + + diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 55a8f06592c..0b02eb687c9 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -163,7 +163,9 @@ - + + + @@ -174,7 +176,9 @@ - + + + From 5782abf8f80fce929e3d6e20068bc165f2360426 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Fri, 29 Mar 2013 11:01:40 -0700 Subject: [PATCH 23/90] Update unit test configuraitons to new custom Spring AOP --- .../CreateNetworkOfferingTest.java | 15 +++++++++-- .../resources/CloneSettingDaoTestContext.xml | 20 +++++++------- .../SecurityGroupManagerTestContext.xml | 19 +++++++------ .../test/resources/SnapshotDaoTestContext.xml | 20 +++++++------- .../resources/StoragePoolDaoTestContext.xml | 20 +++++++------- .../test/resources/VpcApiUnitTestContext.xml | 20 +++++++------- server/test/resources/VpcTestContext.xml | 21 ++++++++------- .../test/resources/createNetworkOffering.xml | 22 ++++++++------- server/test/resources/testContext.xml | 27 +++++++------------ 9 files changed, 100 insertions(+), 84 deletions(-) diff --git a/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java index 135395980c5..67fae3349c1 100644 --- a/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/test/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -46,7 +46,12 @@ import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.UserContext; import com.cloud.user.UserContextInitializer; +import com.cloud.user.UserVO; +import com.cloud.utils.component.ComponentContext; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:/createNetworkOffering.xml") @@ -63,18 +68,24 @@ public class CreateNetworkOfferingTest extends TestCase{ NetworkOfferingDao offDao; @Inject - UserContextInitializer usrCtxInit; + NetworkOfferingServiceMapDao mapDao; @Inject - NetworkOfferingServiceMapDao mapDao; + AccountManager accountMgr; @Before public void setUp() { + ComponentContext.initComponentsLifeCycle(); + ConfigurationVO configVO = new ConfigurationVO("200", "200","200","200","200","200"); Mockito.when(configDao.findByName(Mockito.anyString())).thenReturn(configVO); Mockito.when(offDao.persist(Mockito.any(NetworkOfferingVO.class))).thenReturn(new NetworkOfferingVO()); Mockito.when(mapDao.persist(Mockito.any(NetworkOfferingServiceMapVO.class))).thenReturn(new NetworkOfferingServiceMapVO()); + Mockito.when(accountMgr.getSystemUser()).thenReturn(new UserVO(1)); + Mockito.when(accountMgr.getSystemAccount()).thenReturn(new AccountVO(2)); + + UserContext.registerContext(accountMgr.getSystemUser().getId(), accountMgr.getSystemAccount(), null, false); } //Test Shared network offerings diff --git a/server/test/resources/CloneSettingDaoTestContext.xml b/server/test/resources/CloneSettingDaoTestContext.xml index 1d13500a2e9..cb350041214 100644 --- a/server/test/resources/CloneSettingDaoTestContext.xml +++ b/server/test/resources/CloneSettingDaoTestContext.xml @@ -23,17 +23,19 @@ - - - - - - - - + - + + + + + + + + + + diff --git a/server/test/resources/SecurityGroupManagerTestContext.xml b/server/test/resources/SecurityGroupManagerTestContext.xml index b36599e2987..7ff2976dd6b 100644 --- a/server/test/resources/SecurityGroupManagerTestContext.xml +++ b/server/test/resources/SecurityGroupManagerTestContext.xml @@ -23,17 +23,16 @@ - - - - - - - - - + - + + + + + + + + diff --git a/server/test/resources/SnapshotDaoTestContext.xml b/server/test/resources/SnapshotDaoTestContext.xml index e479e2ebf39..3b87888c3ac 100644 --- a/server/test/resources/SnapshotDaoTestContext.xml +++ b/server/test/resources/SnapshotDaoTestContext.xml @@ -23,17 +23,19 @@ - - - - - - - - + - + + + + + + + + + + diff --git a/server/test/resources/StoragePoolDaoTestContext.xml b/server/test/resources/StoragePoolDaoTestContext.xml index 4936a83b361..345827e9965 100644 --- a/server/test/resources/StoragePoolDaoTestContext.xml +++ b/server/test/resources/StoragePoolDaoTestContext.xml @@ -23,17 +23,19 @@ - - - - - - - - + - + + + + + + + + + + diff --git a/server/test/resources/VpcApiUnitTestContext.xml b/server/test/resources/VpcApiUnitTestContext.xml index d9330229383..1dc11227601 100644 --- a/server/test/resources/VpcApiUnitTestContext.xml +++ b/server/test/resources/VpcApiUnitTestContext.xml @@ -24,17 +24,19 @@ - - - - - - - - + - + + + + + + + + + + diff --git a/server/test/resources/VpcTestContext.xml b/server/test/resources/VpcTestContext.xml index 7ed5f570bb3..530373620d0 100644 --- a/server/test/resources/VpcTestContext.xml +++ b/server/test/resources/VpcTestContext.xml @@ -21,15 +21,20 @@ http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + - - - + - - - - + + + + + + + + + + - - - + + - - - - + + + + + + + + + + @@ -38,7 +43,4 @@ - - - diff --git a/server/test/resources/testContext.xml b/server/test/resources/testContext.xml index b2603867828..6a211981c6d 100644 --- a/server/test/resources/testContext.xml +++ b/server/test/resources/testContext.xml @@ -37,26 +37,19 @@ - - - - - - + - - - - - - - + + + + + + + + + @@ -200,7 +200,7 @@ maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreType="JKS" - keystoreFile="/etc/cloud/management/cloudmanagementserver.keystore" + keystoreFile="/etc/cloudstack/management/cloudmanagementserver.keystore" keystorePass="vmops.com"/> diff --git a/client/tomcatconf/tomcat6-ssl.conf.in b/client/tomcatconf/tomcat6-ssl.conf.in index 84b6d6275bb..0d2650871b6 100644 --- a/client/tomcatconf/tomcat6-ssl.conf.in +++ b/client/tomcatconf/tomcat6-ssl.conf.in @@ -40,7 +40,7 @@ CATALINA_TMPDIR="@MSENVIRON@/temp" # Use JAVA_OPTS to set java.library.path for libtcnative.so #JAVA_OPTS="-Djava.library.path=/usr/lib64" -JAVA_OPTS="-Djava.awt.headless=true -Djavax.net.ssl.trustStore=/etc/cloud/management/cloudmanagementserver.keystore -Djavax.net.ssl.trustStorePassword=vmops.com -Dcom.sun.management.jmxremote.port=45219 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=@MSLOGDIR@ -XX:MaxPermSize=800m -XX:PermSize=512M" +JAVA_OPTS="-Djava.awt.headless=true -Djavax.net.ssl.trustStore=/etc/cloudstack/management/cloudmanagementserver.keystore -Djavax.net.ssl.trustStorePassword=vmops.com -Dcom.sun.management.jmxremote.port=45219 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=@MSLOGDIR@ -XX:MaxPermSize=800m -XX:PermSize=512M" # What user should run tomcat TOMCAT_USER="@MSUSER@" From 44a0facd38159d53365a6444f4e025684add29b9 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Sun, 31 Mar 2013 14:14:52 +0200 Subject: [PATCH 31/90] debian: Copy management server configuration from old location Signed-off-by: Wido den Hollander --- debian/cloudstack-management.postinst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/debian/cloudstack-management.postinst b/debian/cloudstack-management.postinst index 4e9b046caff..293810a97e7 100644 --- a/debian/cloudstack-management.postinst +++ b/debian/cloudstack-management.postinst @@ -20,7 +20,7 @@ if [ "$1" = configure ]; then if ! getent passwd cloud >/dev/null; then adduser --quiet --system --group --no-create-home --home /var/lib/cloudstack/management cloud else - usermod -m -d /var/lib/cloudstack/management cloud + usermod -m -d /var/lib/cloudstack/management cloud || true fi for i in /var/cache/cloudstack/management \ @@ -36,6 +36,20 @@ if [ "$1" = configure ]; then chgrp cloud $i done + OLDCONFDIR="/etc/cloud/management" + NEWCONFDIR="/etc/cloudstack/management" + CONFFILES="db.properties db-enc.properties cloud.keystore key" + + # Copy old configuration so the admin doesn't have to do that + # Only do so when we are installing for the first time + if [ -z "$2" ]; then + for FILE in $CONFFILES; do + if [ -f "$OLDCONFDIR/${FILE}" ]; then + cp -a $OLDCONFDIR/$FILE $NEWCONFDIR/$FILE + fi + done + fi + chmod 0640 /etc/cloudstack/management/db.properties chgrp cloud /etc/cloudstack/management/db.properties fi From 45eb9fdf8bf0e721555921464c239e9f3af03c37 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Sun, 31 Mar 2013 17:02:08 +0200 Subject: [PATCH 32/90] git: Add debian packaging files to .gitignore --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitignore b/.gitignore index 15f7f91c864..f41862895ec 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,11 @@ docs/runbook/tmp docs/runbook/publish .project Gemfile.lock +debian/tmp +debian/files +debian/cloudstack-*/* +debian/*.substvars +debian/*.debhelper +replace.properties.tmp +build-indep-stamp +configure-stamp From 7a3a1c792a0c263ccde74e6156afaa57470b2847 Mon Sep 17 00:00:00 2001 From: Bharat Kumar Date: Fri, 29 Mar 2013 17:14:59 +0530 Subject: [PATCH 33/90] Cloudstack-1739 Signed-off-by: Abhinandan Prateek --- .../hypervisor/kvm/resource/LibvirtComputingResource.java | 4 ++-- .../src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 6852e2cf711..7b70b62f694 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -3066,8 +3066,8 @@ ServerResource { if (vmTO.getMinRam() != vmTO.getMaxRam()){ grd.setMemBalloning(true); - grd.setCurrentMem((int)vmTO.getMinRam()/1024); - grd.setMemorySize((int)vmTO.getMaxRam()/1024); + grd.setCurrentMem((long)vmTO.getMinRam()/1024); + grd.setMemorySize((long)vmTO.getMaxRam()/1024); } else{ grd.setMemorySize(vmTO.getMaxRam() / 1024); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index c93aeeb2dd6..3d896a74c64 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -113,7 +113,7 @@ public class LibvirtVMDef { public static class GuestResourceDef { private long _mem; - private int _currentMem = -1; + private long _currentMem = -1; private String _memBacking; private int _vcpu = -1; private boolean _memBalloning= false; @@ -122,7 +122,7 @@ public class LibvirtVMDef { _mem = mem; } - public void setCurrentMem(int currMem) { + public void setCurrentMem(long currMem) { _currentMem = currMem; } From 355589c1f0c583cbbdc601f74dba504064f81bac Mon Sep 17 00:00:00 2001 From: Bharat Kumar Date: Mon, 1 Apr 2013 10:43:16 +0530 Subject: [PATCH 34/90] CLOUDSTACK-1395 Upgrade script for cpu and ram overcommit. It sets the overcommit values of all the clusters to 1. --- .../cloud/upgrade/dao/Upgrade410to420.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java index d26da4dc916..8ce118f3cbc 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -76,8 +76,45 @@ public class Upgrade410to420 implements DbUpgrade { } } } + updateCluster_details(conn); } + //update the cluster_details table with default overcommit ratios. + private void updateCluster_details(Connection conn) { + PreparedStatement pstmt = null; + PreparedStatement pstmt1 = null; + PreparedStatement pstmt2 =null; + ResultSet rs = null; + + try { + pstmt = conn.prepareStatement("select id from `cloud`.`cluster`"); + pstmt1=conn.prepareStatement("INSERT INTO `cloud`.`cluster_details` (cluster_id, name, value) VALUES(?, 'cpuOvercommitRatio', '1')"); + pstmt2=conn.prepareStatement("INSERT INTO `cloud`.`cluster_details` (cluster_id, name, value) VALUES(?, 'memoryOvercommitRatio', '1')"); + rs = pstmt.executeQuery(); + while (rs.next()) { + long id = rs.getLong(1); + //update cluster_details table with the default overcommit ratios. + pstmt1.setLong(1,id); + pstmt1.execute(); + pstmt2.setLong(1,id); + pstmt2.execute(); + } + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to update cluster_details with default overcommit ratios.", e); + } finally { + try { + if (rs != null) { + rs.close(); + } + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + } + } + } + + @Override public File[] getCleanupScripts() { String script = Script.findScript("", "db/schema-410to420-cleanup.sql"); From 8dd0b7747b2da1aa71110e871b0bd4ffdbcdfcb4 Mon Sep 17 00:00:00 2001 From: Jayapal Reddy Date: Mon, 1 Apr 2013 16:22:12 +0530 Subject: [PATCH 35/90] Mulitiple ip address per nic support for advacned shared networks Description: Changes added for supporting multiple ip address per nic for shared networks Testing Done: Tested adding and removing the ip for nic using the APIs --- .../com/cloud/network/NetworkServiceImpl.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index d5034597f4f..4eb620c4243 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -490,6 +490,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { accountId = network.getAccountId(); domainId = network.getDomainId(); + // Validate network offering + NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(network.getNetworkOfferingId()); + // verify permissions _accountMgr.checkAccess(ipOwner, null, true, network); @@ -518,7 +521,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } catch (InsufficientAddressCapacityException e) { throw new InvalidParameterValueException("Allocating guest ip for nic failed"); } - } else if (dc.getNetworkType() == NetworkType.Basic) { + } else if (dc.getNetworkType() == NetworkType.Basic || ntwkOff.getGuestType() == Network.GuestType.Shared) { Account caller = UserContext.current().getCaller(); long callerUserId = UserContext.current().getCallerUserId(); _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network); @@ -546,14 +549,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { s_logger.error("Allocating ip to guest nic " + nicId + " failed"); return null; } - } else if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) && zone.getNetworkType() == NetworkType.Advanced) { - // if shared network in the advanced zone, then check the caller against the network for 'AccessType.UseNetwork' - Account caller = UserContext.current().getCaller(); - long callerUserId = UserContext.current().getCallerUserId(); - _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Associate IP address called by the user " + callerUserId + " account " + ipOwner.getId()); - } } else { s_logger.error("AddIpToVMNic is not supported in this network..."); return null; @@ -594,6 +589,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { Network network = _networksDao.findById(secIpVO.getNetworkId()); + if (network == null) { + throw new InvalidParameterValueException("Invalid network id is given"); + } + + // Validate network offering + NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(network.getNetworkOfferingId()); + // verify permissions _accountMgr.checkAccess(caller, null, true, network); @@ -627,7 +629,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { s_logger.debug("VM nic IP " + secondaryIp + " is associated with the static NAT rule public IP address id " + publicIpVO.getId()); throw new InvalidParameterValueException("Can' remove the ip " + secondaryIp + "is associate with static NAT rule public IP address id " + publicIpVO.getId()); } - } else if (dc.getNetworkType() == NetworkType.Basic) { + } else if (dc.getNetworkType() == NetworkType.Basic || ntwkOff.getGuestType() == Network.GuestType.Shared) { IPAddressVO ip = _ipAddressDao.findByIpAndNetworkId(secIpVO.getNetworkId(), secIpVO.getIp4Address()); if (ip != null) { Transaction txn = Transaction.currentTxn(); @@ -636,7 +638,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { _ipAddressDao.unassignIpAddress(ip.getId()); txn.commit(); } - } else if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) && dc.getNetworkType() == NetworkType.Advanced) { + } else { throw new InvalidParameterValueException("Not supported for this network now"); } From 6eac4229434b46ee74b5952d3abd26b646166b39 Mon Sep 17 00:00:00 2001 From: Pradeep Soundararajan Date: Mon, 1 Apr 2013 15:31:08 +0100 Subject: [PATCH 36/90] CLOUDSTACK-1689: Adding ipset as part of agent install for debian Signed-off-by: Chip Childers --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 8f82fc3ab2f..27a3150158e 100644 --- a/debian/control +++ b/debian/control @@ -22,7 +22,7 @@ Description: CloudStack server library Package: cloudstack-agent Architecture: all -Depends: openjdk-6-jre | openjdk-7-jre, cloudstack-common (= ${source:Version}), lsb-base (>= 3.2), libcommons-daemon-java, libjna-java, openssh-client, libvirt0, sysvinit-utils, chkconfig, qemu-kvm, libvirt-bin, uuid-runtime, rsync, grep, iproute, perl-base, perl-modules, ebtables, vlan, wget, jsvc +Depends: openjdk-6-jre | openjdk-7-jre, cloudstack-common (= ${source:Version}), lsb-base (>= 3.2), libcommons-daemon-java, libjna-java, openssh-client, libvirt0, sysvinit-utils, chkconfig, qemu-kvm, libvirt-bin, uuid-runtime, rsync, grep, iproute, perl-base, perl-modules, ebtables, vlan, wget, jsvc, ipset 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 From aa79ccf985a172603a9ff15fbaa71dbfb3dad99d Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Mon, 1 Apr 2013 15:40:21 -0700 Subject: [PATCH 37/90] CLOUDSTACK-922: LXC Support in Cloudstack. Signed-off-by: Edison Su --- agent/conf/agent.properties | 9 + api/src/com/cloud/agent/api/Command.java | 2 + .../com/cloud/agent/api/RebootCommand.java | 1 + api/src/com/cloud/agent/api/StopCommand.java | 7 +- api/src/com/cloud/hypervisor/Hypervisor.java | 3 + api/src/com/cloud/storage/Storage.java | 3 +- client/tomcatconf/applicationContext.xml.in | 8 + client/tomcatconf/componentContext.xml.in | 1 + .../kvm/resource/DirectVifDriver.java | 65 +++ .../resource/LibvirtComputingResource.java | 160 ++++--- .../kvm/resource/LibvirtConnection.java | 52 ++- .../kvm/resource/LibvirtDomainXMLParser.java | 21 +- .../kvm/resource/LibvirtStorageVolumeDef.java | 6 +- .../hypervisor/kvm/resource/LibvirtVMDef.java | 71 +++- .../kvm/storage/KVMPhysicalDisk.java | 2 +- .../kvm/storage/KVMStoragePoolManager.java | 4 + .../kvm/storage/LibvirtStorageAdaptor.java | 37 +- .../kvm/resource/LibvirtVMDefTest.java | 14 + .../storage/secondary/cloud-install-sys-tmplt | 4 + .../consoleproxy/ConsoleProxyManagerImpl.java | 12 +- server/src/com/cloud/hypervisor/LXCGuru.java | 58 +++ .../kvm/discoverer/KvmServerDiscoverer.java | 371 +---------------- .../discoverer/LibvirtServerDiscoverer.java | 393 ++++++++++++++++++ .../kvm/discoverer/LxcServerDiscoverer.java | 33 ++ .../cloud/network/SshKeysDistriMonitor.java | 3 +- .../VirtualNetworkApplianceManagerImpl.java | 8 +- .../SecondaryStorageManagerImpl.java | 6 +- .../template/HypervisorTemplateAdapter.java | 3 + .../cloud/vm/VirtualMachineManagerImpl.java | 27 +- setup/db/db/schema-410to420.sql | 12 + ui/scripts/system.js | 62 ++- ui/scripts/templates.js | 4 + ui/scripts/zoneWizard.js | 10 + 33 files changed, 986 insertions(+), 486 deletions(-) create mode 100644 plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/DirectVifDriver.java create mode 100644 server/src/com/cloud/hypervisor/LXCGuru.java create mode 100644 server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java create mode 100644 server/src/com/cloud/hypervisor/kvm/discoverer/LxcServerDiscoverer.java diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index f7eac674712..e49afbf2aaf 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -80,3 +80,12 @@ domr.scripts.dir=scripts/network/domr/kvm # native = com.cloud.hypervisor.kvm.resource.BridgeVifDriver # openvswitch = com.cloud.hypervisor.kvm.resource.OvsBridgeDriver #libvirt.vif.driver=com.cloud.hypervisor.kvm.resource.BridgeVifDriver + +# set the hypervisor type, values are: kvm, lxc +# hypervisor.type=kvm + +# settings to enable direct networking in libvirt, should not be used +# on hosts that run system vms, values for mode are: private, bridge, vepa +# libvirt.vif.driver=com.cloud.hypervisor.kvm.resource.DirectVifDriver +# network.direct.source.mode=private +# network.direct.device=eth0 diff --git a/api/src/com/cloud/agent/api/Command.java b/api/src/com/cloud/agent/api/Command.java index 9cd67495e04..aadbeaf0def 100755 --- a/api/src/com/cloud/agent/api/Command.java +++ b/api/src/com/cloud/agent/api/Command.java @@ -27,6 +27,8 @@ import com.cloud.agent.api.LogLevel.Log4jLevel; */ public abstract class Command { + public static final String HYPERVISOR_TYPE = "hypervisorType"; + // allow command to carry over hypervisor or other environment related context info @LogLevel(Log4jLevel.Trace) protected Map contextMap = new HashMap(); diff --git a/api/src/com/cloud/agent/api/RebootCommand.java b/api/src/com/cloud/agent/api/RebootCommand.java index 299e61b76af..49712b6fce5 100755 --- a/api/src/com/cloud/agent/api/RebootCommand.java +++ b/api/src/com/cloud/agent/api/RebootCommand.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.agent.api; +import com.cloud.hypervisor.Hypervisor; import com.cloud.vm.VirtualMachine; public class RebootCommand extends Command { diff --git a/api/src/com/cloud/agent/api/StopCommand.java b/api/src/com/cloud/agent/api/StopCommand.java index 9ee7ce3c874..1c67f3816ca 100755 --- a/api/src/com/cloud/agent/api/StopCommand.java +++ b/api/src/com/cloud/agent/api/StopCommand.java @@ -38,10 +38,9 @@ public class StopCommand extends RebootCommand { super(vm); this.vnet = vnet; } - - public StopCommand(VirtualMachine vm, String vmName, String vnet) { - super(vmName); - this.vnet = vnet; + + public StopCommand(VirtualMachine vm) { + super(vm); } public StopCommand(String vmName) { diff --git a/api/src/com/cloud/hypervisor/Hypervisor.java b/api/src/com/cloud/hypervisor/Hypervisor.java index 2e0012dca6f..a4ee5b98fd9 100644 --- a/api/src/com/cloud/hypervisor/Hypervisor.java +++ b/api/src/com/cloud/hypervisor/Hypervisor.java @@ -29,6 +29,7 @@ public class Hypervisor { BareMetal, Simulator, Ovm, + LXC, Any; /*If you don't care about the hypervisor type*/ @@ -54,6 +55,8 @@ public class Hypervisor { return HypervisorType.Simulator; } else if (hypervisor.equalsIgnoreCase("Ovm")) { return HypervisorType.Ovm; + } else if (hypervisor.equalsIgnoreCase("LXC")) { + return HypervisorType.LXC; } else if (hypervisor.equalsIgnoreCase("Any")) { return HypervisorType.Any; } else { diff --git a/api/src/com/cloud/storage/Storage.java b/api/src/com/cloud/storage/Storage.java index fba12b62d3d..c130fe222bf 100755 --- a/api/src/com/cloud/storage/Storage.java +++ b/api/src/com/cloud/storage/Storage.java @@ -26,7 +26,8 @@ public class Storage { VHD(true, true, true), ISO(false, false, false), OVA(true, true, true, "ova"), - BAREMETAL(false, false, false); + BAREMETAL(false, false, false), + TAR(false, false, false); private final boolean thinProvisioned; private final boolean supportSparse; diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index ca6b4020364..636eac2b939 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -499,6 +499,10 @@ + + + + @@ -568,6 +572,10 @@ + + + + diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 9d95e150129..fea1d0f6157 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -106,6 +106,7 @@ + + org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java From 8d34b5809d459eac90eea1f01cc5b20dedb39f11 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Tue, 2 Apr 2013 14:55:29 +0530 Subject: [PATCH 40/90] CLOUDSTACK-1887:removing the host option from the scope field for primary storage --- ui/scripts/zoneWizard.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/scripts/zoneWizard.js b/ui/scripts/zoneWizard.js index 76fd5e9f358..8add9bb085e 100755 --- a/ui/scripts/zoneWizard.js +++ b/ui/scripts/zoneWizard.js @@ -1204,7 +1204,7 @@ if(selectedHypervisorObj.hypervisortype != "KVM"){ var scope=[]; scope.push({ id: 'cluster', description: _l('label.cluster') }); - scope.push({ id: 'host', description: _l('label.host') }); + //scope.push({ id: 'host', description: _l('label.host') }); args.response.success({data: scope}); } @@ -1212,7 +1212,7 @@ var scope=[]; scope.push({ id: 'zone', description: _l('label.zone.wide') }); scope.push({ id: 'cluster', description: _l('label.cluster') }); - scope.push({ id: 'host', description: _l('label.host') }); + // scope.push({ id: 'host', description: _l('label.host') }); args.response.success({data: scope}); } From dedec164e8cce17b861d517fe8e29bb99902e113 Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Tue, 2 Apr 2013 16:19:24 +0800 Subject: [PATCH 41/90] fix CLOUDSTACK-1698 --- .../com/cloud/storage/VolumeManagerImpl.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java index ff0235f018a..1e8edafe4e2 100644 --- a/server/src/com/cloud/storage/VolumeManagerImpl.java +++ b/server/src/com/cloud/storage/VolumeManagerImpl.java @@ -169,6 +169,8 @@ import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.SecondaryStorageVmDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.snapshot.VMSnapshotVO; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component public class VolumeManagerImpl extends ManagerBase implements VolumeManager { @@ -289,6 +291,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { @Inject protected ResourceTagDao _resourceTagDao; @Inject + protected VMSnapshotDao _vmSnapshotDao; + @Inject protected List _storagePoolAllocators; @Inject ConfigurationDao _configDao; @@ -1669,6 +1673,13 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } + // if target VM has associated VM snapshots + List vmSnapshots = _vmSnapshotDao.findByVm(vmId); + if(vmSnapshots.size() > 0){ + throw new InvalidParameterValueException( + "Unable to attach volume, please specify a VM that does not have VM snapshots"); + } + // permission check _accountMgr.checkAccess(caller, null, true, volume, vm); @@ -1826,6 +1837,13 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { "Please specify a VM that is either running or stopped."); } + // Check if the VM has VM snapshots + List vmSnapshots = _vmSnapshotDao.findByVm(vmId); + if(vmSnapshots.size() > 0){ + throw new InvalidParameterValueException( + "Unable to detach volume, the specified volume is attached to a VM that has VM snapshots."); + } + AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor .getCurrentExecutor(); if (asyncExecutor != null) { From 4edef1fd305891beb5393b722e96f4a140934f9f Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Tue, 2 Apr 2013 17:24:49 +0800 Subject: [PATCH 42/90] fix CLOUDSTACK-1700 --- .../hypervisor/xen/resource/CitrixResourceBase.java | 12 +++++++++++- server/src/com/cloud/api/ApiResponseHelper.java | 1 + .../com/cloud/vm/snapshot/VMSnapshotManagerImpl.java | 8 ++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index d2f3f69f088..c50f13ce7e5 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -262,6 +262,7 @@ import com.xensource.xenapi.SR; import com.xensource.xenapi.Session; import com.xensource.xenapi.Task; import com.xensource.xenapi.Types; +import com.xensource.xenapi.Types.BadAsyncResult; import com.xensource.xenapi.Types.BadServerResponse; import com.xensource.xenapi.Types.ConsoleProtocol; import com.xensource.xenapi.Types.IpConfigurationMode; @@ -6452,7 +6453,16 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe success = true; return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), cmd.getVolumeTOs()); } catch (Exception e) { - String msg = e.getMessage(); + String msg = ""; + if(e instanceof BadAsyncResult){ + String licenseKeyWord = "LICENCE_RESTRICTION"; + BadAsyncResult errorResult = (BadAsyncResult)e; + if(errorResult.shortDescription != null && errorResult.shortDescription.contains(licenseKeyWord)){ + msg = licenseKeyWord; + } + }else{ + msg = e.getMessage(); + } s_logger.error("Creating VM Snapshot " + cmd.getTarget().getSnapshotName() + " failed due to: " + msg); return new CreateVMSnapshotAnswer(cmd, false, msg); } finally { diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index d350de2dfdd..64be7f8758a 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -446,6 +446,7 @@ public class ApiResponseHelper implements ResponseGenerator { vmSnapshotResponse.setParentName(ApiDBUtils.getVMSnapshotById(vmSnapshot.getParent()).getDisplayName()); vmSnapshotResponse.setCurrent(vmSnapshot.getCurrent()); vmSnapshotResponse.setType(vmSnapshot.getType().toString()); + vmSnapshotResponse.setObjectName("vmsnapshot"); return vmSnapshotResponse; } diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java index 12a059727be..638be6c0c9b 100644 --- a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -367,9 +367,13 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana processAnswer(vmSnapshot, userVm, answer, hostId); s_logger.debug("Create vm snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName()); }else{ - String errMsg = answer.getDetails(); - s_logger.error("Agent reports creating vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + errMsg); + + String errMsg = "Creating VM snapshot: " + vmSnapshot.getName() + " failed"; + if(answer != null && answer.getDetails() != null) + errMsg = errMsg + " due to " + answer.getDetails(); + s_logger.error(errMsg); vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed); + throw new CloudRuntimeException(errMsg); } return vmSnapshot; } catch (Exception e) { From 3d8afb0cfbcf20f4644fb58171f6c587c60f50ba Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Tue, 2 Apr 2013 16:21:25 +0530 Subject: [PATCH 43/90] CLOUDSTACK-1887:removing the host option from the scope field for primary storage --- ui/scripts/system.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 98570d249ea..2fdf5f925be 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -9316,8 +9316,8 @@ select: function(args) { var scope = [ { id: 'zone', description: _l('label.zone.wide') }, - { id: 'cluster', description: _l('label.cluster') }, - { id: 'host', description: _l('label.host') } + { id: 'cluster', description: _l('label.cluster') } + // { id: 'host', description: _l('label.host') } ]; args.response.success({ From 009749fb796bc935f610921f1bdc71e8d993198d Mon Sep 17 00:00:00 2001 From: Sateesh Chodapuneedi Date: Wed, 20 Mar 2013 04:44:59 +0530 Subject: [PATCH 44/90] CLOUDSTACK-301 Nexus 1000v DVS integration is not functional Moved validateVSMCluster method from CiscoNexusVSMDeviceManagerImpl to CiscoNexusVSMElement. Signed-off-by: Sateesh Chodapuneedi --- .../vmware/VmwareServerDiscoverer.java | 17 ++- .../CiscoNexusVSMDeviceManagerImpl.java | 96 ----------------- .../network/element/CiscoNexusVSMElement.java | 100 +++++++++++++++++- .../element/CiscoNexusVSMElementService.java | 7 ++ 4 files changed, 122 insertions(+), 98 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java index 2b3eba690e3..2f82b534af2 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java @@ -45,6 +45,7 @@ import com.cloud.dc.dao.DataCenterDao; import com.cloud.exception.DiscoveredWithErrorException; import com.cloud.exception.DiscoveryException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceInUseException; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; @@ -62,6 +63,8 @@ import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetwork; import com.cloud.network.VmwareTrafficLabel; import com.cloud.network.dao.CiscoNexusVSMDeviceDao; +import com.cloud.network.element.CiscoNexusVSMElement; +import com.cloud.network.element.CiscoNexusVSMElementService; import com.cloud.resource.Discoverer; import com.cloud.resource.DiscovererBase; import com.cloud.resource.ResourceManager; @@ -104,6 +107,8 @@ public class VmwareServerDiscoverer extends DiscovererBase implements @Inject CiscoNexusVSMDeviceDao _nexusDao; @Inject + CiscoNexusVSMElementService _nexusElement; + @Inject NetworkModel _netmgr; @Inject HypervisorCapabilitiesDao _hvCapabilitiesDao; @@ -255,7 +260,17 @@ public class VmwareServerDiscoverer extends DiscovererBase implements guestTrafficLabel = _netmgr.getDefaultGuestTrafficLabel(dcId, HypervisorType.VMware); if (guestTrafficLabel != null) { s_logger.info("Detected guest network label : " + guestTrafficLabel); - } + } + String vsmIp = _urlParams.get("vsmipaddress"); + String vsmUser = _urlParams.get("vsmusername"); + String vsmPassword = _urlParams.get("vsmpassword"); + String clusterName = cluster.getName(); + try { + _nexusElement.validateVsmCluster(vsmIp, vsmUser, vsmPassword, clusterId, clusterName); + } catch(ResourceInUseException ex) { + DiscoveryException discEx = new DiscoveryException(ex.getLocalizedMessage() + ". The resource is " + ex.getResourceName()); + throw discEx; + } vsmCredentials = _vmwareMgr.getNexusVSMCredentialsByClusterId(clusterId); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java index e17d99d3184..9ec64ffce9d 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java @@ -23,8 +23,6 @@ import javax.inject.Inject; import org.apache.log4j.Logger; import com.cloud.agent.api.StartupCommand; -import com.cloud.configuration.Config; -import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.ClusterVSMMapVO; @@ -64,8 +62,6 @@ public abstract class CiscoNexusVSMDeviceManagerImpl extends AdapterBase { HostDetailsDao _hostDetailDao; @Inject PortProfileDao _ppDao; - @Inject - ConfigurationDao _configDao; private static final org.apache.log4j.Logger s_logger = Logger.getLogger(ExternalLoadBalancerDeviceManagerImpl.class); @@ -315,96 +311,4 @@ public abstract class CiscoNexusVSMDeviceManagerImpl extends AdapterBase { // TODO Auto-generated method stub return null; } - - @DB - public boolean vliadateVsmCluster(String vsmIp, String vsmUser, String vsmPassword, long clusterId, String clusterName) throws ResourceInUseException { - // Check if we're associating a Cisco Nexus VSM with a vmware cluster. - if (Boolean.parseBoolean(_configDao.getValue(Config.VmwareUseNexusVSwitch.toString()))) { - - if(vsmIp != null && vsmUser != null && vsmPassword != null) { - NetconfHelper netconfClient; - try { - netconfClient = new NetconfHelper(vsmIp, vsmUser, vsmPassword); - netconfClient.disconnect(); - } catch (CloudRuntimeException e) { - String msg = "Invalid credentials supplied for user " + vsmUser + " for Cisco Nexus 1000v VSM at " + vsmIp; - s_logger.error(msg); - _clusterDao.remove(clusterId); - throw new CloudRuntimeException(msg); - } - - Transaction txn; - - // If VSM already exists and is mapped to a cluster, fail this operation. - CiscoNexusVSMDeviceVO vsm = _ciscoNexusVSMDeviceDao.getVSMbyIpaddress(vsmIp); - if(vsm != null) { - List clusterList = _clusterVSMDao.listByVSMId(vsm.getId()); - if (clusterList != null && !clusterList.isEmpty()) { - s_logger.error("Failed to add cluster: specified Nexus VSM is already associated with another cluster"); - _clusterDao.remove(clusterId); - ResourceInUseException ex = new ResourceInUseException("Failed to add cluster: specified Nexus VSM is already associated with another cluster with specified Id"); - // get clusterUuid to report error - ClusterVO cluster = _clusterDao.findById(clusterList.get(0).getClusterId()); - ex.addProxyObject(cluster.getUuid()); - throw ex; - } - } - // persist credentials to database if the VSM entry is not already in the db. - if (_ciscoNexusVSMDeviceDao.getVSMbyIpaddress(vsmIp) == null) { - vsm = new CiscoNexusVSMDeviceVO(vsmIp, vsmUser, vsmPassword); - txn = Transaction.currentTxn(); - try { - txn.start(); - vsm = _ciscoNexusVSMDeviceDao.persist(vsm); - txn.commit(); - } catch (Exception e) { - txn.rollback(); - s_logger.error("Failed to persist Cisco Nexus 1000v VSM details to database. Exception: " + e.getMessage()); - // Removing the cluster record which was added already because the persistence of Nexus VSM credentials has failed. - _clusterDao.remove(clusterId); - throw new CloudRuntimeException(e.getMessage()); - } - } - // Create a mapping between the cluster and the vsm. - vsm = _ciscoNexusVSMDeviceDao.getVSMbyIpaddress(vsmIp); - if (vsm != null) { - ClusterVSMMapVO connectorObj = new ClusterVSMMapVO(clusterId, vsm.getId()); - txn = Transaction.currentTxn(); - try { - txn.start(); - _clusterVSMDao.persist(connectorObj); - txn.commit(); - } catch (Exception e) { - txn.rollback(); - s_logger.error("Failed to associate Cisco Nexus 1000v VSM with cluster: " + clusterName + ". Exception: " + e.getMessage()); - _clusterDao.remove(clusterId); - throw new CloudRuntimeException(e.getMessage()); - } - } - } else { - String msg; - msg = "The global parameter " + Config.VmwareUseNexusVSwitch.toString() + - " is set to \"true\". Following mandatory parameters are not specified. "; - if(vsmIp == null) { - msg += "vsmipaddress: Management IP address of Cisco Nexus 1000v dvSwitch. "; - } - if(vsmUser == null) { - msg += "vsmusername: Name of a user account with admin privileges over Cisco Nexus 1000v dvSwitch. "; - } - if(vsmPassword == null) { - if(vsmUser != null) { - msg += "vsmpassword: Password of user account " + vsmUser + ". "; - } else { - msg += "vsmpassword: Password of user account with admin privileges over Cisco Nexus 1000v dvSwitch. "; - } - } - s_logger.error(msg); - // Cleaning up the cluster record as addCluster operation failed because Nexus dvSwitch credentials are supplied. - _clusterDao.remove(clusterId); - throw new CloudRuntimeException(msg); - } - return true; - } - return false; - } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java b/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java index daf7dd6bd40..4629b6c2d3e 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java +++ b/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java @@ -34,6 +34,11 @@ import com.cloud.api.commands.EnableCiscoNexusVSMCmd; import com.cloud.api.commands.DisableCiscoNexusVSMCmd; import com.cloud.api.commands.ListCiscoNexusVSMsCmd; import com.cloud.api.response.CiscoNexusVSMResponse; +import com.cloud.configuration.Config; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.ClusterVSMMapVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.ClusterVSMMapDao; import com.cloud.deploy.DeployDestination; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; @@ -55,7 +60,10 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.offering.NetworkOffering; import com.cloud.org.Cluster; +import com.cloud.utils.cisco.n1kv.vsm.NetconfHelper; import com.cloud.utils.component.Manager; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Transaction; import com.cloud.exception.ResourceInUseException; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.server.ManagementService; @@ -66,7 +74,11 @@ public class CiscoNexusVSMElement extends CiscoNexusVSMDeviceManagerImpl impleme private static final Logger s_logger = Logger.getLogger(CiscoNexusVSMElement.class); @Inject - CiscoNexusVSMDeviceDao _vsmDao; + CiscoNexusVSMDeviceDao _vsmDao; + @Inject + ClusterDao _clusterDao; + @Inject + ClusterVSMMapDao _clusterVSMDao; @Override public Map> getCapabilities() { @@ -247,4 +259,90 @@ public class CiscoNexusVSMElement extends CiscoNexusVSMDeviceManagerImpl impleme cmdList.add(DeleteCiscoNexusVSMCmd.class); return cmdList; } + + @DB + public boolean validateVsmCluster(String vsmIp, String vsmUser, String vsmPassword, long clusterId, String clusterName) throws ResourceInUseException { + if(vsmIp != null && vsmUser != null && vsmPassword != null) { + NetconfHelper netconfClient; + try { + netconfClient = new NetconfHelper(vsmIp, vsmUser, vsmPassword); + netconfClient.disconnect(); + } catch (CloudRuntimeException e) { + String msg = "Invalid credentials supplied for user " + vsmUser + " for Cisco Nexus 1000v VSM at " + vsmIp; + s_logger.error(msg); + _clusterDao.remove(clusterId); + throw new CloudRuntimeException(msg); + } + + Transaction txn; + + // If VSM already exists and is mapped to a cluster, fail this operation. + CiscoNexusVSMDeviceVO vsm = _vsmDao.getVSMbyIpaddress(vsmIp); + if(vsm != null) { + List clusterList = _clusterVSMDao.listByVSMId(vsm.getId()); + if (clusterList != null && !clusterList.isEmpty()) { + s_logger.error("Failed to add cluster: specified Nexus VSM is already associated with another cluster"); + ResourceInUseException ex = new ResourceInUseException("Failed to add cluster: specified Nexus VSM is already associated with another cluster with specified Id"); + // get clusterUuid to report error + ClusterVO cluster = _clusterDao.findById(clusterList.get(0).getClusterId()); + ex.addProxyObject(cluster.getUuid()); + _clusterDao.remove(clusterId); + throw ex; + } + } + // persist credentials to database if the VSM entry is not already in the db. + if (_vsmDao.getVSMbyIpaddress(vsmIp) == null) { + vsm = new CiscoNexusVSMDeviceVO(vsmIp, vsmUser, vsmPassword); + txn = Transaction.currentTxn(); + try { + txn.start(); + vsm = _vsmDao.persist(vsm); + txn.commit(); + } catch (Exception e) { + txn.rollback(); + s_logger.error("Failed to persist Cisco Nexus 1000v VSM details to database. Exception: " + e.getMessage()); + throw new CloudRuntimeException(e.getMessage()); + } + } + // Create a mapping between the cluster and the vsm. + vsm = _vsmDao.getVSMbyIpaddress(vsmIp); + if (vsm != null) { + ClusterVSMMapVO connectorObj = new ClusterVSMMapVO(clusterId, vsm.getId()); + txn = Transaction.currentTxn(); + try { + txn.start(); + _clusterVSMDao.persist(connectorObj); + txn.commit(); + } catch (Exception e) { + txn.rollback(); + s_logger.error("Failed to associate Cisco Nexus 1000v VSM with cluster: " + clusterName + ". Exception: " + e.getMessage()); + _vsmDao.remove(vsm.getId()); // Removing VSM from virtual_supervisor_module table because association with cluster failed. + // Cluster would be deleted from cluster table by callee. + throw new CloudRuntimeException(e.getMessage()); + } + } + } else { + String msg; + msg = "The global parameter " + Config.VmwareUseNexusVSwitch.toString() + + " is set to \"true\". Following mandatory parameters are not specified. "; + if(vsmIp == null) { + msg += "vsmipaddress: Management IP address of Cisco Nexus 1000v dvSwitch. "; + } + if(vsmUser == null) { + msg += "vsmusername: Name of a user account with admin privileges over Cisco Nexus 1000v dvSwitch. "; + } + if(vsmPassword == null) { + if(vsmUser != null) { + msg += "vsmpassword: Password of user account " + vsmUser + ". "; + } else { + msg += "vsmpassword: Password of user account with admin privileges over Cisco Nexus 1000v dvSwitch. "; + } + } + s_logger.error(msg); + // Cleaning up the cluster record as addCluster operation failed because of invalid credentials of Nexus dvSwitch. + _clusterDao.remove(clusterId); + throw new CloudRuntimeException(msg); + } + return true; + } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElementService.java b/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElementService.java index 1cc9fafb052..e90581ae56c 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElementService.java +++ b/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElementService.java @@ -24,6 +24,7 @@ import com.cloud.api.commands.EnableCiscoNexusVSMCmd; import com.cloud.api.commands.DisableCiscoNexusVSMCmd; import com.cloud.api.commands.ListCiscoNexusVSMsCmd; import com.cloud.api.response.CiscoNexusVSMResponse; +import com.cloud.exception.ResourceInUseException; import com.cloud.network.CiscoNexusVSMDeviceVO; import com.cloud.network.CiscoNexusVSMDevice; import com.cloud.utils.component.PluggableService; @@ -68,4 +69,10 @@ public interface CiscoNexusVSMElementService extends PluggableService { * @return CiscoNexusVSMResponse */ public CiscoNexusVSMResponse createCiscoNexusVSMDetailedResponse(CiscoNexusVSMDevice vsmDeviceVO); + + /** + * Validate Cisco Nexus VSM before associating with cluster + * + */ + public boolean validateVsmCluster(String vsmIp, String vsmUser, String vsmPassword, long clusterId, String clusterName) throws ResourceInUseException; } From 8e917b1ad3c0d3076b0c6425ea3318a6d6dd5c25 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Tue, 5 Mar 2013 11:48:16 +0530 Subject: [PATCH 45/90] removing unused commented dependencies removing the spring related dependencies that were commented out. Signed-off-by: Prasanna Santhanam --- plugins/pom.xml | 3 +- pom.xml | 354 +++++++++++++++++++++++++++++------------------- 2 files changed, 215 insertions(+), 142 deletions(-) diff --git a/plugins/pom.xml b/plugins/pom.xml index d7e8debbf02..348ffa26308 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -16,7 +16,8 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---> +--> + 4.0.0 cloudstack-plugins Apache CloudStack Plugin POM diff --git a/pom.xml b/pom.xml index dab3db2c7c1..0393d0cc1a3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,15 +1,23 @@ - + + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 @@ -26,8 +34,8 @@ Apache CloudStack is an IaaS (“Infrastracture as a Service”) cloud orchestration platform. http://www.cloudstack.org - scm:git:https://git-wip-us.apache.org/repos/asf/cloudstack.git - scm:git:https://git-wip-us.apache.org/repos/asf/cloudstack.git + scm:git:https://git-wip-us.apache.org/repos/asf/incubator-cloudstack.git + scm:git:https://git-wip-us.apache.org/repos/asf/incubator-cloudstack.git jira @@ -35,7 +43,7 @@ - + 1.6 UTF-8 @@ -84,7 +92,6 @@ 0.10 build/replace.properties 0.4.9 - target @@ -99,49 +106,40 @@ Apache CloudStack User List - users-subscribe@cloudstack.apache.org - users-unsubscribe@cloudstack.apache.org - users@cloudstack.apache.org - http://mail-archives.apache.org/mod_mbox/cloudstack-users - - http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-users - + cloudstack-users-subscribe@incubator.apache.org + cloudstack-users-unsubscribe@incubator.apache.org + cloudstack-users@incubator.apache.org + http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-users Apache CloudStack Developer List - dev-subscribe@cloudstack.apache.org - dev-unsubscribe@cloudstack.apache.org - dev@cloudstack.apache.org - http://mail-archives.apache.org/mod_mbox/cloudstack-dev - - http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-dev - + cloudstack-dev-subscribe@incubator.apache.org + cloudstack-dev-unsubscribe@incubator.apache.org + cloudstack-dev@incubator.apache.org + http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-dev Apache CloudStack Commits List - commits-subscribe@cloudstack.apache.org - commits-unsubscribe@cloudstack.apache.org - commits@cloudstack.apache.org - http://mail-archives.apache.org/mod_mbox/cloudstack-commits - - http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-commits - + cloudstack-commits-subscribe@incubator.apache.org + cloudstack-commits-unsubscribe@incubator.apache.org + cloudstack-commits@incubator.apache.org + http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-commits The Apache CloudStack Team - dev@cloudstack.apache.org - http://cloudstack.apache.org/ + cloudstack-dev@incubator.apache.org + http://incubator.apache.org/projects/cloudstack.html Apache Software Foundation http://apache.org/ - Jenkins - http://builds.apache.org/ + Jenkin + http://jenkins.cloudstack.org/ @@ -176,11 +174,11 @@ - - mysql - mysql-connector-java - ${cs.mysql.version} - + + mysql + mysql-connector-java + ${cs.mysql.version} + @@ -190,12 +188,12 @@ junit ${cs.junit.version} test - - - org.springframework - spring-core - ${org.springframework.version} - + + + org.springframework + spring-core + ${org.springframework.version} + org.springframework spring-context @@ -206,36 +204,18 @@ spring-web ${org.springframework.version} - - org.mockito - mockito-all - 1.9.5 - test - - - org.springframework - spring-test - ${org.springframework.version} - test + org.mockito + mockito-all + 1.9.5 + test + + org.springframework + spring-test + ${org.springframework.version} + test + org.aspectj aspectjrt @@ -247,19 +227,17 @@ 1.7.1 - javax.inject - javax.inject - 1 + javax.inject + javax.inject + 1 install - ${basedir}/${cs.target.dir}/classes - ${basedir}/${cs.target.dir}/test-classes - org.eclipse.m2e @@ -282,7 +260,7 @@ - + @@ -340,9 +318,11 @@ dist/console-proxy/js/jquery.js scripts/vm/systemvm/id_rsa.cloud tools/devcloud/basebuild/puppet-devcloudinitial/files/network.conf - tools/appliance/definitions/devcloud/* - tools/appliance/definitions/systemvmtemplate/* - tools/appliance/definitions/systemvmtemplate64/* + tools/appliance/definitions/systemvmtemplate/base.sh + tools/appliance/definitions/systemvmtemplate/cleanup.sh + tools/appliance/definitions/systemvmtemplate/definition.rb + tools/appliance/definitions/systemvmtemplate/preseed.cfg + tools/appliance/definitions/systemvmtemplate/zerodisk.sh tools/cli/cloudmonkey.egg-info/* tools/devcloud/src/deps/boxes/basebox-build/definition.rb tools/devcloud/src/deps/boxes/basebox-build/preseed.cfg @@ -410,41 +390,41 @@ ${cs.jdk.version} ${cs.jdk.version} - true - 128m - 512m - -XDignore.symbol.file=true + true + 128m + 512m + -XDignore.symbol.file=true - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - true - true - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.7 - - - remove-old-installers - - remove-project-artifact - - - true - - - - + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + true + true + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.7 + + + remove-old-installers + + remove-project-artifact + + + true + + + + org.apache.maven.plugins maven-dependency-plugin @@ -472,31 +452,15 @@ - eclipse - - target-eclipse - - - developer - - tools/devcloud/devcloud.cfg - + + tools/devcloud/devcloud.cfg + developer tools - - impatient - - tools/devcloud/devcloud.cfg - - - developer - - - vmware @@ -508,5 +472,113 @@ vmware-base + + simulator + + + deploydb-simulator + + + + + + org.codehaus.mojo + properties-maven-plugin + 1.0-alpha-2 + + + initialize + + read-project-properties + + + + ${project.basedir}/utils/conf/db.properties + ${project.basedir}/utils/conf/db.properties.override + + true + + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + + mysql + mysql-connector-java + ${cs.mysql.version} + + + commons-dbcp + commons-dbcp + ${cs.dbcp.version} + + + commons-pool + commons-pool + ${cs.pool.version} + + + org.jasypt + jasypt + ${cs.jasypt.version} + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + org.apache.cloudstack + cloud-server + ${project.version} + + + + + process-resources + create-schema + + java + + + + + false + true + + org.apache.cloudstack + cloud-server + + com.cloud.upgrade.DatabaseCreator + + + ${project.basedir}/utils/conf/db.properties + ${project.basedir}/utils/conf/db.properties.override + + ${basedir}/target/db/create-schema-simulator.sql + ${basedir}/target/db/templates.simulator.sql + + com.cloud.upgrade.DatabaseUpgradeChecker + --database=simulator + --rootpassword=${db.root.password} + + + + + catalina.home + ${project.basedir}/utils + + + + + + + From 7ee602beaf85643c643d878e52f77e8c9bbcabb1 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Sun, 10 Mar 2013 21:07:29 +0530 Subject: [PATCH 46/90] simulator: removing cyclic dependency from simulator The database creator caused a cyclic dependecny in the simulator which is removed with this commit. Additionally the simulator profile is now merged with developer profile and a test for server health is included --- client/pom.xml | 25 +- client/tomcatconf/componentContext.xml.in | 418 +++++++++++++--------- pom.xml | 230 ++++-------- 3 files changed, 322 insertions(+), 351 deletions(-) diff --git a/client/pom.xml b/client/pom.xml index 61cda76aa2e..75650295849 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -65,16 +65,6 @@ cloud-plugin-network-nvp ${project.version} - - org.apache.cloudstack - cloud-plugin-syslog-alerts - ${project.version} - - - org.apache.cloudstack - cloud-plugin-snmp-alerts - ${project.version} - org.apache.cloudstack cloud-plugin-network-ovs @@ -100,6 +90,11 @@ cloud-plugin-hypervisor-baremetal ${project.version} + + org.apache.cloudstack + cloud-plugin-hypervisor-ucs + ${project.version} + org.apache.cloudstack cloud-plugin-hypervisor-ovm @@ -224,16 +219,6 @@ cloud-plugin-hypervisor-simulator ${project.version} - - org.apache.cloudstack - cloud-plugin-hypervisor-ucs - ${project.version} - - - org.apache.cloudstack - cloud-plugin-storage-volume-default - ${project.version} - install diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index fea1d0f6157..d5714ea9f01 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -30,192 +30,286 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - + + - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - + + + + + + + + + + + + + + - - diff --git a/pom.xml b/pom.xml index 0393d0cc1a3..5e5f6245f4e 100644 --- a/pom.xml +++ b/pom.xml @@ -174,11 +174,11 @@ - - mysql - mysql-connector-java - ${cs.mysql.version} - + + mysql + mysql-connector-java + ${cs.mysql.version} + @@ -188,12 +188,12 @@ junit ${cs.junit.version} test - - - org.springframework - spring-core - ${org.springframework.version} - + + + org.springframework + spring-core + ${org.springframework.version} + org.springframework spring-context @@ -205,17 +205,17 @@ ${org.springframework.version} - org.mockito - mockito-all - 1.9.5 - test + org.mockito + mockito-all + 1.9.5 + test + + + org.springframework + spring-test + ${org.springframework.version} + test - - org.springframework - spring-test - ${org.springframework.version} - test - org.aspectj aspectjrt @@ -227,9 +227,9 @@ 1.7.1 - javax.inject - javax.inject - 1 + javax.inject + javax.inject + 1 @@ -260,7 +260,7 @@ - + @@ -390,41 +390,41 @@ ${cs.jdk.version} ${cs.jdk.version} - true - 128m - 512m - -XDignore.symbol.file=true + true + 128m + 512m + -XDignore.symbol.file=true - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - true - true - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.7 - - - remove-old-installers - - remove-project-artifact - - - true - - - - + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + true + true + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.7 + + + remove-old-installers + + remove-project-artifact + + + true + + + + org.apache.maven.plugins maven-dependency-plugin @@ -453,9 +453,9 @@ developer - - tools/devcloud/devcloud.cfg - + + tools/devcloud/devcloud.cfg + developer tools @@ -472,113 +472,5 @@ vmware-base - - simulator - - - deploydb-simulator - - - - - - org.codehaus.mojo - properties-maven-plugin - 1.0-alpha-2 - - - initialize - - read-project-properties - - - - ${project.basedir}/utils/conf/db.properties - ${project.basedir}/utils/conf/db.properties.override - - true - - - - - - - org.codehaus.mojo - exec-maven-plugin - 1.2.1 - - - - mysql - mysql-connector-java - ${cs.mysql.version} - - - commons-dbcp - commons-dbcp - ${cs.dbcp.version} - - - commons-pool - commons-pool - ${cs.pool.version} - - - org.jasypt - jasypt - ${cs.jasypt.version} - - - org.apache.cloudstack - cloud-utils - ${project.version} - - - org.apache.cloudstack - cloud-server - ${project.version} - - - - - process-resources - create-schema - - java - - - - - false - true - - org.apache.cloudstack - cloud-server - - com.cloud.upgrade.DatabaseCreator - - - ${project.basedir}/utils/conf/db.properties - ${project.basedir}/utils/conf/db.properties.override - - ${basedir}/target/db/create-schema-simulator.sql - ${basedir}/target/db/templates.simulator.sql - - com.cloud.upgrade.DatabaseUpgradeChecker - --database=simulator - --rootpassword=${db.root.password} - - - - - catalina.home - ${project.basedir}/utils - - - - - - - From 3075d0cf569d8adeacb74dd77b7d9f3bd6707101 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Wed, 13 Mar 2013 11:49:08 +0530 Subject: [PATCH 47/90] marvin: argparse enhancement and unit-test-xml-reporting dependency removed 1. deployAndRun will use the more modern argparse module 2. improving logging within the remoteSSHClient, moving to debug and default logging to INFO 3. removing dependance on the xmlrunner. use nose --with-xunit instead Signed-off-by: Prasanna Santhanam --- tools/marvin/marvin/TestCaseExecuteEngine.py | 13 ++---- tools/marvin/marvin/deployAndRun.py | 40 ++++++++----------- tools/marvin/marvin/remoteSSHClient.py | 9 ++--- .../sandbox/demo/simulator/simulator_setup.py | 2 +- tools/marvin/marvin/testSetupSuccess.py | 2 +- tools/marvin/pom.xml | 39 +++++++++++++++++- tools/marvin/setup.py | 5 +-- 7 files changed, 64 insertions(+), 46 deletions(-) diff --git a/tools/marvin/marvin/TestCaseExecuteEngine.py b/tools/marvin/marvin/TestCaseExecuteEngine.py index 3c34c7efdfc..57438688486 100644 --- a/tools/marvin/marvin/TestCaseExecuteEngine.py +++ b/tools/marvin/marvin/TestCaseExecuteEngine.py @@ -16,7 +16,6 @@ # under the License. import unittest -import xmlrunner import os import sys import logging @@ -27,7 +26,7 @@ def testCaseLogger(message, logger=None): logger.debug(message) class TestCaseExecuteEngine(object): - def __init__(self, testclient, config, testcaseLogFile=None, testResultLogFile=None, format="text", xmlDir="xml-reports"): + def __init__(self, testclient, config, testcaseLogFile=None, testResultLogFile=None): """ Initialize the testcase execution engine, just the basics here @var testcaseLogFile: client log file @@ -38,7 +37,6 @@ class TestCaseExecuteEngine(object): self.logformat = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s") self.loader = unittest.loader.TestLoader() self.suite = None - self.format = format if testcaseLogFile is not None: self.logfile = testcaseLogFile @@ -56,9 +54,7 @@ class TestCaseExecuteEngine(object): self.testResultLogFile = fp else: self.testResultLogFile = sys.stdout - if self.format == "xml" and (xmlDir is not None): - self.xmlDir = xmlDir - + def loadTestsFromDir(self, testDirectory): """ Load the test suites from a package with multiple test files """ self.suite = self.loader.discover(testDirectory) @@ -92,7 +88,4 @@ class TestCaseExecuteEngine(object): def run(self): if self.suite: - if self.format == "text": - unittest.TextTestRunner(stream=self.testResultLogFile, verbosity=2).run(self.suite) - elif self.format == "xml": - xmlrunner.XMLTestRunner(output=self.xmlDir).run(self.suite) + unittest.TextTestRunner(stream=self.testResultLogFile, verbosity=2).run(self.suite) diff --git a/tools/marvin/marvin/deployAndRun.py b/tools/marvin/marvin/deployAndRun.py index e7b005caf68..c83065aaca9 100644 --- a/tools/marvin/marvin/deployAndRun.py +++ b/tools/marvin/marvin/deployAndRun.py @@ -17,22 +17,22 @@ import deployDataCenter import TestCaseExecuteEngine -from optparse import OptionParser -import os - +from argparse import ArgumentParser if __name__ == "__main__": - parser = OptionParser() #TODO: deprecate and use the argparse module - - parser.add_option("-c", "--config", action="store", default="./datacenterCfg", dest="config", help="the path where the json config file generated, by default is ./datacenterCfg") - parser.add_option("-d", "--directory", dest="testCaseFolder", help="the test case directory") - parser.add_option("-r", "--result", dest="result", help="test result log file") - parser.add_option("-t", "--client", dest="testcaselog", help="test case log file") - parser.add_option("-l", "--load", dest="load", action="store_true", help="only load config, do not deploy, it will only run testcase") - parser.add_option("-f", "--file", dest="module", help="run tests in the given file") - parser.add_option("-x", "--xml", dest="xmlrunner", help="use the xml runner to generate xml reports and path to store xml files") - (options, args) = parser.parse_args() - + parser = ArgumentParser() + + parser.add_argument("-d", "--directory", dest="testCaseFolder", help="the test case directory") + parser.add_argument("-f", "--file", dest="module", help="run tests in the given file") + parser.add_argument("-r", "--result", dest="result", help="test result log file", default='/tmp/t.log') + parser.add_argument("-t", "--client", dest="testcaselog", help="test case log file", default='/tmp/r.log') + parser.add_argument("-c", "--config", action="store", default="./datacenterCfg", dest="config", + help="the path where the json config file generated, by default is ./datacenterCfg") + parser.add_argument("-l", "--load", dest="load", action="store_true", + help="only load config, do not deploy, it will only run testcase") + + options = parser.parse_args() + testResultLogFile = None if options.result is not None: testResultLogFile = options.result @@ -46,12 +46,6 @@ if __name__ == "__main__": else: deploy.deploy() - fmt = "text" - xmlDir = None - if options.xmlrunner is not None: - xmlDir = options.xmlrunner - fmt = "xml" - if options.testCaseFolder is None: if options.module is None: parser.print_usage() @@ -61,15 +55,13 @@ if __name__ == "__main__": TestCaseExecuteEngine.TestCaseExecuteEngine(deploy.testClient, deploy.getCfg(), testCaseLogFile, - testResultLogFile, fmt, - xmlDir) + testResultLogFile) engine.loadTestsFromFile(options.module) engine.run() else: engine = TestCaseExecuteEngine.TestCaseExecuteEngine(deploy.testClient, deploy.getCfg(), testCaseLogFile, - testResultLogFile, - fmt, xmlDir) + testResultLogFile) engine.loadTestsFromDir(options.testCaseFolder) engine.run() diff --git a/tools/marvin/marvin/remoteSSHClient.py b/tools/marvin/marvin/remoteSSHClient.py index 95a9adab53f..4fb2f0de8f0 100644 --- a/tools/marvin/marvin/remoteSSHClient.py +++ b/tools/marvin/marvin/remoteSSHClient.py @@ -23,7 +23,7 @@ import logging from contextlib import closing class remoteSSHClient(object): - def __init__(self, host, port, user, passwd, retries = 10): + def __init__(self, host, port, user, passwd, retries = 10, log_lvl=logging.INFO): self.host = host self.port = port self.user = user @@ -32,14 +32,14 @@ class remoteSSHClient(object): self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.logger = logging.getLogger('sshClient') ch = logging.StreamHandler() - ch.setLevel(logging.DEBUG) + ch.setLevel(log_lvl) self.logger.addHandler(ch) retry_count = retries while True: try: self.ssh.connect(str(host),int(port), user, passwd) - self.logger.debug("connecting to server %s with user %s passwd %s"%(str(host), user, passwd)) + self.logger.debug("SSH connect: %s@%s with passwd %s"%(user, str(host), passwd)) except paramiko.SSHException, sshex: if retry_count == 0: raise cloudstackException.InvalidParameterException(repr(sshex)) @@ -52,7 +52,6 @@ class remoteSSHClient(object): def execute(self, command): stdin, stdout, stderr = self.ssh.exec_command(command) - self.logger.debug("sending command %s to host %s"%(command, str(self.host))) output = stdout.readlines() errors = stderr.readlines() results = [] @@ -64,7 +63,7 @@ class remoteSSHClient(object): else: for strOut in output: results.append(strOut.rstrip()) - self.logger.debug("command %s returned %s"%(command, results)) + self.logger.debug("{Cmd: %s via Host: %s} {returns: %s}"%(command, str(self.host), results)) return results def scp(self, srcFile, destPath): diff --git a/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py b/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py index 0d341408aea..e4ec9b7b1b1 100644 --- a/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py +++ b/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py @@ -41,7 +41,6 @@ def describeResources(config): z.name = 'Sandbox-%s'%(config.get('environment', 'hypervisor')) z.networktype = 'Advanced' z.guestcidraddress = '10.1.1.0/24' - z.vlan = config.get('cloudstack', 'zone.vlan') vpcprovider = provider() vpcprovider.name = 'VpcVirtualRouter' @@ -50,6 +49,7 @@ def describeResources(config): pn.name = "Sandbox-pnet" pn.traffictypes = [traffictype("Guest"), traffictype("Management"), traffictype("Public")] pn.providers.append(vpcprovider) + pn.vlan = config.get('cloudstack', 'zone.vlan') z.physical_networks.append(pn) diff --git a/tools/marvin/marvin/testSetupSuccess.py b/tools/marvin/marvin/testSetupSuccess.py index 8a0034cfa9b..319fd21c582 100644 --- a/tools/marvin/marvin/testSetupSuccess.py +++ b/tools/marvin/marvin/testSetupSuccess.py @@ -75,7 +75,7 @@ class TestSetupSuccess(cloudstackTestCase): retry = retry - 1 delay(60) #wait a minute for retry self.assertNotEqual(retry, 0, "builtIn templates not ready in zone %s"%z.name) - + @classmethod def tearDownClass(cls): pass diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index a3bd5460fd5..194d7841030 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -65,8 +65,8 @@ - package - package + install + install exec @@ -117,7 +117,42 @@ exec + + ${basedir}/marvin + /usr/local/bin/nosetests + + --with-marvin + --marvin-config + ${user.dir}/${marvin.config} + --load + -a + tags=simulator + ${basedir}/../../test/integration/smoke/test_vm_life_cycle.py + + + diff --git a/tools/marvin/setup.py b/tools/marvin/setup.py index fea53d07f8a..f8198d7999b 100644 --- a/tools/marvin/setup.py +++ b/tools/marvin/setup.py @@ -37,7 +37,6 @@ setup(name="Marvin", install_requires=[ "mysql-connector-python", "paramiko", - "nose", - "unittest-xml-reporting>1.2" - ], + "nose" + ], ) From fe48bbebda0ff05653fc2341649e410db6bfb159 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Thu, 21 Mar 2013 15:34:26 +0530 Subject: [PATCH 48/90] moving out the vmpasswd into its own suite vm passwords are extended features that don't need to be part of the smoke suite. Signed-off-by: Prasanna Santhanam --- .../component/test_vm_passwdenabled.py | 242 ++++++++++++++++++ test/integration/smoke/test_vm_life_cycle.py | 170 ------------ tools/marvin/marvin/testSetupSuccess.py | 2 +- 3 files changed, 243 insertions(+), 171 deletions(-) create mode 100644 test/integration/component/test_vm_passwdenabled.py diff --git a/test/integration/component/test_vm_passwdenabled.py b/test/integration/component/test_vm_passwdenabled.py new file mode 100644 index 00000000000..fb881708e2f --- /dev/null +++ b/test/integration/component/test_vm_passwdenabled.py @@ -0,0 +1,242 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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.remoteSSHClient import remoteSSHClient +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from nose.plugins.attrib import attr + + +_multiprocess_shared_ = True +class Services: + """Test VM Life Cycle Services + """ + + def __init__(self): + self.services = { + "disk_offering":{ + "displaytext": "Small", + "name": "Small", + "disksize": 1 + }, + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended in create account to + # ensure unique username generated each time + "password": "password", + }, + "service_offerings": + { + "small": + { + # Small service offering ID to for change VM + # service offering from medium to small + "name": "Small Instance", + "displaytext": "Small Instance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 256, + }, + }, + "template": { + "displaytext": "Cent OS Template", + "name": "Cent OS Template", + "passwordenabled": True, + }, + "sleep": 60, + "timeout": 10, + "ostype": 'CentOS 5.3 (64-bit)', + # CentOS 5.3 (64-bit) + } + +@unittest.skip("Additional test") +class TestVMPasswordEnabled(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super( + TestVMPasswordEnabled, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + + # Get Zone, Domain and templates + domain = get_domain(cls.api_client, cls.services) + zone = get_zone(cls.api_client, cls.services) + template = get_template( + cls.api_client, + zone.id, + cls.services["ostype"] + ) + # Set Zones and disk offerings + cls.services["small"]["zoneid"] = zone.id + cls.services["small"]["template"] = template.id + + # Create VMs, NAT Rules etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=domain.id + ) + + cls.small_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offerings"]["small"] + ) + + cls.virtual_machine = VirtualMachine.create( + cls.api_client, + cls.services["small"], + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.small_offering.id, + mode=cls.services["mode"] + ) + #Stop virtual machine + cls.virtual_machine.stop(cls.api_client) + + # Poll listVM to ensure VM is stopped properly + timeout = cls.services["timeout"] + while True: + time.sleep(cls.services["sleep"]) + + # Ensure that VM is in stopped state + list_vm_response = list_virtual_machines( + cls.api_client, + id=cls.virtual_machine.id + ) + + if isinstance(list_vm_response, list): + + vm = list_vm_response[0] + if vm.state == 'Stopped': + break + + if timeout == 0: + raise Exception( + "Failed to stop VM (ID: %s) in change service offering" % + vm.id) + + timeout = timeout - 1 + + list_volume = list_volumes( + cls.api_client, + virtualmachineid=cls.virtual_machine.id, + type='ROOT', + listall=True + ) + if isinstance(list_volume, list): + cls.volume = list_volume[0] + else: + raise Exception( + "Exception: Unable to find root volume foe VM: %s" % + cls.virtual_machine.id) + + cls.services["template"]["ostype"] = cls.services["ostype"] + #Create templates for Edit, Delete & update permissions testcases + cls.pw_enabled_template = Template.create( + cls.api_client, + cls.services["template"], + cls.volume.id, + account=cls.account.account.name, + domainid=cls.account.account.domainid + ) + # Delete the VM - No longer needed + cls.virtual_machine.delete(cls.api_client) + cls.services["small"]["template"] = cls.pw_enabled_template.id + + cls.vm = VirtualMachine.create( + cls.api_client, + cls.services["small"], + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.small_offering.id, + mode=cls.services["mode"] + ) + cls._cleanup = [ + cls.small_offering, + cls.pw_enabled_template, + cls.account + ] + + @classmethod + def tearDownClass(cls): + # Cleanup VMs, templates etc. + cleanup_resources(cls.api_client, cls._cleanup) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + #Clean up, terminate the created instances + cleanup_resources(self.apiclient, self.cleanup) + return + + @attr(tags = ["advanced", "advancedns", "smoke", "basic", "sg"]) + def test_11_get_vm_password(self): + """Test get VM password for password enabled template""" + + # Validate the following + # 1. Create an account + # 2. Deploy VM with default service offering and "password enabled" + # template. Vm should be in running state. + # 3. Stop VM deployed in step 2 + # 4. Reset VM password. SSH with new password should be successful + + self.debug("Stopping VM: %s" % self.vm.name) + self.vm.stop(self.apiclient) + + # Sleep to ensure VM is stopped properly + time.sleep(self.services["sleep"]) + + self.debug("Resetting VM password for VM: %s" % self.vm.name) + password = self.vm.resetPassword(self.apiclient) + self.debug("Password reset to: %s" % password) + + self.debug("Starting VM to verify new password..") + self.vm.start(self.apiclient) + self.debug("VM - %s stated!" % self.vm.name) + + vms = VirtualMachine.list(self.apiclient, id=self.vm.id, listall=True) + self.assertEqual( + isinstance(vms, list), + True, + "List VMs should retun valid response for VM: %s" % self.vm.name + ) + virtual_machine = vms[0] + + self.assertEqual( + virtual_machine.state, + "Running", + "VM state should be running" + ) + try: + self.debug("SSHing into VM: %s" % self.vm.ssh_ip) + self.vm.password = password + ssh = self.vm.get_ssh_client() + except Exception as e: + self.fail("SSH into VM: %s failed" % self.vm.ssh_ip) + return diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index 0a5fbad8376..719984d4fd9 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -998,174 +998,4 @@ class TestVMLifeCycle(cloudstackTestCase): ) return -@unittest.skip("Additional test") -class TestVMPasswordEnabled(cloudstackTestCase): - @classmethod - def setUpClass(cls): - cls.api_client = super( - TestVMPasswordEnabled, - cls - ).getClsTestClient().getApiClient() - cls.services = Services().services - - # Get Zone, Domain and templates - domain = get_domain(cls.api_client, cls.services) - zone = get_zone(cls.api_client, cls.services) - template = get_template( - cls.api_client, - zone.id, - cls.services["ostype"] - ) - # Set Zones and disk offerings - cls.services["small"]["zoneid"] = zone.id - cls.services["small"]["template"] = template.id - - # Create VMs, NAT Rules etc - cls.account = Account.create( - cls.api_client, - cls.services["account"], - domainid=domain.id - ) - - cls.small_offering = ServiceOffering.create( - cls.api_client, - cls.services["service_offerings"]["small"] - ) - - cls.virtual_machine = VirtualMachine.create( - cls.api_client, - cls.services["small"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, - serviceofferingid=cls.small_offering.id, - mode=cls.services["mode"] - ) - #Stop virtual machine - cls.virtual_machine.stop(cls.api_client) - - # Poll listVM to ensure VM is stopped properly - timeout = cls.services["timeout"] - while True: - time.sleep(cls.services["sleep"]) - - # Ensure that VM is in stopped state - list_vm_response = list_virtual_machines( - cls.api_client, - id=cls.virtual_machine.id - ) - - if isinstance(list_vm_response, list): - - vm = list_vm_response[0] - if vm.state == 'Stopped': - break - - if timeout == 0: - raise Exception( - "Failed to stop VM (ID: %s) in change service offering" % - vm.id) - - timeout = timeout - 1 - - list_volume = list_volumes( - cls.api_client, - virtualmachineid=cls.virtual_machine.id, - type='ROOT', - listall=True - ) - if isinstance(list_volume, list): - cls.volume = list_volume[0] - else: - raise Exception( - "Exception: Unable to find root volume foe VM: %s" % - cls.virtual_machine.id) - - cls.services["template"]["ostype"] = cls.services["ostype"] - #Create templates for Edit, Delete & update permissions testcases - cls.pw_enabled_template = Template.create( - cls.api_client, - cls.services["template"], - cls.volume.id, - account=cls.account.account.name, - domainid=cls.account.account.domainid - ) - # Delete the VM - No longer needed - cls.virtual_machine.delete(cls.api_client) - cls.services["small"]["template"] = cls.pw_enabled_template.id - - cls.vm = VirtualMachine.create( - cls.api_client, - cls.services["small"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, - serviceofferingid=cls.small_offering.id, - mode=cls.services["mode"] - ) - cls._cleanup = [ - cls.small_offering, - cls.pw_enabled_template, - cls.account - ] - - @classmethod - def tearDownClass(cls): - # Cleanup VMs, templates etc. - cleanup_resources(cls.api_client, cls._cleanup) - return - - def setUp(self): - self.apiclient = self.testClient.getApiClient() - self.dbclient = self.testClient.getDbConnection() - self.cleanup = [] - - def tearDown(self): - #Clean up, terminate the created instances - cleanup_resources(self.apiclient, self.cleanup) - return - - @attr(tags = ["advanced", "advancedns", "smoke", "basic", "sg"]) - def test_11_get_vm_password(self): - """Test get VM password for password enabled template""" - - # Validate the following - # 1. Create an account - # 2. Deploy VM with default service offering and "password enabled" - # template. Vm should be in running state. - # 3. Stop VM deployed in step 2 - # 4. Reset VM password. SSH with new password should be successful - - self.debug("Stopping VM: %s" % self.vm.name) - self.vm.stop(self.apiclient) - - # Sleep to ensure VM is stopped properly - time.sleep(self.services["sleep"]) - - self.debug("Resetting VM password for VM: %s" % self.vm.name) - password = self.vm.resetPassword(self.apiclient) - self.debug("Password reset to: %s" % password) - - self.debug("Starting VM to verify new password..") - self.vm.start(self.apiclient) - self.debug("VM - %s stated!" % self.vm.name) - - vms = VirtualMachine.list(self.apiclient, id=self.vm.id, listall=True) - self.assertEqual( - isinstance(vms, list), - True, - "List VMs should retun valid response for VM: %s" % self.vm.name - ) - virtual_machine = vms[0] - - self.assertEqual( - virtual_machine.state, - "Running", - "VM state should be running" - ) - try: - self.debug("SSHing into VM: %s" % self.vm.ssh_ip) - self.vm.password = password - ssh = self.vm.get_ssh_client() - except Exception as e: - self.fail("SSH into VM: %s failed" % self.vm.ssh_ip) - return diff --git a/tools/marvin/marvin/testSetupSuccess.py b/tools/marvin/marvin/testSetupSuccess.py index 319fd21c582..b1721c40d3b 100644 --- a/tools/marvin/marvin/testSetupSuccess.py +++ b/tools/marvin/marvin/testSetupSuccess.py @@ -33,7 +33,7 @@ class TestSetupSuccess(cloudstackTestCase): zones = listZones.listZonesCmd() cls.zones_list = cls.apiClient.listZones(zones) - cls.retry = 50 + cls.retry = 2 def test_systemVmReady(self): """ From 2e2046fe389b79b2b105ef40b792263cee831929 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Thu, 21 Mar 2013 20:02:23 +0530 Subject: [PATCH 49/90] marvin changes to do an pre-integration and integration test Introducing the simulator spring context - simulatorComponentContext.xml.in. This separates the simulator beans so that production deployments don't have the simulator in them. Context is enabled with -Dsimulator as part of the developer profile. Also adding config files - Simulator Config for advanced zone and basic zone deployments under setup/dev. Signed-off-by: Prasanna Santhanam --- client/pom.xml | 67 +++-- client/tomcatconf/componentContext.xml.in | 9 - .../simulatorComponentContext.xml.in | 270 ++++++++++++++++++ setup/db/templates.simulator.sql | 2 +- .../simulator.cfg => setup/dev/advanced.cfg | 167 ++++++----- setup/dev/basic.cfg | 178 ++++++++++++ test/integration/smoke/test_vm_life_cycle.py | 14 +- tools/marvin/marvin/testSetupSuccess.py | 5 + tools/marvin/pom.xml | 49 ++-- 9 files changed, 626 insertions(+), 135 deletions(-) create mode 100644 client/tomcatconf/simulatorComponentContext.xml.in rename tools/marvin/marvin/sandbox/demo/simulator/simulator.cfg => setup/dev/advanced.cfg (54%) create mode 100644 setup/dev/basic.cfg diff --git a/client/pom.xml b/client/pom.xml index 75650295849..91dfece3952 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -218,6 +218,10 @@ org.apache.cloudstack cloud-plugin-hypervisor-simulator ${project.version} + + org.apache.cloudstack + cloud-plugin-storage-volume-default + ${project.version} @@ -376,22 +380,38 @@ - - process-nonoss - process-resources - - run - - - - test - - - - + + process-nonoss + process-resources + + run + + + + test + + + + + + process-simulator-context + process-resources + + run + + + + test + + + + process-nonoss-spring-context process-resources @@ -480,6 +500,21 @@ + + developer + + + simulator + + + + + org.apache.cloudstack + cloud-plugin-hypervisor-simulator + ${project.version} + + + netapp diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index d5714ea9f01..584be9787e8 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -203,11 +203,6 @@ - - - - - @@ -304,10 +299,6 @@ - - - - diff --git a/client/tomcatconf/simulatorComponentContext.xml.in b/client/tomcatconf/simulatorComponentContext.xml.in new file mode 100644 index 00000000000..d501ca1d10e --- /dev/null +++ b/client/tomcatconf/simulatorComponentContext.xml.in @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup/db/templates.simulator.sql b/setup/db/templates.simulator.sql index 13246233c16..a8044504487 100755 --- a/setup/db/templates.simulator.sql +++ b/setup/db/templates.simulator.sql @@ -19,4 +19,4 @@ 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, image_data_store_id) VALUES (10, 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', 1); 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, image_data_store_id) - VALUES (11, 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', 1); + VALUES (11, 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', 12, 1, 1, 'Simulator', 1); diff --git a/tools/marvin/marvin/sandbox/demo/simulator/simulator.cfg b/setup/dev/advanced.cfg similarity index 54% rename from tools/marvin/marvin/sandbox/demo/simulator/simulator.cfg rename to setup/dev/advanced.cfg index ca794605540..c031c2a4f84 100644 --- a/tools/marvin/marvin/sandbox/demo/simulator/simulator.cfg +++ b/setup/dev/advanced.cfg @@ -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 @@ -15,181 +15,180 @@ # specific language governing permissions and limitations # under the License. - { "zones": [ { - "name": "Sandbox-simulator", - "guestcidraddress": "10.1.1.0/24", - "dns1": "10.147.28.6", - "vlan": "100-200", + "name": "Sandbox-simulator", + "guestcidraddress": "10.1.1.0/24", + "dns1": "10.147.28.6", "physical_networks": [ { - "broadcastdomainrange": "Zone", - "name": "Sandbox-pnet", + "broadcastdomainrange": "Zone", + "vlan": "100-200", + "name": "Sandbox-pnet", "traffictypes": [ { "typ": "Guest" - }, + }, { "typ": "Management" - }, + }, { "typ": "Public" } - ], + ], "providers": [ { - "broadcastdomainrange": "ZONE", + "broadcastdomainrange": "ZONE", "name": "VirtualRouter" - }, + }, { - "broadcastdomainrange": "ZONE", + "broadcastdomainrange": "ZONE", "name": "VpcVirtualRouter" } ] } - ], + ], "ipranges": [ { - "startip": "192.168.2.2", - "endip": "192.168.2.200", - "netmask": "255.255.255.0", - "vlan": "50", + "startip": "192.168.2.2", + "endip": "192.168.2.200", + "netmask": "255.255.255.0", + "vlan": "50", "gateway": "192.168.2.1" } - ], - "networktype": "Advanced", + ], + "networktype": "Advanced", "pods": [ { - "endip": "172.16.15.200", - "name": "POD0", - "startip": "172.16.15.2", - "netmask": "255.255.255.0", + "endip": "172.16.15.200", + "name": "POD0", + "startip": "172.16.15.2", + "netmask": "255.255.255.0", "clusters": [ { - "clustername": "C0", - "hypervisor": "simulator", + "clustername": "C0", + "hypervisor": "simulator", "hosts": [ { - "username": "root", - "url": "http://sim/c0/h0", + "username": "root", + "url": "http://sim/c0/h0", "password": "password" - }, + }, { - "username": "root", - "url": "http://sim/c0/h1", + "username": "root", + "url": "http://sim/c0/h1", "password": "password" } - ], - "clustertype": "CloudManaged", + ], + "clustertype": "CloudManaged", "primaryStorages": [ { - "url": "nfs://10.147.28.6:/export/home/sandbox/primary", + "url": "nfs://10.147.28.6:/export/home/sandbox/primary", "name": "PS0" } ] } - ], + ], "gateway": "172.16.15.1" } - ], - "internaldns1": "10.147.28.6", + ], + "internaldns1": "10.147.28.6", "secondaryStorages": [ { "url": "nfs://10.147.28.6:/export/home/sandbox/secondary" } ] } - ], + ], "dbSvr": { - "dbSvr": "localhost", - "passwd": "cloud", - "db": "cloud", - "port": 3306, + "dbSvr": "localhost", + "passwd": "cloud", + "db": "cloud", + "port": 3306, "user": "cloud" - }, + }, "logger": [ { - "name": "TestClient", + "name": "TestClient", "file": "/tmp/testclient.log" - }, + }, { - "name": "TestCase", + "name": "TestCase", "file": "/tmp/testcase.log" } - ], + ], "globalConfig": [ { - "name": "network.gc.wait", + "name": "network.gc.wait", "value": "60" - }, + }, { - "name": "storage.cleanup.interval", + "name": "storage.cleanup.interval", "value": "300" - }, + }, { - "name": "vm.op.wait.interval", + "name": "vm.op.wait.interval", "value": "5" - }, + }, { - "name": "default.page.size", + "name": "default.page.size", "value": "10000" - }, + }, { - "name": "network.gc.interval", + "name": "network.gc.interval", "value": "60" - }, + }, { - "name": "instance.name", + "name": "instance.name", "value": "QA" - }, + }, { - "name": "workers", + "name": "workers", "value": "10" - }, + }, { - "name": "account.cleanup.interval", + "name": "account.cleanup.interval", "value": "600" - }, + }, { - "name": "guest.domain.suffix", + "name": "guest.domain.suffix", "value": "sandbox.simulator" - }, + }, { - "name": "expunge.delay", + "name": "expunge.delay", "value": "60" - }, + }, { - "name": "vm.allocation.algorithm", + "name": "vm.allocation.algorithm", "value": "random" - }, + }, { - "name": "expunge.interval", + "name": "expunge.interval", "value": "60" - }, + }, { - "name": "expunge.workers", + "name": "expunge.workers", "value": "3" - }, + }, { - "name": "check.pod.cidrs", + "name": "check.pod.cidrs", "value": "true" - }, + }, { - "name": "secstorage.allowed.internal.sites", + "name": "secstorage.allowed.internal.sites", "value": "10.147.28.0/24" - }, + }, { - "name": "direct.agent.load.size", + "name": "direct.agent.load.size", "value": "1000" } - ], + ], "mgtSvr": [ { - "mgtSvrIp": "localhost", - "passwd": "password", - "user": "root", + "mgtSvrIp": "localhost", + "passwd": "password", + "user": "root", "port": 8096 } ] diff --git a/setup/dev/basic.cfg b/setup/dev/basic.cfg new file mode 100644 index 00000000000..fb99b8b5498 --- /dev/null +++ b/setup/dev/basic.cfg @@ -0,0 +1,178 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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": "Sandbox-simulator", + "dns1": "8.8.8.8", + "physical_networks": [ + { + "broadcastdomainrange": "Zone", + "name": "Sandbox-pnet", + "traffictypes": [ + { + "typ": "Guest" + }, + { + "typ": "Management" + } + ], + "providers": [ + { + "broadcastdomainrange": "ZONE", + "name": "VirtualRouter" + }, + { + "broadcastdomainrange": "Pod", + "name": "SecurityGroupProvider" + } + ] + } + ], + "securitygroupenabled": "true", + "networktype": "Basic", + "pods": [ + { + "endip": "172.16.15.254", + "name": "POD0", + "startip": "172.16.15.2", + "guestIpRanges": [ + { + "startip": "60.147.41.2", + "endip": "60.147.41.254", + "netmask": "255.255.255.0", + "gateway": "60.147.40.1" + } + ], + "netmask": "255.255.255.0", + "clusters": [ + { + "clustername": "C0", + "hypervisor": "simulator", + "hosts": [ + { + "username": "root", + "url": "http://sim/c0/h0", + "password": "password" + } + ], + "clustertype": "CloudManaged", + "primaryStorages": [ + { + "url": "nfs://nfsstor:/export/home/sandbox/primary", + "name": "PS0" + } + ] + } + ], + "gateway": "172.16.15.1" + } + ], + "internaldns1": "8.8.8.8", + "secondaryStorages": [ + { + "url": "nfs://nfsstor:/export/home/sandbox/secondary" + } + ] + } + ], + "dbSvr": { + "dbSvr": "localhost", + "passwd": "cloud", + "db": "cloud", + "port": 3306, + "user": "cloud" + }, + "logger": [ + { + "name": "TestClient", + "file": "/var/log/testclient.log" + }, + { + "name": "TestCase", + "file": "/var/log/testcase.log" + } + ], + "globalConfig": [ + { + "name": "storage.cleanup.interval", + "value": "300" + }, + { + "name": "direct.agent.load.size", + "value": "1000" + }, + { + "name": "default.page.size", + "value": "10000" + }, + { + "name": "instance.name", + "value": "QA" + }, + { + "name": "workers", + "value": "10" + }, + { + "name": "vm.op.wait.interval", + "value": "5" + }, + { + "name": "account.cleanup.interval", + "value": "600" + }, + { + "name": "guest.domain.suffix", + "value": "sandbox.simulator" + }, + { + "name": "expunge.delay", + "value": "60" + }, + { + "name": "vm.allocation.algorithm", + "value": "random" + }, + { + "name": "expunge.interval", + "value": "60" + }, + { + "name": "expunge.workers", + "value": "3" + }, + { + "name": "secstorage.allowed.internal.sites", + "value": "172.16.15.0/24" + }, + { + "name": "check.pod.cidrs", + "value": "true" + } + ], + "mgtSvr": [ + { + "mgtSvrIp": "localhost", + "passwd": "password", + "user": "root", + "port": 8096 + } + ] +} diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index 719984d4fd9..143fea71975 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -20,7 +20,6 @@ import marvin from marvin.cloudstackTestCase import * from marvin.cloudstackAPI import * -from marvin.remoteSSHClient import remoteSSHClient from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * @@ -177,7 +176,7 @@ class TestDeployVM(cloudstackTestCase): self.account ] - @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"]) + @attr(tags = ["simulator", "devcloud", "advanced", "advancedns", "smoke", "basic", "sg"]) def test_deploy_vm(self): """Test Deploy Virtual Machine """ @@ -231,6 +230,13 @@ class TestDeployVM(cloudstackTestCase): self.virtual_machine.name, "Check virtual machine name in listVirtualMachines" ) + + self.assertEqual( + vm_response.state, + 'Running', + msg="VM is not in Running state" + ) + return def tearDown(self): @@ -996,6 +1002,4 @@ class TestVMLifeCycle(cloudstackTestCase): False, "Check if ISO is detached from virtual machine" ) - return - - + return \ No newline at end of file diff --git a/tools/marvin/marvin/testSetupSuccess.py b/tools/marvin/marvin/testSetupSuccess.py index b1721c40d3b..dcd15e674eb 100644 --- a/tools/marvin/marvin/testSetupSuccess.py +++ b/tools/marvin/marvin/testSetupSuccess.py @@ -76,6 +76,11 @@ class TestSetupSuccess(cloudstackTestCase): delay(60) #wait a minute for retry self.assertNotEqual(retry, 0, "builtIn templates not ready in zone %s"%z.name) + def test_deployVmWithBuiltIn(self): + """ + Deploys a VM with the built-in CentOS template + """ + @classmethod def tearDownClass(cls): pass diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index 194d7841030..ff5176fbcb6 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -48,8 +48,8 @@ 1.2.1 - compile - compile + generate-sources + generate-sources exec @@ -80,7 +80,6 @@ - @@ -88,7 +87,9 @@ marvin - marvin.config + + marvin.config + @@ -96,24 +97,32 @@ org.codehaus.mojo exec-maven-plugin 1.2.1 - - ${basedir}/marvin - python - - deployAndRun.py - -c - ${user.dir}/${marvin.config} - -t - /tmp/t.log - -r - /tmp/r.log - -f - ${basedir}/marvin/testSetupSuccess.py - - - test + pre-integration-test + pre-integration-test + + exec + + + ${basedir}/marvin + python + + deployAndRun.py + -c + ${user.dir}/${marvin.config} + -t + /tmp/t.log + -r + /tmp/r.log + -f + ${basedir}/marvin/testSetupSuccess.py + + + + + integration-test + integration-test exec From 9c755e11e5067bfbc14581a3a3fac9b5b7fd21a1 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Sat, 23 Mar 2013 20:25:21 +0530 Subject: [PATCH 50/90] marvin-nose: include the plugin as part of marvin install No need to register the plugin seperately now. The installer will register with nose's entry_point automatically. Signed-off-by: Prasanna Santhanam --- tools/marvin/marvin/setup.py | 52 -------------------------------- tools/marvin/setup.py | 58 ++++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 74 deletions(-) delete mode 100644 tools/marvin/marvin/setup.py diff --git a/tools/marvin/marvin/setup.py b/tools/marvin/marvin/setup.py deleted file mode 100644 index 07ff5b5a577..00000000000 --- a/tools/marvin/marvin/setup.py +++ /dev/null @@ -1,52 +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. - -import os -try: - from setuptools import setup, find_packages -except ImportError: - from distribute_setup import use_setuptools - use_setuptools() - from setuptools import setup, find_packages - - -def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname)).read().strip() - -VERSION = '0.1.0' - -setup( - name = "marvin-nose", - version = VERSION, - author = "Prasanna Santhanam", - author_email = "Prasanna.Santhanam@citrix.com", - description = "Run tests written using CloudStack's Marvin testclient", - license = 'ASL 2.0', - classifiers = [ - "Intended Audience :: Developers", - "Topic :: Software Development :: Testing", - "Programming Language :: Python", - ], - - py_modules = ['marvinPlugin'], - zip_safe = False, - - entry_points = { - 'nose.plugins': ['marvinPlugin = marvinPlugin:MarvinPlugin'] - }, - install_requires = ['nose', 'marvin'], -) diff --git a/tools/marvin/setup.py b/tools/marvin/setup.py index f8198d7999b..ab5eb6f7c24 100644 --- a/tools/marvin/setup.py +++ b/tools/marvin/setup.py @@ -16,27 +16,41 @@ # specific language governing permissions and limitations # under the License. -from setuptools import setup -from sys import version -import sys +try: + from setuptools import setup, find_packages +except ImportError: + from distribute_setup import use_setuptools + use_setuptools() + from setuptools import setup, find_packages + +VERSION = '0.1.0' + +import os +def read(fname): + return open(os.path.join(os.path.dirname(__file__), fname)).read().strip() setup(name="Marvin", - version="0.1.0", - description="Marvin - Python client for testing cloudstack", - author="Edison Su", - author_email="Edison.Su@citrix.com", - maintainer="Prasanna Santhanam", - maintainer_email="Prasanna.Santhanam@citrix.com", - long_description="Marvin is the cloudstack testclient written around the python unittest framework", - platforms=("Any",), - url="http://jenkins.cloudstack.org:8080/job/marvin", - packages=["marvin", "marvin.cloudstackAPI", "marvin.integration", - "marvin.integration.lib", "marvin.sandbox", - "marvin.sandbox.advanced", "marvin.sandbox.basic"], - license="LICENSE.txt", - install_requires=[ - "mysql-connector-python", - "paramiko", - "nose" - ], - ) + version=VERSION, + description="Marvin - Python client for Apache CloudStack", + author="Edison Su", + author_email="Edison.Su@citrix.com", + maintainer="Prasanna Santhanam", + maintainer_email="Prasanna.Santhanam@citrix.com", + long_description="Marvin is the Apache CloudStack python client written around the unittest framework", + platforms=("Any",), + url="https://builds.apache.org/view/CloudStack/job/cloudstack-marvin/", + packages=["marvin", "marvin.cloudstackAPI", "marvin.integration", + "marvin.integration.lib", "marvin.sandbox", + "marvin.sandbox.advanced", "marvin.sandbox.basic"], + license="LICENSE.txt", + install_requires=[ + "mysql-connector-python", + "paramiko", + "nose" + ], + py_modules=['marvin.marvinPlugin'], + zip_safe=False, + entry_points={ + 'nose.plugins': ['marvinPlugin = marvin.marvinPlugin:MarvinPlugin'] + }, +) From d4dc2649173f17d230b1d4332b3e0d9466fb3f20 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Mon, 25 Mar 2013 18:36:37 +0530 Subject: [PATCH 51/90] simulator+marvin: include a router test Added a test that will ensure the advanced router comes up in the account belonging to the deployed VM. It should come up with the publicip, guestip and linklocalip. Signed-off-by: Prasanna Santhanam --- test/integration/smoke/test_vm_life_cycle.py | 137 +++++++++++-------- tools/marvin/pom.xml | 22 --- 2 files changed, 79 insertions(+), 80 deletions(-) diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index 143fea71975..d9571f66833 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -129,72 +129,79 @@ class Services: class TestDeployVM(cloudstackTestCase): - def setUp(self): - - self.apiclient = self.testClient.getApiClient() - self.dbclient = self.testClient.getDbConnection() - self.services = Services().services + @classmethod + def setUpClass(cls): + cls.services = Services().services + cls.apiclient = super(TestDeployVM, cls).getClsTestClient().getApiClient() # Get Zone, Domain and templates - domain = get_domain(self.apiclient, self.services) - zone = get_zone(self.apiclient, self.services) - self.services['mode'] = zone.networktype + domain = get_domain(cls.apiclient, cls.services) + zone = get_zone(cls.apiclient, cls.services) + cls.services['mode'] = zone.networktype - #if local storage is enabled, alter the offerings to use localstorage + #If local storage is enabled, alter the offerings to use localstorage #this step is needed for devcloud if zone.localstorageenabled == True: - self.services["service_offerings"]["tiny"]["storagetype"] = 'local' - self.services["service_offerings"]["small"]["storagetype"] = 'local' - self.services["service_offerings"]["medium"]["storagetype"] = 'local' + cls.services["service_offerings"]["tiny"]["storagetype"] = 'local' + cls.services["service_offerings"]["small"]["storagetype"] = 'local' + cls.services["service_offerings"]["medium"]["storagetype"] = 'local' template = get_template( - self.apiclient, - zone.id, - self.services["ostype"] - ) + cls.apiclient, + zone.id, + cls.services["ostype"] + ) # Set Zones and disk offerings - self.services["small"]["zoneid"] = zone.id - self.services["small"]["template"] = template.id + cls.services["small"]["zoneid"] = zone.id + cls.services["small"]["template"] = template.id - self.services["medium"]["zoneid"] = zone.id - self.services["medium"]["template"] = template.id - self.services["iso"]["zoneid"] = zone.id + cls.services["medium"]["zoneid"] = zone.id + cls.services["medium"]["template"] = template.id + cls.services["iso"]["zoneid"] = zone.id - # Create Account, VMs, NAT Rules etc - self.account = Account.create( - self.apiclient, - self.services["account"], - domainid=domain.id - ) + cls.account = Account.create( + cls.apiclient, + cls.services["account"], + domainid=domain.id + ) + + cls.service_offering = ServiceOffering.create( + cls.apiclient, + cls.services["service_offerings"]["tiny"] + ) + + cls.virtual_machine = VirtualMachine.create( + cls.apiclient, + cls.services["small"], + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services['mode'] + ) + + cls.cleanup = [ + cls.service_offering, + cls.account + ] + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.apiclient, cls.cleanup) + except Exception as e: + cls.debug("Warning! Exception in tearDown: %s" % e) + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() - self.service_offering = ServiceOffering.create( - self.apiclient, - self.services["service_offerings"]["tiny"] - ) - # Cleanup - self.cleanup = [ - self.service_offering, - self.account - ] @attr(tags = ["simulator", "devcloud", "advanced", "advancedns", "smoke", "basic", "sg"]) def test_deploy_vm(self): """Test Deploy Virtual Machine """ - # Validate the following: # 1. Virtual Machine is accessible via SSH # 2. listVirtualMachines returns accurate information - # 3. The Cloud Database contains the valid information - - self.virtual_machine = VirtualMachine.create( - self.apiclient, - self.services["small"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, - serviceofferingid=self.service_offering.id, - mode=self.services['mode'] - ) - list_vm_response = list_virtual_machines( self.apiclient, id=self.virtual_machine.id @@ -204,46 +211,60 @@ class TestDeployVM(cloudstackTestCase): "Verify listVirtualMachines response for virtual machine: %s" \ % self.virtual_machine.id ) - self.assertEqual( isinstance(list_vm_response, list), True, "Check list response returns a valid list" ) - self.assertNotEqual( len(list_vm_response), 0, "Check VM available in List Virtual Machines" ) vm_response = list_vm_response[0] - self.assertEqual( vm_response.id, self.virtual_machine.id, "Check virtual machine id in listVirtualMachines" ) - self.assertEqual( vm_response.name, self.virtual_machine.name, "Check virtual machine name in listVirtualMachines" ) - self.assertEqual( vm_response.state, 'Running', msg="VM is not in Running state" ) - return + + @attr(tags = ["simulator", "advanced"]) + def test_advZoneVirtualRouter(self): + """ + Test advanced zone virtual router + 1. Is Running + 2. is in the account the VM was deployed in + 3. Has a linklocalip, publicip and a guestip + @return: + """ + routers = list_routers(self.apiclient, account=self.account.account.name) + self.assertTrue(len(routers) > 0, msg = "No virtual router found") + router = routers[0] + + self.assertEqual(router.state, 'Running', msg="Router is not in running state") + self.assertEqual(router.account, self.account.account.name, msg="Router does not belong to the account") + + #Has linklocal, public and guest ips + self.assertIsNotNone(router.linklocalip, msg="Router has no linklocal ip") + self.assertIsNotNone(router.publicip, msg="Router has no public ip") + self.assertIsNotNone(router.guestipaddress, msg="Router has no guest ip") + def tearDown(self): - try: - cleanup_resources(self.apiclient, self.cleanup) - except Exception as e: - self.debug("Warning! Exception in tearDown: %s" % e) + pass + class TestVMLifeCycle(cloudstackTestCase): diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index ff5176fbcb6..4f012eedf08 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -140,28 +140,6 @@ - From 5d67c98e5b7b763fde5ea87850e9cd7bafd2a4e1 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Tue, 26 Mar 2013 18:29:23 +0530 Subject: [PATCH 52/90] marvin+apidiscovery: Extend API discovery plugin API discovery plugin will return embedded entities for marvin to discovery and generate it's API classes. Signed-off-by: Prasanna Santhanam --- client/pom.xml | 5 - .../api/response/ApiDiscoveryResponse.java | 4 + .../api/response/ApiResponseResponse.java | 15 +- .../discovery/ApiDiscoveryServiceImpl.java | 167 ++++++++++-------- .../api/response/ApiResponseSerializer.java | 32 ++-- .../response/EmptyFieldExclusionStrategy.java | 40 +++++ test/integration/smoke/test_vm_life_cycle.py | 17 +- tools/marvin/marvin/cloudstackTestClient.py | 15 +- tools/marvin/marvin/codegenerator.py | 96 +++++++++- tools/marvin/marvin/marvinPlugin.py | 14 ++ 10 files changed, 295 insertions(+), 110 deletions(-) create mode 100644 server/src/com/cloud/api/response/EmptyFieldExclusionStrategy.java diff --git a/client/pom.xml b/client/pom.xml index 91dfece3952..35588aa2c93 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -90,11 +90,6 @@ cloud-plugin-hypervisor-baremetal ${project.version} - - org.apache.cloudstack - cloud-plugin-hypervisor-ucs - ${project.version} - org.apache.cloudstack cloud-plugin-hypervisor-ovm diff --git a/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java b/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java index 77484f0f7e7..ce7eb498be9 100644 --- a/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java +++ b/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java @@ -47,6 +47,9 @@ public class ApiDiscoveryResponse extends BaseResponse { @SerializedName(ApiConstants.RESPONSE) @Param(description="api response fields", responseObject = ApiResponseResponse.class) private Set apiResponse; + @SerializedName(ApiConstants.TYPE) @Param(description="response field type") + private String type; + public ApiDiscoveryResponse(){ params = new HashSet(); apiResponse = new HashSet(); @@ -81,6 +84,7 @@ public class ApiDiscoveryResponse extends BaseResponse { this.isAsync = isAsync; } + public boolean getAsync() { return isAsync; } diff --git a/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiResponseResponse.java b/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiResponseResponse.java index b96295e1290..1433879a6ce 100644 --- a/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiResponseResponse.java +++ b/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiResponseResponse.java @@ -16,11 +16,14 @@ // under the License. package org.apache.cloudstack.api.response; -import org.apache.cloudstack.api.ApiConstants; import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; +import java.util.HashSet; +import java.util.Set; + public class ApiResponseResponse extends BaseResponse { @SerializedName(ApiConstants.NAME) @Param(description="the name of the api response field") private String name; @@ -31,6 +34,9 @@ public class ApiResponseResponse extends BaseResponse { @SerializedName(ApiConstants.TYPE) @Param(description="response field type") private String type; + @SerializedName(ApiConstants.RESPONSE) @Param(description="api response fields") + private Set apiResponse; + public void setName(String name) { this.name = name; } @@ -42,4 +48,11 @@ public class ApiResponseResponse extends BaseResponse { public void setType(String type) { this.type = type; } + + public void addApiResponse(ApiResponseResponse childApiResponse) { + if(this.apiResponse == null) { + this.apiResponse = new HashSet(); + } + this.apiResponse.add(childApiResponse); + } } diff --git a/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java b/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java index b3714883964..2d7dbd18671 100755 --- a/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java +++ b/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java @@ -16,25 +16,14 @@ // under the License. package org.apache.cloudstack.discovery; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.annotation.PostConstruct; -import javax.ejb.Local; -import javax.inject.Inject; - +import com.cloud.serializer.Param; +import com.cloud.user.User; +import com.cloud.utils.ReflectUtil; +import com.cloud.utils.StringUtils; +import com.cloud.utils.component.PluggableService; +import com.google.gson.annotations.SerializedName; import org.apache.cloudstack.acl.APIChecker; -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.BaseAsyncCmd; -import org.apache.cloudstack.api.BaseAsyncCreateCmd; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.BaseResponse; -import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.*; import org.apache.cloudstack.api.command.user.discovery.ListApisCmd; import org.apache.cloudstack.api.response.ApiDiscoveryResponse; import org.apache.cloudstack.api.response.ApiParameterResponse; @@ -43,12 +32,11 @@ import org.apache.cloudstack.api.response.ListResponse; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.cloud.serializer.Param; -import com.cloud.user.User; -import com.cloud.utils.ReflectUtil; -import com.cloud.utils.StringUtils; -import com.cloud.utils.component.PluggableService; -import com.google.gson.annotations.SerializedName; +import javax.annotation.PostConstruct; +import javax.ejb.Local; +import javax.inject.Inject; +import java.lang.reflect.Field; +import java.util.*; @Component @Local(value = ApiDiscoveryService.class) @@ -69,9 +57,9 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService { long startTime = System.nanoTime(); s_apiNameDiscoveryResponseMap = new HashMap(); Set> cmdClasses = new HashSet>(); - for(PluggableService service: _services) { + for(PluggableService service: _services) { s_logger.debug(String.format("getting api commands of service: %s", service.getClass().getName())); - cmdClasses.addAll(service.getCommands()); + cmdClasses.addAll(service.getCommands()); } cmdClasses.addAll(this.getCommands()); cacheResponseMap(cmdClasses); @@ -80,72 +68,39 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService { } } - protected void cacheResponseMap(Set> cmdClasses) { + protected Map> cacheResponseMap(Set> cmdClasses) { Map> responseApiNameListMap = new HashMap>(); for(Class cmdClass: cmdClasses) { APICommand apiCmdAnnotation = cmdClass.getAnnotation(APICommand.class); - if (apiCmdAnnotation == null) + if (apiCmdAnnotation == null) { apiCmdAnnotation = cmdClass.getSuperclass().getAnnotation(APICommand.class); + } if (apiCmdAnnotation == null || !apiCmdAnnotation.includeInApiDoc() - || apiCmdAnnotation.name().isEmpty()) + || apiCmdAnnotation.name().isEmpty()) { continue; + } String apiName = apiCmdAnnotation.name(); + ApiDiscoveryResponse response = getCmdRequestMap(cmdClass, apiCmdAnnotation); + String responseName = apiCmdAnnotation.responseObject().getName(); if (!responseName.contains("SuccessResponse")) { - if (!responseApiNameListMap.containsKey(responseName)) + if (!responseApiNameListMap.containsKey(responseName)) { responseApiNameListMap.put(responseName, new ArrayList()); + } responseApiNameListMap.get(responseName).add(apiName); } - ApiDiscoveryResponse response = new ApiDiscoveryResponse(); - response.setName(apiName); - response.setDescription(apiCmdAnnotation.description()); - if (!apiCmdAnnotation.since().isEmpty()) - response.setSince(apiCmdAnnotation.since()); response.setRelated(responseName); + Field[] responseFields = apiCmdAnnotation.responseObject().getDeclaredFields(); for(Field responseField: responseFields) { - SerializedName serializedName = responseField.getAnnotation(SerializedName.class); - if(serializedName != null) { - ApiResponseResponse responseResponse = new ApiResponseResponse(); - responseResponse.setName(serializedName.value()); - Param param = responseField.getAnnotation(Param.class); - if (param != null) - responseResponse.setDescription(param.description()); - responseResponse.setType(responseField.getType().getSimpleName().toLowerCase()); - response.addApiResponse(responseResponse); - } + ApiResponseResponse responseResponse = getFieldResponseMap(responseField); + response.addApiResponse(responseResponse); } - Set fields = ReflectUtil.getAllFieldsForClass(cmdClass, - new Class[]{BaseCmd.class, BaseAsyncCmd.class, BaseAsyncCreateCmd.class}); - - boolean isAsync = ReflectUtil.isCmdClassAsync(cmdClass, - new Class[] {BaseAsyncCmd.class, BaseAsyncCreateCmd.class}); - - response.setAsync(isAsync); - - for(Field field: fields) { - Parameter parameterAnnotation = field.getAnnotation(Parameter.class); - if (parameterAnnotation != null - && parameterAnnotation.expose() - && parameterAnnotation.includeInApiDoc()) { - - ApiParameterResponse paramResponse = new ApiParameterResponse(); - paramResponse.setName(parameterAnnotation.name()); - paramResponse.setDescription(parameterAnnotation.description()); - paramResponse.setType(parameterAnnotation.type().toString().toLowerCase()); - paramResponse.setLength(parameterAnnotation.length()); - paramResponse.setRequired(parameterAnnotation.required()); - if (!parameterAnnotation.since().isEmpty()) - paramResponse.setSince(parameterAnnotation.since()); - paramResponse.setRelated(parameterAnnotation.entityType()[0].getName()); - response.addParam(paramResponse); - } - } response.setObjectName("api"); s_apiNameDiscoveryResponseMap.put(apiName, response); } @@ -173,6 +128,76 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService { } s_apiNameDiscoveryResponseMap.put(apiName, response); } + return responseApiNameListMap; + } + + private ApiResponseResponse getFieldResponseMap(Field responseField) { + ApiResponseResponse responseResponse = new ApiResponseResponse(); + SerializedName serializedName = responseField.getAnnotation(SerializedName.class); + Param param = responseField.getAnnotation(Param.class); + if (serializedName != null && param != null) { + responseResponse.setName(serializedName.value()); + responseResponse.setDescription(param.description()); + responseResponse.setType(responseField.getType().getSimpleName().toLowerCase()); + //If response is not of primitive type - we have a nested entity + Class fieldClass = param.responseObject(); + if (fieldClass != null) { + Class superClass = fieldClass.getSuperclass(); + if (superClass != null) { + String superName = superClass.getName(); + if (superName.equals(BaseResponse.class.getName())) { + Field[] fields = fieldClass.getDeclaredFields(); + for (Field field : fields) { + ApiResponseResponse innerResponse = getFieldResponseMap(field); + if (innerResponse != null) { + responseResponse.addApiResponse(innerResponse); + } + } + } + } + } + } + return responseResponse; + } + + private ApiDiscoveryResponse getCmdRequestMap(Class cmdClass, APICommand apiCmdAnnotation) { + String apiName = apiCmdAnnotation.name(); + ApiDiscoveryResponse response = new ApiDiscoveryResponse(); + response.setName(apiName); + response.setDescription(apiCmdAnnotation.description()); + if (!apiCmdAnnotation.since().isEmpty()) { + response.setSince(apiCmdAnnotation.since()); + } + + + Set fields = ReflectUtil.getAllFieldsForClass(cmdClass, + new Class[]{BaseCmd.class, BaseAsyncCmd.class, BaseAsyncCreateCmd.class}); + + boolean isAsync = ReflectUtil.isCmdClassAsync(cmdClass, + new Class[]{BaseAsyncCmd.class, BaseAsyncCreateCmd.class}); + + response.setAsync(isAsync); + + for(Field field: fields) { + Parameter parameterAnnotation = field.getAnnotation(Parameter.class); + if (parameterAnnotation != null + && parameterAnnotation.expose() + && parameterAnnotation.includeInApiDoc()) { + + ApiParameterResponse paramResponse = new ApiParameterResponse(); + paramResponse.setName(parameterAnnotation.name()); + paramResponse.setDescription(parameterAnnotation.description()); + paramResponse.setType(parameterAnnotation.type().toString().toLowerCase()); + paramResponse.setLength(parameterAnnotation.length()); + paramResponse.setRequired(parameterAnnotation.required()); + if (!parameterAnnotation.since().isEmpty()) { + paramResponse.setSince(parameterAnnotation.since()); + } + paramResponse.setRelated(parameterAnnotation.entityType()[0].getName()); + response.addParam(paramResponse); + } + } + return response; } @Override diff --git a/server/src/com/cloud/api/response/ApiResponseSerializer.java b/server/src/com/cloud/api/response/ApiResponseSerializer.java index 3b1d9a6368b..965660a52cc 100644 --- a/server/src/com/cloud/api/response/ApiResponseSerializer.java +++ b/server/src/com/cloud/api/response/ApiResponseSerializer.java @@ -16,33 +16,25 @@ // under the License. package com.cloud.api.response; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.cloudstack.api.response.ListResponse; -import org.apache.cloudstack.api.response.*; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.ApiConstants; import com.cloud.api.ApiDBUtils; import com.cloud.api.ApiResponseGsonHelper; import com.cloud.api.ApiServer; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.ResponseObject; import com.cloud.utils.encoding.URLEncoder; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.uuididentity.dao.IdentityDao; -import com.cloud.uuididentity.dao.IdentityDaoImpl; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.ResponseObject; +import org.apache.cloudstack.api.response.*; +import org.apache.log4j.Logger; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class ApiResponseSerializer { private static final Logger s_logger = Logger.getLogger(ApiResponseSerializer.class.getName()); diff --git a/server/src/com/cloud/api/response/EmptyFieldExclusionStrategy.java b/server/src/com/cloud/api/response/EmptyFieldExclusionStrategy.java new file mode 100644 index 00000000000..3099d83d75c --- /dev/null +++ b/server/src/com/cloud/api/response/EmptyFieldExclusionStrategy.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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.response; + +import com.cloud.serializer.Param; +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; + +public class EmptyFieldExclusionStrategy implements ExclusionStrategy { + + @Override + public boolean shouldSkipField(FieldAttributes fieldAttributes) { + if (fieldAttributes.getAnnotation(Param.class) != null) { + return true; + } + return false; + } + + @Override + public boolean shouldSkipClass(Class aClass) { + return false; + } +} diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index d9571f66833..564f6e854a5 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -262,11 +262,26 @@ class TestDeployVM(cloudstackTestCase): self.assertIsNotNone(router.publicip, msg="Router has no public ip") self.assertIsNotNone(router.guestipaddress, msg="Router has no guest ip") + @attr(hypervisor = ["simulator"]) + @attr(mode = ["basic"]) + def test_basicZoneVirtualRouter(self): + """ + Tests for basic zone virtual router + 1. Is Running + 2. is in the account the VM was deployed in + @return: + """ + routers = list_routers(self.apiclient, account=self.account.account.name) + self.assertTrue(len(routers) > 0, msg = "No virtual router found") + router = routers[0] + + self.assertEqual(router.state, 'Running', msg="Router is not in running state") + self.assertEqual(router.account, self.account.account.name, msg="Router does not belong to the account") + def tearDown(self): pass - class TestVMLifeCycle(cloudstackTestCase): @classmethod diff --git a/tools/marvin/marvin/cloudstackTestClient.py b/tools/marvin/marvin/cloudstackTestClient.py index cb63179f40f..4bfb90be4a8 100644 --- a/tools/marvin/marvin/cloudstackTestClient.py +++ b/tools/marvin/marvin/cloudstackTestClient.py @@ -24,7 +24,8 @@ import string import hashlib class cloudstackTestClient(object): - def __init__(self, mgtSvr=None, port=8096, apiKey = None, securityKey = None, asyncTimeout=3600, defaultWorkerThreads=10, logging=None): + def __init__(self, mgtSvr=None, port=8096, apiKey = None, securityKey = None, asyncTimeout=3600, + defaultWorkerThreads=10, logging=None): self.connection = cloudstackConnection.cloudConnection(mgtSvr, port, apiKey, securityKey, asyncTimeout, logging) self.apiClient = cloudstackAPIClient.CloudStackAPIClient(self.connection) self.dbConnection = None @@ -32,7 +33,6 @@ class cloudstackTestClient(object): self.ssh = None self.defaultWorkerThreads = defaultWorkerThreads - def dbConfigure(self, host="localhost", port=3306, user='cloud', passwd='cloud', db='cloud'): self.dbConnection = dbConnection.dbConnection(host, port, user, passwd, db) @@ -147,7 +147,16 @@ class cloudstackTestClient(object): if hasattr(self, "userApiClient"): return self.userApiClient return None - + + def synchronize(self): + """ + synchronize the api from an endpoint + """ + apiclient = self.getApiClient() + cmd = listApis.listApisCmd() + response = apiclient.listApis(cmd) + + '''FixME, httplib has issue if more than one thread submitted''' def submitCmdsAndWait(self, cmds, workers=1): if self.asyncJobMgr is None: diff --git a/tools/marvin/marvin/codegenerator.py b/tools/marvin/marvin/codegenerator.py index ed9248c49a3..5d9a2dfc5de 100644 --- a/tools/marvin/marvin/codegenerator.py +++ b/tools/marvin/marvin/codegenerator.py @@ -16,10 +16,12 @@ # under the License. import xml.dom.minidom +import json from optparse import OptionParser from textwrap import dedent import os import sys + class cmdParameterProperty(object): def __init__(self): self.name = None @@ -97,6 +99,7 @@ class codeGenerator: subclass += self.space + self.space + 'self.%s = None\n'%pro.name self.subclass.append(subclass) + def generate(self, cmd): self.cmd = cmd @@ -159,8 +162,7 @@ class codeGenerator: fp.close() self.code = "" self.subclass = [] - - + def finalize(self): '''generate an api call''' @@ -215,8 +217,7 @@ class codeGenerator: fp.write(basecmd) fp.close() - - def constructResponse(self, response): + def constructResponseFromXML(self, response): paramProperty = cmdParameterProperty() paramProperty.name = getText(response.getElementsByTagName('name')) paramProperty.desc = getText(response.getElementsByTagName('description')) @@ -224,7 +225,23 @@ class codeGenerator: '''This is a list''' paramProperty.name = paramProperty.name.split('(*)')[0] for subresponse in response.getElementsByTagName('arguments')[0].getElementsByTagName('arg'): - subProperty = self.constructResponse(subresponse) + subProperty = self.constructResponseFromXML(subresponse) + paramProperty.subProperties.append(subProperty) + return paramProperty + + def constructResponseFromJSON(self, response): + paramProperty = cmdParameterProperty() + if response.has_key('name'): + paramProperty.name = response['name'] + assert paramProperty.name + + if response.has_key('description'): + paramProperty.desc = response['description'] + if response.has_key('type') and response['type'] == 'list': + #Here list becomes a subproperty + paramProperty.name = paramProperty.name.split('(*)')[0] + for subresponse in response.getElementsByTagName('arguments')[0].getElementsByTagName('arg'): + subProperty = self.constructResponseFromXML(subresponse) paramProperty.subProperties.append(subProperty) return paramProperty @@ -269,18 +286,79 @@ class codeGenerator: if response.parentNode != responseEle: continue - paramProperty = self.constructResponse(response) + paramProperty = self.constructResponseFromXML(response) csCmd.response.append(paramProperty) cmds.append(csCmd) return cmds - - def generateCode(self): + + def loadCmdFromJSON(self, apiStream): + if apiStream is None: + raise Exception("No APIs found through discovery") + + apiDict = json.loads(apiStream) + if not apiDict.has_key('listapisresponse'): + raise Exception("API discovery plugin response failed") + if not apiDict['listapisresponse'].has_key('count'): + raise Exception("Malformed api response") + + apilist = apiDict['listapisresponse']['api'] + cmds = [] + for cmd in apilist: + csCmd = cloudStackCmd() + if cmd.has_key('name'): + csCmd.name = cmd['name'] + assert csCmd.name + + if cmd.has_key('description'): + csCmd.desc = cmd['description'] + + if cmd.has_key('async'): + csCmd.async = cmd['isasync'] + + for param in cmd['params']: + paramProperty = cmdParameterProperty() + + if param.has_key('name'): + paramProperty.name = param['name'] + assert paramProperty.name + + if param.has_key('required'): + paramProperty.required = param.getElementsByTagName('required') + + if param.has_key('description'): + paramProperty.desc = param['description'] + + if param.has_key('type'): + paramProperty.type = param['type'] + + csCmd.request.append(paramProperty) + + for response in cmd['response']: + paramProperty = self.constructResponseFromJSON(response) + csCmd.response.append(paramProperty) + + cmds.append(csCmd) + return cmds + + + def generateCodeFromXML(self): cmds = self.loadCmdFromXML() for cmd in cmds: self.generate(cmd) self.finalize() + def generateCodeFromJSON(self, apiJson): + """ + Api Discovery plugin returns the supported APIs of a CloudStack endpoint. + @return: The classes in cloudstackAPI/ formed from api discovery json + """ + with open(apiJson, 'r') as apiStream: + cmds = self.loadCmdFromJSON(apiStream) + for cmd in cmds: + self.generate(cmd) + self.finalize() + def getText(elements): return elements[0].childNodes[0].nodeValue.strip() @@ -315,5 +393,5 @@ if __name__ == "__main__": exit(2) cg = codeGenerator(folder, apiSpecFile) - cg.generateCode() + cg.generateCodeFromXML() diff --git a/tools/marvin/marvin/marvinPlugin.py b/tools/marvin/marvin/marvinPlugin.py index c52596e6d43..518f27fe70b 100644 --- a/tools/marvin/marvin/marvinPlugin.py +++ b/tools/marvin/marvin/marvinPlugin.py @@ -21,6 +21,7 @@ import logging import nose.core from marvin.cloudstackTestCase import cloudstackTestCase from marvin import deployDataCenter +from marvin import apiSynchronizer from nose.plugins.base import Plugin from functools import partial @@ -39,6 +40,10 @@ class MarvinPlugin(Plugin): self.enableOpt = "--with-marvin" self.logformat = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s") + if options.sync: + self.do_sync(options.config) + return + if options.debug_log: self.logger = logging.getLogger("NoseTestExecuteEngine") self.debug_stream = logging.FileHandler(options.debug_log) @@ -65,6 +70,13 @@ class MarvinPlugin(Plugin): cfg.debugLog = self.debug_stream self.testrunner = nose.core.TextTestRunner(stream=self.result_stream, descriptions=True, verbosity=2, config=config) + + def do_sync(self, config): + """ + Use the ApiDiscovery plugin exposed by the CloudStack mgmt server to rebuild the cloudStack API + """ + apiSynchronizer.sync(config) + def options(self, parser, env): """ @@ -84,6 +96,8 @@ class MarvinPlugin(Plugin): help="The path to the testcase debug logs [DEBUG_LOG]") parser.add_option("--load", action="store_true", default=False, dest="load", help="Only load the deployment configuration given") + parser.add_option("--sync", action="store_true", default=False, dest="sync", + help="Sync the APIs from the CloudStack endpoint in marvin-config") Plugin.options(self, parser, env) From 82fd9382b7497f1ee753e1298a9db1aed325fbc6 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Thu, 28 Mar 2013 18:19:15 +0530 Subject: [PATCH 53/90] marvin+sync: apidiscovery sync and regenerate for marvin Use codegenerator to sync marvin cloudstackAPIs from a given cloudstack endpoint. Sometimes you want to synchronize marvin with the new APIs that you have introduced locally or any alterations you may have made the API. In such cases you can sync marvin's libraries as follows. $sudo mvn -Pdeveloper,marvin.sync -Dendpoint=localhost -pl :cloud-marvin This needs sudo privileges since it will call on pip to upgrade the existing marvin installation on your machine. The endpoint is where your management server is running and is exposing the API discovery plugin. A listApis call is made and the resulting json deserialized back into marvin's library entities. Signed-off-by: Prasanna Santhanam --- .../api/response/ServiceResponse.java | 9 +- tools/marvin/marvin/cloudstackTestClient.py | 8 - tools/marvin/marvin/codegenerator.py | 215 ++++++++++-------- tools/marvin/marvin/integration/lib/base.py | 2 + tools/marvin/marvin/marvinPlugin.py | 16 +- tools/marvin/pom.xml | 71 +++++- 6 files changed, 192 insertions(+), 129 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/response/ServiceResponse.java b/api/src/org/apache/cloudstack/api/response/ServiceResponse.java index 445afcfcf5b..c93c55ee16a 100644 --- a/api/src/org/apache/cloudstack/api/response/ServiceResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ServiceResponse.java @@ -16,13 +16,12 @@ // under the License. package org.apache.cloudstack.api.response; -import java.util.List; - +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; -import com.cloud.serializer.Param; -import com.google.gson.annotations.SerializedName; +import java.util.List; @SuppressWarnings("unused") public class ServiceResponse extends BaseResponse { @@ -30,7 +29,7 @@ public class ServiceResponse extends BaseResponse { @SerializedName(ApiConstants.NAME) @Param(description="the service name") private String name; - @SerializedName(ApiConstants.PROVIDER) @Param(description="the service provider name") + @SerializedName(ApiConstants.PROVIDER) @Param(description="the service provider name", responseObject = ProviderResponse.class) private List providers; @SerializedName("capability") @Param(description="the list of capabilities", responseObject = CapabilityResponse.class) diff --git a/tools/marvin/marvin/cloudstackTestClient.py b/tools/marvin/marvin/cloudstackTestClient.py index 4bfb90be4a8..e4735e453db 100644 --- a/tools/marvin/marvin/cloudstackTestClient.py +++ b/tools/marvin/marvin/cloudstackTestClient.py @@ -148,14 +148,6 @@ class cloudstackTestClient(object): return self.userApiClient return None - def synchronize(self): - """ - synchronize the api from an endpoint - """ - apiclient = self.getApiClient() - cmd = listApis.listApisCmd() - response = apiclient.listApis(cmd) - '''FixME, httplib has issue if more than one thread submitted''' def submitCmdsAndWait(self, cmds, workers=1): diff --git a/tools/marvin/marvin/codegenerator.py b/tools/marvin/marvin/codegenerator.py index 5d9a2dfc5de..0622e5dbc9e 100644 --- a/tools/marvin/marvin/codegenerator.py +++ b/tools/marvin/marvin/codegenerator.py @@ -21,6 +21,7 @@ from optparse import OptionParser from textwrap import dedent import os import sys +import urllib2 class cmdParameterProperty(object): def __init__(self): @@ -38,18 +39,21 @@ class cloudStackCmd: self.request = [] self.response = [] -class codeGenerator: - space = " " +class codeGenerator: + """ + Apache CloudStack- marvin python classes can be generated from the json returned by API discovery or from the + xml spec of commands generated by the ApiDocWriter. This class provides helper methods for these uses. + """ + space = " " cmdsName = [] - - def __init__(self, outputFolder, apiSpecFile): + + def __init__(self, outputFolder): self.cmd = None self.code = "" self.required = [] self.subclass = [] self.outputFolder = outputFolder - self.apiSpecFile = apiSpecFile lic = """\ # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -58,19 +62,19 @@ class codeGenerator: # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at - # + # # http://www.apache.org/licenses/LICENSE-2.0 - # + # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations - # under the License. + # under the License. """ self.license = dedent(lic) - + def addAttribute(self, attr, pro): value = pro.value if pro.required: @@ -80,11 +84,11 @@ class codeGenerator: self.code += self.space self.code += "''' " + pro.desc + " '''" self.code += "\n" - + self.code += self.space self.code += attr + " = " + str(value) self.code += "\n" - + def generateSubClass(self, name, properties): '''generate code for sub list''' subclass = 'class %s:\n'%name @@ -97,44 +101,44 @@ class codeGenerator: self.generateSubClass(pro.name, pro.subProperties) else: subclass += self.space + self.space + 'self.%s = None\n'%pro.name - + self.subclass.append(subclass) def generate(self, cmd): - + self.cmd = cmd self.cmdsName.append(self.cmd.name) self.code = self.license self.code += "\n" - self.code += '"""%s"""\n'%self.cmd.desc + self.code += '"""%s"""\n'%self.cmd.desc self.code += 'from baseCmd import *\n' self.code += 'from baseResponse import *\n' self.code += "class %sCmd (baseCmd):\n"%self.cmd.name self.code += self.space + "def __init__(self):\n" - - self.code += self.space + self.space + 'self.isAsync = "%s"\n' %self.cmd.async - + + self.code += self.space + self.space + 'self.isAsync = "%s"\n' %str(self.cmd.async).lower() + for req in self.cmd.request: if req.desc is not None: self.code += self.space + self.space + '"""%s"""\n'%req.desc if req.required == "true": self.code += self.space + self.space + '"""Required"""\n' - + value = "None" if req.type == "list" or req.type == "map": value = "[]" - + self.code += self.space + self.space + 'self.%s = %s\n'%(req.name,value) if req.required == "true": self.required.append(req.name) - + self.code += self.space + self.space + "self.required = [" for require in self.required: self.code += '"' + require + '",' self.code += "]\n" self.required = [] - - + + """generate response code""" subItems = {} self.code += "\n" @@ -146,17 +150,17 @@ class codeGenerator: for res in self.cmd.response: if res.desc is not None: self.code += self.space + self.space + '"""%s"""\n'%res.desc - + if len(res.subProperties) > 0: self.code += self.space + self.space + 'self.%s = []\n'%res.name self.generateSubClass(res.name, res.subProperties) else: self.code += self.space + self.space + 'self.%s = None\n'%res.name self.code += '\n' - + for subclass in self.subclass: self.code += subclass + "\n" - + fp = open(self.outputFolder + "/cloudstackAPI/%s.py"%self.cmd.name, "w") fp.write(self.code) fp.close() @@ -165,7 +169,7 @@ class codeGenerator: def finalize(self): '''generate an api call''' - + header = '"""Test Client for CloudStack API"""\n' imports = "import copy\n" initCmdsList = '__all__ = [' @@ -174,33 +178,33 @@ class codeGenerator: body += self.space + 'def __init__(self, connection):\n' body += self.space + self.space + 'self.connection = connection\n' body += "\n" - + body += self.space + 'def __copy__(self):\n' body += self.space + self.space + 'return CloudStackAPIClient(copy.copy(self.connection))\n' body += "\n" - + for cmdName in self.cmdsName: body += self.space + 'def %s(self,command):\n'%cmdName body += self.space + self.space + 'response = %sResponse()\n'%cmdName body += self.space + self.space + 'response = self.connection.make_request(command, response)\n' body += self.space + self.space + 'return response\n' body += '\n' - + imports += 'from %s import %sResponse\n'%(cmdName, cmdName) initCmdsList += '"%s",'%cmdName - + fp = open(self.outputFolder + '/cloudstackAPI/cloudstackAPIClient.py', 'w') fp.write(self.license) for item in [header, imports, body]: fp.write(item) fp.close() - + '''generate __init__.py''' initCmdsList = self.license + initCmdsList + '"cloudstackAPIClient"]' fp = open(self.outputFolder + '/cloudstackAPI/__init__.py', 'w') fp.write(initCmdsList) fp.close() - + fp = open(self.outputFolder + '/cloudstackAPI/baseCmd.py', 'w') basecmd = self.license basecmd += '"""Base Command"""\n' @@ -208,7 +212,7 @@ class codeGenerator: basecmd += self.space + 'pass\n' fp.write(basecmd) fp.close() - + fp = open(self.outputFolder + '/cloudstackAPI/baseResponse.py', 'w') basecmd = self.license basecmd += '"""Base class for response"""\n' @@ -216,7 +220,7 @@ class codeGenerator: basecmd += self.space + 'pass\n' fp.write(basecmd) fp.close() - + def constructResponseFromXML(self, response): paramProperty = cmdParameterProperty() paramProperty.name = getText(response.getElementsByTagName('name')) @@ -229,74 +233,84 @@ class codeGenerator: paramProperty.subProperties.append(subProperty) return paramProperty - def constructResponseFromJSON(self, response): - paramProperty = cmdParameterProperty() - if response.has_key('name'): - paramProperty.name = response['name'] - assert paramProperty.name - - if response.has_key('description'): - paramProperty.desc = response['description'] - if response.has_key('type') and response['type'] == 'list': - #Here list becomes a subproperty - paramProperty.name = paramProperty.name.split('(*)')[0] - for subresponse in response.getElementsByTagName('arguments')[0].getElementsByTagName('arg'): - subProperty = self.constructResponseFromXML(subresponse) - paramProperty.subProperties.append(subProperty) - return paramProperty - - def loadCmdFromXML(self): - dom = xml.dom.minidom.parse(self.apiSpecFile) + def loadCmdFromXML(self, dom): cmds = [] for cmd in dom.getElementsByTagName("command"): csCmd = cloudStackCmd() csCmd.name = getText(cmd.getElementsByTagName('name')) assert csCmd.name - + desc = getText(cmd.getElementsByTagName('description')) - if desc: + if desc: csCmd.desc = desc - + async = getText(cmd.getElementsByTagName('isAsync')) if async: csCmd.async = async - + for param in cmd.getElementsByTagName("request")[0].getElementsByTagName("arg"): paramProperty = cmdParameterProperty() - + paramProperty.name = getText(param.getElementsByTagName('name')) assert paramProperty.name - + required = param.getElementsByTagName('required') if required: paramProperty.required = getText(required) - + requestDescription = param.getElementsByTagName('description') - if requestDescription: + if requestDescription: paramProperty.desc = getText(requestDescription) - + type = param.getElementsByTagName("type") if type: paramProperty.type = getText(type) - + csCmd.request.append(paramProperty) - + responseEle = cmd.getElementsByTagName("response")[0] for response in responseEle.getElementsByTagName("arg"): if response.parentNode != responseEle: continue - + paramProperty = self.constructResponseFromXML(response) csCmd.response.append(paramProperty) - + cmds.append(csCmd) return cmds + def generateCodeFromXML(self, apiSpecFile): + dom = xml.dom.minidom.parse(apiSpecFile) + cmds = self.loadCmdFromXML(dom) + for cmd in cmds: + self.generate(cmd) + self.finalize() + + def constructResponseFromJSON(self, response): + paramProperty = cmdParameterProperty() + if response.has_key('name'): + paramProperty.name = response['name'] + assert paramProperty.name, "%s has no property name"%response + + if response.has_key('description'): + paramProperty.desc = response['description'] + if response.has_key('type'): + if response['type'] in ['list', 'map', 'set']: + #Here list becomes a subproperty + if response.has_key('response'): + for innerResponse in response['response']: + subProperty = self.constructResponseFromJSON(innerResponse) + paramProperty.subProperties.append(subProperty) + paramProperty.type = response['type'] + return paramProperty + def loadCmdFromJSON(self, apiStream): if apiStream is None: raise Exception("No APIs found through discovery") - apiDict = json.loads(apiStream) + jsonOut = apiStream.readlines() + assert len(jsonOut) > 0 + apiDict = json.loads(jsonOut[0]) if not apiDict.has_key('listapisresponse'): raise Exception("API discovery plugin response failed") if not apiDict['listapisresponse'].has_key('count'): @@ -313,7 +327,7 @@ class codeGenerator: if cmd.has_key('description'): csCmd.desc = cmd['description'] - if cmd.has_key('async'): + if cmd.has_key('isasync'): csCmd.async = cmd['isasync'] for param in cmd['params']: @@ -324,7 +338,7 @@ class codeGenerator: assert paramProperty.name if param.has_key('required'): - paramProperty.required = param.getElementsByTagName('required') + paramProperty.required = param['required'] if param.has_key('description'): paramProperty.desc = param['description'] @@ -335,29 +349,25 @@ class codeGenerator: csCmd.request.append(paramProperty) for response in cmd['response']: - paramProperty = self.constructResponseFromJSON(response) - csCmd.response.append(paramProperty) + #FIXME: ExtractImage related APIs return empty dicts in response + if len(response) > 0: + paramProperty = self.constructResponseFromJSON(response) + csCmd.response.append(paramProperty) cmds.append(csCmd) return cmds - - def generateCodeFromXML(self): - cmds = self.loadCmdFromXML() - for cmd in cmds: - self.generate(cmd) - self.finalize() - - def generateCodeFromJSON(self, apiJson): + def generateCodeFromJSON(self, endpointUrl): """ Api Discovery plugin returns the supported APIs of a CloudStack endpoint. @return: The classes in cloudstackAPI/ formed from api discovery json """ - with open(apiJson, 'r') as apiStream: - cmds = self.loadCmdFromJSON(apiStream) - for cmd in cmds: - self.generate(cmd) - self.finalize() + if endpointUrl.find('response=json') >= 0: + apiStream = urllib2.urlopen(endpointUrl) + cmds = self.loadCmdFromJSON(apiStream) + for cmd in cmds: + self.generate(cmd) + self.finalize() def getText(elements): return elements[0].childNodes[0].nodeValue.strip() @@ -365,20 +375,14 @@ def getText(elements): if __name__ == "__main__": parser = OptionParser() - parser.add_option("-o", "--output", dest="output", help="the root path where code genereted, default is .") - parser.add_option("-s", "--specfile", dest="spec", help="the path and name of the api spec xml file, default is /etc/cloud/cli/commands.xml") - + parser.add_option("-o", "--output", dest="output", + help="The path to the generated code entities, default is .") + parser.add_option("-s", "--specfile", dest="spec", + help="The path and name of the api spec xml file, default is /etc/cloud/cli/commands.xml") + parser.add_option("-e", "--endpoint", dest="endpoint", + help="The endpoint mgmt server (with open 8096) where apis are discovered, default is localhost") + (options, args) = parser.parse_args() - - apiSpecFile = "/etc/cloud/cli/commands.xml" - if options.spec is not None: - apiSpecFile = options.spec - - if not os.path.exists(apiSpecFile): - print "the spec file %s does not exists"%apiSpecFile - print parser.print_help() - exit(1) - folder = "." if options.output is not None: @@ -391,7 +395,18 @@ if __name__ == "__main__": print "Failed to create folder %s, due to %s"%(apiModule,sys.exc_info()) print parser.print_help() exit(2) - - cg = codeGenerator(folder, apiSpecFile) - cg.generateCodeFromXML() - + + apiSpecFile = "/etc/cloud/cli/commands.xml" + if options.spec is not None: + apiSpecFile = options.spec + if not os.path.exists(apiSpecFile): + print "the spec file %s does not exists"%apiSpecFile + print parser.print_help() + exit(1) + + cg = codeGenerator(folder) + if options.spec is not None: + cg.generateCodeFromXML(apiSpecFile) + elif options.endpoint is not None: + endpointUrl='http://%s:8096/client/api?command=listApis&response=json'%options.endpoint + cg.generateCodeFromJSON(endpointUrl) diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 3751d987785..f3370eb3190 100644 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -883,6 +883,8 @@ class PublicIPAddress: if accountid: cmd.account = accountid + elif "account" in services: + cmd.account = services["account"] if zoneid: cmd.zoneid = zoneid diff --git a/tools/marvin/marvin/marvinPlugin.py b/tools/marvin/marvin/marvinPlugin.py index 518f27fe70b..46a8a4f3445 100644 --- a/tools/marvin/marvin/marvinPlugin.py +++ b/tools/marvin/marvin/marvinPlugin.py @@ -21,7 +21,6 @@ import logging import nose.core from marvin.cloudstackTestCase import cloudstackTestCase from marvin import deployDataCenter -from marvin import apiSynchronizer from nose.plugins.base import Plugin from functools import partial @@ -40,10 +39,6 @@ class MarvinPlugin(Plugin): self.enableOpt = "--with-marvin" self.logformat = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s") - if options.sync: - self.do_sync(options.config) - return - if options.debug_log: self.logger = logging.getLogger("NoseTestExecuteEngine") self.debug_stream = logging.FileHandler(options.debug_log) @@ -71,13 +66,6 @@ class MarvinPlugin(Plugin): self.testrunner = nose.core.TextTestRunner(stream=self.result_stream, descriptions=True, verbosity=2, config=config) - def do_sync(self, config): - """ - Use the ApiDiscovery plugin exposed by the CloudStack mgmt server to rebuild the cloudStack API - """ - apiSynchronizer.sync(config) - - def options(self, parser, env): """ Register command line options @@ -96,9 +84,7 @@ class MarvinPlugin(Plugin): help="The path to the testcase debug logs [DEBUG_LOG]") parser.add_option("--load", action="store_true", default=False, dest="load", help="Only load the deployment configuration given") - parser.add_option("--sync", action="store_true", default=False, dest="sync", - help="Sync the APIs from the CloudStack endpoint in marvin-config") - + Plugin.options(self, parser, env) def __init__(self): diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index 4f012eedf08..a5cbd31e24b 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -83,7 +83,76 @@ + + + sync + + + endpoint + localhost + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + generate-sources + generate-sources + + exec + + + ${basedir}/marvin + python + + codegenerator.py + -e + ${endpoint} + Generating ${project.artifactId} API classes} + + + + + package + package + + exec + + + ${exec.workingdir} + python + + setup.py + sdist + + + + + install + install + + exec + + + ${basedir}/dist + pip + + install + --upgrade + Marvin-0.1.0.tar.gz + + + + + + + + marvin @@ -128,7 +197,7 @@ ${basedir}/marvin - /usr/local/bin/nosetests + nosetests --with-marvin --marvin-config From b798c451141c32d46322aae83063eeaa9634b337 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Tue, 2 Apr 2013 13:09:36 +0530 Subject: [PATCH 54/90] maven+marvin+simulator: Changes to the lifecycle steps integration test is now run as follows: Build $ mvn -Pdeveloper -Dsimulator clean install DB: $ mvn -Pdeveloper -pl developer -Ddeploydb $ mvn -Pdeveloper -pl developer -Ddeploydb-simulator Setup: $ mvn -Pdeveloper,marvin.setup -Dmarvin.config=setup/dev/advanced.cfg -pl :cloud-marvin integration-test Test: $ mvn -Pdeveloper,marvin.test -Dmarvin.config=setup/dev/advanced.cfg -pl :cloud-marvin integration-test Signed-off-by: Prasanna Santhanam --- client/pom.xml | 11 + client/tomcatconf/componentContext.xml.in | 400 +++++++----------- .../simulatorComponentContext.xml.in | 383 ++++++++--------- .../agent/manager/MockStorageManagerImpl.java | 36 +- .../dao/HypervisorCapabilitiesDaoImpl.java | 15 +- setup/db/templates.simulator.sql | 4 +- tools/marvin/pom.xml | 40 +- 7 files changed, 403 insertions(+), 486 deletions(-) diff --git a/client/pom.xml b/client/pom.xml index 35588aa2c93..05934f4db17 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -214,10 +214,21 @@ cloud-plugin-hypervisor-simulator ${project.version} + org.apache.cloudstack cloud-plugin-storage-volume-default ${project.version} + + org.apache.cloudstack + cloud-plugin-syslog-alerts + ${project.version} + + + org.apache.cloudstack + cloud-plugin-snmp-alerts + ${project.version} + install diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 584be9787e8..0ddb428d92e 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -1,3 +1,4 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + + + + + + + + + + + + - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - + + + + - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + - - - - - - - + diff --git a/client/tomcatconf/simulatorComponentContext.xml.in b/client/tomcatconf/simulatorComponentContext.xml.in index d501ca1d10e..1cb9f6f2b63 100644 --- a/client/tomcatconf/simulatorComponentContext.xml.in +++ b/client/tomcatconf/simulatorComponentContext.xml.in @@ -1,3 +1,4 @@ + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - + diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java index 859acc85958..a50dff6382c 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java @@ -16,23 +16,6 @@ // under the License. package com.cloud.agent.manager; -import java.io.File; -import java.math.BigInteger; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - import com.cloud.agent.api.Answer; import com.cloud.agent.api.AttachIsoCommand; import com.cloud.agent.api.AttachVolumeAnswer; @@ -97,8 +80,23 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine.State; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.io.File; +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + @Component @Local(value = { MockStorageManager.class }) public class MockStorageManagerImpl extends ManagerBase implements MockStorageManager { @@ -954,7 +952,7 @@ public class MockStorageManagerImpl extends ManagerBase implements MockStorageMa long defaultTemplateSize = 2 * 1024 * 1024 * 1024L; MockVolumeVO template = new MockVolumeVO(); template.setName("simulator-domR"); - template.setPath(storage.getMountPoint() + "template/tmpl/1/10/" + UUID.randomUUID().toString()); + template.setPath(storage.getMountPoint() + "template/tmpl/1/100/" + UUID.randomUUID().toString()); template.setPoolId(storage.getId()); template.setSize(defaultTemplateSize); template.setType(MockVolumeType.TEMPLATE); @@ -975,7 +973,7 @@ public class MockStorageManagerImpl extends ManagerBase implements MockStorageMa template = new MockVolumeVO(); template.setName("simulator-Centos"); - template.setPath(storage.getMountPoint() + "template/tmpl/1/11/" + UUID.randomUUID().toString()); + template.setPath(storage.getMountPoint() + "template/tmpl/1/111/" + UUID.randomUUID().toString()); template.setPoolId(storage.getId()); template.setSize(defaultTemplateSize); template.setType(MockVolumeType.TEMPLATE); diff --git a/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java b/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java index 5421a897b78..759803e67ac 100644 --- a/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java +++ b/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java @@ -16,19 +16,16 @@ // under the License. package com.cloud.hypervisor.dao; -import java.util.List; - -import javax.ejb.Local; - -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorCapabilitiesVO; import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.List; @Component @Local(value=HypervisorCapabilitiesDao.class) @@ -79,6 +76,8 @@ public class HypervisorCapabilitiesDaoImpl extends GenericDaoBase - sync + marvin.sync endpoint @@ -154,7 +154,10 @@ - marvin + marvin.setup + + ${user.dir}/setup/dev/advanced.cfg + marvin.config @@ -179,7 +182,7 @@ deployAndRun.py -c - ${user.dir}/${marvin.config} + ${marvin.config} -t /tmp/t.log -r @@ -189,6 +192,30 @@ + + + + + + + marvin.test + + ${user.dir}/setup/dev/advanced.cfg + simulator + test/integration/smoke + + + + marvin.config + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + integration-test integration-test @@ -201,11 +228,12 @@ --with-marvin --marvin-config - ${user.dir}/${marvin.config} + ${marvin.config} --load -a - tags=simulator - ${basedir}/../../test/integration/smoke/test_vm_life_cycle.py + tags=${tag} + ${user.dir}/${test} + -v From 6110e00c549630e8b08fc6ca4818a60ef6a0c919 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Tue, 2 Apr 2013 19:11:08 +0530 Subject: [PATCH 55/90] CLOUDSTACK-1830: ZWPS: NPE while create volume from snapshot --- .../storage/allocator/ZoneWideStoragePoolAllocator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java index c45f8a822a9..a4aa3d5cf84 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java @@ -56,7 +56,7 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator { VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) { List suitablePools = new ArrayList(); - HypervisorType hypervisor = vmProfile.getHypervisorType(); + HypervisorType hypervisor = dskCh.getHypersorType(); if (hypervisor != null) { if (hypervisor != HypervisorType.KVM) { s_logger.debug("Only kvm supports zone wide storage"); From 231367685789ff6e521879d25365d6ec65a1f076 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Tue, 2 Apr 2013 11:03:25 -0700 Subject: [PATCH 56/90] 41-42 db upgrade - added `cloud` db reference to the upgrade statements for remote access vpn --- setup/db/db/schema-410to420-cleanup.sql | 8 ++++---- setup/db/db/schema-410to420.sql | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/setup/db/db/schema-410to420-cleanup.sql b/setup/db/db/schema-410to420-cleanup.sql index 187076ff984..b65717f3593 100644 --- a/setup/db/db/schema-410to420-cleanup.sql +++ b/setup/db/db/schema-410to420-cleanup.sql @@ -20,9 +20,9 @@ --; #have to drop the foreign key in order to delete primary key; will re-insert the foreign key later -ALTER TABLE remote_access_vpn DROP foreign key `fk_remote_access_vpn__vpn_server_addr_id`; -ALTER TABLE remote_access_vpn DROP primary key; -ALTER TABLE remote_access_vpn ADD primary key (`id`); -ALTER TABLE remote_access_vpn ADD CONSTRAINT `fk_remote_access_vpn__vpn_server_addr_id` FOREIGN KEY (`vpn_server_addr_id`) REFERENCES `user_ip_address` (`id`); +ALTER TABLE `cloud`.`remote_access_vpn` DROP foreign key `fk_remote_access_vpn__vpn_server_addr_id`; +ALTER TABLE `cloud`.`remote_access_vpn` DROP primary key; +ALTER TABLE `cloud`.`remote_access_vpn` ADD primary key (`id`); +ALTER TABLE `cloud`.`remote_access_vpn` ADD CONSTRAINT `fk_remote_access_vpn__vpn_server_addr_id` FOREIGN KEY (`vpn_server_addr_id`) REFERENCES `user_ip_address` (`id`); diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 3dee7aec79b..ab9df05103b 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -391,8 +391,8 @@ CREATE VIEW `cloud`.`account_view` AS and async_job.instance_type = 'Account' and async_job.job_status = 0; -ALTER TABLE remote_access_vpn ADD COLUMN `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id'; -ALTER TABLE remote_access_vpn ADD COLUMN `uuid` varchar(40) UNIQUE; +ALTER TABLE `cloud`.`remote_access_vpn` ADD COLUMN `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id'; +ALTER TABLE `cloud`.`remote_access_vpn` ADD COLUMN `uuid` varchar(40) UNIQUE; -- START: support for LXC From f2ad38aa0f5623551fdd0a295219fb948030bd28 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Mon, 1 Apr 2013 18:25:06 -0700 Subject: [PATCH 57/90] CLOUDSTACK-1865: Change StatsCollector to be a manager so that it can initialize itself at proper run level --- server/src/com/cloud/server/StatsCollector.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index b1f4a570f48..05be0e2e3af 100755 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -66,6 +66,7 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.ComponentMethodInterceptable; +import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.SearchCriteria; import com.cloud.vm.UserVmManager; @@ -78,7 +79,7 @@ import com.cloud.vm.dao.UserVmDao; * */ @Component -public class StatsCollector implements ComponentMethodInterceptable { +public class StatsCollector extends ManagerBase implements ComponentMethodInterceptable { public static final Logger s_logger = Logger.getLogger(StatsCollector.class.getName()); private static StatsCollector s_instance = null; @@ -122,10 +123,11 @@ public class StatsCollector implements ComponentMethodInterceptable { s_instance = this; } - @PostConstruct - private void init(){ + @Override + public boolean start() { init(_configDao.getConfiguration()); - } + return true; + } private void init(Map configs) { _executor = Executors.newScheduledThreadPool(3, new NamedThreadFactory("StatsCollector")); From f52820f2fdbede9ad8f4675223a2306b9d89ac51 Mon Sep 17 00:00:00 2001 From: Min Chen Date: Tue, 2 Apr 2013 11:42:36 -0700 Subject: [PATCH 58/90] CLOUDSTACK-1890: listProjects is not listing state in the response. --- server/src/com/cloud/api/query/vo/ProjectJoinVO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/cloud/api/query/vo/ProjectJoinVO.java b/server/src/com/cloud/api/query/vo/ProjectJoinVO.java index 73ec9313289..4bfddef01fe 100644 --- a/server/src/com/cloud/api/query/vo/ProjectJoinVO.java +++ b/server/src/com/cloud/api/query/vo/ProjectJoinVO.java @@ -25,9 +25,9 @@ import javax.persistence.Enumerated; import javax.persistence.Id; import javax.persistence.Table; +import com.cloud.projects.Project.State; import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.utils.db.GenericDao; -import com.cloud.vm.VirtualMachine.State; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; From 7e54f40a028a909e19756e07ebe05782f31cfd05 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 3 Apr 2013 01:29:45 +0530 Subject: [PATCH 59/90] CLOUDSTACK-1897: Ignore appliance definitions for license checking Regression caused due to 8e917b1ad3c0d3076b0c6425ea3318a6d6dd5c25 Signed-off-by: Rohit Yadav --- pom.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 5e5f6245f4e..62081241445 100644 --- a/pom.xml +++ b/pom.xml @@ -318,11 +318,9 @@ dist/console-proxy/js/jquery.js scripts/vm/systemvm/id_rsa.cloud tools/devcloud/basebuild/puppet-devcloudinitial/files/network.conf - tools/appliance/definitions/systemvmtemplate/base.sh - tools/appliance/definitions/systemvmtemplate/cleanup.sh - tools/appliance/definitions/systemvmtemplate/definition.rb - tools/appliance/definitions/systemvmtemplate/preseed.cfg - tools/appliance/definitions/systemvmtemplate/zerodisk.sh + tools/appliance/definitions/devcloud/* + tools/appliance/definitions/systemvmtemplate/* + tools/appliance/definitions/systemvmtemplate64/* tools/cli/cloudmonkey.egg-info/* tools/devcloud/src/deps/boxes/basebox-build/definition.rb tools/devcloud/src/deps/boxes/basebox-build/preseed.cfg From 58c962ef15d507226a8cc0eb18abca23142cff1f Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Tue, 2 Apr 2013 15:53:09 -0700 Subject: [PATCH 60/90] Retire unused files to avoid confusions --- .../DefaultInterceptorLibrary.java | 33 ----- .../src/com/cloud/event/ActionEventUtils.java | 114 ------------------ .../component/AnnotationInterceptor.java | 36 ------ .../component/ComponentMethodProxyCache.java | 90 -------------- .../utils/component/InterceptorLibrary.java | 25 ---- .../component/MatchAnyMethodPointcut.java | 27 ----- .../com/cloud/utils/db/DatabaseCallback.java | 84 ------------- .../utils/db/DatabaseCallbackFilter.java | 58 --------- 8 files changed, 467 deletions(-) delete mode 100644 server/src/com/cloud/configuration/DefaultInterceptorLibrary.java delete mode 100644 utils/src/com/cloud/utils/component/AnnotationInterceptor.java delete mode 100644 utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java delete mode 100644 utils/src/com/cloud/utils/component/InterceptorLibrary.java delete mode 100644 utils/src/com/cloud/utils/component/MatchAnyMethodPointcut.java delete mode 100644 utils/src/com/cloud/utils/db/DatabaseCallback.java delete mode 100755 utils/src/com/cloud/utils/db/DatabaseCallbackFilter.java diff --git a/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java b/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java deleted file mode 100644 index 13a22dbe827..00000000000 --- a/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java +++ /dev/null @@ -1,33 +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.configuration; - -import com.cloud.event.ActionEventUtils; -import com.cloud.utils.component.AnnotationInterceptor; -import com.cloud.utils.component.InterceptorLibrary; -import com.cloud.utils.db.DatabaseCallback; - -import java.util.List; - -public class DefaultInterceptorLibrary implements InterceptorLibrary { - - @Override - public void addInterceptors(List> interceptors) { - interceptors.add(new DatabaseCallback()); - interceptors.add(new ActionEventUtils.ActionEventCallback()); - } -} diff --git a/server/src/com/cloud/event/ActionEventUtils.java b/server/src/com/cloud/event/ActionEventUtils.java index 3f3ca685f73..a2d490662eb 100755 --- a/server/src/com/cloud/event/ActionEventUtils.java +++ b/server/src/com/cloud/event/ActionEventUtils.java @@ -22,14 +22,9 @@ import com.cloud.server.ManagementServer; import com.cloud.user.Account; import com.cloud.user.AccountVO; import com.cloud.user.User; -import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; -import com.cloud.utils.component.AnnotationInterceptor; import com.cloud.utils.component.ComponentContext; -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; import org.apache.cloudstack.framework.events.EventBus; import org.apache.cloudstack.framework.events.EventBusException; import org.apache.log4j.Logger; @@ -38,8 +33,6 @@ import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.inject.Inject; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; @@ -185,111 +178,4 @@ public class ActionEventUtils { AccountVO account = _accountDao.findByIdIncludingRemoved(accountId); return account.getDomainId(); } - - public static class ActionEventCallback implements MethodInterceptor, AnnotationInterceptor { - - @Override - public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { - EventVO event = interceptStart(method); - boolean success = true; - try { - return methodProxy.invokeSuper(object, args); - } catch (Exception e){ - success = false; - interceptException(method, event); - throw e; - } finally { - if(success){ - interceptComplete(method, event); - } - } - } - - @Override - public boolean needToIntercept(AnnotatedElement element) { - if (!(element instanceof Method)) { - return false; - - } - Method method = (Method)element; - ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); - if (actionEvent != null) { - return true; - } - - return false; - } - - @Override - public EventVO interceptStart(AnnotatedElement element) { - EventVO event = null; - Method method = (Method)element; - ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); - if (actionEvent != null) { - boolean async = actionEvent.async(); - if(async){ - UserContext ctx = UserContext.current(); - long userId = ctx.getCallerUserId(); - long accountId = ctx.getAccountId(); - long startEventId = ctx.getStartEventId(); - String eventDescription = actionEvent.eventDescription(); - if(ctx.getEventDetails() != null){ - eventDescription += ". "+ctx.getEventDetails(); - } - ActionEventUtils.onStartedActionEvent(userId, accountId, actionEvent.eventType(), eventDescription, startEventId); - } - } - return event; - } - - @Override - public void interceptComplete(AnnotatedElement element, EventVO event) { - Method method = (Method)element; - ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); - if (actionEvent != null) { - UserContext ctx = UserContext.current(); - long userId = ctx.getCallerUserId(); - long accountId = ctx.getAccountId(); - long startEventId = ctx.getStartEventId(); - String eventDescription = actionEvent.eventDescription(); - if(ctx.getEventDetails() != null){ - eventDescription += ". "+ctx.getEventDetails(); - } - if(actionEvent.create()){ - //This start event has to be used for subsequent events of this action - startEventId = ActionEventUtils.onCreatedActionEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully created entity for " + eventDescription); - ctx.setStartEventId(startEventId); - } else { - ActionEventUtils.onCompletedActionEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully completed " + eventDescription, startEventId); - } - } - } - - @Override - public void interceptException(AnnotatedElement element, EventVO event) { - Method method = (Method)element; - ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); - if (actionEvent != null) { - UserContext ctx = UserContext.current(); - long userId = ctx.getCallerUserId(); - long accountId = ctx.getAccountId(); - long startEventId = ctx.getStartEventId(); - String eventDescription = actionEvent.eventDescription(); - if(ctx.getEventDetails() != null){ - eventDescription += ". "+ctx.getEventDetails(); - } - if(actionEvent.create()){ - long eventId = ActionEventUtils.onCreatedActionEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while creating entity for " + eventDescription); - ctx.setStartEventId(eventId); - } else { - ActionEventUtils.onCompletedActionEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while " + eventDescription, startEventId); - } - } - } - - @Override - public Callback getCallback() { - return this; - } - } } diff --git a/utils/src/com/cloud/utils/component/AnnotationInterceptor.java b/utils/src/com/cloud/utils/component/AnnotationInterceptor.java deleted file mode 100644 index e69862c9022..00000000000 --- a/utils/src/com/cloud/utils/component/AnnotationInterceptor.java +++ /dev/null @@ -1,36 +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 -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT 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.component; - -import java.lang.reflect.AnnotatedElement; - -import net.sf.cglib.proxy.Callback; - -/** - * AnnotationIntercepter says it can intercept an annotation. - */ -public interface AnnotationInterceptor { - boolean needToIntercept(AnnotatedElement element); - - T interceptStart(AnnotatedElement element); - - void interceptComplete(AnnotatedElement element, T attach); - - void interceptException(AnnotatedElement element, T attach); - - Callback getCallback(); -} diff --git a/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java b/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java deleted file mode 100644 index ea3b68573cf..00000000000 --- a/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java +++ /dev/null @@ -1,90 +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 -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT 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.component; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Method; -import java.util.WeakHashMap; - -public class ComponentMethodProxyCache { - - private static WeakHashMap> s_cache = new WeakHashMap>(); - - public ComponentMethodProxyCache() { - } - - public static Method getTargetMethod(Method method, Object target) { - synchronized(s_cache) { - WeakReference targetMethod = s_cache.get(new TargetKey(method, target)); - if(targetMethod != null && targetMethod.get() != null) - return targetMethod.get(); - - Class clazz = target.getClass(); - for(Method m : clazz.getMethods()) { - if(isMethodMatched(method, m)) { - s_cache.put(new TargetKey(method, target), new WeakReference(m)); - return m; - } - } - - return method; - } - } - - private static boolean isMethodMatched(Method m1, Method m2) { - if(!m1.getName().equals(m2.getName())) - return false; - - Class[] params1 = m1.getParameterTypes(); - Class[] params2 = m2.getParameterTypes(); - - if(params1.length != params2.length) - return false; - - for(int i = 0; i < params1.length; i++) { - if(!params1[i].isAssignableFrom(params2[i])) - return false; - } - - return true; - } - - public static class TargetKey { - Method _method; - Object _target; - - public TargetKey(Method method, Object target) { - _method = method; - _target = target; - } - - @Override - public boolean equals(Object obj) { - if(!(obj instanceof TargetKey)) - return false; - - // for target object, we just check the reference - return _method.equals(((TargetKey)obj)._method) && - _target == ((TargetKey)obj)._target; - } - - public int hashCode() { - return _target.hashCode() ^ _target.hashCode(); - } - } -} diff --git a/utils/src/com/cloud/utils/component/InterceptorLibrary.java b/utils/src/com/cloud/utils/component/InterceptorLibrary.java deleted file mode 100644 index 96be50b07ef..00000000000 --- a/utils/src/com/cloud/utils/component/InterceptorLibrary.java +++ /dev/null @@ -1,25 +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 -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT 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.component; - -import java.util.List; - -public interface InterceptorLibrary { - - void addInterceptors(List> interceptors); - -} diff --git a/utils/src/com/cloud/utils/component/MatchAnyMethodPointcut.java b/utils/src/com/cloud/utils/component/MatchAnyMethodPointcut.java deleted file mode 100644 index dd597344fa3..00000000000 --- a/utils/src/com/cloud/utils/component/MatchAnyMethodPointcut.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 -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT 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.component; - -import java.lang.reflect.Method; - -import org.springframework.aop.support.StaticMethodMatcherPointcut; - -public class MatchAnyMethodPointcut extends StaticMethodMatcherPointcut { - public boolean matches(Method method, Class cls) { - return true; - } -} diff --git a/utils/src/com/cloud/utils/db/DatabaseCallback.java b/utils/src/com/cloud/utils/db/DatabaseCallback.java deleted file mode 100644 index 718acf545c9..00000000000 --- a/utils/src/com/cloud/utils/db/DatabaseCallback.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 -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT 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 java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Method; - -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; - -import com.cloud.utils.component.AnnotationInterceptor; - -public class DatabaseCallback implements MethodInterceptor, AnnotationInterceptor { - - @Override - public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { - Transaction txn = interceptStart(method); - try { - return methodProxy.invokeSuper(object, args); - } finally { - interceptComplete(method, txn); - } - } - - @Override - public boolean needToIntercept(AnnotatedElement element) { - if (!(element instanceof Method)) { - return false; - - } - Method method = (Method)element; - DB db = method.getAnnotation(DB.class); - if (db != null) { - return db.txn(); - } - - Class clazz = method.getDeclaringClass(); - do { - db = clazz.getAnnotation(DB.class); - if (db != null) { - return db.txn(); - } - clazz = clazz.getSuperclass(); - } while (clazz != Object.class && clazz != null); - - return false; - } - - @Override - public Transaction interceptStart(AnnotatedElement element) { - return Transaction.open(((Method)element).getName()); - } - - @Override - public void interceptComplete(AnnotatedElement element, Transaction txn) { - txn.close(); - } - - @Override - public void interceptException(AnnotatedElement element, Transaction txn) { - txn.close(); - } - - @Override - public Callback getCallback() { - return this; - } - -} diff --git a/utils/src/com/cloud/utils/db/DatabaseCallbackFilter.java b/utils/src/com/cloud/utils/db/DatabaseCallbackFilter.java deleted file mode 100755 index 7bace706e29..00000000000 --- a/utils/src/com/cloud/utils/db/DatabaseCallbackFilter.java +++ /dev/null @@ -1,58 +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 -// the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT 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 java.lang.reflect.Method; - -import net.sf.cglib.proxy.CallbackFilter; - -public class DatabaseCallbackFilter implements CallbackFilter { - @Override - public int accept(Method method) { - return checkAnnotation(method) ? 1 : 0; - } - - public static boolean checkAnnotation(Method method) { - /*Check self*/ - DB db = method.getAnnotation(DB.class); - if (db != null) { - return db.txn(); - } - Class clazz = method.getDeclaringClass(); - - /*Check parent method*/ - try { - Method pMethod = clazz.getMethod(method.getName(), method.getParameterTypes()); - db = pMethod.getAnnotation(DB.class); - if (db != null) { - return db.txn(); - } - } catch (SecurityException e) { - } catch (NoSuchMethodException e) { - } - - /*Check class's annotation and ancestor's annotation*/ - do { - db = clazz.getAnnotation(DB.class); - if (db != null) { - return db.txn(); - } - clazz = clazz.getSuperclass(); - } while (clazz != Object.class && clazz != null); - return false; - } -} From 2dbdc46337be375940441ac4b41f95f25bbbf21d Mon Sep 17 00:00:00 2001 From: Vijayendra Bhamidipati Date: Tue, 2 Apr 2013 11:07:41 -0700 Subject: [PATCH 61/90] CLOUDSTACK-1734: Make SHA1 default password encoding mechanism Description: Making SHA256SALT the default encoding algorithm to encode passwords when creating/updating users. Introducing a new configurable list to allow admins to separately configure the order of preference for encoding and authentication schemes. Since passwords are now sent by clients as clear text, fixing the Plain text authenticator to check against the password passed in rather than its md5 digest. --- .../admin/account/CreateAccountCmd.java | 2 +- .../api/command/admin/user/CreateUserCmd.java | 2 +- .../api/command/admin/user/UpdateUserCmd.java | 2 +- client/tomcatconf/applicationContext.xml.in | 54 +++++++++++++++++++ client/tomcatconf/componentContext.xml.in | 28 ---------- .../tomcatconf/nonossComponentContext.xml.in | 28 ---------- developer/developer-prefill.sql | 2 +- .../server/auth/LDAPUserAuthenticator.java | 5 +- .../server/auth/MD5UserAuthenticator.java | 4 ++ .../auth/PlainTextUserAuthenticator.java | 32 +++-------- .../auth/SHA256SaltedUserAuthenticator.java | 3 ++ .../cloud/server/ManagementServerImpl.java | 15 ++++-- .../com/cloud/user/AccountManagerImpl.java | 15 ++++-- 13 files changed, 99 insertions(+), 93 deletions(-) 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 89673ea6123..95d0d07d9ce 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 @@ -63,7 +63,7 @@ public class CreateAccountCmd extends BaseCmd { @Parameter(name=ApiConstants.LASTNAME, type=CommandType.STRING, required=true, description="lastname") private String lastName; - @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Hashed password (Default is MD5). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.") + @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Clear text password (Default hashed to SHA256SALT). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.") private String password; @Parameter(name=ApiConstants.TIMEZONE, type=CommandType.STRING, description="Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.") diff --git a/api/src/org/apache/cloudstack/api/command/admin/user/CreateUserCmd.java b/api/src/org/apache/cloudstack/api/command/admin/user/CreateUserCmd.java index fb29e1a2629..7b3f230d1ec 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/user/CreateUserCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/user/CreateUserCmd.java @@ -56,7 +56,7 @@ public class CreateUserCmd extends BaseCmd { @Parameter(name=ApiConstants.LASTNAME, type=CommandType.STRING, required=true, description="lastname") private String lastname; - @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Hashed password (Default is MD5). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.") + @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Clear text password (Default hashed to SHA256SALT). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.") private String password; @Parameter(name=ApiConstants.TIMEZONE, type=CommandType.STRING, description="Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.") diff --git a/api/src/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java b/api/src/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java index 1f31662e8ca..5ea2dbdef55 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java @@ -59,7 +59,7 @@ public class UpdateUserCmd extends BaseCmd { @Parameter(name=ApiConstants.LASTNAME, type=CommandType.STRING, description="last name") private String lastname; - @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="Hashed password (default is MD5). If you wish to use any other hasing algorithm, you would need to write a custom authentication adapter") + @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="Clear text password (default hashed to SHA256SALT). If you wish to use any other hasing algorithm, you would need to write a custom authentication adapter") private String password; @Parameter(name=ApiConstants.SECRET_KEY, type=CommandType.STRING, description="The secret key for the user. Must be specified with userApiKey") diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 636eac2b939..d3699b93cfb 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -379,6 +379,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 0b02eb687c9..11472adf7b8 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -131,34 +131,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/developer/developer-prefill.sql b/developer/developer-prefill.sql index 6300d35df64..e4f90cad6e8 100644 --- a/developer/developer-prefill.sql +++ b/developer/developer-prefill.sql @@ -36,7 +36,7 @@ INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, -- Add system user with encrypted password=password INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, lastname, email, state, created) VALUES (2, UUID(), 'admin', '5f4dcc3b5aa765d61d8327deb882cf99', - '2', 'Admin', 'User', 'admin@mailprovider.com', 'enabled', NOW()); + '2', 'Admin', 'User', 'admin@mailprovider.com', 'disabled', NOW()); -- Add configurations INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) diff --git a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java b/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java index 61eebe5fc93..d928a5b9e17 100644 --- a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java +++ b/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java @@ -151,7 +151,10 @@ public class LDAPUserAuthenticator extends DefaultUserAuthenticator { @Override public boolean configure(String name, Map params) throws ConfigurationException { - super.configure(name, params); + if (name == null) { + name = "LDAP"; + } + super.configure(name, params); return true; } diff --git a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java index 026125ea0f6..e5b169fc456 100644 --- a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java +++ b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java @@ -59,8 +59,12 @@ public class MD5UserAuthenticator extends DefaultUserAuthenticator { return true; } + @Override public boolean configure(String name, Map params) throws ConfigurationException { + if(name == null) { + name = "MD5"; + } super.configure(name, params); return true; } diff --git a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java index 52e7cb3e297..f102275905f 100644 --- a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java +++ b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java @@ -28,7 +28,6 @@ import org.apache.log4j.Logger; import com.cloud.user.UserAccount; import com.cloud.user.dao.UserAccountDao; - import com.cloud.utils.exception.CloudRuntimeException; @@ -43,45 +42,26 @@ public class PlainTextUserAuthenticator extends DefaultUserAuthenticator { if (s_logger.isDebugEnabled()) { s_logger.debug("Retrieving user: " + username); } + UserAccount user = _userAccountDao.getUserAccount(username, domainId); if (user == null) { s_logger.debug("Unable to find user with " + username + " in domain " + domainId); return false; } - - MessageDigest md5; - try { - md5 = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - throw new CloudRuntimeException("Error", e); - } - md5.reset(); - BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes())); - - // make sure our MD5 hash value is 32 digits long... - StringBuffer sb = new StringBuffer(); - String pwStr = pwInt.toString(16); - int padding = 32 - pwStr.length(); - for (int i = 0; i < padding; i++) { - sb.append('0'); - } - sb.append(pwStr); - - - // Will: The MD5Authenticator is now a straight pass-through comparison of the - // the passwords because we will not assume that the password passed in has - // already been MD5 hashed. I am keeping the above code in case this requirement changes - // or people need examples of how to MD5 hash passwords in java. - if (!user.getPassword().equals(sb.toString())) { + if (!user.getPassword().equals(password)) { s_logger.debug("Password does not match"); return false; } return true; } + @Override public boolean configure(String name, Map params) throws ConfigurationException { + if (name == null) { + name = "PLAINTEXT"; + } super.configure(name, params); return true; } diff --git a/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java b/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java index 1b29f69794a..da939273ea1 100644 --- a/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java +++ b/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java @@ -44,6 +44,9 @@ public class SHA256SaltedUserAuthenticator extends DefaultUserAuthenticator { @Override public boolean configure(String name, Map params) throws ConfigurationException { + if (name == null) { + name = "SHA256SALT"; + } super.configure(name, params); return true; } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index d0904e1049c..af77ba5645f 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -457,7 +457,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe private Map _availableIdsMap; - List _userAuthenticators; + private List _userAuthenticators; + private List _userPasswordEncoders; @Inject ClusterManager _clusterMgr; private String _hashKey = null; @@ -473,7 +474,15 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe public void setUserAuthenticators(List authenticators) { _userAuthenticators = authenticators; } - + + public List getUserPasswordEncoders() { + return _userPasswordEncoders; + } + + public void setUserPasswordEncoders(List encoders) { + _userPasswordEncoders = encoders; + } + public List getHostAllocators() { return _hostAllocators; } @@ -3342,7 +3351,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe // This means its a new account, set the password using the // authenticator - for (UserAuthenticator authenticator: _userAuthenticators) { + for (UserAuthenticator authenticator: _userPasswordEncoders) { encodedPassword = authenticator.encode(password); if (encodedPassword != null) { break; diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 40db4ed2f86..52ca79d5a60 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -222,6 +222,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Inject VolumeManager volumeMgr; private List _userAuthenticators; + List _userPasswordEncoders; private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AccountChecker")); @@ -241,7 +242,15 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M public void setUserAuthenticators(List authenticators) { _userAuthenticators = authenticators; } - + + public List getUserPasswordEncoders() { + return _userPasswordEncoders; + } + + public void setUserPasswordEncoders(List encoders) { + _userPasswordEncoders = encoders; + } + public List getSecurityCheckers() { return _securityCheckers; } @@ -947,7 +956,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M if (password != null) { String encodedPassword = null; - for (Iterator en = _userAuthenticators.iterator(); en.hasNext();) { + for (Iterator en = _userPasswordEncoders.iterator(); en.hasNext();) { UserAuthenticator authenticator = en.next(); encodedPassword = authenticator.encode(password); if (encodedPassword != null) { @@ -1733,7 +1742,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M } String encodedPassword = null; - for (UserAuthenticator authenticator : _userAuthenticators) { + for (UserAuthenticator authenticator : _userPasswordEncoders) { encodedPassword = authenticator.encode(password); if (encodedPassword != null) { break; From 04a511a1a828a829962681525780f80935a161f9 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Tue, 2 Apr 2013 23:29:24 -0600 Subject: [PATCH 62/90] CLOUDSTACK-1900 : Save a default db.properties during upgrade, and make sure we only pull the old configs once. Signed-off-by: Marcus Sorensen 1364966964 -0600 --- packaging/centos63/cloud.spec | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index 7d6e63880b1..5baf58f9fb5 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -363,9 +363,12 @@ if getent passwd cloud | grep -q /var/lib/cloud; then fi # if saved configs from upgrade exist, copy them over -if [ -d "%{_sysconfdir}/cloud.rpmsave/management" ]; then +if [ -f "%{_sysconfdir}/cloud.rpmsave/management/db.properties" ]; then + mv %{_sysconfdir}/%{name}/management/db.properties %{_sysconfdir}/%{name}/management/db.properties.rpmnew cp -p %{_sysconfdir}/cloud.rpmsave/management/db.properties %{_sysconfdir}/%{name}/management cp -p %{_sysconfdir}/cloud.rpmsave/management/key %{_sysconfdir}/%{name}/management + # make sure we only do this on the first install of this RPM, don't want to overwrite on a reinstall + mv %{_sysconfdir}/cloud.rpmsave/management/db.properties %{_sysconfdir}/cloud.rpmsave/management/db.properties.rpmsave fi # Choose server.xml and tomcat.conf links based on old config, if exists @@ -407,6 +410,8 @@ fi if [ -f "%{_sysconfdir}/cloud.rpmsave/agent/agent.properties" ]; then mv %{_sysconfdir}/%{name}/agent/agent.properties %{_sysconfdir}/%{name}/agent/agent.properties.rpmnew cp -p %{_sysconfdir}/cloud.rpmsave/agent/agent.properties %{_sysconfdir}/%{name}/agent + # make sure we only do this on the first install of this RPM, don't want to overwrite on a reinstall + mv %{_sysconfdir}/cloud.rpmsave/agent/agent.properties %{_sysconfdir}/cloud.rpmsave/agent/agent.properties.rpmsave fi #%post awsapi From 8bb28fd7134626b3a967474abf3ae418aace72be Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Wed, 3 Apr 2013 08:35:39 +0200 Subject: [PATCH 63/90] With commit 16216720c6e981af4860ba83426b5ce91de1dc81 autoscanning is removed so Nicira needs to be properly added to the componentContext --- client/tomcatconf/componentContext.xml.in | 17 +++++++++++++++++ client/tomcatconf/nonossComponentContext.xml.in | 7 +++++++ 2 files changed, 24 insertions(+) diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 18d21c0a758..51980c912af 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -140,6 +140,7 @@ + @@ -148,6 +149,7 @@ + + + + + + + + + + + + diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 11472adf7b8..a9418d73882 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -78,6 +78,10 @@ + + @@ -230,6 +234,7 @@ + @@ -238,6 +243,7 @@ + @@ -275,6 +281,7 @@ + From bca7f9df5f6936c4ed95694970779303502f6eec Mon Sep 17 00:00:00 2001 From: Gavin Lee Date: Wed, 3 Apr 2013 16:57:42 +0800 Subject: [PATCH 64/90] CLOUDSTACK-1596: Choosing a hypervisor matrix to xml and add to Install Guide --- docs/en-US/Installation_Guide.xml | 1 + docs/en-US/choosing-a-hypervisor.xml | 136 +++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 docs/en-US/choosing-a-hypervisor.xml diff --git a/docs/en-US/Installation_Guide.xml b/docs/en-US/Installation_Guide.xml index fed53fc4a1d..28df071d42f 100644 --- a/docs/en-US/Installation_Guide.xml +++ b/docs/en-US/Installation_Guide.xml @@ -50,6 +50,7 @@ + diff --git a/docs/en-US/choosing-a-hypervisor.xml b/docs/en-US/choosing-a-hypervisor.xml new file mode 100644 index 00000000000..3c654881329 --- /dev/null +++ b/docs/en-US/choosing-a-hypervisor.xml @@ -0,0 +1,136 @@ + +%BOOK_ENTITIES; +]> + + + + Choosing a Hypervisor: Supported Features + &PRODUCT; supports many popular hypervisors. Your cloud can consist entirely of hosts running a single hypervisor, or you can use multiple hypervisors. Each cluster of hosts must run the same hypervisor. + You might already have an installed base of nodes running a particular hypervisor, in which case, your choice of hypervisor has already been made. If you are starting from scratch, you need to decide what hypervisor software best suits your needs. A discussion of the relative advantages of each hypervisor is outside the scope of our documentation. However, it will help you to know which features of each hypervisor are supported by &PRODUCT;. The following table provides this information. + + + + + + + + + + + + Feature + XenServer 6.0.2 + vSphere 4.1/5.0 + KVM - RHEL 6.2 + OVM 2.3 + Bare Metal + + + + + Network Throttling + Yes + Yes + No + No + N/A + + + Security groups in zones that use basic networking + Yes + No + Yes + No + No + + + iSCSI + Yes + Yes + Yes + Yes + N/A + + + FibreChannel + Yes + Yes + Yes + No + N/A + + + Local Disk + Yes + Yes + Yes + No + Yes + + + HA + Yes + Yes (Native) + Yes + Yes + N/A + + + Snapshots of local disk + Yes + Yes + Yes + No + N/A + + + Local disk as data disk + No + No + No + No + N/A + + + Work load balancing + No + DRS + No + No + N/A + + + Manual live migration of VMs from host to host + Yes + Yes + Yes + Yes + N/A + + + Conserve management traffic IP address by using link local network to communicate with virtual router + Yes + No + Yes + Yes + N/A + + + + + From 213c163011c1e783229997ffe857303d2022f3ed Mon Sep 17 00:00:00 2001 From: Gavin Lee Date: Wed, 3 Apr 2013 17:26:37 +0800 Subject: [PATCH 65/90] Convert tab to space chars --- docs/en-US/choosing-a-hypervisor.xml | 218 +++++++++++++-------------- 1 file changed, 109 insertions(+), 109 deletions(-) diff --git a/docs/en-US/choosing-a-hypervisor.xml b/docs/en-US/choosing-a-hypervisor.xml index 3c654881329..bf83fe3d17f 100644 --- a/docs/en-US/choosing-a-hypervisor.xml +++ b/docs/en-US/choosing-a-hypervisor.xml @@ -23,114 +23,114 @@ &PRODUCT; supports many popular hypervisors. Your cloud can consist entirely of hosts running a single hypervisor, or you can use multiple hypervisors. Each cluster of hosts must run the same hypervisor. You might already have an installed base of nodes running a particular hypervisor, in which case, your choice of hypervisor has already been made. If you are starting from scratch, you need to decide what hypervisor software best suits your needs. A discussion of the relative advantages of each hypervisor is outside the scope of our documentation. However, it will help you to know which features of each hypervisor are supported by &PRODUCT;. The following table provides this information. - - - - - - - - - - - Feature - XenServer 6.0.2 - vSphere 4.1/5.0 - KVM - RHEL 6.2 - OVM 2.3 - Bare Metal - - - - - Network Throttling - Yes - Yes - No - No - N/A - - - Security groups in zones that use basic networking - Yes - No - Yes - No - No - - - iSCSI - Yes - Yes - Yes - Yes - N/A - - - FibreChannel - Yes - Yes - Yes - No - N/A - - - Local Disk - Yes - Yes - Yes - No - Yes - - - HA - Yes - Yes (Native) - Yes - Yes - N/A - - - Snapshots of local disk - Yes - Yes - Yes - No - N/A - - - Local disk as data disk - No - No - No - No - N/A - - - Work load balancing - No - DRS - No - No - N/A - - - Manual live migration of VMs from host to host - Yes - Yes - Yes - Yes - N/A - - - Conserve management traffic IP address by using link local network to communicate with virtual router - Yes - No - Yes - Yes - N/A - - - + + + + + + + + + + + Feature + XenServer 6.0.2 + vSphere 4.1/5.0 + KVM - RHEL 6.2 + OVM 2.3 + Bare Metal + + + + + Network Throttling + Yes + Yes + No + No + N/A + + + Security groups in zones that use basic networking + Yes + No + Yes + No + No + + + iSCSI + Yes + Yes + Yes + Yes + N/A + + + FibreChannel + Yes + Yes + Yes + No + N/A + + + Local Disk + Yes + Yes + Yes + No + Yes + + + HA + Yes + Yes (Native) + Yes + Yes + N/A + + + Snapshots of local disk + Yes + Yes + Yes + No + N/A + + + Local disk as data disk + No + No + No + No + N/A + + + Work load balancing + No + DRS + No + No + N/A + + + Manual live migration of VMs from host to host + Yes + Yes + Yes + Yes + N/A + + + Conserve management traffic IP address by using link local network to communicate with virtual router + Yes + No + Yes + Yes + N/A + + + From d392445f7e9adab7d6effd4daf0d76bb0e6f9bd9 Mon Sep 17 00:00:00 2001 From: Dave Cahill Date: Wed, 13 Mar 2013 17:27:09 +0900 Subject: [PATCH 66/90] Rename MidoNetElement and MidoNetGuestNetworkGuru - Creating this as a separate commit so that it is marked as a rename - Over 50% code changed, so would count as a delete and add otherwise Signed-off-by: Dave Cahill Signed-off-by: Hugo Trippaers --- .../src/com/cloud/network/element/MidoNetElement.java} | 0 .../src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename plugins/network-elements/{midokura-midonet/src/com/cloud/network/element/MidokuraMidonetElement.java => midonet/src/com/cloud/network/element/MidoNetElement.java} (100%) rename plugins/network-elements/{midokura-midonet/src/com/cloud/network/guru/MidokuraMidonetGuestNetworkGuru.java => midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java} (100%) diff --git a/plugins/network-elements/midokura-midonet/src/com/cloud/network/element/MidokuraMidonetElement.java b/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java similarity index 100% rename from plugins/network-elements/midokura-midonet/src/com/cloud/network/element/MidokuraMidonetElement.java rename to plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java diff --git a/plugins/network-elements/midokura-midonet/src/com/cloud/network/guru/MidokuraMidonetGuestNetworkGuru.java b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java similarity index 100% rename from plugins/network-elements/midokura-midonet/src/com/cloud/network/guru/MidokuraMidonetGuestNetworkGuru.java rename to plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java From eddf7b9357bc18497b8cb16a6c6f3382ac52f61c Mon Sep 17 00:00:00 2001 From: Dave Cahill Date: Mon, 25 Mar 2013 10:56:13 +0900 Subject: [PATCH 67/90] MidoNet Networking Plugin - Supports DHCP, Source NAT, Static NAT, Firewall rules, Port Forwarding - Renamed MidokuraMidonet to MidoNet - Related Jira ticket is CLOUDSTACK-996 Signed-off-by: Dave Cahill Signed-off-by: Hugo Trippaers --- api/src/com/cloud/network/Network.java | 3 +- api/src/com/cloud/network/Networks.java | 1 + .../com/cloud/network/PhysicalNetwork.java | 3 +- .../network/ExternalNetworkDeviceManager.java | 1 - client/pom.xml | 5 + .../kvm/resource/LibvirtDomainXMLParser.java | 3 + .../hypervisor/kvm/resource/LibvirtVMDef.java | 11 +- .../network-elements/midokura-midonet/pom.xml | 30 - plugins/network-elements/midonet/pom.xml | 66 + .../cloud/network/element/MidoNetElement.java | 1622 ++++++++++++++++- .../network/element/SimpleFirewallRule.java | 192 ++ .../network/guru/MidoNetGuestNetworkGuru.java | 144 +- .../guru/MidoNetPublicNetworkGuru.java | 223 +++ .../network/resource/MidoNetVifDriver.java | 179 ++ .../network/element/MidoNetElementTest.java | 178 ++ plugins/pom.xml | 1 + .../src/com/cloud/configuration/Config.java | 4 + .../com/cloud/network/NetworkManagerImpl.java | 20 + ui/scripts/system.js | 114 ++ 19 files changed, 2720 insertions(+), 80 deletions(-) delete mode 100644 plugins/network-elements/midokura-midonet/pom.xml create mode 100644 plugins/network-elements/midonet/pom.xml create mode 100644 plugins/network-elements/midonet/src/com/cloud/network/element/SimpleFirewallRule.java create mode 100644 plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetPublicNetworkGuru.java create mode 100644 plugins/network-elements/midonet/src/com/cloud/network/resource/MidoNetVifDriver.java create mode 100644 plugins/network-elements/midonet/test/com/cloud/network/element/MidoNetElementTest.java diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index c2ab655b103..c0b0117fc7e 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -136,8 +136,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Provider VPCVirtualRouter = new Provider("VpcVirtualRouter", false); public static final Provider None = new Provider("None", false); // NiciraNvp is not an "External" provider, otherwise we get in trouble with NetworkServiceImpl.providersConfiguredForExternalNetworking - public static final Provider NiciraNvp = new Provider("NiciraNvp", false); - public static final Provider MidokuraMidonet = new Provider("MidokuraMidonet", true); + public static final Provider NiciraNvp = new Provider("NiciraNvp", false); private String name; private boolean isExternal; diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java index e3d21584ad8..f085e9f3029 100755 --- a/api/src/com/cloud/network/Networks.java +++ b/api/src/com/cloud/network/Networks.java @@ -62,6 +62,7 @@ public class Networks { Vnet("vnet", Long.class), Storage("storage", Integer.class), Lswitch("lswitch", String.class), + Mido("mido", String.class), UnDecided(null, null); private String scheme; diff --git a/api/src/com/cloud/network/PhysicalNetwork.java b/api/src/com/cloud/network/PhysicalNetwork.java index 343a2b14e33..a2044a61047 100644 --- a/api/src/com/cloud/network/PhysicalNetwork.java +++ b/api/src/com/cloud/network/PhysicalNetwork.java @@ -36,7 +36,8 @@ public interface PhysicalNetwork extends Identity, InternalIdentity { L3, GRE, STT, - VNS; + VNS, + MIDO; } public enum BroadcastDomainRange { diff --git a/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java b/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java index bc22804ae06..aeed81d2011 100644 --- a/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java +++ b/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java @@ -43,7 +43,6 @@ public interface ExternalNetworkDeviceManager extends Manager { public static final NetworkDevice F5BigIpLoadBalancer = new NetworkDevice("F5BigIpLoadBalancer", Network.Provider.F5BigIp.getName()); public static final NetworkDevice JuniperSRXFirewall = new NetworkDevice("JuniperSRXFirewall", Network.Provider.JuniperSRX.getName()); public static final NetworkDevice NiciraNvp = new NetworkDevice("NiciraNvp", Network.Provider.NiciraNvp.getName()); - public static final NetworkDevice MidokuraMidonet = new NetworkDevice("MidokuraMidonet", Network.Provider.MidokuraMidonet.getName()); public NetworkDevice(String deviceName, String ntwkServiceprovider) { _name = deviceName; diff --git a/client/pom.xml b/client/pom.xml index 05934f4db17..ff861b778d7 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -80,6 +80,11 @@ cloud-plugin-network-vns ${project.version} + + org.apache.cloudstack + cloud-plugin-network-midonet + ${project.version} + org.apache.cloudstack cloud-plugin-hypervisor-xen diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java index 403ed379c9f..ac4baf122a9 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java @@ -111,6 +111,9 @@ public class LibvirtDomainXMLParser { String bridge = getAttrValue("source", "bridge", nic); def.defBridgeNet(bridge, dev, mac, nicModel.valueOf(model.toUpperCase())); + } else if (type.equalsIgnoreCase("ethernet")) { + String scriptPath = getAttrValue("script", "path", nic); + def.defEthernet(dev, mac, nicModel.valueOf(model.toUpperCase()), scriptPath); } interfaces.add(def); } diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index 63133a8440f..9cddb2e4323 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -711,13 +711,19 @@ public class LibvirtVMDef { _model = model; } - public void defEthernet(String targetName, String macAddr, nicModel model) { + public void defEthernet(String targetName, String macAddr, nicModel model, String scriptPath) { _netType = guestNetType.ETHERNET; _networkName = targetName; + _sourceName = targetName; _macAddr = macAddr; _model = model; + _scriptPath = scriptPath; } + public void defEthernet(String targetName, String macAddr, nicModel model) { + defEthernet(targetName, macAddr, model, null); + } + public void setHostNetType(hostNicType hostNetType) { _hostNetType = hostNetType; } @@ -790,6 +796,9 @@ public class LibvirtVMDef { if (_model != null) { netBuilder.append("\n"); } + if (_scriptPath != null) { + netBuilder.append("