-
Notifications
You must be signed in to change notification settings - Fork 0
/
localpuppet.py
executable file
·134 lines (124 loc) · 4.2 KB
/
localpuppet.py
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
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/python
#
# Example script to do a standalone puppet run with a custom modulepath
# based on versioned application recipes and an ENC.
#
# Copyright 2012 Robert Thomson
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
"""
This script will let you run puppet standalone with
support for multiple environments (eg. version'd environments)
It requires a directories of release directories under /etc/puppet/apps
Each top-level release directory requires a manifest.yaml file
which includes the key 'modulepath' with a list of directories
relative to /etc/puppet/src/. These will be added to
puppet's modulepath.
"""
import sys
import os
import yaml
import shutil
import os.path
APP_MODULE_DIR="/etc/puppet/modules"
DEST_ENC_YAML="/etc/puppet/node.yaml"
INPUT_YAML="/etc/puppet/input.yaml"
PUPPET_MANIFEST="/etc/puppet/manifests/default.pp"
ENC_PATH="/etc/puppet/enc.sh"
def die(msg, exitcode=1):
print >>sys.stderr, msg
sys.exit(exitcode)
def get_raw_enc_data(args):
if args:
filename = args[0]
else:
filename = INPUT_YAML
return yaml.load(open(filename, "rb"))
def normalise_enc_data(encdata):
classes = encdata.get("classes", {})
parameters = encdata.get("parameters", {})
# ensure each class is a dictionary, and strip None items so
# that parameter defaults can take effect.
for key in classes.keys():
value = classes[key]
if value is None:
classes[key] = {}
elif type(value) == dict:
# remove None items, so puppet defaults can take effect
for k,v in value.items():
if v is None:
del value[k]
else:
del classes[key]
# return only classes and parameters
return {
"classes": classes,
"parameters": parameters,
}
def get_modulepath(module_dir, app_dirs):
"""Verify app_dirs and return the colon-separated module path"""
assert module_dir and os.path.isdir(module_dir)
assert app_dirs
assert len(app_dirs) < 10
modulepath = []
for appdir in iter(app_dirs):
assert not appdir.startswith("/")
assert ".." not in appdir
fullpath = os.path.join(module_dir, appdir)
if not os.path.exists(fullpath):
die("app_dir {0} does not exist.".format(appdir))
modulepath.append(fullpath)
return ":".join(modulepath)
def get_app_dirs(module_dir, app_dir):
assert not app_dir.startswith("/")
assert ".." not in app_dir
dir = os.path.join(module_dir, app_dir)
if not os.path.isdir(dir):
die("Directory doesn't exist: {0}".format(dir))
manifest = os.path.join(dir, "manifest.yaml")
if not os.path.exists(manifest):
die("Manifest file doesn't exist: {0}".format(manifest))
data = yaml.load(open(manifest))
if "modulepath" in data:
return [app_dir] + data["modulepath"]
return []
def main():
encdata = get_raw_enc_data(sys.argv[1:])
try:
app = encdata["app"]
except KeyError:
die("ERROR: Input YAML must have an 'app' key")
sys.exit(1)
app_dirs = get_app_dirs(APP_MODULE_DIR, app)
modulepath = get_modulepath(APP_MODULE_DIR, app_dirs)
with open(DEST_ENC_YAML,"wb") as fd:
yaml.dump(normalise_enc_data(encdata), fd)
args = [
"/usr/bin/puppet",
"apply",
"--node_terminus",
"exec",
"--external_nodes",
ENC_PATH,
"--modulepath",
modulepath,
PUPPET_MANIFEST
]
print("# "+' '.join(args))
os.execv("/usr/bin/puppet", args)
if __name__ == "__main__":
main()