Merge branch 'master' into javelin

This commit is contained in:
Rohit Yadav 2013-01-27 05:20:49 -08:00
commit 2fb346ab62
No known key found for this signature in database
GPG Key ID: 484248210EE3D884
12 changed files with 348 additions and 212 deletions

View File

@ -25,6 +25,9 @@
<artifactId>cloudstack</artifactId> <artifactId>cloudstack</artifactId>
<version>4.1.0-SNAPSHOT</version> <version>4.1.0-SNAPSHOT</version>
</parent> </parent>
<properties>
<mkisofs>mkisofs</mkisofs>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>log4j</groupId> <groupId>log4j</groupId>
@ -167,6 +170,19 @@
</plugins> </plugins>
</build> </build>
<profiles> <profiles>
<!-- Debian will never distribute mkisofs due to licensing issues.
Fortunately genisoimage is a work-alike -->
<profile>
<id>genisoimage</id>
<activation>
<file>
<exists>/usr/bin/genisoimage</exists>
</file>
</activation>
<properties>
<mkisofs>genisoimage</mkisofs>
</properties>
</profile>
<profile> <profile>
<id>vmware</id> <id>vmware</id>
<activation> <activation>
@ -209,7 +225,7 @@
</execution> </execution>
</executions> </executions>
<configuration> <configuration>
<executable>mkisofs</executable> <executable>${mkisofs}</executable>
<workingDirectory>dist</workingDirectory> <workingDirectory>dist</workingDirectory>
<arguments> <arguments>
<argument>-quiet</argument> <argument>-quiet</argument>

View File

@ -1,25 +1,22 @@
<?xml version='1.0' encoding='utf-8' ?> <?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "cloudstack.ent"> <!ENTITY % BOOK_ENTITIES SYSTEM "cloudstack.ent">
%BOOK_ENTITIES; %BOOK_ENTITIES;
]> ]>
<!-- Licensed to the Apache Software Foundation (ASF) under one <!-- Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file or more contributor license agreements. See the NOTICE file
distributed with this work for additional information distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
Unless required by applicable law or agreed to in writing, "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
software distributed under the License is distributed on an KIND, either express or implied. See the License for the
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY specific language governing permissions and limitations
KIND, either express or implied. See the License for the under the License.
specific language governing permissions and limitations
under the License.
--> -->
<chapter id="offerings"> <chapter id="offerings">
@ -28,4 +25,5 @@
are discussed in the section on setting up networking for users.</para> are discussed in the section on setting up networking for users.</para>
<xi:include href="compute-disk-service-offerings.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> <xi:include href="compute-disk-service-offerings.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="system-service-offerings.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> <xi:include href="system-service-offerings.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="sys-offering-sysvm.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</chapter> </chapter>

View File

@ -0,0 +1,75 @@
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "cloudstack.ent">
%BOOK_ENTITIES;
]>
<!-- Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<section id="sys-offering-sysvm">
<title>Changing the Default System Offering for System VMs</title>
<para>You can manually change the system offering for a particular System VM. Additionally, as a
&PRODUCT; administrator, you can also change the default system offering used for System
VMs.</para>
<orderedlist>
<listitem>
<para>Create a new system offering.</para>
<para>For more information, see <phrase condition="install"><xref
linkend="creating-system-service-offerings"/></phrase>
<phrase condition="admin">Creating a New System Service Offering</phrase>. </para>
</listitem>
<listitem>
<para>Back up the database:</para>
<programlisting>mysqldump -u root -p cloud | bzip2 > cloud_backup.sql.bz2</programlisting>
</listitem>
<listitem>
<para>Open an MySQL prompt:</para>
<programlisting>mysql -u cloud -p cloud</programlisting>
</listitem>
<listitem>
<para>Run the following queries on the cloud database.</para>
<orderedlist numeration="loweralpha">
<listitem>
<para>In the disk_offering table, identify the original default offering and the new
offering you want to use by default. </para>
<para>Take a note of the ID of the new offering.</para>
<programlisting>select id,name,unique_name,type from disk_offering;</programlisting>
</listitem>
<listitem>
<para>For the original default offering, set the value of unique_name to NULL.</para>
<programlisting># update disk_offering set unique_name = NULL where id = 10;</programlisting>
<para>Ensure that you use the correct value for the ID.</para>
</listitem>
<listitem>
<para>For the new offering that you want to use by default, set the value of unique_name
as follows:</para>
<para>For the default Console Proxy VM (CPVM) offering,set unique_name to
'Cloud.com-ConsoleProxy'. For the default Secondary Storage VM (SSVM) offering, set
unique_name to 'Cloud.com-SecondaryStorage'. For example:</para>
<programlisting>update disk_offering set unique_name = 'Cloud.com-ConsoleProxy' where id = 16;</programlisting>
</listitem>
</orderedlist>
</listitem>
<listitem>
<para>Restart &PRODUCT; Management Server. Restarting is required because the default
offerings are loaded into the memory at startup.</para>
<programlisting>service cloud-management restart</programlisting>
</listitem>
<listitem>
<para>Destroy the existing CPVM or SSVM offerings and wait for them to be recreated. The new
CPVM or SSVM are configured with the new offering. </para>
</listitem>
</orderedlist>
</section>

