aboutsummaryrefslogtreecommitdiff
path: root/pyenc/app/model.py
diff options
context:
space:
mode:
Diffstat (limited to 'pyenc/app/model.py')
-rw-r--r--pyenc/app/model.py191
1 files changed, 191 insertions, 0 deletions
diff --git a/pyenc/app/model.py b/pyenc/app/model.py
new file mode 100644
index 0000000..f67cd10
--- /dev/null
+++ b/pyenc/app/model.py
@@ -0,0 +1,191 @@
+"""Database model for application."""
+
+from flask_sqlalchemy import SQLAlchemy
+
+# db = SQLAlchemy(session_options={"autoflush": False})
+db = SQLAlchemy()
+
+
+def init_app(app):
+ """Adds database bindings to a Flask App."""
+ db.init_app(app)
+ import logging
+ # logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
+
+
+host_classes = db.Table(
+ 'host_classes',
+ db.Column('host_id', db.ForeignKey('host.id'), primary_key=True),
+ db.Column('class_id', db.ForeignKey('puppet_class.id'), primary_key=True),
+)
+
+
+# NOTE this is non-final, and might get removed shortly
+environment_classes = db.Table(
+ 'environment_classes',
+ db.Column('environment_id', db.ForeignKey('puppet_environment.id'), primary_key=True),
+ db.Column('class_id', db.ForeignKey('puppet_class.id'), primary_key=True),
+)
+
+
+class_files = db.Table(
+ 'class_files',
+ db.Column('class_id', db.ForeignKey('puppet_class.id'), primary_key=True),
+ db.Column('file_id', db.ForeignKey('puppet_file.id'), primary_key=True),
+ db.UniqueConstraint('class_id', 'file_id'),
+)
+
+
+# class HostClasses(db.Model):
+# __tablename__ = 'host_classes'
+# id = db.Column(db.Integer, primary_key=True)
+# host_id = db.Column(db.Integer, db.ForeignKey('host.id'), nullable=False)
+# class_id = db.Column(db.Integer, db.ForeignKey('puppet_class.id'), nullable=False)
+
+
+class PuppetEnvironment(db.Model):
+ """
+ A puppet environment.
+
+ An enviromnet is a collection of modules, but here we only keep
+ the files of the modules, in PuppetFile.
+ """
+ __tablename__ = 'puppet_environment'
+ id = db.Column(db.Integer, primary_key=True)
+ name = db.Column(db.Text, nullable=False, unique=True)
+ classes = db.relationship(
+ 'PuppetClass',
+ back_populates='environments',
+ secondary=environment_classes)
+ hosts = db.relationship(
+ 'Host',
+ back_populates='environment')
+
+
+class Host(db.Model):
+ """
+ Single computer.
+
+ A computer has a name (machine.example.com.), an environment
+ (production) and a list of puppet classes.
+
+ (TODO and direct values?)
+ """
+
+ __tablename__ = 'host'
+ id = db.Column(db.Integer, primary_key=True)
+ fqdn = db.Column(db.Text, nullable=False, unique=True)
+ environment_id = db.Column(db.Integer, db.ForeignKey(f'{PuppetEnvironment.__tablename__}.id'))
+ environment = db.relationship('PuppetEnvironment', back_populates='hosts')
+ # classes = db.relationship('HostClasses', backref='host', lazy='dynamic')
+ classes = db.relationship(
+ 'PuppetClass',
+ back_populates='hosts',
+ secondary=host_classes)
+
+ def serialize(self): # pylint: disable=missing-function-docstring
+ return {column.name: self.__getattribute__(column.name)
+ for column in self.__table__.columns}
+
+
+class PuppetFile(db.Model):
+ """
+ Puppet source code file.
+
+ Keeps track of known puppet files. Each file contains 0 to many
+ puppet classes.
+
+ Each file is uniquely identified by the pair (path, environment).
+ """
+
+ __tablename__ = 'puppet_file'
+ id = db.Column(db.Integer, primary_key=True)
+ # Where we found the file (path inside environment)
+ # e.g. /etc/puppetlabs/code/environments/<environment name>/<this path>
+ path = db.Column(db.Text, nullable=False)
+
+ # Puppet environment this file belongs in
+ environment = db.Column(db.Integer,
+ db.ForeignKey(f'{PuppetEnvironment.__tablename__}.id'),
+ nullable=False)
+
+ # Checksum of the content, should be usable as a key in PuppetFileContent
+ checksum = db.Column(db.Text, nullable=False)
+
+ # When we last read data into json
+ last_parse = db.Column(db.Float)
+
+ classes = db.relationship('PuppetClass',
+ back_populates='files',
+ secondary=class_files)
+ content = db.relationship('PuppetFileContent', backref='file')
+
+ __table_args__ = (
+ db.UniqueConstraint('path', 'environment'),
+ )
+
+
+class PuppetFileContent(db.Model):
+ """
+ (Parsed) contents of puppet source files.
+
+ Separate from PuppetFile since many environments can share files,
+ and I don't want to store reduntand data.
+ """
+ __tablename__ = 'puppet_file_content'
+
+ id = db.Column(db.Integer, primary_key=True)
+
+ file_id = db.Column(db.Integer, db.ForeignKey(f'{PuppetFile.__tablename__}.id'))
+
+ # Checksum of the original file
+ checksum = db.Column(db.Text, nullable=False)
+
+ # Output of 'puppet parser dump --format json <filename>'
+ json = db.Column(db.Text, nullable=False)
+
+
+# TODO class environment mappings?
+# - the same class can exist in multiple environmentns
+# - the same class in multiple environments might be different
+# - the class can come or go when the file is changed (??)
+# - when a node changes environment it still has its classes, but they
+# refer to something else now
+
+# Possibly:
+# nodes holds its list of classes as a list of strings
+# I have tables which maps class names to files per environment
+
+# What happens when two different environments have separate classes
+# which share a name
+
+class PuppetClass(db.Model):
+ """
+ A puppet class.
+
+ The class itself only keeps track of its name here, and mostly
+ ensures that only existing classes can be added to a given node/host.
+ """
+ __tablename__ = 'puppet_class'
+ id = db.Column(db.Integer, primary_key=True)
+ class_name = db.Column(db.Text, nullable=False, unique=True)
+
+ hosts = db.relationship(
+ 'Host',
+ back_populates='classes',
+ secondary=host_classes)
+ environments = db.relationship(
+ 'PuppetEnvironment',
+ back_populates='classes',
+ secondary=environment_classes)
+ files = db.relationship(
+ 'PuppetFile',
+ back_populates='classes',
+ secondary=class_files)
+
+
+class Misc(db.Model):
+ __tablename__ = 'misc'
+ id = db.Column(db.Integer, primary_key=True)
+ key = db.Column(db.Text, nullable=False)
+ value = db.Column(db.Text)