summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2013-03-08 13:34:33 -0500
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2013-03-08 14:06:47 -0500
commita5b5c1926d437a8132115bd608d2fd8141982f70 (patch)
treea418a68a60e4266f555605bf1da6e342d63f9ade
parentd624e7eba92731c99909d74a1c20d502a6695837 (diff)
downloadbcfg2-a5b5c1926d437a8132115bd608d2fd8141982f70.tar.gz
bcfg2-a5b5c1926d437a8132115bd608d2fd8141982f70.tar.bz2
bcfg2-a5b5c1926d437a8132115bd608d2fd8141982f70.zip
Reporting: added support for various SELinux entries
-rw-r--r--src/lib/Bcfg2/Reporting/Storage/DjangoORM.py354
-rw-r--r--src/lib/Bcfg2/Reporting/migrations/0005_add_selinux_entry_support.py485
-rw-r--r--src/lib/Bcfg2/Reporting/models.py198
-rw-r--r--src/lib/Bcfg2/Reporting/templates/config_items/item.html31
-rw-r--r--src/lib/Bcfg2/Reporting/views.py24
5 files changed, 912 insertions, 180 deletions
diff --git a/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py b/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py
index bca4a9c1e..8826d6991 100644
--- a/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py
+++ b/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py
@@ -16,6 +16,7 @@ from Bcfg2.Reporting.Storage.base import StorageBase, StorageError
from Bcfg2.Server.Plugin.exceptions import PluginExecutionError
from django.core import management
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
+from django.db.models import FieldDoesNotExist
from django.core.cache import cache
from django.db import transaction
@@ -30,6 +31,212 @@ class DjangoORM(StorageBase):
super(DjangoORM, self).__init__(setup)
self.size_limit = setup.get('reporting_file_limit')
+ def _import_default(self, entry, state, entrytype=None, defaults=None,
+ mapping=None, boolean=None, xforms=None):
+ """ Default entry importer. Maps the entry (in state
+ ``state``) to an appropriate *Entry object; by default, this
+ is determined by the entry tag, e.g., from an Action entry an
+ ActionEntry object is created. This can be overridden with
+ ``entrytype``, which should be the class to instantiate for
+ this entry.
+
+ ``defaults`` is an optional mapping of <attribute
+ name>:<value> that will be used to set the default values for
+ various attributes.
+
+ ``mapping`` is a mapping of <field name>:<attribute name> that
+ can be used to map fields that are named differently on the
+ XML entry and in the database model.
+
+ ``boolean`` is a list of attribute names that should be
+ treated as booleans.
+
+ ``xforms`` is a dict of <attribute name>:<function>, where the
+ given function will be applied to the value of the named
+ attribute before trying to store it in the database.
+ """
+ if entrytype is None:
+ entrytype = globals()["%sEntry" % entry.tag]
+ if defaults is None:
+ defaults = dict()
+ if mapping is None:
+ mapping = dict()
+ if boolean is None:
+ boolean = []
+ if xforms is None:
+ xforms = dict()
+ mapping['exists'] = 'current_exists'
+ defaults['current_exists'] = 'true'
+ boolean.append("current_exists")
+
+ def boolean_xform(val):
+ try:
+ return val.lower() == "true"
+ except AttributeError:
+ return False
+
+ for attr in boolean + ["current_exists"]:
+ xforms[attr] = boolean_xform
+ act_dict = dict(state=state)
+ for fieldname in entrytype._meta.get_all_field_names():
+ if fieldname in ['id', 'hash_key', 'state']:
+ continue
+ try:
+ field = entrytype._meta.get_field(fieldname)
+ except FieldDoesNotExist:
+ continue
+ attrname = mapping.get(fieldname, fieldname)
+ val = entry.get(fieldname, defaults.get(attrname))
+ act_dict[fieldname] = xforms.get(attrname, lambda v: v)(val)
+ self.logger.debug("Adding %s:%s" % (entry.tag, entry.get("name")))
+ return entrytype.entry_get_or_create(act_dict)
+
+ def _import_Action(self, entry, state):
+ return self._import_default(entry, state,
+ defaults=dict(status='check', rc=-1),
+ mapping=dict(output="rc"))
+
+ def _import_Package(self, entry, state):
+ name = entry.get('name')
+ exists = entry.get('current_exists', default="true").lower() == "true"
+ act_dict = dict(name=name, state=state, exists=exists,
+ target_version=entry.get('version', default=''),
+ current_version=entry.get('current_version',
+ default=''))
+
+ # extra entries are a bit different. They can have Instance
+ # objects
+ if not act_dict['target_version']:
+ for instance in entry.findall("Instance"):
+ # FIXME - this probably only works for rpms
+ release = instance.get('release', '')
+ arch = instance.get('arch', '')
+ act_dict['current_version'] = instance.get('version')
+ if release:
+ act_dict['current_version'] += "-" + release
+ if arch:
+ act_dict['current_version'] += "." + arch
+ self.logger.debug("Adding package %s %s" %
+ (name, act_dict['current_version']))
+ return PackageEntry.entry_get_or_create(act_dict)
+ else:
+ self.logger.debug("Adding package %s %s" %
+ (name, act_dict['target_version']))
+
+ # not implemented yet
+ act_dict['verification_details'] = \
+ entry.get('verification_details', '')
+ return PackageEntry.entry_get_or_create(act_dict)
+
+ def _import_Path(self, entry, state):
+ name = entry.get('name')
+ exists = entry.get('current_exists', default="true").lower() == "true"
+ path_type = entry.get("type").lower()
+ act_dict = dict(name=name, state=state, exists=exists,
+ path_type=path_type)
+
+ target_dict = dict(
+ owner=entry.get('owner', default="root"),
+ group=entry.get('group', default="root"),
+ mode=entry.get('mode', default=entry.get('perms',
+ default=""))
+ )
+ fperm, created = FilePerms.objects.get_or_create(**target_dict)
+ act_dict['target_perms'] = fperm
+
+ current_dict = dict(
+ owner=entry.get('current_owner', default=""),
+ group=entry.get('current_group', default=""),
+ mode=entry.get('current_mode',
+ default=entry.get('current_perms', default=""))
+ )
+ fperm, created = FilePerms.objects.get_or_create(**current_dict)
+ act_dict['current_perms'] = fperm
+
+ if path_type in ('symlink', 'hardlink'):
+ act_dict['target_path'] = entry.get('to', default="")
+ act_dict['current_path'] = entry.get('current_to', default="")
+ self.logger.debug("Adding link %s" % name)
+ return LinkEntry.entry_get_or_create(act_dict)
+ elif path_type == 'device':
+ # TODO devices
+ self.logger.warn("device path types are not supported yet")
+ return
+
+ # TODO - vcs output
+ act_dict['detail_type'] = PathEntry.DETAIL_UNUSED
+ if path_type == 'directory' and entry.get('prune', 'false') == 'true':
+ unpruned_elist = [e.get('path') for e in entry.findall('Prune')]
+ if unpruned_elist:
+ act_dict['detail_type'] = PathEntry.DETAIL_PRUNED
+ act_dict['details'] = "\n".join(unpruned_elist)
+ elif entry.get('sensitive', 'false').lower() == 'true':
+ act_dict['detail_type'] = PathEntry.DETAIL_SENSITIVE
+ else:
+ cdata = None
+ if entry.get('current_bfile', None):
+ act_dict['detail_type'] = PathEntry.DETAIL_BINARY
+ cdata = entry.get('current_bfile')
+ elif entry.get('current_bdiff', None):
+ act_dict['detail_type'] = PathEntry.DETAIL_DIFF
+ cdata = b64decode(entry.get('current_bdiff'))
+ elif entry.get('current_diff', None):
+ act_dict['detail_type'] = PathEntry.DETAIL_DIFF
+ cdata = entry.get('current_bdiff')
+ if cdata:
+ if len(cdata) > self.size_limit:
+ act_dict['detail_type'] = PathEntry.DETAIL_SIZE_LIMIT
+ act_dict['details'] = md5(cdata).hexdigest()
+ else:
+ act_dict['details'] = cdata
+ self.logger.debug("Adding path %s" % name)
+ return PathEntry.entry_get_or_create(act_dict)
+ # TODO - secontext
+ # TODO - acls
+
+ def _import_Service(self, entry, state):
+ return self._import_default(entry, state,
+ defaults=dict(status='',
+ current_status=''),
+ mapping=dict(status='target_status'))
+
+ def _import_SEBoolean(self, entry, state):
+ return self._import_default(
+ entry, state,
+ xforms=dict(value=lambda v: v.lower() == "on"))
+
+ def _import_SEFcontext(self, entry, state):
+ return self._import_default(entry, state,
+ defaults=dict(filetype='all'))
+
+ def _import_SEInterface(self, entry, state):
+ return self._import_default(entry, state)
+
+ def _import_SEPort(self, entry, state):
+ return self._import_default(entry, state)
+
+ def _import_SENode(self, entry, state):
+ return self._import_default(entry, state)
+
+ def _import_SELogin(self, entry, state):
+ return self._import_default(entry, state)
+
+ def _import_SEUser(self, entry, state):
+ return self._import_default(entry, state)
+
+ def _import_SEPermissive(self, entry, state):
+ return self._import_default(entry, state)
+
+ def _import_SEModule(self, entry, state):
+ return self._import_default(entry, state,
+ defaults=dict(disabled='false'),
+ boolean=['disabled', 'current_disabled'])
+
+ def _import_unknown(self, entry, _):
+ self.logger.error("Unknown type %s not handled by reporting yet" %
+ entry.tag)
+ return None
+
@transaction.commit_on_success
def _import_interaction(self, interaction):
"""Real import function"""
@@ -46,13 +253,15 @@ class DjangoORM(StorageBase):
cache.set(hostname, client)
timestamp = datetime(*strptime(stats.get('time'))[0:6])
- if len(Interaction.objects.filter(client=client, timestamp=timestamp)) > 0:
+ if len(Interaction.objects.filter(client=client,
+ timestamp=timestamp)) > 0:
self.logger.warn("Interaction for %s at %s already exists" %
(hostname, timestamp))
return
if 'profile' in metadata:
- profile, created = Group.objects.get_or_create(name=metadata['profile'])
+ profile, created = \
+ Group.objects.get_or_create(name=metadata['profile'])
else:
profile = None
inter = Interaction(client=client,
@@ -65,10 +274,10 @@ class DjangoORM(StorageBase):
server=server,
profile=profile)
inter.save()
- self.logger.debug("Interaction for %s at %s with INSERTED in to db" %
+ self.logger.debug("Interaction for %s at %s with INSERTED in to db" %
(client.id, timestamp))
- #FIXME - this should be more efficient
+ # FIXME - this should be more efficient
for group_name in metadata['groups']:
group = cache.get("GROUP_" + group_name)
if not group:
@@ -76,12 +285,13 @@ class DjangoORM(StorageBase):
if created:
self.logger.debug("Added group %s" % group)
cache.set("GROUP_" + group_name, group)
-
+
inter.groups.add(group)
- for bundle_name in metadata['bundles']:
+ for bundle_name in metadata.get('bundles', []):
bundle = cache.get("BUNDLE_" + bundle_name)
if not bundle:
- bundle, created = Bundle.objects.get_or_create(name=bundle_name)
+ bundle, created = \
+ Bundle.objects.get_or_create(name=bundle_name)
if created:
self.logger.debug("Added bundle %s" % bundle)
cache.set("BUNDLE_" + bundle_name, bundle)
@@ -94,130 +304,26 @@ class DjangoORM(StorageBase):
pattern = [('Bad/*', TYPE_BAD),
('Extra/*', TYPE_EXTRA),
('Modified/*', TYPE_MODIFIED)]
- updates = dict(failures=[], paths=[], packages=[], actions=[], services=[])
+ updates = dict([(etype, []) for etype in Interaction.entry_types])
for (xpath, state) in pattern:
for entry in stats.findall(xpath):
counter_fields[state] = counter_fields[state] + 1
- entry_type = entry.tag
- name = entry.get('name')
- exists = entry.get('current_exists', default="true").lower() == "true"
-
# handle server failures differently
failure = entry.get('failure', '')
if failure:
- act_dict = dict(name=name, entry_type=entry_type,
- message=failure)
+ act_dict = dict(name=entry.get("name"),
+ entry_type=entry.tag,
+ message=failure)
newact = FailureEntry.entry_get_or_create(act_dict)
updates['failures'].append(newact)
continue
- act_dict = dict(name=name, state=state, exists=exists)
-
- if entry_type == 'Action':
- act_dict['status'] = entry.get('status', default="check")
- act_dict['output'] = entry.get('rc', default=-1)
- self.logger.debug("Adding action %s" % name)
- updates['actions'].append(ActionEntry.entry_get_or_create(act_dict))
- elif entry_type == 'Package':
- act_dict['target_version'] = entry.get('version', default='')
- act_dict['current_version'] = entry.get('current_version', default='')
-
- # extra entries are a bit different. They can have Instance objects
- if not act_dict['target_version']:
- for instance in entry.findall("Instance"):
- #TODO - this probably only works for rpms
- release = instance.get('release', '')
- arch = instance.get('arch', '')
- act_dict['current_version'] = instance.get('version')
- if release:
- act_dict['current_version'] += "-" + release
- if arch:
- act_dict['current_version'] += "." + arch
- self.logger.debug("Adding package %s %s" % (name, act_dict['current_version']))
- updates['packages'].append(PackageEntry.entry_get_or_create(act_dict))
- else:
-
- self.logger.debug("Adding package %s %s" % (name, act_dict['target_version']))
-
- # not implemented yet
- act_dict['verification_details'] = entry.get('verification_details', '')
- updates['packages'].append(PackageEntry.entry_get_or_create(act_dict))
-
- elif entry_type == 'Path':
- path_type = entry.get("type").lower()
- act_dict['path_type'] = path_type
-
- target_dict = dict(
- owner=entry.get('owner', default="root"),
- group=entry.get('group', default="root"),
- mode=entry.get('mode', default=entry.get('perms', default=""))
- )
- fperm, created = FilePerms.objects.get_or_create(**target_dict)
- act_dict['target_perms'] = fperm
-
- current_dict = dict(
- owner=entry.get('current_owner', default=""),
- group=entry.get('current_group', default=""),
- mode=entry.get('current_mode',
- default=entry.get('current_perms', default=""))
- )
- fperm, created = FilePerms.objects.get_or_create(**current_dict)
- act_dict['current_perms'] = fperm
-
- if path_type in ('symlink', 'hardlink'):
- act_dict['target_path'] = entry.get('to', default="")
- act_dict['current_path'] = entry.get('current_to', default="")
- self.logger.debug("Adding link %s" % name)
- updates['paths'].append(LinkEntry.entry_get_or_create(act_dict))
- continue
- elif path_type == 'device':
- #TODO devices
- self.logger.warn("device path types are not supported yet")
- continue
-
- # TODO - vcs output
- act_dict['detail_type'] = PathEntry.DETAIL_UNUSED
- if path_type == 'directory' and entry.get('prune', 'false') == 'true':
- unpruned_elist = [e.get('path') for e in entry.findall('Prune')]
- if unpruned_elist:
- act_dict['detail_type'] = PathEntry.DETAIL_PRUNED
- act_dict['details'] = "\n".join(unpruned_elist)
- elif entry.get('sensitive', 'false').lower() == 'true':
- act_dict['detail_type'] = PathEntry.DETAIL_SENSITIVE
- else:
- cdata = None
- if entry.get('current_bfile', None):
- act_dict['detail_type'] = PathEntry.DETAIL_BINARY
- cdata = entry.get('current_bfile')
- elif entry.get('current_bdiff', None):
- act_dict['detail_type'] = PathEntry.DETAIL_DIFF
- cdata = b64decode(entry.get('current_bdiff'))
- elif entry.get('current_diff', None):
- act_dict['detail_type'] = PathEntry.DETAIL_DIFF
- cdata = entry.get('current_bdiff')
- if cdata:
- if len(cdata) > self.size_limit:
- act_dict['detail_type'] = PathEntry.DETAIL_SIZE_LIMIT
- act_dict['details'] = md5(cdata).hexdigest()
- else:
- act_dict['details'] = cdata
- self.logger.debug("Adding path %s" % name)
- updates['paths'].append(PathEntry.entry_get_or_create(act_dict))
-
-
- #TODO - secontext
- #TODO - acls
-
- elif entry_type == 'Service':
- act_dict['target_status'] = entry.get('status', default='')
- act_dict['current_status'] = entry.get('current_status', default='')
- self.logger.debug("Adding service %s" % name)
- updates['services'].append(ServiceEntry.entry_get_or_create(act_dict))
- elif entry_type == 'SELinux':
- self.logger.info("SELinux not implemented yet")
- else:
- self.logger.error("Unknown type %s not handled by reporting yet" % entry_type)
+ updatetype = entry.tag.lower() + "s"
+ update = getattr(self, "_import_%s" % entry.tag,
+ self._import_unknown)(entry, state)
+ if update is not None:
+ updates[updatetype].append(update)
inter.bad_count = counter_fields[TYPE_BAD]
inter.modified_count = counter_fields[TYPE_MODIFIED]
@@ -227,15 +333,16 @@ class DjangoORM(StorageBase):
# batch this for sqlite
i = 0
while(i < len(updates[entry_type])):
- getattr(inter, entry_type).add(*updates[entry_type][i:i+100])
+ getattr(inter, entry_type).add(*updates[entry_type][i:i + 100])
i += 100
# performance metrics
for times in stats.findall('OpStamps'):
for metric, value in list(times.items()):
- Performance(interaction=inter, metric=metric, value=value).save()
+ Performance(interaction=inter,
+ metric=metric,
+ value=value).save()
-
def import_interaction(self, interaction):
"""Import the data into the backend"""
@@ -245,7 +352,6 @@ class DjangoORM(StorageBase):
self.logger.error("Failed to import interaction: %s" %
traceback.format_exc().splitlines()[-1])
-
def validate(self):
"""Validate backend storage. Should be called once when loaded"""
diff --git a/src/lib/Bcfg2/Reporting/migrations/0005_add_selinux_entry_support.py b/src/lib/Bcfg2/Reporting/migrations/0005_add_selinux_entry_support.py
new file mode 100644
index 000000000..d5f5d801a
--- /dev/null
+++ b/src/lib/Bcfg2/Reporting/migrations/0005_add_selinux_entry_support.py
@@ -0,0 +1,485 @@
+# -*- 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 model 'SELoginEntry'
+ db.create_table('Reporting_seloginentry', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=128, db_index=True)),
+ ('hash_key', self.gf('django.db.models.fields.BigIntegerField')(db_index=True)),
+ ('state', self.gf('django.db.models.fields.IntegerField')()),
+ ('exists', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('selinuxuser', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('current_selinuxuser', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
+ ))
+ db.send_create_signal('Reporting', ['SELoginEntry'])
+
+ # Adding model 'SEUserEntry'
+ db.create_table('Reporting_seuserentry', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=128, db_index=True)),
+ ('hash_key', self.gf('django.db.models.fields.BigIntegerField')(db_index=True)),
+ ('state', self.gf('django.db.models.fields.IntegerField')()),
+ ('exists', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('roles', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('current_roles', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
+ ('prefix', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('current_prefix', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
+ ))
+ db.send_create_signal('Reporting', ['SEUserEntry'])
+
+ # Adding model 'SEBooleanEntry'
+ db.create_table('Reporting_sebooleanentry', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=128, db_index=True)),
+ ('hash_key', self.gf('django.db.models.fields.BigIntegerField')(db_index=True)),
+ ('state', self.gf('django.db.models.fields.IntegerField')()),
+ ('exists', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('value', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ))
+ db.send_create_signal('Reporting', ['SEBooleanEntry'])
+
+ # Adding model 'SENodeEntry'
+ db.create_table('Reporting_senodeentry', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=128, db_index=True)),
+ ('hash_key', self.gf('django.db.models.fields.BigIntegerField')(db_index=True)),
+ ('state', self.gf('django.db.models.fields.IntegerField')()),
+ ('exists', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('selinuxtype', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('current_selinuxtype', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
+ ('proto', self.gf('django.db.models.fields.CharField')(max_length=4)),
+ ))
+ db.send_create_signal('Reporting', ['SENodeEntry'])
+
+ # Adding model 'SEFcontextEntry'
+ db.create_table('Reporting_sefcontextentry', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=128, db_index=True)),
+ ('hash_key', self.gf('django.db.models.fields.BigIntegerField')(db_index=True)),
+ ('state', self.gf('django.db.models.fields.IntegerField')()),
+ ('exists', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('selinuxtype', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('current_selinuxtype', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
+ ('filetype', self.gf('django.db.models.fields.CharField')(max_length=16)),
+ ))
+ db.send_create_signal('Reporting', ['SEFcontextEntry'])
+
+ # Adding model 'SEInterfaceEntry'
+ db.create_table('Reporting_seinterfaceentry', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=128, db_index=True)),
+ ('hash_key', self.gf('django.db.models.fields.BigIntegerField')(db_index=True)),
+ ('state', self.gf('django.db.models.fields.IntegerField')()),
+ ('exists', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('selinuxtype', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('current_selinuxtype', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
+ ))
+ db.send_create_signal('Reporting', ['SEInterfaceEntry'])
+
+ # Adding model 'SEPermissiveEntry'
+ db.create_table('Reporting_sepermissiveentry', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=128, db_index=True)),
+ ('hash_key', self.gf('django.db.models.fields.BigIntegerField')(db_index=True)),
+ ('state', self.gf('django.db.models.fields.IntegerField')()),
+ ('exists', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ))
+ db.send_create_signal('Reporting', ['SEPermissiveEntry'])
+
+ # Adding model 'SEModuleEntry'
+ db.create_table('Reporting_semoduleentry', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=128, db_index=True)),
+ ('hash_key', self.gf('django.db.models.fields.BigIntegerField')(db_index=True)),
+ ('state', self.gf('django.db.models.fields.IntegerField')()),
+ ('exists', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('disabled', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('current_disabled', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ))
+ db.send_create_signal('Reporting', ['SEModuleEntry'])
+
+ # Adding model 'SEPortEntry'
+ db.create_table('Reporting_seportentry', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=128, db_index=True)),
+ ('hash_key', self.gf('django.db.models.fields.BigIntegerField')(db_index=True)),
+ ('state', self.gf('django.db.models.fields.IntegerField')()),
+ ('exists', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('selinuxtype', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('current_selinuxtype', self.gf('django.db.models.fields.CharField')(max_length=128, null=True)),
+ ))
+ db.send_create_signal('Reporting', ['SEPortEntry'])
+
+ # Adding M2M table for field sebooleans on 'Interaction'
+ db.create_table('Reporting_interaction_sebooleans', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('interaction', models.ForeignKey(orm['Reporting.interaction'], null=False)),
+ ('sebooleanentry', models.ForeignKey(orm['Reporting.sebooleanentry'], null=False))
+ ))
+ db.create_unique('Reporting_interaction_sebooleans', ['interaction_id', 'sebooleanentry_id'])
+
+ # Adding M2M table for field seports on 'Interaction'
+ db.create_table('Reporting_interaction_seports', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('interaction', models.ForeignKey(orm['Reporting.interaction'], null=False)),
+ ('seportentry', models.ForeignKey(orm['Reporting.seportentry'], null=False))
+ ))
+ db.create_unique('Reporting_interaction_seports', ['interaction_id', 'seportentry_id'])
+
+ # Adding M2M table for field sefcontexts on 'Interaction'
+ db.create_table('Reporting_interaction_sefcontexts', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('interaction', models.ForeignKey(orm['Reporting.interaction'], null=False)),
+ ('sefcontextentry', models.ForeignKey(orm['Reporting.sefcontextentry'], null=False))
+ ))
+ db.create_unique('Reporting_interaction_sefcontexts', ['interaction_id', 'sefcontextentry_id'])
+
+ # Adding M2M table for field senodes on 'Interaction'
+ db.create_table('Reporting_interaction_senodes', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('interaction', models.ForeignKey(orm['Reporting.interaction'], null=False)),
+ ('senodeentry', models.ForeignKey(orm['Reporting.senodeentry'], null=False))
+ ))
+ db.create_unique('Reporting_interaction_senodes', ['interaction_id', 'senodeentry_id'])
+
+ # Adding M2M table for field selogins on 'Interaction'
+ db.create_table('Reporting_interaction_selogins', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('interaction', models.ForeignKey(orm['Reporting.interaction'], null=False)),
+ ('seloginentry', models.ForeignKey(orm['Reporting.seloginentry'], null=False))
+ ))
+ db.create_unique('Reporting_interaction_selogins', ['interaction_id', 'seloginentry_id'])
+
+ # Adding M2M table for field seusers on 'Interaction'
+ db.create_table('Reporting_interaction_seusers', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('interaction', models.ForeignKey(orm['Reporting.interaction'], null=False)),
+ ('seuserentry', models.ForeignKey(orm['Reporting.seuserentry'], null=False))
+ ))
+ db.create_unique('Reporting_interaction_seusers', ['interaction_id', 'seuserentry_id'])
+
+ # Adding M2M table for field seinterfaces on 'Interaction'
+ db.create_table('Reporting_interaction_seinterfaces', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('interaction', models.ForeignKey(orm['Reporting.interaction'], null=False)),
+ ('seinterfaceentry', models.ForeignKey(orm['Reporting.seinterfaceentry'], null=False))
+ ))
+ db.create_unique('Reporting_interaction_seinterfaces', ['interaction_id', 'seinterfaceentry_id'])
+
+ # Adding M2M table for field sepermissives on 'Interaction'
+ db.create_table('Reporting_interaction_sepermissives', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('interaction', models.ForeignKey(orm['Reporting.interaction'], null=False)),
+ ('sepermissiveentry', models.ForeignKey(orm['Reporting.sepermissiveentry'], null=False))
+ ))
+ db.create_unique('Reporting_interaction_sepermissives', ['interaction_id', 'sepermissiveentry_id'])
+
+ # Adding M2M table for field semodules on 'Interaction'
+ db.create_table('Reporting_interaction_semodules', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('interaction', models.ForeignKey(orm['Reporting.interaction'], null=False)),
+ ('semoduleentry', models.ForeignKey(orm['Reporting.semoduleentry'], null=False))
+ ))
+ db.create_unique('Reporting_interaction_semodules', ['interaction_id', 'semoduleentry_id'])
+
+
+ def backwards(self, orm):
+ # Deleting model 'SELoginEntry'
+ db.delete_table('Reporting_seloginentry')
+
+ # Deleting model 'SEUserEntry'
+ db.delete_table('Reporting_seuserentry')
+
+ # Deleting model 'SEBooleanEntry'
+ db.delete_table('Reporting_sebooleanentry')
+
+ # Deleting model 'SENodeEntry'
+ db.delete_table('Reporting_senodeentry')
+
+ # Deleting model 'SEFcontextEntry'
+ db.delete_table('Reporting_sefcontextentry')
+
+ # Deleting model 'SEInterfaceEntry'
+ db.delete_table('Reporting_seinterfaceentry')
+
+ # Deleting model 'SEPermissiveEntry'
+ db.delete_table('Reporting_sepermissiveentry')
+
+ # Deleting model 'SEModuleEntry'
+ db.delete_table('Reporting_semoduleentry')
+
+ # Deleting model 'SEPortEntry'
+ db.delete_table('Reporting_seportentry')
+
+ # Removing M2M table for field sebooleans on 'Interaction'
+ db.delete_table('Reporting_interaction_sebooleans')
+
+ # Removing M2M table for field seports on 'Interaction'
+ db.delete_table('Reporting_interaction_seports')
+
+ # Removing M2M table for field sefcontexts on 'Interaction'
+ db.delete_table('Reporting_interaction_sefcontexts')
+
+ # Removing M2M table for field senodes on 'Interaction'
+ db.delete_table('Reporting_interaction_senodes')
+
+ # Removing M2M table for field selogins on 'Interaction'
+ db.delete_table('Reporting_interaction_selogins')
+
+ # Removing M2M table for field seusers on 'Interaction'
+ db.delete_table('Reporting_interaction_seusers')
+
+ # Removing M2M table for field seinterfaces on 'Interaction'
+ db.delete_table('Reporting_interaction_seinterfaces')
+
+ # Removing M2M table for field sepermissives on 'Interaction'
+ db.delete_table('Reporting_interaction_sepermissives')
+
+ # Removing M2M table for field semodules on 'Interaction'
+ db.delete_table('Reporting_interaction_semodules')
+
+
+ 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']"}),
+ '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'}),
+ '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'}),
+ '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.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 ab2dc8418..a04203c73 100644
--- a/src/lib/Bcfg2/Reporting/models.py
+++ b/src/lib/Bcfg2/Reporting/models.py
@@ -11,21 +11,9 @@ except ImproperlyConfigured:
from django.core.cache import cache
from datetime import datetime, timedelta
+from Bcfg2.Compat import cPickle
+
-try:
- import cPickle as pickle
-except:
- import pickle
-
-KIND_CHOICES = (
- #These are the kinds of config elements
- ('Package', 'Package'),
- ('Path', 'directory'),
- ('Path', 'file'),
- ('Path', 'permissions'),
- ('Path', 'symlink'),
- ('Service', 'Service'),
-)
TYPE_GOOD = 0
TYPE_BAD = 1
TYPE_MODIFIED = 2
@@ -57,8 +45,8 @@ def hash_entry(entry_dict):
for key in sorted(entry_dict.keys()):
if key in ('id', 'hash_key') or key.startswith('_'):
continue
- dataset.append( (key, entry_dict[key]) )
- return hash(pickle.dumps(dataset))
+ dataset.append((key, entry_dict[key]))
+ return hash(cPickle.dumps(dataset))
class Client(models.Model):
@@ -121,7 +109,8 @@ class InteractionManager(models.Manager):
class Interaction(models.Model):
- """Models each reconfiguration operation interaction between client and server."""
+ """ Models each reconfiguration operation interaction between
+ client and server. """
client = models.ForeignKey(Client, related_name="interactions")
timestamp = models.DateTimeField(db_index=True) # Timestamp for this record
state = models.CharField(max_length=32) # good/bad/modified/etc
@@ -137,8 +126,21 @@ class Interaction(models.Model):
packages = models.ManyToManyField("PackageEntry")
paths = models.ManyToManyField("PathEntry")
services = models.ManyToManyField("ServiceEntry")
+ sebooleans = models.ManyToManyField("SEBooleanEntry")
+ seports = models.ManyToManyField("SEPortEntry")
+ sefcontexts = models.ManyToManyField("SEFcontextEntry")
+ senodes = models.ManyToManyField("SENodeEntry")
+ selogins = models.ManyToManyField("SELoginEntry")
+ seusers = models.ManyToManyField("SEUserEntry")
+ seinterfaces = models.ManyToManyField("SEInterfaceEntry")
+ sepermissives = models.ManyToManyField("SEPermissiveEntry")
+ semodules = models.ManyToManyField("SEModuleEntry")
failures = models.ManyToManyField("FailureEntry")
+ entry_types = ('actions', 'packages', 'paths', 'services', 'sebooleans',
+ 'seports', 'sefcontexts', 'senodes', 'selogins', 'seusers',
+ 'seinterfaces', 'sepermissives', 'semodules')
+
# Formerly InteractionMetadata
profile = models.ForeignKey("Group", related_name="+", null=True)
groups = models.ManyToManyField("Group")
@@ -157,7 +159,8 @@ class Interaction(models.Model):
def percentbad(self):
if not self.total_count == 0:
- return ((self.total_count - self.good_count) / (float(self.total_count))) * 100
+ return ((self.total_count - self.good_count) /
+ (float(self.total_count))) * 100
else:
return 0
@@ -189,7 +192,8 @@ class Interaction(models.Model):
self.client.save() # save again post update
def delete(self):
- '''Override the default delete. Allows us to remove Performance items'''
+ '''Override the default delete. Allows us to remove
+ Performance items '''
pitems = list(self.performance_items.all())
super(Interaction, self).delete()
for perf in pitems:
@@ -201,19 +205,19 @@ class Interaction(models.Model):
def bad(self):
rv = []
- for entry in ('actions', 'packages', 'paths', 'services'):
+ for entry in self.entry_types:
rv.extend(getattr(self, entry).filter(state=TYPE_BAD))
return rv
def modified(self):
rv = []
- for entry in ('actions', 'packages', 'paths', 'services'):
+ for entry in self.entry_types:
rv.extend(getattr(self, entry).filter(state=TYPE_MODIFIED))
return rv
def extra(self):
rv = []
- for entry in ('actions', 'packages', 'paths', 'services'):
+ for entry in self.entry_types:
rv.extend(getattr(self, entry).filter(state=TYPE_EXTRA))
return rv
@@ -325,7 +329,6 @@ class BaseEntry(models.Model):
self.hash_key = hash_entry(self.__dict__)
super(BaseEntry, self).save(*args, **kwargs)
-
def class_name(self):
return self.__class__.__name__
@@ -333,7 +336,6 @@ class BaseEntry(models.Model):
"""todo"""
return []
-
@classmethod
def entry_from_name(cls, name):
try:
@@ -344,28 +346,26 @@ class BaseEntry(models.Model):
except KeyError:
raise ValueError("Invalid type %s" % name)
-
@classmethod
def entry_from_type(cls, etype):
- for entry_cls in (ActionEntry, PackageEntry, PathEntry, ServiceEntry):
+ for entry_cls in ENTRY_CLASSES:
if etype == entry_cls.ENTRY_TYPE:
return entry_cls
else:
raise ValueError("Invalid type %s" % etype)
-
@classmethod
def entry_get_or_create(cls, act_dict):
"""Helper to quickly lookup an object"""
cls_name = cls().__class__.__name__
act_hash = hash_entry(act_dict)
-
+
# TODO - get form cache and validate
act_key = "%s_%s" % (cls_name, act_hash)
newact = cache.get(act_key)
if newact:
return newact
-
+
acts = cls.objects.filter(hash_key=act_hash)
if len(acts) > 0:
for act in acts:
@@ -375,20 +375,18 @@ class BaseEntry(models.Model):
#match found
newact = act
break
-
+
# worst case, its new
if not newact:
newact = cls(**act_dict)
newact.save(hash_key=act_hash)
-
+
cache.set(act_key, newact, 60 * 60)
return newact
-
def is_failure(self):
return isinstance(self, FailureEntry)
-
@classmethod
def prune_orphans(cls):
'''Remove unused entries'''
@@ -397,7 +395,7 @@ class BaseEntry(models.Model):
for x in cls.objects.filter(interaction__isnull=True).values("id")]
i = 0
while i < len(cls_orphans):
- cls.objects.filter(id__in=cls_orphans[i:i+100]).delete()
+ cls.objects.filter(id__in=cls_orphans[i:i + 100]).delete()
i += 100
@@ -439,13 +437,137 @@ class FailureEntry(BaseEntry):
class ActionEntry(SuccessEntry):
- """ The new model for package information """
+ """ Action entry """
status = models.CharField(max_length=128, default="check")
output = models.IntegerField(default=0)
ENTRY_TYPE = r"Action"
+class SEBooleanEntry(SuccessEntry):
+ """ SELinux boolean """
+ value = models.BooleanField(default=True)
+
+ ENTRY_TYPE = r"SEBoolean"
+
+
+class SEPortEntry(SuccessEntry):
+ """ SELinux port """
+ selinuxtype = models.CharField(max_length=128)
+ current_selinuxtype = models.CharField(max_length=128, null=True)
+
+ ENTRY_TYPE = r"SEPort"
+
+ def selinuxtype_problem(self):
+ """Check for an selinux type problem."""
+ if not self.current_selinuxtype:
+ return True
+ return self.selinuxtype != self.current_selinuxtype
+
+ def short_list(self):
+ """Return a list of problems"""
+ rv = super(SEPortEntry, self).short_list()
+ if self.selinuxtype_problem():
+ rv.append("Wrong SELinux type")
+ return rv
+
+
+class SEFcontextEntry(SuccessEntry):
+ """ SELinux file context """
+ selinuxtype = models.CharField(max_length=128)
+ current_selinuxtype = models.CharField(max_length=128, null=True)
+ filetype = models.CharField(max_length=16)
+
+ ENTRY_TYPE = r"SEFcontext"
+
+ def selinuxtype_problem(self):
+ """Check for an selinux type problem."""
+ if not self.current_selinuxtype:
+ return True
+ return self.selinuxtype != self.current_selinuxtype
+
+ def short_list(self):
+ """Return a list of problems"""
+ rv = super(SEFcontextEntry, self).short_list()
+ if self.selinuxtype_problem():
+ rv.append("Wrong SELinux type")
+ return rv
+
+
+class SENodeEntry(SuccessEntry):
+ """ SELinux node """
+ selinuxtype = models.CharField(max_length=128)
+ current_selinuxtype = models.CharField(max_length=128, null=True)
+ proto = models.CharField(max_length=4)
+
+ ENTRY_TYPE = r"SENode"
+
+ def selinuxtype_problem(self):
+ """Check for an selinux type problem."""
+ if not self.current_selinuxtype:
+ return True
+ return self.selinuxtype != self.current_selinuxtype
+
+ def short_list(self):
+ """Return a list of problems"""
+ rv = super(SENodeEntry, self).short_list()
+ if self.selinuxtype_problem():
+ rv.append("Wrong SELinux type")
+ return rv
+
+
+class SELoginEntry(SuccessEntry):
+ """ SELinux login """
+ selinuxuser = models.CharField(max_length=128)
+ current_selinuxuser = models.CharField(max_length=128, null=True)
+
+ ENTRY_TYPE = r"SELogin"
+
+
+class SEUserEntry(SuccessEntry):
+ """ SELinux user """
+ roles = models.CharField(max_length=128)
+ current_roles = models.CharField(max_length=128, null=True)
+ prefix = models.CharField(max_length=128)
+ current_prefix = models.CharField(max_length=128, null=True)
+
+ ENTRY_TYPE = r"SEUser"
+
+
+class SEInterfaceEntry(SuccessEntry):
+ """ SELinux interface """
+ selinuxtype = models.CharField(max_length=128)
+ current_selinuxtype = models.CharField(max_length=128, null=True)
+
+ ENTRY_TYPE = r"SEInterface"
+
+ def selinuxtype_problem(self):
+ """Check for an selinux type problem."""
+ if not self.current_selinuxtype:
+ return True
+ return self.selinuxtype != self.current_selinuxtype
+
+ def short_list(self):
+ """Return a list of problems"""
+ rv = super(SEInterfaceEntry, self).short_list()
+ if self.selinuxtype_problem():
+ rv.append("Wrong SELinux type")
+ return rv
+
+
+class SEPermissiveEntry(SuccessEntry):
+ """ SELinux permissive domain """
+ ENTRY_TYPE = r"SEPermissive"
+
+
+class SEModuleEntry(SuccessEntry):
+ """ SELinux module """
+ disabled = models.BooleanField(default=False)
+ current_disabled = models.BooleanField(default=False)
+
+ ENTRY_TYPE = r"SEModule"
+
+
class PackageEntry(SuccessEntry):
""" The new model for package information """
@@ -455,7 +577,7 @@ class PackageEntry(SuccessEntry):
verification_details = models.TextField(default="")
ENTRY_TYPE = r"Package"
- #TODO - prune
+ # TODO - prune
def version_problem(self):
"""Check for a version problem."""
@@ -612,3 +734,7 @@ class ServiceEntry(SuccessEntry):
return rv
+ENTRY_TYPES = (ActionEntry, PackageEntry, PathEntry, ServiceEntry,
+ SEBooleanEntry, SEPortEntry, SEFcontextEntry, SENodeEntry,
+ SELoginEntry, SEUserEntry, SEInterfaceEntry, SEPermissiveEntry,
+ SEModuleEntry)
diff --git a/src/lib/Bcfg2/Reporting/templates/config_items/item.html b/src/lib/Bcfg2/Reporting/templates/config_items/item.html
index 737760252..259414399 100644
--- a/src/lib/Bcfg2/Reporting/templates/config_items/item.html
+++ b/src/lib/Bcfg2/Reporting/templates/config_items/item.html
@@ -45,36 +45,47 @@ div.entry_list h3 {
{% endif %}
{# Really need a better test here #}
-{% if item.mdoe_problem or item.status_problem or item.linkentry.link_problem or item.version_problem %}
+{% if item.mode_problem or item.status_problem or item.linkentry.link_problem or item.version_problem %}
<table class='entry_list'>
<tr id='table_list_header'>
<td style='text-align: right;'>Problem Type</td><td>Expected</td><td style='border-bottom: 1px solid #98DBCC;'>Found</td></tr>
{% if item.mode_problem %}
{% if item.current_perms.owner %}
- <tr><td style='text-align: right'><b>Owner</b></td><td>{{item.target_perms.owner}}</td>
+ <tr><td style='text-align: right'><b>Owner</b></td>
+ <td>{{item.target_perms.owner}}</td>
<td>{{item.current_perms.owner}}</td></tr>
{% endif %}
{% if item.current_perms.group %}
- <tr><td style='text-align: right'><b>Group</b></td><td>{{item.target_perms.group}}</td>
+ <tr><td style='text-align: right'><b>Group</b></td>
+ <td>{{item.target_perms.group}}</td>
<td>{{item.current_perms.group}}</td></tr>
{% endif %}
{% if item.current_perms.mode%}
- <tr><td style='text-align: right'><b>Mode</b></td><td>{{item.target_perms.mode}}</td>
+ <tr><td style='text-align: right'><b>Permissions</b>
+ </td><td>{{item.target_perms.mode}}</td>
<td>{{item.current_perms.mode}}</td></tr>
{% endif %}
{% endif %}
{% if item.status_problem %}
- <tr><td style='text-align: right'><b>Status</b></td><td>{{item.target_status}}</td>
- <td>{{item.current_status}}</td></tr>
+ <tr><td style='text-align: right'><b>Status</b></td>
+ <td>{{item.target_status}}</td>
+ <td>{{item.current_status}}</td></tr>
{% endif %}
{% if item.linkentry.link_problem %}
- <tr><td style='text-align: right'><b>{{item.get_path_type_display}}</b></td><td>{{item.linkentry.target_path}}</td>
- <td>{{item.linkentry.current_path}}</td></tr>
+ <tr><td style='text-align: right'><b>{{item.get_path_type_display}}</b></td>
+ <td>{{item.linkentry.target_path}}</td>
+ <td>{{item.linkentry.current_path}}</td></tr>
{% endif %}
{% if item.version_problem %}
- <tr><td style='text-align: right'><b>Package Version</b></td><td>{{item.target_version|cut:"("|cut:")"}}</td>
+ <tr><td style='text-align: right'><b>Package Version</b></td>
+ <td>{{item.target_version|cut:"("|cut:")"}}</td>
<td>{{item.current_version|cut:"("|cut:")"}}</td></tr>
{% endif %}
+ {% if item.selinuxtype_problem %}
+ <tr><td style='text-align: right'><b>SELinux Type</b></td>
+ <td>{{item.selinuxtype}}</td>
+ <td>{{item.current_selinuxtype}}</td></tr>
+ {% endif %}
</table>
{% endif %}
@@ -92,7 +103,7 @@ div.entry_list h3 {
{{ item.details|syntaxhilight }}
</div>
{% else %}
- {{ item.details }}
+ {{ item.details }}
{% endif %}
</div>
{% endif %}
diff --git a/src/lib/Bcfg2/Reporting/views.py b/src/lib/Bcfg2/Reporting/views.py
index 0341a18af..6cba7bf8c 100644
--- a/src/lib/Bcfg2/Reporting/views.py
+++ b/src/lib/Bcfg2/Reporting/views.py
@@ -161,7 +161,7 @@ def config_item(request, pk, entry_type, interaction=None):
ts_end = ts_start + timedelta(days=1)
associated_list = item.interaction_set.select_related('client').filter(\
timestamp__gte=ts_start, timestamp__lt=ts_end)
-
+
if item.is_failure():
template = 'config_items/item-failure.html'
else:
@@ -184,7 +184,7 @@ def config_item_list(request, item_state, timestamp=None, **kwargs):
current_clients = [q['id'] for q in _handle_filters(current_clients, **kwargs).values('id')]
lists = []
- for etype in ActionEntry, PackageEntry, PathEntry, ServiceEntry:
+ for etype in ENTRY_TYPES:
ldata = etype.objects.filter(state=state, interaction__in=current_clients)\
.annotate(num_entries=Count('id')).select_related('linkentry', 'target_perms', 'current_perms')
if len(ldata) > 0:
@@ -218,7 +218,7 @@ def entry_status(request, entry_type, pk, timestamp=None, **kwargs):
if it.pk not in seen:
items.append((it, it.interaction_set.filter(pk__in=current_clients).order_by('client__name').select_related('client')))
seen.append(it.pk)
-
+
return render_to_response('config_items/entry_status.html',
{'entry': item,
'items': items,
@@ -254,8 +254,8 @@ def common_problems(request, timestamp=None, threshold=None, group=None):
else:
current_clients = Interaction.objects.recent_ids(timestamp)
lists = []
- for etype in ActionEntry, PackageEntry, PathEntry, ServiceEntry:
- ldata = etype.objects.exclude(state=TYPE_GOOD).filter(
+ for etype in ENTRY_TYPES:
+ ldata = etype.objects.exclude(state=TYPE_GOOD).filter(
interaction__in=current_clients).annotate(num_entries=Count('id')).filter(num_entries__gte=threshold)\
.order_by('-num_entries', 'name')
if len(ldata) > 0:
@@ -315,7 +315,8 @@ def client_detailed_list(request, timestamp=None, **kwargs):
kwargs['orderby'] = "client__name"
kwargs['sort'] = "client"
- kwargs['interaction_base'] = Interaction.objects.recent(timestamp).select_related()
+ kwargs['interaction_base'] = \
+ Interaction.objects.recent(timestamp).select_related()
kwargs['page_limit'] = 0
return render_history_view(request, 'clients/detailed-list.html', **kwargs)
@@ -330,16 +331,18 @@ def client_detail(request, hostname=None, pk=None):
inter = client.interactions.get(pk=pk)
maxdate = inter.timestamp
- etypes = { TYPE_BAD: 'bad', TYPE_MODIFIED: 'modified', TYPE_EXTRA: 'extra' }
+ etypes = {TYPE_BAD: 'bad',
+ TYPE_MODIFIED: 'modified',
+ TYPE_EXTRA: 'extra'}
edict = dict()
for label in etypes.values():
edict[label] = []
- for ekind in ('actions', 'packages', 'paths', 'services'):
+ for ekind in inter.entry_types:
for ent in getattr(inter, ekind).all():
edict[etypes[ent.state]].append(ent)
context['entry_types'] = edict
- context['interaction']=inter
+ context['interaction'] = inter
return render_history_view(request, 'clients/detail.html', page_limit=5,
client=client, maxdate=maxdate, context=context)
@@ -356,7 +359,8 @@ def client_manage(request):
client.expiration = datetime.now()
client.save()
message = "Expiration for %s set to %s." % \
- (client_name, client.expiration.strftime("%Y-%m-%d %H:%M:%S"))
+ (client_name,
+ client.expiration.strftime("%Y-%m-%d %H:%M:%S"))
elif client_action == 'unexpire':
client.expiration = None
client.save()