-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathMoveIncludedManifestsToSubfolder.py
177 lines (156 loc) · 7.4 KB
/
MoveIncludedManifestsToSubfolder.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/local/munki/munki-python
'''
This script moves all top-level Munki manifests to the top-level of the manifests directory
and then moves all included manifests into a subfolder of the manifests folder. At the end
of the script, your original manifests folder remains untouched. If you like the results,
you can replace your old manifests folder with the new one this script generates.
'''
import os
import plistlib
import shutil
import sys
import time
###########################################################################
########## Modify these variables to fit your situation ###################
# Top-level manifest directory
manifests='/Volumes/munki_repo/manifests'
'''
Name of subfolder to put included manifests in. Cannot be blank or null for obvious
reasons (no point in running this script if you aren't putting included manifests in a
subfolder), but also because it will break the copy_modify_manifests function.
'''
subfolder_name='groups'
###########################################################################
###########################################################################
# Copy to the new manifest structure location and then modify the manifest
def copy_modify_manifests(old_manifest, old_root, new_manifest_folder, subfolder, \
is_included):
print("Processing {}".format(old_manifest))
# Copy the manifest to the new manifest structure location
if is_included == False:
new_path = os.path.join(new_manifest_folder, old_manifest)
else:
new_path = os.path.join(new_manifest_folder, subfolder, old_manifest)
old_path = os.path.join(old_root, old_manifest)
try:
shutil.copyfile(old_path, new_path)
except:
print("Copy of {} failed".format(old_manifest))
sys.exit(1)
# Get the plist information from this manifest
try:
f = open(new_path, 'r+b')
except:
print("Unable to open {}".format(new_path))
sys.exit(1)
try:
plist = plistlib.load(f)
except:
print("Unable to get contents of {}".format(new_path))
sys.exit(1)
# Modify the paths to the included manifests
if 'included_manifests' in plist:
old_includes = plist['included_manifests']
# Even if the key itself exists, it may be an empty array, so check to see if
# it's empty or not
if old_includes:
# Create a new list to store the modified values
new_includes = []
# Loop through the includes, modify them, and put them in the new includes
for old_include in old_includes:
new_include = os.path.join(subfolder, old_include)
new_includes.append(new_include)
plist['included_manifests'] = new_includes
# Included manifests should never have catalogs, so delete those if needed
if is_included == True and 'catalogs' in plist.keys():
print("Removing catalogs from included manifest {}".format(old_manifest))
del plist['catalogs']
# Empty file before writing back to it
f.seek(0)
f.truncate()
# Write back the modified plist information
try:
plistlib.dump(plist, f)
except:
print("Could not write back plist changes to {}".format(old_manifest))
sys.exit(1)
f.close()
# Main
def main():
# Make sure the manifest directory exists
if os.path.isdir(manifests):
# Create new directory to put any modified manifests
modified_manifests = manifests + '_' + str(int(time.time()))
# New subdirectory path, too
new_subfolder = os.path.join(modified_manifests, subfolder_name)
# The chances that a new directory with the exact timestamp of now already exists
# is low, but we should double-check that directory doesn't already exist
if not os.path.isdir(modified_manifests) and not os.path.isdir(new_subfolder):
# Create the new manifest directory and subfolder
try:
os.makedirs(new_subfolder)
except:
print("Unable to make directory {} for new manifest \
structure".format(modified_manifests))
sys.exit(1)
# Create a dictionary that stores any manifests that are not included in any
# other manifests
top_levels = {}
# Create a list that stores any included manifests
included_manifests = {}
# Loop through the manifests
for root, dirs, files in os.walk(manifests):
for file in files:
# Skip files that start with a period
if file.startswith("."):
continue
# Get the full path to the file
fullfile = os.path.join(root, file)
# If it's not in the included manifests list or the top level list,
# add it to the top level list
if file not in top_levels and file not in included_manifests:
top_levels[file] = root
# Get the included manifests for this manifest
try:
f = open(fullfile, 'rb')
except:
print("Unable to open {}".format(fullfile))
sys.exit(1)
try:
current_manifest = plistlib.load(f)
except:
print("Unable to get contents of {}".format(fullfile))
sys.exit(1)
f.close()
# Check if the key itself exists
if 'included_manifests' in current_manifest:
current_includes = current_manifest['included_manifests']
# Even if the key itself exists, it may be an empty array, so
# check to see if it's empty or not
if current_includes:
# Loop through each of the included manifests
for current_include in current_includes:
# If it's in the top_levels manifest list, take it out
if current_include in top_levels:
del top_levels[current_include]
# If it's not in the included list, add it
if current_include not in included_manifests:
included_manifests[current_include] = root
# Now that we know which manifests are top-level manifests and which are
# included ones, let's loop through both sets
# Loop through the top-level manifests
for top_level in top_levels:
copy_modify_manifests(top_level, top_levels[top_level], \
modified_manifests, subfolder_name, False)
# Loop through the included manifests, which themselves may include other manifests
for included_manifest in included_manifests:
copy_modify_manifests(included_manifest, included_manifests[included_manifest], \
modified_manifests, subfolder_name, True)
else:
print("{} already exists as a directory.".format(modified_manifests))
sys.exit(1)
else:
print("{} is not a valid manifests folder.".format(manifests))
sys.exit(1)
if __name__ == '__main__':
main()