summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lib/Bcfg2/Client/__init__.py12
-rwxr-xr-xsrc/lib/Bcfg2/Reporting/Reports.py170
-rw-r--r--src/lib/Bcfg2/Reporting/Storage/DjangoORM.py5
-rw-r--r--src/lib/Bcfg2/Reporting/migrations/0007_add_flag_fields_interaction.py298
-rw-r--r--src/lib/Bcfg2/Reporting/models.py2
5 files changed, 414 insertions, 73 deletions
diff --git a/src/lib/Bcfg2/Client/__init__.py b/src/lib/Bcfg2/Client/__init__.py
index 161f9a562..0fad2460b 100644
--- a/src/lib/Bcfg2/Client/__init__.py
+++ b/src/lib/Bcfg2/Client/__init__.py
@@ -926,10 +926,14 @@ class Client(object):
states[item] = val
feedback = XML.Element("upload-statistics")
- stats = XML.SubElement(feedback,
- 'Statistics', total=str(len(states)),
- version='2.0',
- revision=self.config.get('revision', '-1'))
+ stats = XML.SubElement(
+ feedback,
+ 'Statistics',
+ total=str(len(states)),
+ version='2.0',
+ revision=self.config.get('revision', '-1'),
+ dry_run=str(Bcfg2.Options.setup.dry_run),
+ only_important=str(Bcfg2.Options.setup.only_important))
good_entries = [key for key, val in list(states.items()) if val]
good = len(good_entries)
stats.set('good', str(good))
diff --git a/src/lib/Bcfg2/Reporting/Reports.py b/src/lib/Bcfg2/Reporting/Reports.py
index 3b9c83433..ebd0db58f 100755
--- a/src/lib/Bcfg2/Reporting/Reports.py
+++ b/src/lib/Bcfg2/Reporting/Reports.py
@@ -7,59 +7,40 @@ import datetime
import Bcfg2.DBSettings
-def hosts_by_entry_type(clients, etype, entryspec):
- result = []
- for entry in entryspec:
- for client in clients:
- items = getattr(client.current_interaction, etype)()
- for item in items:
- if (item.entry_type == entry[0] and
- item.name == entry[1]):
- result.append(client)
- return result
-
-
-def print_fields(fields, client, fmt, extra=None):
- """ Prints the fields specified in fields of client, max_name
- specifies the column width of the name column. """
- fdata = []
- if extra is None:
- extra = dict()
- for field in fields:
- if field == 'time':
- fdata.append(str(client.current_interaction.timestamp))
- elif field == 'state':
- if client.current_interaction.isclean():
- fdata.append("clean")
- else:
- fdata.append("dirty")
- elif field == 'total':
- fdata.append(client.current_interaction.total_count)
- elif field == 'good':
- fdata.append(client.current_interaction.good_count)
- elif field == 'modified':
- fdata.append(client.current_interaction.modified_count)
- elif field == 'extra':
- fdata.append(client.current_interaction.extra_count)
- elif field == 'bad':
- fdata.append((client.current_interaction.bad_count))
- elif field == 'stale':
- fdata.append(client.current_interaction.isstale())
- else:
- try:
- fdata.append(getattr(client, field))
- except AttributeError:
- fdata.append(extra.get(field, "N/A"))
-
- print(fmt % tuple(fdata))
-
-
def print_entries(interaction, etype):
items = getattr(interaction, etype)()
for item in items:
print("%-70s %s" % (item.entry_type + ":" + item.name, etype))
+class _FlagsFilterMixin(object):
+ """ Mixin that allows to filter the interactions based on the
+ only_important and/or the dry_run flag """
+
+ options = [
+ Bcfg2.Options.BooleanOption(
+ "-n", "--no-dry-run",
+ help="Do not consider interactions created with the --dry-run "
+ "flag"),
+ Bcfg2.Options.BooleanOption(
+ "-i", "--no-only-important",
+ help="Do not consider interactions created with the "
+ "--only-important flag")]
+
+ def get_interaction(self, client, setup):
+ if not setup.no_dry_run and not setup.no_only_important:
+ return client.current_interaction
+
+ filter = {}
+ if setup.no_dry_run:
+ filter['dry_run'] = False
+ if setup.no_only_important:
+ filter['only_important'] = False
+
+ from Bcfg2.Reporting.models import Interaction
+ return Interaction.objects.filter(client=client, **filter).latest()
+
+
class _SingleHostCmd(Bcfg2.Options.Subcommand): # pylint: disable=W0223
""" Base class for bcfg2-reports modes that take a single host as
a positional argument """
@@ -74,10 +55,10 @@ class _SingleHostCmd(Bcfg2.Options.Subcommand): # pylint: disable=W0223
raise SystemExit(2)
-class Show(_SingleHostCmd):
+class Show(_SingleHostCmd, _FlagsFilterMixin):
""" Show bad, extra, modified, or all entries from a given host """
- options = _SingleHostCmd.options + [
+ options = _SingleHostCmd.options + _FlagsFilterMixin.options + [
Bcfg2.Options.BooleanOption(
"-b", "--bad", help="Show bad entries from HOST"),
Bcfg2.Options.BooleanOption(
@@ -88,21 +69,25 @@ class Show(_SingleHostCmd):
def run(self, setup):
client = self.get_client(setup)
show_all = not setup.bad and not setup.extra and not setup.modified
+ interaction = self.get_interaction(client, setup)
if setup.bad or show_all:
- print_entries(client.current_interaction, "bad")
+ print_entries(interaction, "bad")
if setup.modified or show_all:
- print_entries(client.current_interaction, "modified")
+ print_entries(interaction, "modified")
if setup.extra or show_all:
- print_entries(client.current_interaction, "extra")
+ print_entries(interaction, "extra")
-class Total(_SingleHostCmd):
+class Total(_SingleHostCmd, _FlagsFilterMixin):
""" Show total number of managed and good entries from HOST """
+ options = _SingleHostCmd.options + _FlagsFilterMixin.options
+
def run(self, setup):
client = self.get_client(setup)
- managed = client.current_interaction.total_count
- good = client.current_interaction.good_count
+ interaction = self.get_interaction(client, setup)
+ managed = interaction.total_count
+ good = interaction.good_count
print("Total managed entries: %d (good: %d)" % (managed, good))
@@ -120,9 +105,9 @@ class Expire(_SingleHostCmd):
client.save()
-class _ClientSelectCmd(Bcfg2.Options.Subcommand):
+class _ClientSelectCmd(Bcfg2.Options.Subcommand, _FlagsFilterMixin):
""" Base class for subcommands that display lists of clients """
- options = [
+ options = _FlagsFilterMixin.options + [
Bcfg2.Options.Option("--fields", metavar="FIELD,FIELD,...",
help="Only display the listed fields",
type=Bcfg2.Options.Types.comma_list,
@@ -132,7 +117,42 @@ class _ClientSelectCmd(Bcfg2.Options.Subcommand):
from Bcfg2.Reporting.models import Client
return Client.objects.exclude(current_interaction__isnull=True)
- def display(self, result, fields, extra=None):
+ def _print_fields(self, setup, fields, client, fmt, extra=None):
+ """ Prints the fields specified in fields of client, max_name
+ specifies the column width of the name column. """
+ fdata = []
+ if extra is None:
+ extra = dict()
+ interaction = self.get_interaction(client, setup)
+ for field in fields:
+ if field == 'time':
+ fdata.append(str(interaction.timestamp))
+ elif field == 'state':
+ if interaction.isclean():
+ fdata.append("clean")
+ else:
+ fdata.append("dirty")
+ elif field == 'total':
+ fdata.append(interaction.total_count)
+ elif field == 'good':
+ fdata.append(interaction.good_count)
+ elif field == 'modified':
+ fdata.append(interaction.modified_count)
+ elif field == 'extra':
+ fdata.append(interaction.extra_count)
+ elif field == 'bad':
+ fdata.append(interaction.bad_count)
+ elif field == 'stale':
+ fdata.append(interaction.isstale())
+ else:
+ try:
+ fdata.append(getattr(client, field))
+ except AttributeError:
+ fdata.append(extra.get(field, "N/A"))
+
+ print(fmt % tuple(fdata))
+
+ def display(self, setup, result, fields, extra=None):
if 'name' not in fields:
fields.insert(0, "name")
if not result:
@@ -153,8 +173,8 @@ class _ClientSelectCmd(Bcfg2.Options.Subcommand):
print(fmt % tuple(f.title() for f in fields))
for client in result:
if not client.expiration:
- print_fields(fields, client, fmt,
- extra=extra.get(client, None))
+ self._print_fields(setup, fields, client, fmt,
+ extra=extra.get(client, None))
class Clients(_ClientSelectCmd):
@@ -172,14 +192,14 @@ class Clients(_ClientSelectCmd):
result = []
show_all = not setup.stale and not setup.clean and not setup.dirty
for client in self.get_clients():
- interaction = client.current_interaction
+ interaction = self.get_interaction(client, setup)
if (show_all or
(setup.stale and interaction.isstale()) or
(setup.clean and interaction.isclean()) or
(setup.dirty and not interaction.isclean())):
result.append(client)
- self.display(result, setup.fields)
+ self.display(setup, result, setup.fields)
class Entries(_ClientSelectCmd):
@@ -201,6 +221,18 @@ class Entries(_ClientSelectCmd):
Bcfg2.Options.PositionalArgument(
"entries", metavar="TYPE:NAME", nargs="*")]
+ def _hosts_by_entry_type(self, setup, clients, etype, entryspec):
+ result = []
+ for entry in entryspec:
+ for client in clients:
+ interaction = self.get_interaction(client, setup)
+ items = getattr(interaction, etype)()
+ for item in items:
+ if (item.entry_type == entry[0] and
+ item.name == entry[1]):
+ result.append(client)
+ return result
+
def run(self, setup):
result = []
if setup.file:
@@ -216,13 +248,15 @@ class Entries(_ClientSelectCmd):
clients = self.get_clients()
if setup.badentry:
- result = hosts_by_entry_type(clients, "bad", entries)
+ result = self._hosts_by_entry_type(setup, clients, "bad", entries)
elif setup.modifiedentry:
- result = hosts_by_entry_type(clients, "modified", entries)
+ result = self._hosts_by_entry_type(setup, clients, "modified",
+ entries)
elif setup.extraentry:
- result = hosts_by_entry_type(clients, "extra", entries)
+ result = self._hosts_by_entry_type(setup, clients, "extra",
+ entries)
- self.display(result, setup.fields)
+ self.display(setup, result, setup.fields)
class Entry(_ClientSelectCmd):
@@ -252,14 +286,14 @@ class Entry(_ClientSelectCmd):
for client in self.get_clients():
ents = entry_cls.objects.filter(
name=ename,
- interaction=client.current_interaction)
+ interaction=self.get_interaction(client, setup))
if len(ents) == 0:
continue
extra[client] = {"entry state": ents[0].get_state_display(),
"reason": ents[0]}
result.append(client)
- self.display(result, fields, extra=extra)
+ self.display(setup, result, fields, extra=extra)
class CLI(Bcfg2.Options.CommandRegistry):
diff --git a/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py b/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py
index efd9e594c..ac09766ff 100644
--- a/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py
+++ b/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py
@@ -292,7 +292,10 @@ class DjangoORM(StorageBase):
good_count=stats.get('good', default="0"),
total_count=stats.get('total', default="0"),
server=server,
- profile=profile)
+ profile=profile,
+ dry_run=stats.get('dry_run', default=False),
+ only_important=stats.get('only_important',
+ default=False))
inter.save()
self.logger.debug("Interaction for %s at %s with INSERTED in to db" %
(client.id, timestamp))
diff --git a/src/lib/Bcfg2/Reporting/migrations/0007_add_flag_fields_interaction.py b/src/lib/Bcfg2/Reporting/migrations/0007_add_flag_fields_interaction.py
new file mode 100644
index 000000000..491ecb845
--- /dev/null
+++ b/src/lib/Bcfg2/Reporting/migrations/0007_add_flag_fields_interaction.py
@@ -0,0 +1,298 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Interaction.dry_run'
+ db.add_column('Reporting_interaction', 'dry_run',
+ self.gf('django.db.models.fields.BooleanField')(default=False),
+ keep_default=False)
+
+ # Adding field 'Interaction.only_important'
+ db.add_column('Reporting_interaction', 'only_important',
+ self.gf('django.db.models.fields.BooleanField')(default=False),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Interaction.dry_run'
+ db.delete_column('Reporting_interaction', 'dry_run')
+
+ # Deleting field 'Interaction.only_important'
+ db.delete_column('Reporting_interaction', 'only_important')
+
+
+ models = {
+ 'Reporting.actionentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'ActionEntry'},
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'output': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'check'", 'max_length': '128'})
+ },
+ 'Reporting.bundle': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Bundle'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
+ },
+ 'Reporting.client': {
+ 'Meta': {'object_name': 'Client'},
+ 'creation': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'current_interaction': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'parent_client'", 'null': 'True', 'to': "orm['Reporting.Interaction']"}),
+ 'expiration': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'Reporting.deviceentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'DeviceEntry', '_ormbases': ['Reporting.PathEntry']},
+ 'current_major': ('django.db.models.fields.IntegerField', [], {}),
+ 'current_minor': ('django.db.models.fields.IntegerField', [], {}),
+ 'device_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'pathentry_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['Reporting.PathEntry']", 'unique': 'True', 'primary_key': 'True'}),
+ 'target_major': ('django.db.models.fields.IntegerField', [], {}),
+ 'target_minor': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'Reporting.failureentry': {
+ 'Meta': {'object_name': 'FailureEntry'},
+ 'entry_type': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'message': ('django.db.models.fields.TextField', [], {}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'})
+ },
+ 'Reporting.fileacl': {
+ 'Meta': {'object_name': 'FileAcl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'})
+ },
+ 'Reporting.fileperms': {
+ 'Meta': {'unique_together': "(('owner', 'group', 'mode'),)", 'object_name': 'FilePerms'},
+ 'group': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mode': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'owner': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'Reporting.group': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Group'},
+ 'bundles': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.Bundle']", 'symmetrical': 'False'}),
+ 'category': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.Group']", 'symmetrical': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'profile': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'public': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'Reporting.interaction': {
+ 'Meta': {'ordering': "['-timestamp']", 'unique_together': "(('client', 'timestamp'),)", 'object_name': 'Interaction'},
+ 'actions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.ActionEntry']", 'symmetrical': 'False'}),
+ 'bad_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'bundles': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.Bundle']", 'symmetrical': 'False'}),
+ 'client': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'interactions'", 'to': "orm['Reporting.Client']"}),
+ 'dry_run': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'extra_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'failures': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.FailureEntry']", 'symmetrical': 'False'}),
+ 'good_count': ('django.db.models.fields.IntegerField', [], {}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.Group']", 'symmetrical': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'modified_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'only_important': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'packages': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.PackageEntry']", 'symmetrical': 'False'}),
+ 'paths': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.PathEntry']", 'symmetrical': 'False'}),
+ 'posixgroups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.POSIXGroupEntry']", 'symmetrical': 'False'}),
+ 'posixusers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.POSIXUserEntry']", 'symmetrical': 'False'}),
+ 'profile': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': "orm['Reporting.Group']"}),
+ 'repo_rev_code': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'sebooleans': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.SEBooleanEntry']", 'symmetrical': 'False'}),
+ 'sefcontexts': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.SEFcontextEntry']", 'symmetrical': 'False'}),
+ 'seinterfaces': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.SEInterfaceEntry']", 'symmetrical': 'False'}),
+ 'selogins': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.SELoginEntry']", 'symmetrical': 'False'}),
+ 'semodules': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.SEModuleEntry']", 'symmetrical': 'False'}),
+ 'senodes': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.SENodeEntry']", 'symmetrical': 'False'}),
+ 'sepermissives': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.SEPermissiveEntry']", 'symmetrical': 'False'}),
+ 'seports': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.SEPortEntry']", 'symmetrical': 'False'}),
+ 'server': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
+ 'services': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.ServiceEntry']", 'symmetrical': 'False'}),
+ 'seusers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.SEUserEntry']", 'symmetrical': 'False'}),
+ 'state': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'timestamp': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
+ 'total_count': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'Reporting.linkentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'LinkEntry', '_ormbases': ['Reporting.PathEntry']},
+ 'current_path': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
+ 'pathentry_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['Reporting.PathEntry']", 'unique': 'True', 'primary_key': 'True'}),
+ 'target_path': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'})
+ },
+ 'Reporting.packageentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'PackageEntry'},
+ 'current_version': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {}),
+ 'target_version': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
+ 'verification_details': ('django.db.models.fields.TextField', [], {'default': "''"})
+ },
+ 'Reporting.pathentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'PathEntry'},
+ 'acls': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['Reporting.FileAcl']", 'symmetrical': 'False'}),
+ 'current_perms': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['Reporting.FilePerms']"}),
+ 'detail_type': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'details': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'path_type': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {}),
+ 'target_perms': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['Reporting.FilePerms']"})
+ },
+ 'Reporting.performance': {
+ 'Meta': {'object_name': 'Performance'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'interaction': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'performance_items'", 'to': "orm['Reporting.Interaction']"}),
+ 'metric': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'value': ('django.db.models.fields.DecimalField', [], {'max_digits': '32', 'decimal_places': '16'})
+ },
+ 'Reporting.posixgroupentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'POSIXGroupEntry'},
+ 'current_gid': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'gid': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'Reporting.posixuserentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'POSIXUserEntry'},
+ 'current_gecos': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'current_group': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True'}),
+ 'current_home': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'current_shell': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
+ 'current_uid': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'gecos': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'group': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'home': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'shell': ('django.db.models.fields.CharField', [], {'default': "'/bin/bash'", 'max_length': '1024'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {}),
+ 'uid': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
+ },
+ 'Reporting.sebooleanentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'SEBooleanEntry'},
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {}),
+ 'value': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'Reporting.sefcontextentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'SEFcontextEntry'},
+ 'current_selinuxtype': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'filetype': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'selinuxtype': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'Reporting.seinterfaceentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'SEInterfaceEntry'},
+ 'current_selinuxtype': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'selinuxtype': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'Reporting.seloginentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'SELoginEntry'},
+ 'current_selinuxuser': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'selinuxuser': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'Reporting.semoduleentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'SEModuleEntry'},
+ 'current_disabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'disabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'Reporting.senodeentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'SENodeEntry'},
+ 'current_selinuxtype': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'proto': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'selinuxtype': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'Reporting.sepermissiveentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'SEPermissiveEntry'},
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'Reporting.seportentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'SEPortEntry'},
+ 'current_selinuxtype': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'selinuxtype': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'Reporting.serviceentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'ServiceEntry'},
+ 'current_status': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '128'}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {}),
+ 'target_status': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '128'})
+ },
+ 'Reporting.seuserentry': {
+ 'Meta': {'ordering': "('state', 'name')", 'object_name': 'SEUserEntry'},
+ 'current_prefix': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'current_roles': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'exists': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'hash_key': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
+ 'prefix': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'roles': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'state': ('django.db.models.fields.IntegerField', [], {})
+ }
+ }
+
+ complete_apps = ['Reporting'] \ No newline at end of file
diff --git a/src/lib/Bcfg2/Reporting/models.py b/src/lib/Bcfg2/Reporting/models.py
index ae6f6731b..2380621e6 100644
--- a/src/lib/Bcfg2/Reporting/models.py
+++ b/src/lib/Bcfg2/Reporting/models.py
@@ -144,6 +144,8 @@ class Interaction(models.Model):
bad_count = models.IntegerField(default=0)
modified_count = models.IntegerField(default=0)
extra_count = models.IntegerField(default=0)
+ dry_run = models.BooleanField(default=False)
+ only_important = models.BooleanField(default=False)
actions = models.ManyToManyField("ActionEntry")
packages = models.ManyToManyField("PackageEntry")