From fb94b72213bf96f2878b90260067f61629c6a956 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Mon, 18 Mar 2013 18:05:09 -0700 Subject: [PATCH 01/14] CLOUDSTACK-1568,CLOUDSTACK-1664: Fix ActionEvent interception and optimize @DB lookup with caching --- .../cloud/event/ActionEventInterceptor.java | 15 +++- .../ConsoleProxyHttpHandlerHelper.java | 14 ++- .../component/ComponentMethodProxyCache.java | 90 +++++++++++++++++++ .../component/SpringComponentScanUtils.java | 1 - .../utils/db/TransactionContextBuilder.java | 14 ++- 5 files changed, 119 insertions(+), 15 deletions(-) create mode 100644 utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java diff --git a/server/src/com/cloud/event/ActionEventInterceptor.java b/server/src/com/cloud/event/ActionEventInterceptor.java index fb89498ffce..a6c2565510e 100644 --- a/server/src/com/cloud/event/ActionEventInterceptor.java +++ b/server/src/com/cloud/event/ActionEventInterceptor.java @@ -19,22 +19,29 @@ 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; public class ActionEventInterceptor { + private static final Logger s_logger = Logger.getLogger(ActionEventInterceptor.class); public ActionEventInterceptor() { } public Object AroundAnyMethod(ProceedingJoinPoint call) throws Throwable { MethodSignature methodSignature = (MethodSignature)call.getSignature(); - Method targetMethod = methodSignature.getMethod(); - if(needToIntercept(targetMethod)) { + + // 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 { @@ -49,6 +56,8 @@ public class ActionEventInterceptor { } } return ret; + } else { + s_logger.error("Unable to find the proxied method behind. Method: " + methodSignature.getMethod().getName()); } return call.proceed(); } diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java index 6815b0d43bc..297e71118ad 100644 --- a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java +++ b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyHttpHandlerHelper.java @@ -53,7 +53,7 @@ public class ConsoleProxyHttpHandlerHelper { ConsoleProxyClientParam param = encryptor.decryptObject(ConsoleProxyClientParam.class, map.get("token")); // make sure we get information from token only - map.clear(); + guardUserInput(map); if(param != null) { if(param.getClientHostAddress() != null) map.put("host", param.getClientHostAddress()); @@ -72,9 +72,19 @@ public class ConsoleProxyHttpHandlerHelper { } } else { // we no longer accept information from parameter other than token - map.clear(); + guardUserInput(map); } return map; } + + private static void guardUserInput(Map map) { + map.remove("host"); + map.remove("port"); + map.remove("tag"); + map.remove("sid"); + map.remove("consoleurl"); + map.remove("sessionref"); + map.remove("ticket"); + } } diff --git a/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java b/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java new file mode 100644 index 00000000000..ea3b68573cf --- /dev/null +++ b/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java @@ -0,0 +1,90 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT 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/SpringComponentScanUtils.java b/utils/src/com/cloud/utils/component/SpringComponentScanUtils.java index fda11b74609..9a85c79fa80 100644 --- a/utils/src/com/cloud/utils/component/SpringComponentScanUtils.java +++ b/utils/src/com/cloud/utils/component/SpringComponentScanUtils.java @@ -38,5 +38,4 @@ public class SpringComponentScanUtils { } return false; } - } diff --git a/utils/src/com/cloud/utils/db/TransactionContextBuilder.java b/utils/src/com/cloud/utils/db/TransactionContextBuilder.java index e03b25f912d..7ca33ab5f5d 100644 --- a/utils/src/com/cloud/utils/db/TransactionContextBuilder.java +++ b/utils/src/com/cloud/utils/db/TransactionContextBuilder.java @@ -22,9 +22,10 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.log4j.Logger; import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.Signature; import org.aspectj.lang.reflect.MethodSignature; +import com.cloud.utils.component.ComponentMethodProxyCache; + public class TransactionContextBuilder implements MethodInterceptor { private static final Logger s_logger = Logger.getLogger(TransactionContextBuilder.class); public TransactionContextBuilder() { @@ -72,14 +73,9 @@ public class TransactionContextBuilder implements MethodInterceptor { Class clazz = method.getDeclaringClass(); if(clazz.isInterface()) { clazz = target.getClass(); - for(Method m : clazz.getMethods()) { - // it is supposed that we need to check against type arguments, - // this can be simplified by just checking method name - if(m.getName().equals(method.getName())) { - if(m.getAnnotation(DB.class) != null) - return true; - } - } + Method targetMethod = ComponentMethodProxyCache.getTargetMethod(method, target); + if(targetMethod != null && targetMethod.getAnnotation(DB.class) != null) + return true; } do { From beb15af0f267c59b7e070d279e1df960701b6cf6 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 19 Mar 2013 12:21:19 +0530 Subject: [PATCH 02/14] CLOUDSTACK-1720: Add upgrade paths from 4.0.x to 4.2.0 Signed-off-by: Rohit Yadav --- server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java b/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java index 5bd749fe842..8f9be0f5d57 100755 --- a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java +++ b/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java @@ -162,6 +162,10 @@ public class DatabaseUpgradeChecker implements SystemIntegrityChecker { _upgradeMap.put("4.0.0", new DbUpgrade[] { new Upgrade40to41(), new Upgrade410to420() }); + _upgradeMap.put("4.0.1", new DbUpgrade[] { new Upgrade40to41(), new Upgrade410to420() }); + + _upgradeMap.put("4.0.2", new DbUpgrade[] { new Upgrade40to41(), new Upgrade410to420() }); + _upgradeMap.put("4.1.0", new DbUpgrade[] { new Upgrade410to420() }); } From 19d1a30360750df280e46e1da5cf138625243852 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Tue, 19 Mar 2013 15:35:31 +0530 Subject: [PATCH 03/14] Dv switch UI space removal changes --- ui/scripts/system.js | 4 ++-- ui/scripts/zoneWizard.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 4d529aeb04e..c0a5d141700 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -7597,7 +7597,7 @@ if(vSwitchEnabled) { - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); @@ -7610,7 +7610,7 @@ else{ items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } args.response.success({data: items}); diff --git a/ui/scripts/zoneWizard.js b/ui/scripts/zoneWizard.js index 47932664927..5108c5c0c3b 100755 --- a/ui/scripts/zoneWizard.js +++ b/ui/scripts/zoneWizard.js @@ -897,7 +897,7 @@ if(vSwitchEnabled) { - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); @@ -909,9 +909,9 @@ // items.push({id: " ", description: " "}); else{ - items.push({id: "vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); - items.push({id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); - items.push({ id:" nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); + items.push({id:"vmwaredvs", description: "VMware vNetwork Distributed Virtual Switch"}); + items.push({ id: "vmwaresvs", description: "VMware vNetwork Standard Virtual Switch"}); + items.push({ id:"nexusdvs" , description: "Cisco Nexus 1000v Distributed Virtual Switch"}); } args.response.success({data: items}); From 93bc669a0e2fdfc5860e72113e7a51866c93ab2c Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 19 Mar 2013 15:34:20 +0530 Subject: [PATCH 04/14] cli: Pass config file by value in cloudmonkey's config Signed-off-by: Rohit Yadav --- tools/cli/cloudmonkey/config.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tools/cli/cloudmonkey/config.py b/tools/cli/cloudmonkey/config.py index 6a5feab8d12..4a4aa99cdc8 100644 --- a/tools/cli/cloudmonkey/config.py +++ b/tools/cli/cloudmonkey/config.py @@ -19,6 +19,12 @@ # Use following rules for versioning: # - __version__ = "4.1.0-0" +__description__ = "Command Line Interface for Apache CloudStack" +__maintainer__ = "Rohit Yadav" +__maintaineremail__ = "bhaisaab@apache.org" +__project__ = "The Apache CloudStack Team" +__projectemail__ = "cloudstack-dev@incubator.apache.org" +__projecturl__ = "http://incubator.apache.org/cloudstack" try: import os @@ -36,14 +42,14 @@ iterable_type = ['set', 'list', 'object'] config_dir = expanduser('~/.cloudmonkey') config_file = expanduser(config_dir + '/config') -cache_file = expanduser(config_dir + '/cache') # cloudmonkey config fields -config_fields = {'core': {}, 'ui': {}, 'server': {}, 'user': {}} +config_fields = {'core': {}, 'server': {}, 'user': {}, 'ui': {}} # core config_fields['core']['asyncblock'] = 'true' config_fields['core']['paramcompletion'] = 'false' +config_fields['core']['cache_file'] = expanduser(config_dir + '/cache') config_fields['core']['history_file'] = expanduser(config_dir + '/history') config_fields['core']['log_file'] = expanduser(config_dir + '/log') @@ -64,8 +70,8 @@ config_fields['user']['apikey'] = '' config_fields['user']['secretkey'] = '' -def write_config(get_attr, first_time=False): - global config_fields, config_file +def write_config(get_attr, config_file, first_time=False): + global config_fields config = ConfigParser() for section in config_fields.keys(): config.add_section(section) @@ -79,8 +85,8 @@ def write_config(get_attr, first_time=False): return config -def read_config(get_attr, set_attr): - global config_fields, config_dir, config_file +def read_config(get_attr, set_attr, config_file): + global config_fields, config_dir if not os.path.exists(config_dir): os.makedirs(config_dir) @@ -95,7 +101,7 @@ def read_config(get_attr, set_attr): except IOError, e: print "Error: config_file not found", e else: - config = write_config(get_attr, True) + config = write_config(get_attr, config_file, True) print "Welcome! Using `set` configure the necessary settings:" print " ".join(sorted(config_options)) print "Config file:", config_file From e28aa09f01fcaf6abd806ab94d962563e1fba6c2 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 19 Mar 2013 15:47:51 +0530 Subject: [PATCH 05/14] cli: cachemaker should import config and not the field Signed-off-by: Rohit Yadav --- tools/cli/cloudmonkey/cachemaker.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cli/cloudmonkey/cachemaker.py b/tools/cli/cloudmonkey/cachemaker.py index 42a077ad928..8ac123caa4b 100644 --- a/tools/cli/cloudmonkey/cachemaker.py +++ b/tools/cli/cloudmonkey/cachemaker.py @@ -21,7 +21,7 @@ try: import os import types - from config import cache_file + from config import config_fields except ImportError, e: import sys print "ImportError", e @@ -168,6 +168,7 @@ def main(json_file): f.close() if __name__ == "__main__": + cache_file = config_fields['core']['cache_file'] print "[cachemaker] Pre-caching using user's cloudmonkey cache", cache_file if os.path.exists(cache_file): main(cache_file) From 4421f2bb60ea44a6b28593eb7e0254d5108919ff Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 19 Mar 2013 15:49:42 +0530 Subject: [PATCH 06/14] CLOUDSTACK-1708: Let cloudmonkey accept cfg passed in cmd line The patch adds feature in cloudmonkey to have multiple profiles by passing custom cfg file to set custom profile in both interactive shell and cmd line tool use cases. Signed-off-by: Rohit Yadav --- tools/cli/cloudmonkey/cloudmonkey.py | 47 +++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/tools/cli/cloudmonkey/cloudmonkey.py b/tools/cli/cloudmonkey/cloudmonkey.py index 25422412613..f88632d828c 100644 --- a/tools/cli/cloudmonkey/cloudmonkey.py +++ b/tools/cli/cloudmonkey/cloudmonkey.py @@ -29,8 +29,9 @@ try: import types from cachemaker import loadcache, savecache, monkeycache, splitverbsubject - from config import __version__, cache_file - from config import read_config, write_config + from config import __version__, __description__, __projecturl__ + from config import read_config, write_config, config_file + from optparse import OptionParser from prettytable import PrettyTable from printer import monkeyprint from requester import monkeyrequest @@ -63,13 +64,14 @@ class CloudMonkeyShell(cmd.Cmd, object): intro = ("☁ Apache CloudStack 🐵 cloudmonkey " + __version__ + ". Type help or ? to list commands.\n") ruler = "=" - cache_file = cache_file config_options = [] verbs = [] - def __init__(self, pname): + def __init__(self, pname, cfile): self.program_name = pname - self.config_options = read_config(self.get_attr, self.set_attr) + self.config_file = cfile + self.config_options = read_config(self.get_attr, self.set_attr, + self.config_file) self.loadcache() self.prompt = self.prompt.strip() + " " # Cosmetic fix for prompt @@ -364,7 +366,7 @@ class CloudMonkeyShell(cmd.Cmd, object): key, value = (args[0], args[2]) setattr(self, key, value) # keys and attributes should have same names self.prompt = self.prompt.strip() + " " # prompt fix - write_config(self.get_attr) + write_config(self.get_attr, self.config_file) def complete_set(self, text, line, begidx, endidx): mline = line.partition(" ")[2] @@ -458,10 +460,39 @@ class CloudMonkeyShell(cmd.Cmd, object): return self.do_EOF(args) +class MonkeyParser(OptionParser): + def format_help(self, formatter=None): + if formatter is None: + formatter = self.formatter + result = [] + if self.usage: + result.append("Usage: cloudmonkey [options] [cmds] [params]\n\n") + if self.description: + result.append(self.format_description(formatter) + "\n") + result.append(self.format_option_help(formatter)) + result.append("\nTry cloudmonkey [help|?]\n") + return "".join(result) + + def main(): - shell = CloudMonkeyShell(sys.argv[0]) + parser = MonkeyParser() + parser.add_option("-c", "--config-file", + dest="cfile", default=config_file, + help="config file for cloudmonkey", metavar="FILE") + parser.add_option("-v", "--version", + action="store_true", dest="version", default=False, + help="prints cloudmonkey version information") + + (options, args) = parser.parse_args() + print 'args', args + print 'options', options + if options.version: + print "cloudmonkey", __version__ + print __description__, "(%s)" % __projecturl__ + + shell = CloudMonkeyShell(sys.argv[0], options.cfile) if len(sys.argv) > 1: - shell.onecmd(' '.join(sys.argv[1:])) + shell.onecmd(' '.join(args)) else: shell.cmdloop() From 19a290500e17765a67eddc0d61769e483ee3d7f7 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 19 Mar 2013 15:52:03 +0530 Subject: [PATCH 07/14] cli: Import project info from config in setup.py, fix debug msgs Signed-off-by: Rohit Yadav lsdfjk Signed-off-by: Rohit Yadav --- tools/cli/cloudmonkey/__init__.py | 4 +++- tools/cli/cloudmonkey/cloudmonkey.py | 2 -- tools/cli/setup.py | 34 +++++++++++++--------------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/tools/cli/cloudmonkey/__init__.py b/tools/cli/cloudmonkey/__init__.py index e4c4e6d24f1..cf689e79480 100644 --- a/tools/cli/cloudmonkey/__init__.py +++ b/tools/cli/cloudmonkey/__init__.py @@ -16,6 +16,8 @@ # under the License. try: - from config import __version__ + from config import __version__, __description__ + from config import __maintainer__, __maintaineremail__ + from config import __project__, __projecturl__, __projectemail__ except ImportError, e: print e diff --git a/tools/cli/cloudmonkey/cloudmonkey.py b/tools/cli/cloudmonkey/cloudmonkey.py index f88632d828c..f750c3afa8d 100644 --- a/tools/cli/cloudmonkey/cloudmonkey.py +++ b/tools/cli/cloudmonkey/cloudmonkey.py @@ -484,8 +484,6 @@ def main(): help="prints cloudmonkey version information") (options, args) = parser.parse_args() - print 'args', args - print 'options', options if options.version: print "cloudmonkey", __version__ print __description__, "(%s)" % __projecturl__ diff --git a/tools/cli/setup.py b/tools/cli/setup.py index 9624115ed5f..4c7b2978b2f 100644 --- a/tools/cli/setup.py +++ b/tools/cli/setup.py @@ -22,13 +22,9 @@ except ImportError: use_setuptools() from setuptools import setup, find_packages -from cloudmonkey import __version__ - -name = 'cloudmonkey' -version = __version__ -requires = ['Pygments>=1.5', - 'prettytable>=0.6', - ] +from cloudmonkey import __version__, __description__ +from cloudmonkey import __maintainer__, __maintaineremail__ +from cloudmonkey import __project__, __projecturl__, __projectemail__ try: import readline @@ -36,20 +32,22 @@ except ImportError: requires.append('readline') setup( - name = name, - version = version, - author = "The Apache CloudStack Team", - author_email = "cloudstack-dev@incubator.apache.org", - maintainer = "Rohit Yadav", - maintainer_email = "bhaisaab@apache.org", - url = "http://incubator.apache.org/cloudstack", - description = "Command Line Interface for Apache CloudStack", - long_description = "cloudmonkey is a command line interface for Apache " - "CloudStack powered by CloudStack Marvin", + name = 'cloudmonkey', + version = __version__, + author = __project__, + author_email = __projectemail__, + maintainer = __maintainer__, + maintainer_email = __maintaineremail__, + url = __projecturl__, + description = __description__, + long_description = "cloudmonkey is a CLI for Apache CloudStack", platforms = ("Any",), license = 'ASL 2.0', packages = find_packages(), - install_requires = requires, + install_requires = [ + 'Pygments>=1.5', + 'prettytable>=0.6', + ], include_package_data = True, zip_safe = False, classifiers = [ From c02ab3f4d7a502eadca76026bdeeec40f00ca8ee Mon Sep 17 00:00:00 2001 From: Anshul Gangwar Date: Tue, 19 Mar 2013 16:08:11 +0530 Subject: [PATCH 08/14] CLOUDSTACK-1723:Fix for dashboard alerts --- ui/scripts/sharedFunctions.js | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index ad26b34196e..8bcdff91574 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -400,20 +400,28 @@ cloudStack.converters = { case 4 : return _l('label.public.ips'); case 5 : return _l('label.management.ips'); case 6 : return _l('label.secondary.storage'); - case 7 : return _l('label.vlan'); - case 8 : return _l('label.direct.ips'); - case 9 : return _l('label.local.storage'); + case 7 : return _l('label.host'); + case 9 : return _l('label.domain.router'); + case 10 : return _l('label.console.proxy'); - // These are old values -- can be removed in the future - case 10 : return "Routing Host"; - case 11 : return "Storage"; - case 12 : return "Usage Server"; - case 13 : return "Management Server"; - case 14 : return "Domain Router"; - case 15 : return "Console Proxy"; - case 16 : return "User VM"; - case 17 : return "VLAN"; - case 18 : return "Secondary Storage VM"; + // These are old values -- can be removed in the future + case 8 : return "User VM"; + case 11 : return "Routing Host"; + case 12 : return "Storage"; + case 13 : return "Usage Server"; + case 14 : return "Management Server"; + case 15 : return "Domain Router"; + case 16 : return "Console Proxy"; + case 17 : return "User VM"; + case 18 : return "VLAN"; + case 19 : return "Secondary Storage VM"; + case 20 : return "Usage Server"; + case 21 : return "Storage"; + case 22 : return "Update Resource Count"; + case 23 : return "Usage Sanity Result"; + case 24 : return "Direct Attached Public IP"; + case 25 : return "Local Storage"; + case 26 : return "Resource Limit Exceeded"; } }, convertByType: function(alertCode, value) { From 217ebf20a62006c999505ff1535a7bbf908b7763 Mon Sep 17 00:00:00 2001 From: Kishan Kavala Date: Tue, 19 Mar 2013 14:24:12 +0530 Subject: [PATCH 09/14] CLOUDSTACK-1717, CLOUDSTACK-1718: Corrected RemoveRegion response. Removed /api in Local region end_point --- .../cloudstack/api/command/admin/region/RemoveRegionCmd.java | 2 +- setup/db/db/schema-40to410.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/admin/region/RemoveRegionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/region/RemoveRegionCmd.java index 79c34d0690f..d2b696d2b6b 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/region/RemoveRegionCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/region/RemoveRegionCmd.java @@ -33,7 +33,7 @@ import com.cloud.user.Account; @APICommand(name = "removeRegion", description="Removes specified region", responseObject=SuccessResponse.class) public class RemoveRegionCmd extends BaseCmd { public static final Logger s_logger = Logger.getLogger(RemoveRegionCmd.class.getName()); - private static final String s_name = "updateregionresponse"; + private static final String s_name = "removeregionresponse"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// diff --git a/setup/db/db/schema-40to410.sql b/setup/db/db/schema-40to410.sql index 865fbd3181c..0f316a5acdd 100644 --- a/setup/db/db/schema-40to410.sql +++ b/setup/db/db/schema-40to410.sql @@ -261,7 +261,7 @@ CREATE TABLE `cloud`.`region` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `cloud`.`region` values ('1','Local','http://localhost:8080/client/api'); +INSERT INTO `cloud`.`region` values ('1','Local','http://localhost:8080/client'); INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Account Defaults', 'DEFAULT', 'management-server', 'max.account.cpus', '40', 'The default maximum number of cpu cores that can be used for an account'); From 0b7a4e04aaf2228a41bfb39d2699184220e1cc7d Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 19 Mar 2013 18:04:31 +0530 Subject: [PATCH 10/14] cli: Check args from optparser and not sys.argv Signed-off-by: Rohit Yadav --- tools/cli/cloudmonkey/cloudmonkey.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cli/cloudmonkey/cloudmonkey.py b/tools/cli/cloudmonkey/cloudmonkey.py index f750c3afa8d..e94d53091ac 100644 --- a/tools/cli/cloudmonkey/cloudmonkey.py +++ b/tools/cli/cloudmonkey/cloudmonkey.py @@ -489,7 +489,7 @@ def main(): print __description__, "(%s)" % __projecturl__ shell = CloudMonkeyShell(sys.argv[0], options.cfile) - if len(sys.argv) > 1: + if len(args) > 1: shell.onecmd(' '.join(args)) else: shell.cmdloop() From 90678c3d14d31617108ed30c4c06d3f1ee65a3e4 Mon Sep 17 00:00:00 2001 From: Kishan Kavala Date: Tue, 19 Mar 2013 18:16:36 +0530 Subject: [PATCH 11/14] CLOUDSTACK-198: Included VpnUsers in Add state while listing. Added state to Vpn user response. --- .../cloudstack/api/response/VpnUsersResponse.java | 10 ++++++++++ server/src/com/cloud/api/ApiResponseHelper.java | 1 + .../cloud/network/vpn/RemoteAccessVpnManagerImpl.java | 4 ++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/response/VpnUsersResponse.java b/api/src/org/apache/cloudstack/api/response/VpnUsersResponse.java index e654e8a522a..c29a37e7a48 100644 --- a/api/src/org/apache/cloudstack/api/response/VpnUsersResponse.java +++ b/api/src/org/apache/cloudstack/api/response/VpnUsersResponse.java @@ -48,6 +48,8 @@ public class VpnUsersResponse extends BaseResponse implements ControlledEntityRe @SerializedName(ApiConstants.PROJECT) @Param(description="the project name of the vpn") private String projectName; + @SerializedName(ApiConstants.STATE) @Param(description="the state of the Vpn User") + private String state; public void setId(String id) { this.id = id; @@ -80,4 +82,12 @@ public class VpnUsersResponse extends BaseResponse implements ControlledEntityRe this.projectName = projectName; } + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index ebf0fcf73d3..663139da41f 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -1108,6 +1108,7 @@ public class ApiResponseHelper implements ResponseGenerator { VpnUsersResponse vpnResponse = new VpnUsersResponse(); vpnResponse.setId(vpnUser.getUuid()); vpnResponse.setUserName(vpnUser.getUsername()); + vpnResponse.setState(vpnUser.getState().toString()); populateOwner(vpnResponse, vpnUser); diff --git a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java index 82c0015e317..d64a0212b46 100755 --- a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java +++ b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java @@ -511,13 +511,13 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); sb.and("username", sb.entity().getUsername(), SearchCriteria.Op.EQ); - sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ); + sb.and("state", sb.entity().getState(), Op.IN); SearchCriteria sc = sb.create(); _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); //list only active users - sc.setParameters("state", State.Active); + sc.setParameters("state", State.Active, State.Add); if (id != null) { sc.setParameters("id", id); From 7acdb17228582c62e3c30c3c712d58d330f54161 Mon Sep 17 00:00:00 2001 From: radhikap Date: Tue, 19 Mar 2013 19:41:21 +0530 Subject: [PATCH 12/14] IPv6 support doc --- docs/en-US/changed-apicommands-4.1.xml | 130 ++++++++++++++++- docs/en-US/ipv6-support.xml | 191 +++++++++++++++++++++++++ docs/en-US/whats-new.xml | 3 +- 3 files changed, 320 insertions(+), 4 deletions(-) create mode 100644 docs/en-US/ipv6-support.xml diff --git a/docs/en-US/changed-apicommands-4.1.xml b/docs/en-US/changed-apicommands-4.1.xml index 42bd088afb3..f0045a56de3 100644 --- a/docs/en-US/changed-apicommands-4.1.xml +++ b/docs/en-US/changed-apicommands-4.1.xml @@ -34,15 +34,139 @@ createNetworkOffering + + + The following request parameters have been added: + + + isPersistent + + + startipv6 + + + endipv6 + + + ip6gateway + + + ip6cidr + + + + + + listNetworkOfferings listNetworks - The following request parameters is added: isPersistent. - This parameter determines if the network or network offering created or listed by - using this offering are persistent or not. + The following request parameters has been added: isPersistent + This parameter determines if the network or network offering listed by using this + offering are persistent or not. + + + createVlanIpRange + + + The following request parameters have been added: + + + startipv6 + + + endipv6 + + + ip6gateway + + + ip6cidr + + + + + + + deployVirtualMachine + + + The following parameter has been added: ip6Address. + The following parameter is updated to accept the IPv6 address: + iptonetworklist. + + + + + CreateZoneCmd + + + The following parameter are added: ip6dns1, ip6dns2. + + + + + listRouters + listVirtualMachines + + + For nic responses, the following fields has been added. + + + ip6address + + + ip6gateway + + + ip6cidr + + + + + + + listVlanIpRanges + + + For nic responses, the following fields has been added. + + + startipv6 + + + endipv6 + + + ip6gateway + + + ip6cidr + + + + + + + listRouters + listZones + + + For DomainRouter and DataCenter response, the following fields have been + added. + + + ip6dns1 + + + ip6dns2 + + + + addF5LoadBalancer diff --git a/docs/en-US/ipv6-support.xml b/docs/en-US/ipv6-support.xml new file mode 100644 index 00000000000..22a5d7a5370 --- /dev/null +++ b/docs/en-US/ipv6-support.xml @@ -0,0 +1,191 @@ + + +%BOOK_ENTITIES; +]> + + +
+ IPv6 Support in &PRODUCT; + &PRODUCT;supports Internet Protocol version 6 (IPv6), the recent version of the Internet + Protocol (IP) that defines routing the network traffic. IPv6 uses a 128-bit address that + exponentially expands the current address space that is available to the users. IPv6 addresses + consist of eight groups of four hexadecimal digits separated by colons, for example, + 5001:0dt8:83a3:1012:1000:8s2e:0870:7454. &PRODUCT; supports IPv6 for public IPs in shared + networks. With IPv6 support, VMs in shared networks can obtain both IPv4 and IPv6 addresses from + the DHCP server. You can deploy VMs either in a IPv6 or IPv4 network, or in a dual network + environment. If IPv6 network is used, the VM generates a link-local IPv6 address by itself, and + receives a stateful IPv6 address from the DHCPv6 server. + IPv6 is supported only on KVM and XenServer hypervisors. The IPv6 support is only an + experimental feature. + Here's the sequence of events when IPv6 is used: + + + The administrator creates an IPv6 shared network in an advanced zone. + + + The user deploys a VM in an IPv6 shared network. + + + The user VM generates an IPv6 link local address by itself, and gets an IPv6 global or + site local address through DHCPv6. + For information on API changes, see . + + +
+ Prerequisites and Guidelines + Consider the following: + + + CIDR size must be 64 for IPv6 networks. + + + The DHCP client of the guest VMs should support generating DUID based on Link-layer + Address (DUID- LL). DUID-LL derives from the MAC address of guest VMs, and therefore the + user VM can be identified by using DUID. See Dynamic Host Configuration Protocol for IPv6 + for more information. + + + The gateway of the guest network generates Router Advisement and Response messages to + Router Solicitation. The M (Managed Address Configuration) flag of Router Advisement + should enable stateful IP address configuration. Set the M flag to where the end nodes + receive their IPv6 addresses from the DHCPv6 server as opposed to the router or + switch. + + The M flag is the 1-bit Managed Address Configuration flag for Router Advisement. + When set, Dynamic Host Configuration Protocol (DHCPv6) is available for address + configuration in addition to any IPs set by using stateless address + auto-configuration. + + + + Use the System VM template exclusively designed to support IPv6. Download the System + VM template from http://nfs1.lab.vmops.com/templates/routing/debian/ipv6/. + + + The concept of Default Network applies to IPv6 networks. However, unlike IPv4 + &PRODUCT; does not control the routing information of IPv6 in shared network; the choice + of Default Network will not affect the routing in the user VM. + + + In a multiple shared network, the default route is set by the rack router, rather than + the DHCP server, which is out of &PRODUCT; control. Therefore, in order for the user VM to + get only the default route from the default NIC, modify the configuration of the user VM, + and set non-default NIC's accept_ra to 0 explicitly. The + accept_ra parameter accepts Router Advertisements and auto-configure + /proc/sys/net/ipv6/conf/interface with received data. + + +
+
+ Limitations of IPv6 in &PRODUCT; + The following are not yet supported: + + + Security groups + + + Userdata and metadata + + + Passwords + + + The administrator cannot specify the IPv6 address of a VM. + + +
+
+ Network Configuration for DHCPv6 + Use DUID-LL to get IPv6 address from DHCP server + + + Set up dhclient by using DUID-LL. + Perform the following for DHCP Client 4.2 and above: + + + Run the following command on the selected VM to get the dhcpv6 offer from + VR: + dhclient -6 -D LL <dev> + + + Perform the following for DHCP Client 4.1: + + + Open the following to the dhclient configuration file: + vi /etc/dhcp/dhclient.conf + + + Add the following to the dhclient configuration file: + send dhcp6.client-id = concat(00:03:00, hardware); + + + + + Get IPv6 address from DHCP server as part of the system or network restart. + Based on the operating systems, perform the following: + On CentOS 6.2: + + + Open the Ethernet interface configuration file: + vi /etc/sysconfig/network-scripts/ifcfg-eth0 + The ifcfg-eth0 file controls the first NIC in a system. + + + Make the necessary configuration changes, as given below: + DEVICE=eth0 +HWADDR=06:A0:F0:00:00:38 +NM_CONTROLLED=no +ONBOOT=yes +BOOTPROTO=dhcp6 +TYPE=Ethernet +USERCTL=no +PEERDNS=yes +IPV6INIT=yes +DHCPV6C=yes + + + Open the following: + vi /etc/sysconfig/network + + + Make the necessary configuration changes, as given below: + NETWORKING=yes +HOSTNAME=centos62mgmt.lab.vmops.com +NETWORKING_IPV6=yes +IPV6_AUTOCONF=no + + + On Ubuntu 12.10 + + + Open the following: + etc/network/interfaces: + + + Make the necessary configuration changes, as given below: + iface eth0 inet6 dhcp +autoconf 0 +accept_ra 1 + + + + +
+
diff --git a/docs/en-US/whats-new.xml b/docs/en-US/whats-new.xml index 761d7a2eb37..252f87d0543 100644 --- a/docs/en-US/whats-new.xml +++ b/docs/en-US/whats-new.xml @@ -1,5 +1,5 @@ - %BOOK_ENTITIES; ]> @@ -25,6 +25,7 @@
What's New in the API for 4.1 + From ba69ce0c8911eb7186774d2ddbae97483e65d48c Mon Sep 17 00:00:00 2001 From: Gavin Lee Date: Tue, 19 Mar 2013 22:23:09 +0800 Subject: [PATCH 13/14] CLOUDSTACK-1599:Convert "Best Practices" section to XML and add to Install Guide --- docs/en-US/Installation_Guide.xml | 1 + docs/en-US/best-practices.xml | 82 +++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 docs/en-US/best-practices.xml diff --git a/docs/en-US/Installation_Guide.xml b/docs/en-US/Installation_Guide.xml index 2f60acac984..f2f27ad9621 100644 --- a/docs/en-US/Installation_Guide.xml +++ b/docs/en-US/Installation_Guide.xml @@ -57,5 +57,6 @@ + diff --git a/docs/en-US/best-practices.xml b/docs/en-US/best-practices.xml new file mode 100644 index 00000000000..41d7cde9036 --- /dev/null +++ b/docs/en-US/best-practices.xml @@ -0,0 +1,82 @@ + + +%BOOK_ENTITIES; +]> + + + + + Best Practices + Deploying a cloud is challenging. There are many different technology choices to make, and &PRODUCT; is flexible enough in its configuration that there are many possible ways to combine and configure the chosen technology. This section contains suggestions and requirements about cloud deployments. + These should be treated as suggestions and not absolutes. However, we do encourage anyone planning to build a cloud outside of these guidelines to seek guidance and advice on the project mailing lists. +
+ Process Best Practices + + + A staging system that models the production environment is strongly advised. It is critical if customizations have been applied to &PRODUCT;. + + + Allow adequate time for installation, a beta, and learning the system. Installs with basic networking can be done in hours. Installs with advanced networking usually take several days for the first attempt, with complicated installations taking longer. For a full production system, allow at least 4-8 weeks for a beta to work through all of the integration issues. You can get help from fellow users on the cloudstack-users mailing list. + + +
+
+ Setup Best Practices + + + Each host should be configured to accept connections only from well-known entities such as the &PRODUCT; Management Server or your network monitoring software. + + + Use multiple clusters per pod if you need to achieve a certain switch density. + + + Primary storage mountpoints or LUNs should not exceed 6 TB in size. It is better to have multiple smaller primary storage elements per cluster than one large one. + + + When exporting shares on primary storage, avoid data loss by restricting the range of IP addresses that can access the storage. See "Linux NFS on Local Disks and DAS" or "Linux NFS on iSCSI". + + + NIC bonding is straightforward to implement and provides increased reliability. + + + 10G networks are generally recommended for storage access when larger servers that can support relatively more VMs are used. + + + Host capacity should generally be modeled in terms of RAM for the guests. Storage and CPU may be overprovisioned. RAM may not. RAM is usually the limiting factor in capacity designs. + + + (XenServer) Configure the XenServer dom0 settings to allocate more memory to dom0. This can enable XenServer to handle larger numbers of virtual machines. We recommend 2940 MB of RAM for XenServer dom0. For instructions on how to do this, see http://support.citrix.com/article/CTX126531. The article refers to XenServer 5.6, but the same information applies to XenServer 6.0. + + +
+
+ Maintenance Best Practices + + + Monitor host disk space. Many host failures occur because the host's root disk fills up from logs that were not rotated adequately. + + + Monitor the total number of VM instances in each cluster, and disable allocation to the cluster if the total is approaching the maximum that the hypervisor can handle. Be sure to leave a safety margin to allow for the possibility of one or more hosts failing, which would increase the VM load on the other hosts as the VMs are redeployed. Consult the documentation for your chosen hypervisor to find the maximum permitted number of VMs per host, then use &PRODUCT; global configuration settings to set this as the default limit. Monitor the VM activity in each cluster and keep the total number of VMs below a safe level that allows for the occasional host failure. For example, if there are N hosts in the cluster, and you want to allow for one host in the cluster to be down at any given time, the total number of VM instances you can permit in the cluster is at most (N-1) * (per-host-limit). Once a cluster reaches this number of VMs, use the &PRODUCT; UI to disable allocation to the cluster. + + + The lack of up-do-date hotfixes can lead to data corruption and lost VMs. + Be sure all the hotfixes provided by the hypervisor vendor are applied. Track the release of hypervisor patches through your hypervisor vendor’s support channel, and apply patches as soon as possible after they are released. &PRODUCT; will not track or notify you of required hypervisor patches. It is essential that your hosts are completely up to date with the provided hypervisor patches. The hypervisor vendor is likely to refuse to support any system that is not up to date with patches. +
+
From 13691048fb622467271b75fc7b64298e3afe9912 Mon Sep 17 00:00:00 2001 From: hongtu_zang Date: Sat, 16 Mar 2013 09:54:09 +0800 Subject: [PATCH 14/14] fix bug vmware create volume from snapshot will missing data --- .../vmware/manager/VmwareStorageManagerImpl.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index e11dd53f3c9..1f116455761 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -684,13 +684,16 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); String srcOVAFileName = secondaryMountPoint + "/" + secStorageDir + "/" + backupName + "." + ImageFormat.OVA.getFileExtension(); - + String snapshotDir = ""; + if (backupName.contains("/")){ + snapshotDir = backupName.split("/")[0]; + } String srcFileName = getOVFFilePath(srcOVAFileName); if(srcFileName == null) { Script command = new Script("tar", 0, s_logger); command.add("--no-same-owner"); command.add("-xf", srcOVAFileName); - command.setWorkDir(secondaryMountPoint + "/" + secStorageDir); + command.setWorkDir(secondaryMountPoint + "/" + secStorageDir + "/" + snapshotDir); s_logger.info("Executing command: " + command.toString()); String result = command.execute(); if(result != null) { @@ -731,7 +734,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { String backupUuid = UUID.randomUUID().toString(); exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), backupUuid, workerVmName); - return backupUuid; + return backupUuid + "/" + backupUuid; } private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, @@ -739,8 +742,8 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { String workerVmName) throws Exception { String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); - String exportPath = secondaryMountPoint + "/" + secStorageDir; - + String exportPath = secondaryMountPoint + "/" + secStorageDir + "/" + exportName; + synchronized(exportPath.intern()) { if(!new File(exportPath).exists()) { Script command = new Script(false, "mkdir", _timeout, s_logger);