Commit 5b5363b7 authored by Sylvain Thénault's avatar Sylvain Thénault
Browse files

[c-c create] unification of c-c create and its subcommands handling

* create/db-create/db-init uniformly accept --automatic and --config-level
  options, properly passed along the way
* --automatic option fixed so it doesn't need yes or no argument
* closes ##1537265 on the way

--HG--
branch : stable
parent 20807d3d7cf6
......@@ -300,6 +300,11 @@ class ListCommand(Command):
print '* cube %s version %s is installed, but version %s is required by %s' % (
cube, cfgpb.cubes[cube], version, src)
def check_options_consistency(config):
if config.automatic and config.config_level > 0:
raise BadCommandUsage('--automatic and --config-level should not be '
'used together')
class CreateInstanceCommand(Command):
"""Create an instance from a cube. This is an unified
command which can handle web / server / all-in-one installation
......@@ -309,7 +314,7 @@ class CreateInstanceCommand(Command):
<cube>
the name of cube to use (list available cube names using
the "list" command). You can use several cubes by separating
them using comma (e.g. 'jpl,eemail')
them using comma (e.g. 'jpl,email')
<instance>
an identifier for the instance to create
"""
......@@ -317,28 +322,34 @@ class CreateInstanceCommand(Command):
arguments = '<cube> <instance>'
min_args = max_args = 2
options = (
("config-level",
('automatic',
{'short': 'a', 'action' : 'store_true',
'default': False,
'help': 'automatic mode: never ask and use default answer to every '
'question. this may require that your login match a database super '
'user (allowed to create database & all).',
}),
('config-level',
{'short': 'l', 'type' : 'int', 'metavar': '<level>',
'default': 0,
'help': 'configuration level (0..2): 0 will ask for essential \
configuration parameters only while 2 will ask for all parameters',
}
),
("config",
'help': 'configuration level (0..2): 0 will ask for essential '
'configuration parameters only while 2 will ask for all parameters',
}),
('config',
{'short': 'c', 'type' : 'choice', 'metavar': '<install type>',
'choices': ('all-in-one', 'repository', 'twisted'),
'default': 'all-in-one',
'help': 'installation type, telling which part of an instance \
should be installed. You can list available configurations using the "list" \
command. Default to "all-in-one", e.g. an installation embedding both the RQL \
repository and the web server.',
}
),
'help': 'installation type, telling which part of an instance '
'should be installed. You can list available configurations using the'
' "list" command. Default to "all-in-one", e.g. an installation '
'embedding both the RQL repository and the web server.',
}),
)
def run(self, args):
"""run the command with its specific arguments"""
from logilab.common.textutils import splitstrip
check_options_consistency(self.config)
configname = self.config.config
cubes, appid = args
cubes = splitstrip(cubes)
......@@ -360,17 +371,19 @@ repository and the web server.',
print '\n'+underline_title('Creating the instance %s' % appid)
create_dir(config.apphome)
# cubicweb-ctl configuration
print '\n'+underline_title('Configuring the instance (%s.conf)' % configname)
config.input_config('main', self.config.config_level)
if not self.config.automatic:
print '\n'+underline_title('Configuring the instance (%s.conf)'
% configname)
config.input_config('main', self.config.config_level)
# configuration'specific stuff
print
helper.bootstrap(cubes, self.config.config_level)
helper.bootstrap(cubes, self.config.automatic, self.config.config_level)
# input for cubes specific options
sections = set(sect.lower() for sect, opt, odict in config.all_options()
if 'type' in odict
and odict.get('level') <= self.config.config_level)
for section in sections:
if section not in ('main', 'email', 'pyro'):
if section not in ('main', 'email', 'pyro', 'web'):
print '\n' + underline_title('%s options' % section)
config.input_config(section, self.config.config_level)
# write down configuration
......@@ -385,8 +398,9 @@ repository and the web server.',
errors = config.i18ncompile(langs)
if errors:
print '\n'.join(errors)
if not ASK.confirm('error while compiling message catalogs, '
'continue anyway ?'):
if self.config.automatic \
or not ASK.confirm('error while compiling message catalogs, '
'continue anyway ?'):
print 'creation not completed'
return
# create the additional data directory for this instance
......@@ -399,7 +413,7 @@ repository and the web server.',
print 'set %s as owner of the data directory' % config['uid']
chown(config.appdatahome, config['uid'])
print '\n-> creation done for %r.\n' % config.apphome
helper.postcreate()
helper.postcreate(self.config.automatic)
def _handle_win32(self, config, appid):
if sys.platform != 'win32':
......
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
......
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
......@@ -51,10 +51,10 @@ try:
"""
cfgname = 'all-in-one'
def bootstrap(self, cubes, inputlevel=0):
def bootstrap(self, cubes, automatic=False, inputlevel=0):
"""bootstrap this configuration"""
serverctl.RepositoryCreateHandler.bootstrap(self, cubes, inputlevel)
TWCreateHandler.bootstrap(self, cubes, inputlevel)
serverctl.RepositoryCreateHandler.bootstrap(self, cubes, automatic, inputlevel)
TWCreateHandler.bootstrap(self, cubes, automatic, inputlevel)
class AllInOneStartHandler(TWStartHandler):
cmdname = 'start'
......
......@@ -27,11 +27,11 @@ import os
from logilab.common import nullobject
from logilab.common.configuration import Configuration
from logilab.common.shellutils import ASK
from logilab.common.shellutils import ASK, generate_password
from cubicweb import AuthenticationError, ExecutionError, ConfigurationError
from cubicweb.toolsutils import Command, CommandHandler, underline_title
from cubicweb.cwctl import CWCTL
from cubicweb.cwctl import CWCTL, check_options_consistency
from cubicweb.server import SOURCE_TYPES
from cubicweb.server.serverconfig import (
USER_OPTIONS, ServerConfiguration, SourceConfiguration,
......@@ -154,38 +154,49 @@ class RepositoryCreateHandler(CommandHandler):
cmdname = 'create'
cfgname = 'repository'
def bootstrap(self, cubes, inputlevel=0):
def bootstrap(self, cubes, automatic=False, inputlevel=0):
"""create an instance by copying files from the given cube and by asking
information necessary to build required configuration files
"""
config = self.config
print underline_title('Configuring the repository')
config.input_config('email', inputlevel)
# ask for pyro configuration if pyro is activated and we're not using a
# all-in-one config, in which case this is done by the web side command
# handler
if config.pyro_enabled() and config.name != 'all-in-one':
config.input_config('pyro', inputlevel)
print '\n'+underline_title('Configuring the sources')
if not automatic:
print underline_title('Configuring the repository')
config.input_config('email', inputlevel)
# ask for pyro configuration if pyro is activated and we're not
# using a all-in-one config, in which case this is done by the web
# side command handler
if config.pyro_enabled() and config.name != 'all-in-one':
config.input_config('pyro', inputlevel)
print '\n'+underline_title('Configuring the sources')
sourcesfile = config.sources_file()
# XXX hack to make Method('default_instance_id') usable in db option
# defs (in native.py)
# hack to make Method('default_instance_id') usable in db option defs
# (in native.py)
sconfig = SourceConfiguration(config,
options=SOURCE_TYPES['native'].options)
sconfig.input_config(inputlevel=inputlevel)
if not automatic:
sconfig.input_config(inputlevel=inputlevel)
print
sourcescfg = {'system': sconfig}
print
sconfig = Configuration(options=USER_OPTIONS)
sconfig.input_config(inputlevel=inputlevel)
if automatic:
# XXX modify a copy
password = generate_password()
print 'Administration account is admin / %s' % password
USER_OPTIONS[1][1]['default'] = password
sconfig = Configuration(options=USER_OPTIONS)
else:
sconfig = Configuration(options=USER_OPTIONS)
sconfig.input_config(inputlevel=inputlevel)
sourcescfg['admin'] = sconfig
config.write_sources_file(sourcescfg)
# remember selected cubes for later initialization of the database
config.write_bootstrap_cubes_file(cubes)
def postcreate(self):
if ASK.confirm('Run db-create to create the system database ?'):
verbosity = (self.config.mode == 'installed') and 'y' or 'n'
CWCTL.run(['db-create', self.config.appid])
def postcreate(self, automatic=False, inputlevel=0):
if automatic:
CWCTL.run(['db-create', '--automatic', self.config.appid])
elif ASK.confirm('Run db-create to create the system database ?'):
CWCTL.run(['db-create', '--config-level', str(inputlevel),
self.config.appid])
else:
print ('-> nevermind, you can do it later with '
'"cubicweb-ctl db-create %s".' % self.config.appid)
......@@ -293,27 +304,30 @@ class CreateInstanceDBCommand(Command):
arguments = '<instance>'
min_args = max_args = 1
options = (
('automatic',
{'short': 'a', 'action' : 'store_true',
'default': False,
'help': 'automatic mode: never ask and use default answer to every '
'question. this may require that your login match a database super '
'user (allowed to create database & all).',
}),
('config-level',
{'short': 'l', 'type' : 'int', 'metavar': '<level>',
'default': 0,
'help': 'configuration level (0..2): 0 will ask for essential '
'configuration parameters only while 2 will ask for all parameters',
}),
('create-db',
{'short': 'c', 'type': 'yn', 'metavar': '<y or n>',
'default': True,
'help': 'create the database (yes by default)'}),
('quiet',
{'short': 'q', 'action' : 'store_true',
'default': False,
'help': 'be quiet. Suppose database user in the sources file is a '
'super user and don\'t ask for alternate login.',
'help': 'create the database (yes by default)'
}),
('automatic',
{'short': 'a', 'type' : 'yn', 'metavar': '<auto>',
'default': 'n',
'help': 'automatic mode: never ask and use default answer to every question',
}
),
)
def run(self, args):
"""run the command with its specific arguments"""
from logilab.database import get_db_helper
quiet = self.get('quiet')
check_options_consistency(self.config)
automatic = self.get('automatic')
appid = args.pop()
config = ServerConfiguration.config_for(appid)
......@@ -330,7 +344,7 @@ class CreateInstanceDBCommand(Command):
print '\n'+underline_title('Creating the system database')
# connect on the dbms system base to create our base
dbcnx = _db_sys_cnx(source, 'CREATE/DROP DATABASE and / or USER',
interactive=not quiet)
interactive=not automatic)
cursor = dbcnx.cursor()
try:
if helper.users_support:
......@@ -343,6 +357,8 @@ class CreateInstanceDBCommand(Command):
if automatic or ASK.confirm('Database %s already exists -- do you want to drop it ?' % dbname):
cursor.execute('DROP DATABASE %s' % dbname)
else:
print ('you may want to run "cubicweb-ctl db-init '
'--drop %s" manually to continue.' % config.appid)
return
createdb(helper, source, dbcnx, cursor)
dbcnx.commit()
......@@ -351,7 +367,7 @@ class CreateInstanceDBCommand(Command):
dbcnx.rollback()
raise
cnx = system_source_cnx(source, special_privs='CREATE LANGUAGE',
interactive=not quiet)
interactive=not automatic)
cursor = cnx.cursor()
helper.init_fti_extensions(cursor)
# postgres specific stuff
......@@ -364,8 +380,12 @@ class CreateInstanceDBCommand(Command):
cnx.commit()
print '-> database for instance %s created and necessary extensions installed.' % appid
print
if automatic or ASK.confirm('Run db-init to initialize the system database ?'):
CWCTL.run(['db-init', config.appid])
if automatic:
CWCTL.run(['db-init', '--automatic', '--config-level', '0',
config.appid])
elif ASK.confirm('Run db-init to initialize the system database ?'):
CWCTL.run(['db-init', '--config-level',
str(self.config.config_level), config.appid])
else:
print ('-> nevermind, you can do it later with '
'"cubicweb-ctl db-init %s".' % config.appid)
......@@ -384,18 +404,27 @@ class InitInstanceCommand(Command):
arguments = '<instance>'
min_args = max_args = 1
options = (
('drop',
{'short': 'd', 'action': 'store_true',
('automatic',
{'short': 'a', 'action' : 'store_true',
'default': False,
'help': 'insert drop statements to remove previously existant \
tables, indexes... (no by default)'}),
'help': 'automatic mode: never ask and use default answer to every '
'question.',
}),
('config-level',
{'short': 'l', 'type': 'int', 'default': 1,
'help': 'level threshold for questions asked when configuring another source'
'help': 'level threshold for questions asked when configuring '
'another source'
}),
('drop',
{'short': 'd', 'action': 'store_true',
'default': False,
'help': 'insert drop statements to remove previously existant '
'tables, indexes... (no by default)'
}),
)
def run(self, args):
check_options_consistency(self.config)
print '\n'+underline_title('Initializing the system database')
from cubicweb.server import init_repository
from logilab.database import get_connection
......@@ -416,8 +445,10 @@ tables, indexes... (no by default)'}),
'the %s file. Resolve this first (error: %s).'
% (config.sources_file(), str(ex).strip()))
init_repository(config, drop=self.config.drop)
while ASK.confirm('Enter another source ?', default_is_yes=False):
CWCTL.run(['add-source', '--config-level', self.config.config_level, config.appid])
if not self.config.automatic:
while ASK.confirm('Enter another source ?', default_is_yes=False):
CWCTL.run(['add-source', '--config-level',
str(self.config.config_level), config.appid])
class AddSourceCommand(Command):
......
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
......
......@@ -28,16 +28,18 @@ from cubicweb.toolsutils import CommandHandler, underline_title
class WebCreateHandler(CommandHandler):
cmdname = 'create'
def bootstrap(self, cubes, inputlevel=0):
def bootstrap(self, cubes, automatic=False, inputlevel=0):
"""bootstrap this configuration"""
print '\n' + underline_title('Generic web configuration')
config = self.config
if config.repo_method == 'pyro' or config.pyro_enabled():
print '\n' + underline_title('Pyro configuration')
config.input_config('pyro', inputlevel)
if ASK.confirm('Allow anonymous access ?', False):
config.global_set_option('anonymous-user', 'anon')
config.global_set_option('anonymous-password', 'anon')
if not automatic:
print '\n' + underline_title('Generic web configuration')
config = self.config
if config.repo_method == 'pyro' or config.pyro_enabled():
print '\n' + underline_title('Pyro configuration')
config.input_config('pyro', inputlevel)
config.input_config('web', inputlevel)
if ASK.confirm('Allow anonymous access ?', False):
config.global_set_option('anonymous-user', 'anon')
config.global_set_option('anonymous-password', 'anon')
def postcreate(self):
def postcreate(self, *args, **kwargs):
"""hooks called once instance's initialization has been completed"""
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment