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