aboutsummaryrefslogtreecommitdiff
path: root/pyenc/model.py
blob: e77401434a1767348e7a9cd746dbb7886a39bbda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""Database model for application."""

from flask_sqlalchemy import SQLAlchemy
import requests
import yaml

db = SQLAlchemy()

host_classes = db.Table(
        'host_classes',
        db.Column('host_id', db.ForeignKey('host.id')),
        db.Column('class_id', db.ForeignKey('puppet_class.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 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)
    environment = db.Column(db.Text)
    # classes = db.relationship('HostClasses', backref='host', lazy='dynamic')
    classes = db.relationship(
            'PuppetClass',
            back_populates='hosts',
            secondary=host_classes)

    def serialize(self):
        return {column.name: self.__getattribute__(column.name)
                for column in self.__table__.columns}


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)


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
    # TODO normalize this to <path-inside-environment>
    path = db.Column(db.Text, nullable=False)

    environment = db.Column(db.Integer, db.ForeignKey(f'{PuppetEnvironment.__tablename__}.id'))

    # Checksum of the content, should be usable as a key in
    # PuppetFileContent
    # TODO flask weak keys?
    checksum = db.Column(db.Text)

    # When we last read data into json
    last_parse = db.Column(db.Float)
    # classes = db.relationship('PuppetClass', back_populates='comes_from')
    classes = db.relationship('PuppetClass', backref='comes_from')


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)

    # 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)



class PuppetClass(db.Model):
    """
    A puppet class.

    The class itself only keeps track of its name here, and mostyl
    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)
    # comes_from = db.relationship('PuppetFile', back_populates='classes')
    comes_from_id = db.Column(db.Integer,
                              db.ForeignKey(f'{PuppetFile.__tablename__}.id'))
    hosts = db.relationship(
            'Host',
            back_populates='classes',
            secondary=host_classes)