summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xgen-doc.bash29
-rw-r--r--ipa_webui/__init__.py24
-rw-r--r--ipa_webui/controller.py71
-rw-r--r--ipa_webui/templates/__init__.py21
-rw-r--r--ipa_webui/templates/form.kid16
-rw-r--r--ipa_webui/templates/main.kid14
-rw-r--r--ipa_webui/tests/__init__.py21
-rw-r--r--ipa_webui/tests/test_controllers.py70
-rw-r--r--ipalib/cli.py58
-rw-r--r--ipalib/config.py37
-rw-r--r--ipalib/plugins/f_user.py4
-rw-r--r--ipalib/tests/test_config.py101
-rwxr-xr-xwebui-cherry.py47
13 files changed, 481 insertions, 32 deletions
diff --git a/gen-doc.bash b/gen-doc.bash
index ba77547c..f2176de4 100755
--- a/gen-doc.bash
+++ b/gen-doc.bash
@@ -2,11 +2,10 @@
# Hackish script to generate documentation using epydoc
-mod="ipalib"
-d="./$mod-doc"
-f="$d.tar.bz2"
+sources="ipalib ipa_server ipa_webui"
+out="./freeipa2-dev-doc"
-init="./$mod/__init__.py"
+init="./ipalib/__init__.py"
echo "Looking for $init"
if [[ ! -f $init ]]
then
@@ -16,19 +15,15 @@ fi
echo "You appear to be in the project directory"
# Documentation
-if [[ -d $d ]]
+if [[ -d $out ]]
then
- echo "Removing old $d directory"
- rm -r $d
+ echo "Removing old $out directory"
+ rm -r $out
fi
-echo "Creating documentation in $d"
-epydoc -v --output=$d --docformat=restructuredtext --html --no-frames $mod
+echo "Creating documentation in $out"
-# Tarball
-if [[ -f $f ]]
-then
- echo "Removing old $f file"
- rm $f
-fi
-echo "Creating tarball $f"
-tar --create --bzip2 --file=$f $d
+epydoc -v --parse-only --html --no-frames --include-log \
+ --name="FreeIPA2 developer documentation" \
+ --docformat=restructuredtext \
+ --output=$out \
+ $sources
diff --git a/ipa_webui/__init__.py b/ipa_webui/__init__.py
new file mode 100644
index 00000000..d0b43301
--- /dev/null
+++ b/ipa_webui/__init__.py
@@ -0,0 +1,24 @@
+# Authors: Jason Gerard DeRose <jderose@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+IPA web-based user interface.
+"""
+
+import kid
+kid.enable_import()
diff --git a/ipa_webui/controller.py b/ipa_webui/controller.py
new file mode 100644
index 00000000..a2a270cb
--- /dev/null
+++ b/ipa_webui/controller.py
@@ -0,0 +1,71 @@
+# Authors: Jason Gerard DeRose <jderose@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Controller classes.
+"""
+
+import simplejson
+from ipalib.plugable import ReadOnly, lock
+
+
+class Controller(ReadOnly):
+ exposed = True
+
+ def __init__(self, template=None):
+ self.template = template
+ lock(self)
+
+ def output_xhtml(self, **kw):
+ return self.template.serialize(
+ output='xhtml-strict',
+ format='pretty',
+ **kw
+ )
+
+ def output_json(self, **kw):
+ return simplejson.dumps(kw, sort_keys=True, indent=4)
+
+ def __call__(self, **kw):
+ json = bool(kw.pop('_format', None) == 'json')
+ result = self.run(**kw)
+ assert type(result) is dict
+ if json or self.template is None:
+ return self.output_json(**result)
+ return self.output_xhtml(**result)
+
+ def run(self, **kw):
+ return {}
+
+
+class Command(Controller):
+ def __init__(self, command, template=None):
+ self.command = command
+ super(Command, self).__init__(template)
+
+ def run(self, **kw):
+ return dict(command=self.command)
+
+
+class Index(Controller):
+ def __init__(self, api, template=None):
+ self.api = api
+ super(Index, self).__init__(template)
+
+ def run(self):
+ return dict(api=self.api)
diff --git a/ipa_webui/templates/__init__.py b/ipa_webui/templates/__init__.py
new file mode 100644
index 00000000..710dbb2e
--- /dev/null
+++ b/ipa_webui/templates/__init__.py
@@ -0,0 +1,21 @@
+# Authors: Jason Gerard DeRose <jderose@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Kid templates.
+"""
diff --git a/ipa_webui/templates/form.kid b/ipa_webui/templates/form.kid
new file mode 100644
index 00000000..64015700
--- /dev/null
+++ b/ipa_webui/templates/form.kid
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='utf-8'?>
+<html xmlns:py="http://purl.org/kid/ns#">
+
+<head>
+ <title>Hello</title>
+</head>
+
+<body>
+ <table>
+ <tr py:for="param in command.params()">
+ <td py:content="param.name"/>
+ </tr>
+ </table>
+</body>
+
+</html>
diff --git a/ipa_webui/templates/main.kid b/ipa_webui/templates/main.kid
new file mode 100644
index 00000000..692f2b57
--- /dev/null
+++ b/ipa_webui/templates/main.kid
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='utf-8'?>
+<html xmlns:py="http://purl.org/kid/ns#">
+
+<head>
+ <title>FreeIPA</title>
+</head>
+
+<body>
+ <p py:for="name in api.Command">
+ <a href="${name}" py:content="name"/>
+ </p>
+</body>
+
+</html>
diff --git a/ipa_webui/tests/__init__.py b/ipa_webui/tests/__init__.py
new file mode 100644
index 00000000..c0647132
--- /dev/null
+++ b/ipa_webui/tests/__init__.py
@@ -0,0 +1,21 @@
+# Authors: Jason Gerard DeRose <jderose@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Test the `ipa_webui` package.
+"""
diff --git a/ipa_webui/tests/test_controllers.py b/ipa_webui/tests/test_controllers.py
new file mode 100644
index 00000000..f5944dd9
--- /dev/null
+++ b/ipa_webui/tests/test_controllers.py
@@ -0,0 +1,70 @@
+# Authors: Jason Gerard DeRose <jderose@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Test the `ipa_webui.controller` module.
+"""
+
+from ipa_webui import controller
+
+
+
+class test_Controller(object):
+ """
+ Test the `controller.Controller` class.
+ """
+
+ def test_init(self):
+ """
+ Test the `ipa_webui.controller.Controller.__init__()` method.
+ """
+ o = controller.Controller()
+ assert o.template is None
+ template = 'The template.'
+ o = controller.Controller(template)
+ assert o.template is template
+
+ def test_output_xhtml(self):
+ """
+ Test the `ipa_webui.controller.Controller.output_xhtml` method.
+ """
+ class Template(object):
+ def __init__(self):
+ self.calls = 0
+ self.kw = {}
+
+ def serialize(self, **kw):
+ self.calls += 1
+ self.kw = kw
+ return dict(kw)
+
+ d = dict(output='xhtml-strict', format='pretty')
+ t = Template()
+ o = controller.Controller(t)
+ assert o.output_xhtml() == d
+ assert t.calls == 1
+
+ def test_output_json(self):
+ """
+ Test the `ipa_webui.controller.Controller.output_json` method.
+ """
+ o = controller.Controller()
+ assert o.output_json() == '{}'
+ e = '{\n "age": 27, \n "first": "John", \n "last": "Doe"\n}'
+ j = o.output_json(last='Doe', first='John', age=27)
+ assert j == e
diff --git a/ipalib/cli.py b/ipalib/cli.py
index d66e1e2e..aae4e31c 100644
--- a/ipalib/cli.py
+++ b/ipalib/cli.py
@@ -205,6 +205,9 @@ class CLI(object):
def __init__(self, api):
self.__api = api
+ self.__all_interactive = False
+ self.__not_interactive = False
+ self.__config = None
def __get_api(self):
return self.__api
@@ -219,6 +222,7 @@ class CLI(object):
print '\nSpecial CLI commands:'
for cmd in self.api.Application():
self.print_cmd(cmd)
+ print '\nUse the --help option to see all the global options'
print ''
def print_cmd(self, cmd):
@@ -252,19 +256,21 @@ class CLI(object):
def run(self):
self.finalize()
- if len(sys.argv) < 2:
+ (args, env_dict) = self.parse_globals()
+ env_dict.update(config.read_config(self.__config))
+ self.api.env.update(config.generate_env(env_dict))
+ if len(args) < 1:
self.print_commands()
- print 'Usage: ipa COMMAND'
+ print 'Usage: ipa [global-options] COMMAND'
sys.exit(2)
- self.api.env.update(config.generate_env())
- key = sys.argv[1]
+ key = args[0]
if key not in self:
self.print_commands()
print 'ipa: ERROR: unknown command %r' % key
sys.exit(2)
self.run_cmd(
self[key],
- list(s.decode('utf-8') for s in sys.argv[2:])
+ list(s.decode('utf-8') for s in args[1:])
)
def run_cmd(self, cmd, argv):
@@ -275,7 +281,10 @@ class CLI(object):
for param in cmd.params():
if param.name not in kw:
if not param.required:
- continue
+ if not self.__all_interactive:
+ continue
+ elif self.__not_interactive:
+ exit_error('Not enough arguments given')
default = param.get_default(**kw)
if default is None:
prompt = '%s: ' % param.name
@@ -318,11 +327,46 @@ class CLI(object):
)
return parser
+ def parse_globals(self, argv=sys.argv[1:]):
+ env_dict = {}
+ parser = optparse.OptionParser()
+ parser.disable_interspersed_args()
+ parser.add_option('-a', dest='interactive', action='store_true',
+ help='Prompt for all missing options interactively')
+ parser.add_option('-n', dest='interactive', action='store_false',
+ help='Don\'t prompt for any options interactively')
+ parser.add_option('-c', dest='config_file',
+ help='Specify different configuration file')
+ parser.add_option('-e', dest='environment',
+ help='Specify or override environment variables')
+ parser.add_option('-v', dest='verbose', action='store_true',
+ help='Verbose output')
+ (options, args) = parser.parse_args(argv)
+
+ if options.interactive == True:
+ self.__all_interactive = True
+ elif options.interactive == False:
+ self.__not_interactive = True
+ if options.config_file:
+ self.__config = options.config_file
+ if options.environment:
+ for a in options.environment.split(','):
+ a = a.split('=', 1)
+ if len(a) < 2:
+ parser.error('badly specified environment string,'\
+ 'use var1=val1[,var2=val2]..')
+ env_dict[a[0].strip()] = a[1].strip()
+ if options.verbose != None:
+ env_dict.update(verbose=True)
+
+ return (args, env_dict)
+
+
def get_usage(self, cmd):
return ' '.join(self.get_usage_iter(cmd))
def get_usage_iter(self, cmd):
- yield 'Usage: %%prog %s' % to_cli(cmd.name)
+ yield 'Usage: %%prog [global-options] %s' % to_cli(cmd.name)
for arg in cmd.args():
name = to_cli(arg.name).upper()
if arg.multivalue:
diff --git a/ipalib/config.py b/ipalib/config.py
index f327cab7..a0a33b40 100644
--- a/ipalib/config.py
+++ b/ipalib/config.py
@@ -17,7 +17,9 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+from ConfigParser import SafeConfigParser, ParsingError
import types
+import os
DEFAULT_CONF='/etc/ipa/ipa.conf'
@@ -26,7 +28,8 @@ def generate_env(d={}):
server_context = False,
query_dns = True,
verbose = False,
- servers = LazyIter(get_servers),
+ interactive = True,
+ server = LazyIter(get_servers),
realm = LazyProp(get_realm),
domain = LazyProp(get_domain),
)
@@ -68,11 +71,33 @@ class LazyIter(LazyProp):
yield item
-def read_config(file=DEFAULT_CONF):
- assert isinstance(file, basestring)
- # open the file and read configuration, return a dict
- # for now, these are here just for testing purposes
- return dict(servers="server.ipatest.com", realm="IPATEST.COM")
+def read_config(config_file=None):
+ assert config_file == None or isinstance(config_file, (basestring, file))
+
+ parser = SafeConfigParser()
+ if config_file == None:
+ files = [DEFAULT_CONF, os.path.expanduser('~/.ipa.conf')]
+ else:
+ files = [config_file]
+
+ for f in files:
+ try:
+ if isinstance(f, file):
+ parser.readfp(f)
+ else:
+ parser.read(f)
+ except ParsingError:
+ print "Can't read %s" % f
+
+ ret = {}
+ if parser.has_section('defaults'):
+ for name, value in parser.items('defaults'):
+ value = tuple(elem.strip() for elem in value.split(','))
+ if len(value) == 1:
+ value = value[0]
+ ret[name] = value
+
+ return ret
# these functions are here just to "emulate" dns resolving for now
diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py
index e560d03c..b006c24b 100644
--- a/ipalib/plugins/f_user.py
+++ b/ipalib/plugins/f_user.py
@@ -37,10 +37,10 @@ class envtest(frontend.Command):
print "Environment variables:"
for var in api.env:
val = api.env[var]
- if var is 'servers':
+ if var is 'server':
print ""
print " Servers:"
- for item in api.env.servers:
+ for item in api.env.server:
print " %s" % item
print ""
else:
diff --git a/ipalib/tests/test_config.py b/ipalib/tests/test_config.py
new file mode 100644
index 00000000..de7d4c22
--- /dev/null
+++ b/ipalib/tests/test_config.py
@@ -0,0 +1,101 @@
+# Authors:
+# Martin Nagy <mnagy@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+Unit tests for `ipalib.config` module.
+"""
+
+import types
+
+from tstutil import raises
+from ipalib import config
+
+
+def test_generate_env():
+ """
+ Test the `config.generate_env` function
+ """
+
+ # Make sure we don't overwrite any properties
+ env = dict(
+ query_dns = False,
+ server = ('first', 'second'),
+ realm = 'myrealm',
+ )
+ d = config.generate_env(env)
+ assert d['query_dns'] == False
+
+ # Make sure the servers is overwrote properly (that it is still LazyProp)
+ iter = d['server'].get_value()
+ assert iter.next() == 'first'
+ assert iter.next() == 'second'
+
+
+def test_LazyProp():
+ """
+ Test the `config.LazyProp` class
+ """
+
+ def dummy():
+ return 1
+
+ # Basic sanity testing with no initial value
+ prop = config.LazyProp(dummy)
+ assert prop.get_value() == 1
+ prop.set_value(2)
+ assert prop.get_value() == 2
+
+ # Basic sanity testing with initial value
+ prop = config.LazyProp(dummy, 3)
+ assert prop.get_value() == 3
+ prop.set_value(4)
+ assert prop.get_value() == 4
+
+
+def test_LazyIter():
+ """
+ Test the `config.LazyIter` class
+ """
+
+ def dummy():
+ yield 1
+ yield 2
+
+ # Basic sanity testing with no initial value
+ prop = config.LazyIter(dummy)
+ iter = prop.get_value()
+ assert iter.next() == 1
+ assert iter.next() == 2
+ raises(StopIteration, iter.next)
+
+ # Basic sanity testing with initial value
+ prop = config.LazyIter(dummy, 0)
+ iter = prop.get_value()
+ assert iter.next() == 0
+ assert iter.next() == 1
+ assert iter.next() == 2
+ raises(StopIteration, iter.next)
+
+
+def test_read_config():
+ """
+ Test the `config.read_config` class
+ """
+
+ raises(AssertionError, config.read_config, 1)
diff --git a/webui-cherry.py b/webui-cherry.py
new file mode 100755
index 00000000..985a838b
--- /dev/null
+++ b/webui-cherry.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+
+# Authors: Jason Gerard DeRose <jderose@redhat.com>
+#
+# Copyright (C) 2008 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; version 2 only
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+A web-UI test server using cherrypy.
+"""
+
+from cherrypy import expose, config, quickstart
+from ipa_webui.templates import form, main
+from ipa_webui import controller
+from ipalib import api
+from ipalib import load_plugins
+
+
+api.finalize()
+
+
+class root(object):
+ index = controller.Index(api, main)
+
+ def __init__(self):
+ for cmd in api.Command():
+ ctr = controller.Command(cmd, form)
+ setattr(self, cmd.name, ctr)
+
+
+
+
+
+quickstart(root())