diff options
31 files changed, 294 insertions, 60 deletions
diff --git a/.travis.yml b/.travis.yml index 8b336e7f8..b868e83b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,17 @@ language: python -python: - - "2.6" - - "2.7_with_system_site_packages" -env: - - WITH_OPTIONAL_DEPS=yes - - WITH_OPTIONAL_DEPS=no +matrix: + include: + - python: "2.6" + env: WITH_OPTIONAL_DEPS=no TEST_SPHINX=no + - python: "2.6" + env: WITH_OPTIONAL_DEPS=yes TEST_SPHINX=no + - python: "2.7_with_system_site_packages" + env: WITH_OPTIONAL_DEPS=no TEST_SPHINX=no + - python: "2.7_with_system_site_packages" + env: WITH_OPTIONAL_DEPS=yes TEST_SPHINX=yes install: - testsuite/install.sh - - pip install --use-mirrors -e . + - pip install -e . script: - nosetests testsuite after_failure: diff --git a/debian/bcfg2-server.install b/debian/bcfg2-server.install index 3f1a73b06..cea918d00 100644 --- a/debian/bcfg2-server.install +++ b/debian/bcfg2-server.install @@ -5,3 +5,4 @@ debian/tmp/usr/lib/python*/*-packages/Bcfg2/Reporting/* debian/tmp/usr/share/bcfg2/schemas/* debian/tmp/usr/share/bcfg2/xsl-transforms/* debian/tmp/usr/share/man/man8/* +debian/tmp/etc/bash_completion.d/* diff --git a/debian/bcfg2-utils.install b/debian/bcfg2-utils.install new file mode 100644 index 000000000..ccddfa1af --- /dev/null +++ b/debian/bcfg2-utils.install @@ -0,0 +1 @@ +tools/* usr/share/bcfg2 diff --git a/debian/bcfg2.install b/debian/bcfg2.install index a240dac53..eaf58141c 100644 --- a/debian/bcfg2.install +++ b/debian/bcfg2.install @@ -7,4 +7,3 @@ debian/tmp/usr/share/man/man5/* examples/bcfg2.conf usr/share/bcfg2 debian/bcfg2.default usr/share/bcfg2 tools/bcfg2-cron usr/lib/bcfg2 -tools/bcfg2-import-config usr/share/bcfg2 diff --git a/debian/changelog b/debian/changelog index 789891961..f6b395624 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +bcfg2 (1.4.0pre2-0.1) UNRELEASED; urgency=low + + * Helper scripts packed in bcfg2-utils + + -- Holger Mueller <zarath@gmx.de> Wed, 07 Aug 2013 21:41:10 +0200 + bcfg2 (1.4.0pre2-0.0) unstable; urgency=low * New upstream release diff --git a/debian/control b/debian/control index 452fa3d5f..f131bbe05 100644 --- a/debian/control +++ b/debian/control @@ -17,8 +17,8 @@ Build-Depends: debhelper (>= 7.0.50~), python-m2crypto, python-doc, python-mock, - python-mock-doc -Build-Depends-Indep: python-support (>= 0.5.3) + python-mock-doc, + dh-python Standards-Version: 3.8.0.0 Homepage: http://bcfg2.org/ @@ -51,6 +51,16 @@ Description: Configuration management web interface for clients bound by client profiles. bcfg2-web is the reporting server for bcfg2. +Package: bcfg2-utils +Architecture: all +Depends: ${python:Depends}, ${misc:Depends}, bcfg2 (= ${binary:Version}) +Suggests: bcfg2-doc (= ${binary:Version}) +Description: Configuration management helper package + Bcfg2 is a configuration management system that generates configuration sets + for clients bound by client profiles. + bcfg2-utils contains scripts for gethering useful information for config + creation. + Package: bcfg2-doc Section: doc Architecture: all diff --git a/debian/rules b/debian/rules index eaf80a4d7..102a340e9 100755 --- a/debian/rules +++ b/debian/rules @@ -23,3 +23,7 @@ override_dh_auto_build: override_dh_auto_clean: dh_auto_clean rm -rf build + +override_dh_auto_install: + dh_auto_install + install -m 644 -D tools/bcfg2-completion.bash debian/tmp/etc/bash_completion.d/bcfg2 diff --git a/doc/conf.py b/doc/conf.py index 1da6b3b01..6af9fba05 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -133,7 +133,7 @@ html_theme_options = { # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -html_favicon = 'favicon.ico' +html_favicon = '_static/favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, diff --git a/doc/development/compat.txt b/doc/development/compat.txt index 132bf67c0..a6a85cbab 100644 --- a/doc/development/compat.txt +++ b/doc/development/compat.txt @@ -129,7 +129,7 @@ below, since some of these implementations may be feature-incomplete. +----------------+--------------------------------+--------------------------------------------+ | MutableMapping | :class:`UserDict.DictMixin` | :class:`collections.MutableMapping` (2.6+) | +----------------+--------------------------------+--------------------------------------------+ -| literal_eval | :func:`eval` | :func:`ast.literal_eval`(2.6+) | +| literal_eval | :func:`eval` | :func:`ast.literal_eval` (2.6+) | +----------------+--------------------------------+--------------------------------------------+ walk_packages diff --git a/doc/releases/index.txt b/doc/releases/index.txt index db9ba989c..911fe070f 100644 --- a/doc/releases/index.txt +++ b/doc/releases/index.txt @@ -11,5 +11,6 @@ Release Announcements 1.4.0pre2 1.4.0pre1 + 1.3.6 1.3.5 1.3.4 diff --git a/doc/server/plugins/generators/packages.txt b/doc/server/plugins/generators/packages.txt index 2fe71f895..eea6c6659 100644 --- a/doc/server/plugins/generators/packages.txt +++ b/doc/server/plugins/generators/packages.txt @@ -213,7 +213,7 @@ something like this: Packages plugin to add recommended packages by adding the :xml:attribute:`SourceType:recommended` attribute, e.g.: - .. code-block:: xml + .. code-block:: none <Source type="apt" recommended="true" ...> @@ -222,9 +222,9 @@ something like this: setting the :xml:attribute:`SourceType:essential` attribute to *false*: - .. code-block:: xml + .. code-block:: none - <Source type="apt" essential="false" ...> + <Source type="apt" essential="false" ...> Yum sources can be similarly specified: diff --git a/doc/server/plugins/grouping/metadata.txt b/doc/server/plugins/grouping/metadata.txt index 832b1a13f..f0ff2b29c 100644 --- a/doc/server/plugins/grouping/metadata.txt +++ b/doc/server/plugins/grouping/metadata.txt @@ -175,6 +175,9 @@ groups: <Group name="selinux-enabled" negate="true"/> </Client> +Negated groups can also be used to declare other Group assignments, +but not to declare Bundle assignments. + .. note:: Nested Group conditionals, Client tags, and negated Group tags are diff --git a/doc/server/plugins/structures/bundler/index.txt b/doc/server/plugins/structures/bundler/index.txt index f8962d42c..afdbbecf2 100644 --- a/doc/server/plugins/structures/bundler/index.txt +++ b/doc/server/plugins/structures/bundler/index.txt @@ -269,7 +269,7 @@ or alternately <Path name="/etc/bacula/bconsole.conf"/> <Path name="/etc/bacula/bacula-fd.conf"/> <Path name="/etc/bacula/bacula-sd.conf"/> - <py:if="metadata.hostname == 'foo.bar.com'"> + <py:if test="metadata.hostname == 'foo.bar.com'"> <Path name="/etc/bacula/bacula-dir.conf"/> </py:if> </Bundle> diff --git a/doc/unsorted/vim_snippet.txt b/doc/unsorted/vim_snippet.txt index 4598b5c1d..537bb00a2 100644 --- a/doc/unsorted/vim_snippet.txt +++ b/doc/unsorted/vim_snippet.txt @@ -13,7 +13,7 @@ that allow quick composition of bundles and base files. #. Install it using the install instructions (unzip snipMate.zip -d ~/.vim or equivalent, e.g. $HOME\vimfiles on Windows) #. Add the following to ``~/.vim/snippets/xml.snippets`` - .. code-block:: cl + .. code-block:: none # Bundle snippet <Bundle diff --git a/src/lib/Bcfg2/DBSettings.py b/src/lib/Bcfg2/DBSettings.py index 03e34bbc3..3b5cbbbd8 100644 --- a/src/lib/Bcfg2/DBSettings.py +++ b/src/lib/Bcfg2/DBSettings.py @@ -79,7 +79,8 @@ if HAS_DJANGO and django.VERSION[0] == 1 and django.VERSION[1] >= 7: elif HAS_SOUTH: settings['INSTALLED_APPS'] += ('south', 'Bcfg2.Reporting') settings['SOUTH_MIGRATION_MODULES'] = { - 'Bcfg2.Reporting': 'Bcfg2.Reporting.south_migrations' + 'Reporting': 'Bcfg2.Reporting.south_migrations', + 'Server': 'Bcfg2.Server.south_migrations', } if 'BCFG2_LEGACY_MODELS' in os.environ: settings['INSTALLED_APPS'] += ('Bcfg2.Server.Reports.reports',) diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index ad78800fb..445bc17b5 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -91,7 +91,7 @@ def close_db_connection(func): for connection in django.db.connections.all(): connection.close() else: - django.db.close_connection() + django.db.close_connection() # pylint: disable=E1101 return rv return inner diff --git a/src/lib/Bcfg2/Server/Encryption.py b/src/lib/Bcfg2/Server/Encryption.py index b60302871..c6cd4232e 100755 --- a/src/lib/Bcfg2/Server/Encryption.py +++ b/src/lib/Bcfg2/Server/Encryption.py @@ -176,7 +176,7 @@ def ssl_encrypt(plaintext, passwd, algorithm=None, salt=None): def is_encrypted(val): """ Make a best guess if the value is encrypted or not. This just checks to see if ``val`` is a base64-encoded string whose content - starts with "Salted__", so it may have (rare) false positives. It + starts with "Salted\\_\\_", so it may have (rare) false positives. It will not have false negatives. """ try: return b64decode(val).startswith("Salted__") diff --git a/src/lib/Bcfg2/Server/Plugins/Ldap.py b/src/lib/Bcfg2/Server/Plugins/Ldap.py index 895c6380f..757150300 100644 --- a/src/lib/Bcfg2/Server/Plugins/Ldap.py +++ b/src/lib/Bcfg2/Server/Plugins/Ldap.py @@ -119,22 +119,27 @@ class Ldap(Bcfg2.Server.Plugin.Plugin, class LdapConnection(Debuggable): """ Connection to an LDAP server. """ - __scopes__ = { - 'base': ldap.SCOPE_BASE, - 'one': ldap.SCOPE_ONELEVEL, - 'sub': ldap.SCOPE_SUBTREE, - } - def __init__(self, host="localhost", port=389, binddn=None, bindpw=None): Debuggable.__init__(self) + if HAS_LDAP: + msg = "Python ldap module is required for Ldap plugin" + self.logger.error(msg) + raise Bcfg2.Server.Plugin.PluginInitError(msg) + self.host = host self.port = port self.binddn = binddn self.bindpw = bindpw self.conn = None + self.__scopes__ = { + 'base': ldap.SCOPE_BASE, + 'one': ldap.SCOPE_ONELEVEL, + 'sub': ldap.SCOPE_SUBTREE, + } + def __del__(self): """ Disconnection if the instance is destroyed. """ self.disconnect() diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py index 30f60fffe..40504e15e 100644 --- a/src/lib/Bcfg2/Server/Plugins/Metadata.py +++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py @@ -42,6 +42,9 @@ def load_django_models(): HAS_DJANGO = False return + if django.VERSION[0] == 1 and django.VERSION[1] >= 7: + django.setup() # pylint: disable=E1101 + class MetadataClientModel(models.Model, # pylint: disable=W0621 Bcfg2.Server.Plugin.PluginDatabaseModel): """ django model for storing clients in the database """ @@ -100,9 +103,6 @@ def load_django_models(): except MetadataClientModel.DoesNotExist: return False - if django.VERSION[0] == 1 and django.VERSION[1] >= 7: - django.setup() # pylint: disable=E1101 - class XMLMetadataConfig(Bcfg2.Server.Plugin.XMLFileBacked): """Handles xml config files and all XInclude statements""" diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py index 7de79e2f3..2637fadfe 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py @@ -34,8 +34,12 @@ class AptCollection(Collection): for source in self: if source.rawurl: - self.logger.info("Packages: Skipping rawurl %s" % - source.rawurl) + if source.rawurl[-1] != '/': + source.rawurl = source.rawurl + "/" + index = source.rawurl.rfind("/", 0, -1) + lines.append("deb %s %s" % + (source.rawurl[:index], + source.rawurl[index + 1:])) else: lines.append("deb %s %s %s" % (source.url, source.version, " ".join(source.components))) @@ -44,7 +48,7 @@ class AptCollection(Collection): (source.url, source.version, " ".join(source.components))) - lines.append("") + lines.append("") return "\n".join(lines) diff --git a/src/lib/Bcfg2/Server/Plugins/Probes.py b/src/lib/Bcfg2/Server/Plugins/Probes.py index 573c9af71..33b0d4284 100644 --- a/src/lib/Bcfg2/Server/Plugins/Probes.py +++ b/src/lib/Bcfg2/Server/Plugins/Probes.py @@ -27,13 +27,18 @@ def load_django_models(): # pylint: disable=W0602 global ProbesDataModel, ProbesGroupsModel, HAS_DJANGO # pylint: enable=W0602 + try: + import django from django.db import models HAS_DJANGO = True except ImportError: HAS_DJANGO = False return + if django.VERSION[0] == 1 and django.VERSION[1] >= 7: + django.setup() # pylint: disable=E1101 + class ProbesDataModel(models.Model, # pylint: disable=W0621,W0612 Bcfg2.Server.Plugin.PluginDatabaseModel): """ The database model for storing probe data """ diff --git a/src/lib/Bcfg2/Server/migrations/0001_initial.py b/src/lib/Bcfg2/Server/migrations/0001_initial.py new file mode 100644 index 000000000..3b3dca455 --- /dev/null +++ b/src/lib/Bcfg2/Server/migrations/0001_initial.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.9 on 2016-08-17 18:52 +from __future__ import unicode_literals + +import Bcfg2.Server.Plugin.helpers +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='MetadataClientModel', + fields=[ + ('hostname', models.CharField(max_length=255, primary_key=True, serialize=False)), + ('version', models.CharField(max_length=31, null=True)), + ], + bases=(models.Model, Bcfg2.Server.Plugin.helpers.PluginDatabaseModel), + ), + migrations.CreateModel( + name='ProbesDataModel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('hostname', models.CharField(max_length=255)), + ('probe', models.CharField(max_length=255)), + ('timestamp', models.DateTimeField(auto_now=True)), + ('data', models.TextField(null=True)), + ], + bases=(models.Model, Bcfg2.Server.Plugin.helpers.PluginDatabaseModel), + ), + migrations.CreateModel( + name='ProbesGroupsModel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('hostname', models.CharField(max_length=255)), + ('group', models.CharField(max_length=255)), + ], + bases=(models.Model, Bcfg2.Server.Plugin.helpers.PluginDatabaseModel), + ), + ] diff --git a/src/lib/Bcfg2/Server/migrations/__init__.py b/src/lib/Bcfg2/Server/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/lib/Bcfg2/Server/migrations/__init__.py diff --git a/src/lib/Bcfg2/Server/models.py b/src/lib/Bcfg2/Server/models.py index 9c0153c74..7f28fd0d8 100644 --- a/src/lib/Bcfg2/Server/models.py +++ b/src/lib/Bcfg2/Server/models.py @@ -4,20 +4,44 @@ import sys import logging import Bcfg2.Options import Bcfg2.Server.Plugins +from Bcfg2.Compat import walk_packages -LOGGER = logging.getLogger(__name__) +LOGGER = logging.getLogger('Bcfg2.Server.models') MODELS = [] INTERNAL_DATABASE_VERSION = None -class _OptionContainer(object): - """Options for Bcfg2 database models.""" +def _get_all_plugins(): + rv = [] + for submodule in walk_packages(path=Bcfg2.Server.Plugins.__path__, + prefix="Bcfg2.Server.Plugins."): + module = submodule[1].rsplit('.', 1)[-1] + if module == 'Reporting': + # Exclude Reporting plugin. The reporting database + # is handled separately in Bcfg2.Reporting. + continue + if submodule[1] == "Bcfg2.Server.Plugins.%s" % module: + # we only include direct children of + # Bcfg2.Server.Plugins -- e.g., all_plugins should + # include Bcfg2.Server.Plugins.Cfg, but not + # Bcfg2.Server.Plugins.Cfg.CfgInfoXML + rv.append(module) + return rv + + +_ALL_PLUGINS = _get_all_plugins() + +class _OptionContainer(object): # we want to provide a different default plugin list -- # namely, _all_ plugins, so that the database is guaranteed to # work, even if /etc/bcfg2.conf isn't set up properly - options = [Bcfg2.Options.Common.plugins] + options = [ + Bcfg2.Options.Option( + cf=('server', 'plugins'), type=Bcfg2.Options.Types.comma_list, + default=_ALL_PLUGINS, dest="models_plugins", + action=Bcfg2.Options.PluginsAction)] @staticmethod def options_parsed_hook(): @@ -39,7 +63,7 @@ def load_models(plugins=None): global MODELS if not plugins: - plugins = Bcfg2.Options.setup.plugins + plugins = Bcfg2.Options.setup.models_plugins if MODELS: # load_models() has been called once, so first unload all of diff --git a/src/lib/Bcfg2/Server/south_migrations/0001_initial.py b/src/lib/Bcfg2/Server/south_migrations/0001_initial.py new file mode 100644 index 000000000..864c311e5 --- /dev/null +++ b/src/lib/Bcfg2/Server/south_migrations/0001_initial.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'MetadataClientModel' + db.create_table(u'Server_metadataclientmodel', ( + ('hostname', self.gf('django.db.models.fields.CharField')(max_length=255, primary_key=True)), + ('version', self.gf('django.db.models.fields.CharField')(max_length=31, null=True)), + )) + db.send_create_signal('Server', ['MetadataClientModel']) + + # Adding model 'ProbesDataModel' + db.create_table(u'Server_probesdatamodel', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('hostname', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('probe', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('timestamp', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)), + ('data', self.gf('django.db.models.fields.TextField')(null=True)), + )) + db.send_create_signal('Server', ['ProbesDataModel']) + + # Adding model 'ProbesGroupsModel' + db.create_table(u'Server_probesgroupsmodel', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('hostname', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('group', self.gf('django.db.models.fields.CharField')(max_length=255)), + )) + db.send_create_signal('Server', ['ProbesGroupsModel']) + + + def backwards(self, orm): + # Deleting model 'MetadataClientModel' + db.delete_table(u'Server_metadataclientmodel') + + # Deleting model 'ProbesDataModel' + db.delete_table(u'Server_probesdatamodel') + + # Deleting model 'ProbesGroupsModel' + db.delete_table(u'Server_probesgroupsmodel') + + + models = { + 'Server.metadataclientmodel': { + 'Meta': {'object_name': 'MetadataClientModel'}, + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}), + 'version': ('django.db.models.fields.CharField', [], {'max_length': '31', 'null': 'True'}) + }, + 'Server.probesdatamodel': { + 'Meta': {'object_name': 'ProbesDataModel'}, + 'data': ('django.db.models.fields.TextField', [], {'null': 'True'}), + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'probe': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}) + }, + 'Server.probesgroupsmodel': { + 'Meta': {'object_name': 'ProbesGroupsModel'}, + 'group': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + } + } + + complete_apps = ['Server']
\ No newline at end of file diff --git a/src/lib/Bcfg2/Server/south_migrations/__init__.py b/src/lib/Bcfg2/Server/south_migrations/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/lib/Bcfg2/Server/south_migrations/__init__.py diff --git a/src/lib/Bcfg2/manage.py b/src/lib/Bcfg2/manage.py index f88233133..b156deb0f 100755 --- a/src/lib/Bcfg2/manage.py +++ b/src/lib/Bcfg2/manage.py @@ -5,19 +5,19 @@ import django import Bcfg2.Options import Bcfg2.DBSettings -Bcfg2.Options.get_parser().parse() +try: + import Bcfg2.Server.models +except ImportError: + pass -if django.VERSION[0] == 1 and django.VERSION[1] <= 6: - try: - imp.find_module('settings') # Assumed to be in the same directory. - except ImportError: - import sys - sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__) - sys.exit(1) +parser = Bcfg2.Options.get_parser() +parser.add_options([Bcfg2.Options.PositionalArgument('django_command', nargs='*')]) +parser.parse() if __name__ == "__main__": - if django.VERSION[0] == 1 and django.VERSION[1] >= 7: + if django.VERSION[0] == 1 and django.VERSION[1] >= 6: from django.core.management import execute_from_command_line - execute_from_command_line(sys.argv) + execute_from_command_line(sys.argv[:1] + Bcfg2.Options.setup.django_command) else: - execute_manager(settings) + from django.core.management import execute_manager + execute_manager(Bcfg2.DBSettings.settings) diff --git a/testsuite/Testsrc/test_code_checks.py b/testsuite/Testsrc/test_code_checks.py index 6d3c4c714..c26d8c139 100644 --- a/testsuite/Testsrc/test_code_checks.py +++ b/testsuite/Testsrc/test_code_checks.py @@ -76,6 +76,8 @@ no_checks = { "lib/Bcfg2": ["manage.py"], "lib/Bcfg2/Server/Reports": ["manage.py"], "lib/Bcfg2/Server/Plugins": ["Base.py"], + "lib/Bcfg2/Server/migrations": ["*.py"], + "lib/Bcfg2/Server/south_migrations": ["*.py"], } if sys.version_info < (2, 6): # multiprocessing core requires py2.6 diff --git a/testsuite/Testsrc/test_doc.py b/testsuite/Testsrc/test_doc.py new file mode 100644 index 000000000..93c8d1bb4 --- /dev/null +++ b/testsuite/Testsrc/test_doc.py @@ -0,0 +1,39 @@ +import os +import sys + +# add all parent testsuite directories to sys.path to allow (most) +# relative imports in python 2.4 +_path = os.path.dirname(__file__) +while _path != '/': + if os.path.basename(_path).lower().startswith("test"): + sys.path.append(_path) + if os.path.basename(_path) == "testsuite": + break + _path = os.path.dirname(_path) +from common import * + + +try: + from sphinx.application import Sphinx + HAS_SPHINX = True +except ImportError: + HAS_SPHINX = False + + +TEST_SPHINX = bool(os.environ.get('TEST_SPHINX', 'yes') != 'no') + + +class DocTest(Bcfg2TestCase): + top = os.path.join(os.path.dirname(__file__), '..', '..') + source_dir = os.path.join(top, 'doc/') + doctree_dir = os.path.join(top, 'build', 'doctree') + + @skipUnless(HAS_SPHINX, 'Sphinx not found') + @skipUnless(TEST_SPHINX, 'Documentation testing disabled') + def test_html_documentation(self): + output_dir = os.path.join(self.top, 'build', 'html') + + app = Sphinx(self.source_dir, self.source_dir, output_dir, + self.doctree_dir, buildername='html', + warningiserror=True) + app.build(force_all=True) diff --git a/testsuite/common.py b/testsuite/common.py index 396f1887b..9db2cb94a 100644 --- a/testsuite/common.py +++ b/testsuite/common.py @@ -219,12 +219,18 @@ class DBModelTestCase(Bcfg2TestCase): def test_syncdb(self): """ Create the test database and sync the schema """ if self.models: - import django.core.management import django - if django.VERSION[0] == 1 and django.VERSION[1] >= 7: - django.setup() + import django.core.management + from django.core.exceptions import ImproperlyConfigured + + if django.VERSION[0] == 1 and django.VERSION[1] < 7: + try: + django.core.management.call_command('syncdb', interactive=False, + verbosity=0) + except ImproperlyConfigured: + pass - django.core.management.call_command("syncdb", interactive=False, + django.core.management.call_command('migrate', interactive=False, verbosity=0) self.assertTrue( os.path.exists( diff --git a/testsuite/install.sh b/testsuite/install.sh index 42d5bbadb..d8e5079be 100755 --- a/testsuite/install.sh +++ b/testsuite/install.sh @@ -10,19 +10,23 @@ pip install -r testsuite/requirements.txt PYVER=$(python -c 'import sys;print(".".join(str(v) for v in sys.version_info[0:2]))') if [[ ${PYVER:0:1} == "2" && $PYVER != "2.7" ]]; then - pip install --use-mirrors unittest2 + pip install unittest2 fi if [[ "$WITH_OPTIONAL_DEPS" == "yes" ]]; then - sudo apt-get install -y yum libaugeas0 augeas-lenses libacl1-dev libssl-dev + sudo apt-get install -y yum libaugeas0 augeas-lenses libacl1-dev libssl-dev \ + python-gamin python-selinux - pip install --use-mirrors PyYAML pyinotify boto pylibacl 'django<1.5' \ - Jinja2 mercurial guppy + pip install PyYAML pyinotify boto pylibacl Jinja2 mercurial guppy cherrypy easy_install https://fedorahosted.org/released/python-augeas/python-augeas-0.4.1.tar.gz + if [[ ${PYVER:0:1} == "2" ]]; then - # django supports py3k, but South doesn't, and the django bits - # in bcfg2 require South - pip install cheetah 'South<0.8' - pip install m2crypto + pip install cheetah m2crypto + + if [[ $PYVER != "2.7" ]]; then + pip install 'django<1.7' 'South<0.8' + else + pip install 'django<1.10' + fi fi fi |