View File

@ -1371,6 +1371,7 @@ CREATE TABLE `cloud`.`alert` (
`last_sent` DATETIME NULL COMMENT 'Last time the alert was sent', `last_sent` DATETIME NULL COMMENT 'Last time the alert was sent',
`resolved` DATETIME NULL COMMENT 'when the alert status was resolved (available memory no longer at critical level, etc.)', `resolved` DATETIME NULL COMMENT 'when the alert status was resolved (available memory no longer at critical level, etc.)',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
INDEX `last_sent` (`last_sent` DESC),
CONSTRAINT `uc_alert__uuid` UNIQUE (`uuid`) CONSTRAINT `uc_alert__uuid` UNIQUE (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -77,6 +77,8 @@ ALTER TABLE `cloud`.`inline_load_balancer_nic_map` DROP COLUMN load_balancer_id;
ALTER TABLE upload ADD uuid VARCHAR(40); ALTER TABLE upload ADD uuid VARCHAR(40);
ALTER TABLE async_job modify job_cmd VARCHAR(255); ALTER TABLE async_job modify job_cmd VARCHAR(255);
ALTER TABLE `cloud`.`alert` ADD INDEX `last_sent` (`last_sent` DESC) ;
-- populate uuid column with db id if uuid is null -- populate uuid column with db id if uuid is null
UPDATE `cloud`.`account` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`account` set uuid=id WHERE uuid is NULL;
UPDATE `cloud`.`alert` set uuid=id WHERE uuid is NULL; UPDATE `cloud`.`alert` set uuid=id WHERE uuid is NULL;

View File

@ -16,11 +16,13 @@
# under the License. # under the License.
try: try:
from common import grammar import re
from marvin.cloudstackAPI import * from marvin.cloudstackAPI import *
from marvin import cloudstackAPI from marvin import cloudstackAPI
except ImportError, e: except ImportError, e:
pass import sys
print "ImportError", e
sys.exit(1)
completions = cloudstackAPI.__all__ completions = cloudstackAPI.__all__
@ -43,9 +45,12 @@ def main():
completing commands and help docs. This reduces the overall search and completing commands and help docs. This reduces the overall search and
cache_miss (computation) complexity from O(n) to O(1) for any valid cmd. cache_miss (computation) complexity from O(n) to O(1) for any valid cmd.
""" """
pattern = re.compile("[A-Z]")
verbs = list(set([x[:pattern.search(x).start()] for x in completions
if pattern.search(x) is not None]).difference(['cloudstack']))
# datastructure {'verb': {cmd': ['api', [params], doc, required=[]]}} # datastructure {'verb': {cmd': ['api', [params], doc, required=[]]}}
cache_verbs = {} cache_verbs = {}
for verb in grammar: for verb in verbs:
completions_found = filter(lambda x: x.startswith(verb), completions) completions_found = filter(lambda x: x.startswith(verb), completions)
cache_verbs[verb] = {} cache_verbs[verb] = {}
for api_name in completions_found: for api_name in completions_found:

View File

@ -26,6 +26,7 @@ try:
import logging import logging
import os import os
import pdb import pdb
import re
import shlex import shlex
import sys import sys
import time import time
@ -38,7 +39,7 @@ try:
from prettytable import PrettyTable from prettytable import PrettyTable
from common import __version__, config_file, config_fields from common import __version__, config_file, config_fields
from common import grammar, precached_verbs from common import precached_verbs
from marvin.cloudstackConnection import cloudConnection from marvin.cloudstackConnection import cloudConnection
from marvin.cloudstackException import cloudstackAPIException from marvin.cloudstackException import cloudstackAPIException
from marvin.cloudstackAPI import * from marvin.cloudstackAPI import *
@ -71,12 +72,12 @@ class CloudMonkeyShell(cmd.Cmd, object):
ruler = "=" ruler = "="
config_file = config_file config_file = config_file
config_fields = config_fields config_fields = config_fields
grammar = grammar
# datastructure {'verb': {cmd': ['api', [params], doc, required=[]]}} # datastructure {'verb': {cmd': ['api', [params], doc, required=[]]}}
cache_verbs = precached_verbs cache_verbs = precached_verbs
def __init__(self, pname): def __init__(self, pname, verbs):
self.program_name = pname self.program_name = pname
self.verbs = verbs
if os.path.exists(self.config_file): if os.path.exists(self.config_file):
config = self.read_config() config = self.read_config()
else: else:
@ -102,11 +103,9 @@ class CloudMonkeyShell(cmd.Cmd, object):
logger.debug("Loaded config fields:\n%s" % self.config_fields) logger.debug("Loaded config fields:\n%s" % self.config_fields)
cmd.Cmd.__init__(self) cmd.Cmd.__init__(self)
# Update config if config_file does not exist
if not os.path.exists(self.config_file): if not os.path.exists(self.config_file):
config = self.write_config() config = self.write_config()
# Enable history support
try: try:
if os.path.exists(self.history_file): if os.path.exists(self.history_file):
readline.read_history_file(self.history_file) readline.read_history_file(self.history_file)
@ -381,13 +380,13 @@ class CloudMonkeyShell(cmd.Cmd, object):
def completedefault(self, text, line, begidx, endidx): def completedefault(self, text, line, begidx, endidx):
partitions = line.partition(" ") partitions = line.partition(" ")
verb = partitions[0] verb = partitions[0].strip()
rline = partitions[2].partition(" ") rline = partitions[2].lstrip().partition(" ")
subject = rline[0] subject = rline[0]
separator = rline[1] separator = rline[1]
params = rline[2] params = rline[2].lstrip()
if verb not in self.grammar: if verb not in self.verbs:
return [] return []
autocompletions = [] autocompletions = []
@ -436,7 +435,7 @@ class CloudMonkeyShell(cmd.Cmd, object):
args = args.strip().partition(" ") args = args.strip().partition(" ")
key, value = (args[0], args[2]) key, value = (args[0], args[2])
setattr(self, key, value) # keys and attributes should have same names setattr(self, key, value) # keys and attributes should have same names
self.prompt = self.prompt.strip() + " " # prompt fix self.prompt = self.prompt.strip() + " " # prompt fix
self.write_config() self.write_config()
def complete_set(self, text, line, begidx, endidx): def complete_set(self, text, line, begidx, endidx):
@ -513,22 +512,22 @@ class CloudMonkeyShell(cmd.Cmd, object):
def main(): def main():
# Create handlers on the fly using closures pattern = re.compile("[A-Z]")
self = CloudMonkeyShell verbs = list(set([x[:pattern.search(x).start()] for x in completions
global grammar if pattern.search(x) is not None]).difference(['cloudstack']))
for rule in grammar: for verb in verbs:
def add_grammar(rule): def add_grammar(verb):
def grammar_closure(self, args): def grammar_closure(self, args):
if self.pipe_runner("%s %s" % (rule, args)): if self.pipe_runner("%s %s" % (verb, args)):
return return
try: try:
args_partition = args.partition(" ") args_partition = args.partition(" ")
res = self.cache_verbs[rule][args_partition[0]] res = self.cache_verbs[verb][args_partition[0]]
cmd = res[0] cmd = res[0]
helpdoc = res[2] helpdoc = res[2]
args = args_partition[2] args = args_partition[2]
except KeyError, e: except KeyError, e:
self.print_shell("Error: invalid %s api arg" % rule, e) self.print_shell("Error: invalid %s api arg" % verb, e)
return return
if ' --help' in args or ' -h' in args: if ' --help' in args or ' -h' in args:
self.print_shell(helpdoc) self.print_shell(helpdoc)
@ -536,12 +535,12 @@ def main():
self.default("%s %s" % (cmd, args)) self.default("%s %s" % (cmd, args))
return grammar_closure return grammar_closure
grammar_handler = add_grammar(rule) grammar_handler = add_grammar(verb)
grammar_handler.__doc__ = "%ss resources" % rule.capitalize() grammar_handler.__doc__ = "%ss resources" % verb.capitalize()
grammar_handler.__name__ = 'do_' + rule grammar_handler.__name__ = 'do_' + verb
setattr(self, grammar_handler.__name__, grammar_handler) setattr(CloudMonkeyShell, grammar_handler.__name__, grammar_handler)
shell = CloudMonkeyShell(sys.argv[0]) shell = CloudMonkeyShell(sys.argv[0], verbs)
if len(sys.argv) > 1: if len(sys.argv) > 1:
shell.onecmd(' '.join(sys.argv[1:])) shell.onecmd(' '.join(sys.argv[1:]))
else: else:

View File

@ -39,12 +39,3 @@ config_fields = {'host': 'localhost', 'port': '8080',
'history_file': 'history_file':
os.path.expanduser('~/.cloudmonkey_history')} os.path.expanduser('~/.cloudmonkey_history')}
# Add verbs in grammar
grammar = ['create', 'list', 'delete', 'update', 'lock',
'enable', 'activate', 'disable', 'add', 'remove',
'attach', 'detach', 'associate', 'disassociate', 'generate', 'ldap',
'assign', 'authorize', 'change', 'register', 'configure',
'start', 'restart', 'reboot', 'stop', 'reconnect',
'cancel', 'destroy', 'revoke', 'mark', 'reset',
'copy', 'extract', 'migrate', 'restore', 'suspend',
'get', 'query', 'prepare', 'deploy', 'upload']

View File

@ -642,12 +642,16 @@
}, },
vmLimit: { vmLimit: {
label: 'label.instance.limits', label: 'label.instance.limits',
isEditable: function(context) { isEditable: function(context) {
if(context.accounts == undefined)
return false;
else {
if (context.accounts[0].accounttype == roleTypeUser || context.accounts[0].accounttype == roleTypeDomainAdmin) //updateResourceLimits is only allowed on account whose type is user or domain-admin 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; return true;
else else
return false; return false;
} } }
}, },
ipLimit: { ipLimit: {
label: 'label.ip.limits', label: 'label.ip.limits',

View File

@ -1322,6 +1322,13 @@
networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering; networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering;
if (networkOfferingObjs != null && networkOfferingObjs.length > 0) { if (networkOfferingObjs != null && networkOfferingObjs.length > 0) {
for (var i = 0; i < networkOfferingObjs.length; i++) { for (var i = 0; i < networkOfferingObjs.length; i++) {
if(args.scope=="account-specific" && args.context.zones[0].securitygroupsenabled == true) { //BUG - CLOUDSTACK-1063
var serviceObjArray = networkOfferingObjs[i].name;
if(serviceObjArray == "DefaultSharedNetworkOfferingWithSGService"){
continue;
}
}
//comment out the following 12 lines because of CS-16718 //comment out the following 12 lines because of CS-16718
/* /*

View File

@ -860,8 +860,19 @@
// Previous button // Previous button
if ($target.closest('div.button.previous').size()) { if ($target.closest('div.button.previous').size()) {
var index = $steps.filter(':visible').index(); var $step = $steps.filter(':visible');
if (index) showStep(index); var $networkStep = $steps.filter('.network');
var index = $step.index();
$networkStep.removeClass('next-use-security-groups');
if (index) {
if (index == $steps.size() - 1 && $networkStep.hasClass('next-use-security-groups')) {
showStep(5);
} else {
showStep(index);
}
}
return false; return false;
} }

View File

@ -57,22 +57,80 @@
var fields = $.map(args.form.fields, function(value, key) { var fields = $.map(args.form.fields, function(value, key) {
return key; return key;
}) })
$(fields).each(function() { var ret = function() {
return $formContainer.dialog({
dialogClass: 'create-form',
closeOnEscape: false,
draggable: false,
width: 400,
title: _l(args.form.title),
open: function() {
if (args.form.preFilter) {
args.form.preFilter({ $form: $form, context: args.context });
}
},
buttons: [
{
text: createLabel ? createLabel : _l('label.ok'),
'class': 'ok',
click: function() {
if (!complete($formContainer)) { return false; }
$('div.overlay').remove();
$('.tooltip-box').remove();
$formContainer.remove();
$(this).dialog('destroy');
$('.hovered-elem').hide();
return true;
}
},
{
text: _l('label.cancel'),
'class': 'cancel',
click: function() {
$('div.overlay').remove();
$('.tooltip-box').remove();
$formContainer.remove();
$(this).dialog('destroy');
$('.hovered-elem').hide();
}
}
]
}).closest('.ui-dialog').overlay();
};
var isLastAsync = function(idx) {
for(var i = idx+1; i < $(fields).length ; i++) {
var f = args.form.fields[$(fields).get(i)];
if(f.select || f.dynamic){
return false;
}
}
return true;
};
var isAsync = false;
var isNoDialog = args.noDialog ? args.noDialog : false;
$(fields).each(function(idx, element) {
var key = this; var key = this;
var field = args.form.fields[key]; var field = args.form.fields[key];
var $formItem = $('<div>') var $formItem = $('<div>')
.addClass('form-item') .addClass('form-item')
.attr({ rel: key }); .attr({ rel: key });
if(field.isHidden != null) { if(field.isHidden != null) {
if (typeof(field.isHidden) == 'boolean' && field.isHidden == true) if (typeof(field.isHidden) == 'boolean' && field.isHidden == true)
$formItem.hide(); $formItem.hide();
else if (typeof(field.isHidden) == 'function' && field.isHidden() == true) else if (typeof(field.isHidden) == 'function' && field.isHidden() == true)
$formItem.hide(); $formItem.hide();
} }
$formItem.appendTo($form); $formItem.appendTo($form);
//Handling Escape KeyPress events //Handling Escape KeyPress events
@ -96,7 +154,7 @@
closeOnEscape: false closeOnEscape: false
}); */ }); */
// Label field // Label field
var $name = $('<div>').addClass('name') var $name = $('<div>').addClass('name')
.appendTo($formItem) .appendTo($formItem)
.append( .append(
@ -104,9 +162,10 @@
); );
// red asterisk // red asterisk
var $astersikSpan = $('<span>').addClass('field-required').html('*'); var $astersikSpan = $('<span>').addClass('field-required').html('*');
$name.find('label').prepend($astersikSpan); $name.find('label').prepend($astersikSpan);
if (field.validation == null || field.validation.required == false) {
if (field.validation == null || field.validation.required == false) {
$astersikSpan.hide(); $astersikSpan.hide();
} }
@ -169,6 +228,7 @@
// Determine field type of input // Determine field type of input
if (field.select) { if (field.select) {
isAsync = true;
selectArgs = { selectArgs = {
context: args.context, context: args.context,
response: { response: {
@ -193,6 +253,10 @@
} }
$input.trigger('change'); $input.trigger('change');
if((!isNoDialog) && isLastAsync(idx)) {
ret();
}
} }
} }
}; };
@ -200,7 +264,7 @@
selectFn = field.select; selectFn = field.select;
$input = $('<select>') $input = $('<select>')
.attr({ name: key }) .attr({ name: key })
.data('dialog-select-fn', function(args) { .data('dialog-select-fn', function(args) {
selectFn(args ? $.extend(true, {}, selectArgs, args) : selectArgs); selectFn(args ? $.extend(true, {}, selectArgs, args) : selectArgs);
}) })
.appendTo($value); .appendTo($value);
@ -221,21 +285,21 @@
var dependsOnArgs = {}; var dependsOnArgs = {};
$input.find('option').remove(); $input.find('option').remove();
if (!$target.children().size()) return true; if (!$target.children().size()) return true;
dependsOnArgs[dependsOn] = $target.val(); dependsOnArgs[dependsOn] = $target.val();
selectFn($.extend(selectArgs, dependsOnArgs)); selectFn($.extend(selectArgs, dependsOnArgs));
return true; return true;
}); });
if (!$dependsOn.is('select')) { if (!$dependsOn.is('select')) {
selectFn(selectArgs); selectFn(selectArgs);
} }
} else { } else {
selectFn(selectArgs); selectFn(selectArgs);
} }
} else if (field.isBoolean) { } else if (field.isBoolean) {
if (field.multiArray) { if (field.multiArray) {
@ -263,7 +327,7 @@
} else { } else {
// This is mainly for IE compatibility // This is mainly for IE compatibility
setTimeout(function() { setTimeout(function() {
$input.attr('checked', false); $input.attr('checked', false);
}, 100); }, 100);
} }
} }
@ -277,6 +341,7 @@
}); });
} }
} else if (field.dynamic) { } else if (field.dynamic) {
isAsync = true;
// Generate a 'sub-create-form' -- append resulting fields // Generate a 'sub-create-form' -- append resulting fields
$input = $('<div>').addClass('dynamic-input').appendTo($value); $input = $('<div>').addClass('dynamic-input').appendTo($value);
$form.hide(); $form.hide();
@ -297,6 +362,9 @@
// Form should be slightly wider // Form should be slightly wider
$form.closest(':ui-dialog').dialog('option', { position: 'center',closeOnEscape: false }); $form.closest(':ui-dialog').dialog('option', { position: 'center',closeOnEscape: false });
if((!isNoDialog) && isLastAsync(idx)) {
ret();
}
} }
} }
}); });
@ -308,63 +376,64 @@
if (field.defaultValue) { if (field.defaultValue) {
$input.val(field.defaultValue); $input.val(field.defaultValue);
} }
} else if (field.isDatepicker) { //jQuery datepicker } else if (field.isDatepicker) { //jQuery datepicker
$input = $('<input>').attr({ $input = $('<input>').attr({
name: key, name: key,
type: 'text' type: 'text'
}).appendTo($value); }).appendTo($value);
if (field.defaultValue) { if (field.defaultValue) {
$input.val(field.defaultValue); $input.val(field.defaultValue);
} }
if (field.id) { if (field.id) {
$input.attr('id', field.id); $input.attr('id', field.id);
} }
$input.addClass("disallowSpecialCharacters"); $input.addClass("disallowSpecialCharacters");
$input.datepicker({dateFormat: 'yy-mm-dd'}); $input.datepicker({dateFormat: 'yy-mm-dd'});
} else if(field.range) { //2 text fields on the same line (e.g. port range: startPort - endPort)
$input = $.merge(
// Range start
$('<input>').attr({
type: 'text',
name: field.range[0]
}),
// Range end } else if(field.range) {//2 text fields on the same line (e.g. port range: startPort - endPort)
$('<input>').attr({ $input = $.merge(
type: 'text', // Range start
name: field.range[1] $('<input>').attr({
}) type: 'text',
).appendTo( name: field.range[0]
$('<div>').addClass('range-edit').appendTo($value) }),
);
$input.wrap($('<div>').addClass('range-item'));
$input.addClass("disallowSpecialCharacters");
} else { //text field
$input = $('<input>').attr({
name: key,
type: field.password || field.isPassword ? 'password' : 'text'
}).appendTo($value);
if (field.defaultValue) { // Range end
$input.val(field.defaultValue); $('<input>').attr({
} type: 'text',
if (field.id) { name: field.range[1]
$input.attr('id', field.id); })
} ).appendTo(
$('<div>').addClass('range-edit').appendTo($value)
);
$input.wrap($('<div>').addClass('range-item'));
$input.addClass("disallowSpecialCharacters");
} else { //text field
$input = $('<input>').attr({
name: key,
type: field.password || field.isPassword ? 'password' : 'text'
}).appendTo($value);
if (field.defaultValue) {
$input.val(field.defaultValue);
}
if (field.id) {
$input.attr('id', field.id);
}
$input.addClass("disallowSpecialCharacters"); $input.addClass("disallowSpecialCharacters");
} }
if(field.validation != null) if(field.validation != null)
$input.data('validation-rules', field.validation); $input.data('validation-rules', field.validation);
else else
$input.data('validation-rules', {}); $input.data('validation-rules', {});
var fieldLabel = field.label; var fieldLabel = field.label;
var inputId = $input.attr('id') ? $input.attr('id') : fieldLabel.replace(/\./g,'_'); var inputId = $input.attr('id') ? $input.attr('id') : fieldLabel.replace(/\./g,'_');
$input.attr('id', inputId); $input.attr('id', inputId);
$name.find('label').attr('for', inputId); $name.find('label').attr('for', inputId);
@ -380,29 +449,32 @@
attachTo: '.form-item' attachTo: '.form-item'
}); });
} }
/* $input.blur(function() { /* $input.blur(function() {
console.log('tooltip remove->' + $input.attr('name')); console.log('tooltip remove->' + $input.attr('name'));
});*/ });*/
}); });
var getFormValues = function() { var getFormValues = function() {
var formValues = {}; var formValues = {};
$.each(args.form.fields, function(key) {}); $.each(args.form.fields, function(key) {});
}; };
// Setup form validation // Setup form validation
$formContainer.find('form').validate(); $formContainer.find('form').validate();
$formContainer.find('input, select').each(function() { $formContainer.find('input, select').each(function() {
if ($(this).data('validation-rules')) { if ($(this).data('validation-rules')) {
$(this).rules('add', $(this).data('validation-rules')); $(this).rules('add', $(this).data('validation-rules'));
} }
else { else {
$(this).rules('add', {}); $(this).rules('add', {});
} }
}); });
$form.find('select').trigger('change'); $form.find('select').trigger('change');
var complete = function($formContainer) { var complete = function($formContainer) {
var $form = $formContainer.find('form'); var $form = $formContainer.find('form');
var data = cloudStack.serializeForm($form); var data = cloudStack.serializeForm($form);
@ -429,93 +501,48 @@
$formContainer: $formContainer, $formContainer: $formContainer,
completeAction: complete completeAction: complete
}; };
} else if (!isAsync) {
return ret();
} }
return $formContainer.dialog({
dialogClass: 'create-form',
closeOnEscape: false,
draggable: false,
width: 400,
title: _l(args.form.title),
open: function() {
if (args.form.preFilter) {
args.form.preFilter({ $form: $form, context: args.context });
}
},
buttons: [
{
text: createLabel ? createLabel : _l('label.ok'),
'class': 'ok',
click: function() {
if (!complete($formContainer)) { return false; }
$('div.overlay').remove();
$('.tooltip-box').remove();
$formContainer.remove();
$(this).dialog('destroy');
$('.hovered-elem').hide();
return true;
}
},
{
text: _l('label.cancel'),
'class': 'cancel',
click: function() {
$('div.overlay').remove();
$('.tooltip-box').remove();
$formContainer.remove();
$(this).dialog('destroy');
$('.hovered-elem').hide();
}
}
]
}).closest('.ui-dialog').overlay();
}, },
/** /**
* to change a property(e.g. validation) of a createForm field after a createForm is rendered * to change a property(e.g. validation) of a createForm field after a createForm is rendered
*/ */
createFormField: { createFormField: {
validation: { validation: {
required: { required: {
add: function($formField) { add: function($formField) {
var $input = $formField.find('input, select');
var validationRules = $input.data('validation-rules');
if(validationRules == null || validationRules.required == null || validationRules.required == false) {
$formField.find('.name').find('label').find('span.field-required').css('display', 'inline'); //show red asterisk
if(validationRules == null)
validationRules = {};
validationRules.required = true;
$input.data('validation-rules', validationRules);
$input.rules('add', { required: true });
}
},
remove: function($formField) {
var $input = $formField.find('input, select'); var $input = $formField.find('input, select');
var validationRules = $input.data('validation-rules'); var validationRules = $input.data('validation-rules');
if(validationRules != null && validationRules.required != null && validationRules.required == true) { if(validationRules == null || validationRules.required == null || validationRules.required == false) {
$formField.find('.name').find('label').find('span.field-required').hide(); //hide red asterisk $formField.find('.name').find('label').find('span.field-required').css('display', 'inline'); //show red asterisk
delete validationRules.required; if(validationRules == null)
$input.data('validation-rules', validationRules); validationRules = {};
validationRules.required = true;
$input.data('validation-rules', validationRules);
$input.rules('add', { required: true });
}
},
remove: function($formField) {
var $input = $formField.find('input, select');
var validationRules = $input.data('validation-rules');
if(validationRules != null && validationRules.required != null && validationRules.required == true) {
$formField.find('.name').find('label').find('span.field-required').hide(); //hide red asterisk
delete validationRules.required;
$input.data('validation-rules', validationRules);
$input.rules('remove', 'required');
$formField.find('.value').find('label.error').hide();
}
}
}
}
},
$input.rules('remove', 'required');
$formField.find('.value').find('label.error').hide();
}
}
}
}
},
/** /**
* Confirmation dialog * Confirmation dialog
*/ */