-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnebman.py
executable file
·372 lines (340 loc) · 60.4 KB
/
nebman.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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
#!/usr/bin/python3
##
## required imports
import os.path
import subprocess
import sqlite3
import sys
import requests
import shutil
import tarfile
import base64
# Set Constants
NEBMANDB='nebmanDB.db'
CURRENTVERSION='1.9.5'
# Set global variables
existingLighthouseID = 10
existingEndpointID = 50
existingNetwork = "notset"
existingVersion='Unknown'
# terminal colour text codes (found via a so page)
class bcolors:
GREEN = '\033[92m'
ORANGE = '\033[93m'
RED = '\033[91m'
END = '\033[0m'
vmTag = ''
# Report on the current state of key elements of the app.
def checkState():
# Ref gobal variable
global existingVersion
# Does the DB exist
if os.path.exists(NEBMANDB):
print("- Database is found: " + bcolors.GREEN + "Yes" + bcolors.END)
else:
print("- Database is found: " + bcolors.RED + "No" + bcolors.END)
# Does the Certs folder exist
if os.path.exists('./certs/'):
print("- Certs folder is found: " + bcolors.GREEN + "Yes" + bcolors.END)
else:
print("- Certs folder is found: " + bcolors.RED + "No" + bcolors.END)
# Does the CA exist
if os.path.exists('./certs/ca.crt') and os.path.exists('./certs/ca.key'):
print("- CA cert and key are found: " + bcolors.GREEN + "Yes" + bcolors.END)
else:
print("- CA cert and key are found: " + bcolors.RED + "No" + bcolors.END)
# Does nebula binary exist and if so what's the version.
if os.path.exists('nebula'):
getNewVersion="./nebula --version"
existingVersion = str(subprocess.check_output(getNewVersion, shell=True))
existingVersion = str(existingVersion[11:16])
print("- Nebula binary found, version: " + existingVersion)
else:
print("- Nebula binary note found: " + bcolors.RED + "Not found" + bcolors.END)
# initialise a new DB for nebman or load settings if existing DB and contents are located.
def initDB():
# check if database file exists, if not, create it.
if not os.path.exists(NEBMANDB):
dbConnect = sqlite3.connect(NEBMANDB)
dbCurser = dbConnect.cursor()
dbCurser.execute("CREATE TABLE nebmanClients(id, hostname, network, lighthouse, os, services, version, UNIQUE(hostname))")
dbConnect.commit()
dbConnect.close()
# confirm DB exists, in case create above failed/ did not complete.
if not os.path.exists(NEBMANDB):
sys.exit("Database does not exist, exiting")
# if database does exist set required values
else:
# Reference the global variables
global existingLighthouseID
global existingEndpointID
global existingNetwork
dbConnect = sqlite3.connect(NEBMANDB)
dbCurser = dbConnect.cursor()
dbContent = dbCurser.execute("SELECT * FROM nebmanClients")
for row in dbContent:
existingNetwork = row[2]
if row[3] == 'y':
if row[0] > existingLighthouseID:
existingLighthouseID = row[0]
else:
if row[0] > existingEndpointID:
existingEndpointID = row[0]
# Add a function to create ansible directory for inventory file
def ansibleInit():
if not os.path.exists('ansible'):
os.makedirs('ansible')
if not os.path.exists('ansible/inventory'):
os.makedirs('ansible/inventory')
if not os.path.exists('ansible/playbooks'):
os.makedirs('ansible/playbooks')
if not os.path.exists('ansible/playbooks/templates'):
os.makedirs('ansible/playbooks/templates')
if not os.path.exists('ansible/playbooks/files'):
os.makedirs('ansible/playbooks/files')
def ansibleGen():
# Generate ansile directory structure if it doesn't exist.
ansibleInit()
# Generate inventory file once database exists
if not os.path.exists(NEBMANDB):
sys.exit("Database does not exist, exiting")
elif existingNetwork == "notset":
sys.exit("Network not configured, please ensure hosts including a lighthouse are defined, exiting")
else:
# open DB connection and iterate through to find Lighthouse details
x = 0
dbConnect = sqlite3.connect(NEBMANDB)
dbCurser = dbConnect.cursor()
dbContent = dbCurser.execute("SELECT * FROM nebmanClients")
for row in dbContent:
if row[3] == 'y' and x < 1:
lighthouseHostname = row[1]
lighthouseIP = existingNetwork + "." + str(row[0])
x+=1
dbConnect.close()
# open DB connection and filestream for ansible inventory.ini file to find host details
dbConnect = sqlite3.connect(NEBMANDB)
dbCurser = dbConnect.cursor()
dbContent = dbCurser.execute("SELECT * FROM nebmanClients")
ansIventory = open("ansible/inventory/inventory.ini", "w")
ansIventory.write("[nebula]\n")
for row in dbContent:
ansIventory.write(row[1]+" cert_name="+row[1]+" lighthouse_ip="+lighthouseIP+" lighthouse_hostname="+lighthouseHostname+"\n")
# Write hostnames out to inventory file
for row in dbContent:
ansIventory.write(row[1]+" cert_name="+row[1]+"\n")
# Close DB connection and file stream
dbConnect.close()
ansIventory.close()
# Copy nebula binary to Ansible files folder.
if os.path.exists("nebula"):
shutil.copy2('./nebula', './ansible/playbooks/files/nebula')
# Copy certs to Ansible files folder.
if os.path.exists("certs"):
shutil.copytree('certs', './ansible/playbooks/files/certs', dirs_exist_ok=True)
# Write ansible playbook out to file from base64 version
# base64 of playbook to simplify storage
ansPlaybook="IyEvdXNyL2Jpbi9lbnYgYW5zaWJsZS1wbGF5Ym9vawotLS0KLSBuYW1lOiBDb25maWd1cmUgYW5kIHN0YXJ0IE5lYnVsYQogIGhvc3RzOiBuZWJ1bGEKICBiZWNvbWU6IHRydWUKICBnYXRoZXJfZmFjdHM6IGZhbHNlCgogIHRhc2tzOgogIC0gbmFtZTogQ3JlYXRlIGRpciBmb3IgTmVidWxhIGZpbGVzCiAgICBmaWxlOgogICAgICBwYXRoOiAiL3Vzci9sb2NhbC9iaW4vbmVidWxhIgogICAgICBzdGF0ZTogZGlyZWN0b3J5CiAgICAgIG1vZGU6ICcwNzAwJwoKICAtIG5hbWU6IENvcHkgY2VydCBmaWxlcwogICAgY29weToKICAgICAgc3JjOiAie3sgaXRlbSB9fSIKICAgICAgZGVzdDogIi91c3IvbG9jYWwvYmluL25lYnVsYSIKICAgICAgbW9kZTogJzA2MDAnCiAgICBsb29wOgogICAgICAtIGNlcnRzL3t7IGNlcnRfbmFtZSB9fS5rZXkKICAgICAgLSBjZXJ0cy97eyBjZXJ0X25hbWUgfX0uY3J0CiAgICAgIC0gY2VydHMvY2EuY3J0CgogIC0gbmFtZTogQ29weSBuZWJ1bGEgYmluYXJ5CiAgICBjb3B5OgogICAgICBzcmM6ICJ7eyBpdGVtIH19IgogICAgICBkZXN0OiAiL3Vzci9sb2NhbC9iaW4vbmVidWxhLyIKICAgICAgbW9kZTogJzA3MDAnCiAgICBsb29wOgogICAgICAtIG5lYnVsYQogIAogIC0gbmFtZTogQ29weSBOZWJ1bGEgTGlnaHRob3VzZSBjb25maWcKICAgIHRlbXBsYXRlOgogICAgICBzcmM6IG5lYnVsYS1saWdodGhvdXNlLnltbC5qMgogICAgICBkZXN0OiAvdXNyL2xvY2FsL2Jpbi9uZWJ1bGEve3sgY2VydF9uYW1lIH19LnltbAogICAgICBtb2RlOiAnMDY0NCcKICAgIHdoZW46IGNlcnRfbmFtZSA9PSBsaWdodGhvdXNlX2hvc3RuYW1lCgogIC0gbmFtZTogQ29weSBOZWJ1bGEgRW5kcG9pbnQgY29uZmlnCiAgICB0ZW1wbGF0ZToKICAgICAgc3JjOiBuZWJ1bGEtZW5kcG9pbnQueW1sLmoyCiAgICAgIGRlc3Q6IC91c3IvbG9jYWwvYmluL25lYnVsYS97eyBjZXJ0X25hbWUgfX0ueW1sCiAgICAgIG1vZGU6ICcwNjQ0JwogICAgd2hlbjogY2VydF9uYW1lICE9IGxpZ2h0aG91c2VfaG9zdG5hbWUKCiAgLSBuYW1lOiBDb3B5IHNlcnZpY2UKICAgIHRlbXBsYXRlOgogICAgICBzcmM6IG5lYnVsYS5zZXJ2aWNlLmoyCiAgICAgIGRlc3Q6IC9ldGMvc3lzdGVtZC9zeXN0ZW0vbmVidWxhLnNlcnZpY2UKICAgICAgbW9kZTogJzA2NDQnCgogIC0gbmFtZTogRW5hYmxlIElQIEZvcndhcmRpbmcKICAgIGFuc2libGUuYnVpbHRpbi5saW5laW5maWxlOgogICAgICBwYXRoOiAvZXRjL3N5c2N0bC5jb25mCiAgICAgIGxpbmU6IG5ldC5pcHY0LmlwX2ZvcndhcmQgPSAxCiAgICAgIGNyZWF0ZTogeWVzCgogIC0gbmFtZTogU3RhcnQgTmVidWxhIHNlcnZpY2UKICAgIGFuc2libGUuYnVpbHRpbi5zZXJ2aWNlOgogICAgICBuYW1lOiBuZWJ1bGEKICAgICAgc3RhdGU6IHN0YXJ0ZWQKICAgICAgZW5hYmxlZDogeWVzCgogIC0gbmFtZTogQ29uZmlndXJlIFVGVyBOZWJ1bGEKICAgIGNvbW11bml0eS5nZW5lcmFsLnVmdzoKICAgICAgcnVsZTogYWxsb3cKICAgICAgcG9ydDogJzQyNDInCiAgICAgIHByb3RvOiB1ZHAKCiAgLSBuYW1lOiBSZWxvYWQgVUZXICh0byBhcHBseSBuZXcgcnVsZSkKICAgIGNvbW11bml0eS5nZW5lcmFsLnVmdzoKICAgICAgc3RhdGU6IHJlbG9hZGVkCi4uLg=="
ansPlaybookDecode = base64.b64decode(ansPlaybook)
ansPlaybookDecode = ansPlaybookDecode.decode("utf-8")
ansPlaybook = open("ansible/playbooks/nebula.yml", "w")
ansPlaybook.write(ansPlaybookDecode)
ansPlaybook.close()
# Write Linux service config template out to file from base64 version
# base64 of template to simplify storage
ansLinuxService="W1VuaXRdCkRlc2NyaXB0aW9uPU5lYnVsYSBNZXNoIFNlcnZpY2UKQWZ0ZXI9bmV0d29yay50YXJnZXQKCltTZXJ2aWNlXQpFeGVjU3RhcnQ9L3Vzci9sb2NhbC9iaW4vbmVidWxhL25lYnVsYSAtY29uZmlnIC91c3IvbG9jYWwvYmluL25lYnVsYS97eyBjZXJ0X25hbWUgfX0ueW1sClJlc3RhcnQ9YWx3YXlzCgpbSW5zdGFsbF0KV2FudGVkQnk9bXVsdGktdXNlci50YXJnZXQ="
ansLinuxServiceDecode = base64.b64decode(ansLinuxService)
ansLinuxServiceDecode = ansLinuxServiceDecode.decode("utf-8")
ansLinuxService = open("ansible/playbooks/templates/nebula.service.j2", "w")
ansLinuxService.write(ansLinuxServiceDecode)
ansLinuxService.close()
# Write Nebula Endpoint config template out to file from base64 version
# base64 of template to simplify storage
ansNebulaEndpointConfig="IyBUaGlzIGlzIHRoZSBuZWJ1bGEgZXhhbXBsZSBjb25maWd1cmF0aW9uIGZpbGUuIFlvdSBtdXN0IGVkaXQsIGF0IGEgbWluaW11bSwgdGhlIHN0YXRpY19ob3N0X21hcCwgbGlnaHRob3VzZSwgYW5kIGZpcmV3YWxsIHNlY3Rpb25zCiMgU29tZSBvcHRpb25zIGluIHRoaXMgZmlsZSBhcmUgSFVQYWJsZSwgaW5jbHVkaW5nIHRoZSBwa2kgc2VjdGlvbi4gKEEgSFVQIHdpbGwgcmVsb2FkIGNyZWRlbnRpYWxzIGZyb20gZGlzayB3aXRob3V0IGFmZmVjdGluZyBleGlzdGluZyB0dW5uZWxzKQoKIyBQS0kgZGVmaW5lcyB0aGUgbG9jYXRpb24gb2YgY3JlZGVudGlhbHMgZm9yIHRoaXMgbm9kZS4gRWFjaCBvZiB0aGVzZSBjYW4gYWxzbyBiZSBpbmxpbmVkIGJ5IHVzaW5nIHRoZSB5YW1sICI6IHwiIHN5bnRheC4KcGtpOgogICMgVGhlIENBcyB0aGF0IGFyZSBhY2NlcHRlZCBieSB0aGlzIG5vZGUuIE11c3QgY29udGFpbiBvbmUgb3IgbW9yZSBjZXJ0aWZpY2F0ZXMgY3JlYXRlZCBieSAnbmVidWxhLWNlcnQgY2EnCiAgY2E6IC91c3IvbG9jYWwvYmluL25lYnVsYS9jYS5jcnQKICBjZXJ0OiAvdXNyL2xvY2FsL2Jpbi9uZWJ1bGEve3sgY2VydF9uYW1lIH19LmNydAogIGtleTogL3Vzci9sb2NhbC9iaW4vbmVidWxhL3t7IGNlcnRfbmFtZSB9fS5rZXkKICAjIGJsb2NrbGlzdCBpcyBhIGxpc3Qgb2YgY2VydGlmaWNhdGUgZmluZ2VycHJpbnRzIHRoYXQgd2Ugd2lsbCByZWZ1c2UgdG8gdGFsayB0bwogICNibG9ja2xpc3Q6CiAgIyAgLSBjOTlkNGU2NTA1MzNiOTIwNjFiMDk5MThlODM4YTVhMGE2YWFlZTIxZWVkMWQxMmZkOTM3NjgyODY1OTM2YzcyCiAgIyBkaXNjb25uZWN0X2ludmFsaWQgaXMgYSB0b2dnbGUgdG8gZm9yY2UgYSBjbGllbnQgdG8gYmUgZGlzY29ubmVjdGVkIGlmIHRoZSBjZXJ0aWZpY2F0ZSBpcyBleHBpcmVkIG9yIGludmFsaWQuCiAgI2Rpc2Nvbm5lY3RfaW52YWxpZDogZmFsc2UKCiMgVGhlIHN0YXRpYyBob3N0IG1hcCBkZWZpbmVzIGEgc2V0IG9mIGhvc3RzIHdpdGggZml4ZWQgSVAgYWRkcmVzc2VzIG9uIHRoZSBpbnRlcm5ldCAob3IgYW55IG5ldHdvcmspLgojIEEgaG9zdCBjYW4gaGF2ZSBtdWx0aXBsZSBmaXhlZCBJUCBhZGRyZXNzZXMgZGVmaW5lZCBoZXJlLCBhbmQgbmVidWxhIHdpbGwgdHJ5IGVhY2ggd2hlbiBlc3RhYmxpc2hpbmcgYSB0dW5uZWwuCiMgVGhlIHN5bnRheCBpczoKIyAgICJ7bmVidWxhIGlwfSI6IFsie3JvdXRhYmxlIGlwL2RucyBuYW1lfTp7cm91dGFibGUgcG9ydH0iXQojIEV4YW1wbGUsIGlmIHlvdXIgbGlnaHRob3VzZSBoYXMgdGhlIG5lYnVsYSBJUCBvZiAxOTIuMTY4LjEwMC4xIGFuZCBoYXMgdGhlIHJlYWwgaXAgYWRkcmVzcyBvZiAxMDAuNjQuMjIuMTEgYW5kIHJ1bnMgb24gcG9ydCA0MjQyOgpzdGF0aWNfaG9zdF9tYXA6CiAgInt7IGxpZ2h0aG91c2VfaXAgfX0iOiBbInt7IGxpZ2h0aG91c2VfaG9zdG5hbWUgfX06NDI0MiJdCgojIFRoZSBzdGF0aWNfbWFwIGNvbmZpZyBzdGFuemEgY2FuIGJlIHVzZWQgdG8gY29uZmlndXJlIGhvdyB0aGUgc3RhdGljX2hvc3RfbWFwIGJlaGF2ZXMuCiNzdGF0aWNfbWFwOgogICMgY2FkZW5jZSBkZXRlcm1pbmVzIGhvdyBmcmVxdWVudGx5IEROUyBpcyByZS1xdWVyaWVkIGZvciB1cGRhdGVkIElQIGFkZHJlc3NlcyB3aGVuIGEgc3RhdGljX2hvc3RfbWFwIGVudHJ5IGNvbnRhaW5zCiAgIyBhIEROUyBuYW1lLgogICNjYWRlbmNlOiAzMHMKCiAgIyBuZXR3b3JrIGRldGVybWluZXMgdGhlIHR5cGUgb2YgSVAgYWRkcmVzc2VzIHRvIGFzayB0aGUgRE5TIHNlcnZlciBmb3IuIFRoZSBkZWZhdWx0IGlzICJpcDQiIGJlY2F1c2Ugbm9kZXMgdHlwaWNhbGx5CiAgIyBkbyBub3Qga25vdyB0aGVpciBwdWJsaWMgSVB2NCBhZGRyZXNzLiBDb25uZWN0aW5nIHRvIHRoZSBMaWdodGhvdXNlIHZpYSBJUHY0IGFsbG93cyB0aGUgTGlnaHRob3VzZSB0byBkZXRlY3QgdGhlCiAgIyBwdWJsaWMgYWRkcmVzcy4gT3RoZXIgdmFsaWQgb3B0aW9ucyBhcmUgImlwNiIgYW5kICJpcCIgKHJldHVybnMgYm90aC4pCiAgI25ldHdvcms6IGlwNAoKICAjIGxvb2t1cF90aW1lb3V0IGlzIHRoZSBETlMgcXVlcnkgdGltZW91dC4KICAjbG9va3VwX3RpbWVvdXQ6IDI1MG1zCgpsaWdodGhvdXNlOgogICMgYW1fbGlnaHRob3VzZSBpcyB1c2VkIHRvIGVuYWJsZSBsaWdodGhvdXNlIGZ1bmN0aW9uYWxpdHkgZm9yIGEgbm9kZS4gVGhpcyBzaG91bGQgT05MWSBiZSB0cnVlIG9uIG5vZGVzCiAgIyB5b3UgaGF2ZSBjb25maWd1cmVkIHRvIGJlIGxpZ2h0aG91c2VzIGluIHlvdXIgbmV0d29yawogIGFtX2xpZ2h0aG91c2U6IGZhbHNlCiAgIyBzZXJ2ZV9kbnMgb3B0aW9uYWxseSBzdGFydHMgYSBkbnMgbGlzdGVuZXIgdGhhdCByZXNwb25kcyB0byB2YXJpb3VzIHF1ZXJpZXMgYW5kIGNhbiBldmVuIGJlCiAgIyBkZWxlZ2F0ZWQgdG8gZm9yIHJlc29sdXRpb24KICAjc2VydmVfZG5zOiBmYWxzZQogICNkbnM6CiAgICAjIFRoZSBETlMgaG9zdCBkZWZpbmVzIHRoZSBJUCB0byBiaW5kIHRoZSBkbnMgbGlzdGVuZXIgdG8uIFRoaXMgYWxzbyBhbGxvd3MgYmluZGluZyB0byB0aGUgbmVidWxhIG5vZGUgSVAuCiAgICAjaG9zdDogMC4wLjAuMAogICAgI3BvcnQ6IDUzCiAgIyBpbnRlcnZhbCBpcyB0aGUgbnVtYmVyIG9mIHNlY29uZHMgYmV0d2VlbiB1cGRhdGVzIGZyb20gdGhpcyBub2RlIHRvIGEgbGlnaHRob3VzZS4KICAjIGR1cmluZyB1cGRhdGVzLCBhIG5vZGUgc2VuZHMgaW5mb3JtYXRpb24gYWJvdXQgaXRzIGN1cnJlbnQgSVAgYWRkcmVzc2VzIHRvIGVhY2ggbm9kZS4KICBpbnRlcnZhbDogNjAKICAjIGhvc3RzIGlzIGEgbGlzdCBvZiBsaWdodGhvdXNlIGhvc3RzIHRoaXMgbm9kZSBzaG91bGQgcmVwb3J0IHRvIGFuZCBxdWVyeSBmcm9tCiAgIyBJTVBPUlRBTlQ6IFRISVMgU0hPVUxEIEJFIEVNUFRZIE9OIExJR0hUSE9VU0UgTk9ERVMKICAjIElNUE9SVEFOVDI6IFRISVMgU0hPVUxEIEJFIExJR0hUSE9VU0VTJyBORUJVTEEgSVBzLCBOT1QgTElHSFRIT1VTRVMnIFJFQUwgUk9VVEFCTEUgSVBzCiAgaG9zdHM6CiAgICAtICJ7eyBsaWdodGhvdXNlX2lwIH19IgoKICAjIHJlbW90ZV9hbGxvd19saXN0IGFsbG93cyB5b3UgdG8gY29udHJvbCBpcCByYW5nZXMgdGhhdCB0aGlzIG5vZGUgd2lsbAogICMgY29uc2lkZXIgd2hlbiBoYW5kc2hha2luZyB0byBhbm90aGVyIG5vZGUuIEJ5IGRlZmF1bHQsIGFueSByZW1vdGUgSVBzIGFyZQogICMgYWxsb3dlZC4gWW91IGNhbiBwcm92aWRlIENJRFJzIGhlcmUgd2l0aCBgdHJ1ZWAgdG8gYWxsb3cgYW5kIGBmYWxzZWAgdG8KICAjIGRlbnkuIFRoZSBtb3N0IHNwZWNpZmljIENJRFIgcnVsZSBhcHBsaWVzIHRvIGVhY2ggcmVtb3RlLiBJZiBhbGwgcnVsZXMgYXJlCiAgIyAiYWxsb3ciLCB0aGUgZGVmYXVsdCB3aWxsIGJlICJkZW55IiwgYW5kIHZpY2UtdmVyc2EuIElmIGJvdGggImFsbG93IiBhbmQKICAjICJkZW55IiBJUHY0IHJ1bGVzIGFyZSBwcmVzZW50LCB0aGVuIHlvdSBNVVNUIHNldCBhIHJ1bGUgZm9yICIwLjAuMC4wLzAiIGFzCiAgIyB0aGUgZGVmYXVsdC4gU2ltaWxhcmx5IGlmIGJvdGggImFsbG93IiBhbmQgImRlbnkiIElQdjYgcnVsZXMgYXJlIHByZXNlbnQsCiAgIyB0aGVuIHlvdSBNVVNUIHNldCBhIHJ1bGUgZm9yICI6Oi8wIiBhcyB0aGUgZGVmYXVsdC4KICAjcmVtb3RlX2FsbG93X2xpc3Q6CiAgICAjIEV4YW1wbGUgdG8gYmxvY2sgSVBzIGZyb20gdGhpcyBzdWJuZXQgZnJvbSBiZWluZyB1c2VkIGZvciByZW1vdGUgSVBzLgogICAgIyIxNzIuMTYuMC4wLzEyIjogZmFsc2UKCiAgICAjIEEgbW9yZSBjb21wbGljYXRlZCBleGFtcGxlLCBhbGxvdyBwdWJsaWMgSVBzIGJ1dCBvbmx5IHByaXZhdGUgSVBzIGZyb20gYSBzcGVjaWZpYyBzdWJuZXQKICAgICMiMC4wLjAuMC8wIjogdHJ1ZQogICAgIyIxMC4wLjAuMC84IjogZmFsc2UKICAgICMiMTAuNDIuNDIuMC8yNCI6IHRydWUKCiAgIyBFWFBFUklNRU5UQUw6IFRoaXMgb3B0aW9uIG1heSBjaGFuZ2Ugb3IgZGlzYXBwZWFyIGluIHRoZSBmdXR1cmUuCiAgIyBPcHRpb25hbGx5IGFsbG93cyB0aGUgZGVmaW5pdGlvbiBvZiByZW1vdGVfYWxsb3dfbGlzdCBibG9ja3MKICAjIHNwZWNpZmljIHRvIGFuIGluc2lkZSBWUE4gSVAgQ0lEUi4KICAjcmVtb3RlX2FsbG93X3JhbmdlczoKICAgICMgVGhpcyBydWxlIHdvdWxkIG9ubHkgYWxsb3cgb25seSBwcml2YXRlIElQcyBmb3IgdGhpcyBWUE4gcmFuZ2UKICAgICMiMTAuNDIuNDIuMC8yNCI6CiAgICAgICMiMTkyLjE2OC4wLjAvMTYiOiB0cnVlCgogICMgbG9jYWxfYWxsb3dfbGlzdCBhbGxvd3MgeW91IHRvIGZpbHRlciB3aGljaCBsb2NhbCBJUCBhZGRyZXNzZXMgd2UgYWR2ZXJ0aXNlCiAgIyB0byB0aGUgbGlnaHRob3VzZXMuIFRoaXMgdXNlcyB0aGUgc2FtZSBsb2dpYyBhcyBgcmVtb3RlX2FsbG93X2xpc3RgLCBidXQKICAjIGFkZGl0aW9uYWxseSwgeW91IGNhbiBzcGVjaWZ5IGFuIGBpbnRlcmZhY2VzYCBtYXAgb2YgcmVndWxhciBleHByZXNzaW9ucwogICMgdG8gbWF0Y2ggYWdhaW5zdCBpbnRlcmZhY2UgbmFtZXMuIFRoZSByZWdleHAgbXVzdCBtYXRjaCB0aGUgZW50aXJlIG5hbWUuCiAgIyBBbGwgaW50ZXJmYWNlIHJ1bGVzIG11c3QgYmUgZWl0aGVyIHRydWUgb3IgZmFsc2UgKGFuZCB0aGUgZGVmYXVsdCB3aWxsIGJlCiAgIyB0aGUgaW52ZXJzZSkuIENJRFIgcnVsZXMgYXJlIG1hdGNoZWQgYWZ0ZXIgaW50ZXJmYWNlIG5hbWUgcnVsZXMuCiAgIyBEZWZhdWx0IGlzIGFsbCBsb2NhbCBJUCBhZGRyZXNzZXMuCiAgI2xvY2FsX2FsbG93X2xpc3Q6CiAgICAjIEV4YW1wbGUgdG8gYmxvY2sgdHVuMCBhbmQgYWxsIGRvY2tlciBpbnRlcmZhY2VzLgogICAgI2ludGVyZmFjZXM6CiAgICAgICN0dW4wOiBmYWxzZQogICAgICAjJ2RvY2tlci4qJzogZmFsc2UKICAgICMgRXhhbXBsZSB0byBvbmx5IGFkdmVydGlzZSB0aGlzIHN1Ym5ldCB0byB0aGUgbGlnaHRob3VzZS4KICAgICMiMTAuMC4wLjAvOCI6IHRydWUKCiAgIyBhZHZlcnRpc2VfYWRkcnMgYXJlIHJvdXRhYmxlIGFkZHJlc3NlcyB0aGF0IHdpbGwgYmUgaW5jbHVkZWQgYWxvbmcgd2l0aCBkaXNjb3ZlcmVkIGFkZHJlc3NlcyB0byByZXBvcnQgdG8gdGhlCiAgIyBsaWdodGhvdXNlLCB0aGUgZm9ybWF0IGlzICJpcDpwb3J0Ii4gYHBvcnRgIGNhbiBiZSBgMGAsIGluIHdoaWNoIGNhc2UgdGhlIGFjdHVhbCBsaXN0ZW5pbmcgcG9ydCB3aWxsIGJlIHVzZWQgaW4gaXRzCiAgIyBwbGFjZSwgdXNlZnVsIGlmIGBsaXN0ZW4ucG9ydGAgaXMgc2V0IHRvIDAuCiAgIyBUaGlzIG9wdGlvbiBpcyBtYWlubHkgdXNlZnVsIHdoZW4gdGhlcmUgYXJlIHN0YXRpYyBpcCBhZGRyZXNzZXMgdGhlIGhvc3QgY2FuIGJlIHJlYWNoZWQgYXQgdGhhdCBuZWJ1bGEgY2FuIG5vdAogICMgdHlwaWNhbGx5IGRpc2NvdmVyIG9uIGl0cyBvd24uIEV4YW1wbGVzIGJlaW5nIHBvcnQgZm9yd2FyZGluZyBvciBtdWx0aXBsZSBwYXRocyB0byB0aGUgaW50ZXJuZXQuCiAgI2FkdmVydGlzZV9hZGRyczoKICAgICMtICIxLjEuMS4xOjQyNDIiCiAgICAjLSAiMS4yLjMuNDowIiAjIHBvcnQgd2lsbCBiZSByZXBsYWNlZCB3aXRoIHRoZSByZWFsIGxpc3RlbmluZyBwb3J0CgogICMgRVhQRVJJTUVOVEFMOiBUaGlzIG9wdGlvbiBtYXkgY2hhbmdlIG9yIGRpc2FwcGVhciBpbiB0aGUgZnV0dXJlLgogICMgVGhpcyBzZXR0aW5nIGFsbG93cyB1cyB0byAiZ3Vlc3MiIHdoYXQgdGhlIHJlbW90ZSBtaWdodCBiZSBmb3IgYSBob3N0CiAgIyB3aGlsZSB3ZSB3YWl0IGZvciB0aGUgbGlnaHRob3VzZSByZXNwb25zZS4KICAjY2FsY3VsYXRlZF9yZW1vdGVzOgogICAgIyBGb3IgYW55IE5lYnVsYSBJUHMgaW4gMTAuMC4xMC4wLzI0LCB0aGlzIHdpbGwgYXBwbHkgdGhlIG1hc2sgYW5kIGFkZAogICAgIyB0aGUgY2FsY3VsYXRlZCBJUCBhcyBhbiBpbml0aWFsIHJlbW90ZSAod2hpbGUgd2Ugd2FpdCBmb3IgdGhlIHJlc3BvbnNlCiAgICAjIGZyb20gdGhlIGxpZ2h0aG91c2UpLiBCb3RoIENJRFJzIG11c3QgaGF2ZSB0aGUgc2FtZSBtYXNrIHNpemUuCiAgICAjIEZvciBleGFtcGxlLCBOZWJ1bGEgSVAgMTAuMC4xMC4xMjMgd2lsbCBoYXZlIGEgY2FsY3VsYXRlZCByZW1vdGUgb2YKICAgICMgMTkyLjE2OC4xLjEyMwogICAgIzEwLjAuMTAuMC8yNDoKICAgICAgIy0gbWFzazogMTkyLjE2OC4xLjAvMjQKICAgICAgIyAgcG9ydDogNDI0MgoKIyBQb3J0IE5lYnVsYSB3aWxsIGJlIGxpc3RlbmluZyBvbi4gVGhlIGRlZmF1bHQgaGVyZSBpcyA0MjQyLiBGb3IgYSBsaWdodGhvdXNlIG5vZGUsIHRoZSBwb3J0IHNob3VsZCBiZSBkZWZpbmVkLAojIGhvd2V2ZXIgdXNpbmcgcG9ydCAwIHdpbGwgZHluYW1pY2FsbHkgYXNzaWduIGEgcG9ydCBhbmQgaXMgcmVjb21tZW5kZWQgZm9yIHJvYW1pbmcgbm9kZXMuCmxpc3RlbjoKICAjIFRvIGxpc3RlbiBvbiBib3RoIGFueSBpcHY0IGFuZCBpcHY2IHVzZSAiOjoiCiAgaG9zdDogMC4wLjAuMAogIHBvcnQ6IDAKICAjIFNldHMgdGhlIG1heCBudW1iZXIgb2YgcGFja2V0cyB0byBwdWxsIGZyb20gdGhlIGtlcm5lbCBmb3IgZWFjaCBzeXNjYWxsICh1bmRlciBzeXN0ZW1zIHRoYXQgc3VwcG9ydCByZWN2bW1zZykKICAjIGRlZmF1bHQgaXMgNjQsIGRvZXMgbm90IHN1cHBvcnQgcmVsb2FkCiAgI2JhdGNoOiA2NAogICMgQ29uZmlndXJlIHNvY2tldCBidWZmZXJzIGZvciB0aGUgdWRwIHNpZGUgKG91dHNpZGUpLCBsZWF2ZSB1bnNldCB0byB1c2UgdGhlIHN5c3RlbSBkZWZhdWx0cy4gVmFsdWVzIHdpbGwgYmUgZG91YmxlZCBieSB0aGUga2VybmVsCiAgIyBEZWZhdWx0IGlzIG5ldC5jb3JlLnJtZW1fZGVmYXVsdCBhbmQgbmV0LmNvcmUud21lbV9kZWZhdWx0ICgvcHJvYy9zeXMvbmV0L2NvcmUvcm1lbV9kZWZhdWx0IGFuZCAvcHJvYy9zeXMvbmV0L2NvcmUvcm1lbV9kZWZhdWx0KQogICMgTWF4aW11bSBpcyBsaW1pdGVkIGJ5IG1lbW9yeSBpbiB0aGUgc3lzdGVtLCBTT19SQ1ZCVUZGT1JDRSBhbmQgU09fU05EQlVGRk9SQ0UgaXMgdXNlZCB0byBhdm9pZCBoYXZpbmcgdG8gcmFpc2UgdGhlIHN5c3RlbSB3aWRlCiAgIyBtYXgsIG5ldC5jb3JlLnJtZW1fbWF4IGFuZCBuZXQuY29yZS53bWVtX21heAogICNyZWFkX2J1ZmZlcjogMTA0ODU3NjAKICAjd3JpdGVfYnVmZmVyOiAxMDQ4NTc2MAogICMgQnkgZGVmYXVsdCwgTmVidWxhIHJlcGxpZXMgdG8gcGFja2V0cyBpdCBoYXMgbm8gdHVubmVsIGZvciB3aXRoIGEgInJlY3ZfZXJyb3IiIHBhY2tldC4gVGhpcyBwYWNrZXQgaGVscHMgc3BlZWQgdXAgcmVjb25uZWN0aW9uCiAgIyBpbiB0aGUgY2FzZSB0aGF0IE5lYnVsYSBvbiBlaXRoZXIgc2lkZSBkaWQgbm90IHNodXQgZG93biBjbGVhbmx5LiBUaGlzIHJlc3BvbnNlIGNhbiBiZSBhYnVzZWQgYXMgYSB3YXkgdG8gZGlzY292ZXIgaWYgTmVidWxhIGlzIHJ1bm5pbmcKICAjIG9uIGEgaG9zdCB0aG91Z2guIFRoaXMgb3B0aW9uIGxldHMgeW91IGNvbmZpZ3VyZSBpZiB5b3Ugd2FudCB0byBzZW5kICJyZWN2X2Vycm9yIiBwYWNrZXRzIGFsd2F5cywgbmV2ZXIsIG9yIG9ubHkgdG8gcHJpdmF0ZSBuZXR3b3JrIHJlbW90ZXMuCiAgIyB2YWxpZCB2YWx1ZXM6IGFsd2F5cywgbmV2ZXIsIHByaXZhdGUKICAjIFRoaXMgc2V0dGluZyBpcyByZWxvYWRhYmxlLgogICNzZW5kX3JlY3ZfZXJyb3I6IGFsd2F5cwoKIyBSb3V0aW5lcyBpcyB0aGUgbnVtYmVyIG9mIHRocmVhZCBwYWlycyB0byBydW4gdGhhdCBjb25zdW1lIGZyb20gdGhlIHR1biBhbmQgVURQIHF1ZXVlcy4KIyBDdXJyZW50bHksIHRoaXMgZGVmYXVsdHMgdG8gMSB3aGljaCBtZWFucyB3ZSBoYXZlIDEgdHVuIHF1ZXVlIHJlYWRlciBhbmQgMQojIFVEUCBxdWV1ZSByZWFkZXIuIFNldHRpbmcgdGhpcyBhYm92ZSBvbmUgd2lsbCBzZXQgSUZGX01VTFRJX1FVRVVFIG9uIHRoZSB0dW4KIyBkZXZpY2UgYW5kIFNPX1JFVVNFUE9SVCBvbiB0aGUgVURQIHNvY2tldCB0byBhbGxvdyBtdWx0aXBsZSBxdWV1ZXMuCiMgVGhpcyBvcHRpb24gaXMgb25seSBzdXBwb3J0ZWQgb24gTGludXguCiNyb3V0aW5lczogMQoKcHVuY2h5OgogICMgQ29udGludWVzIHRvIHB1bmNoIGluYm91bmQvb3V0Ym91bmQgYXQgYSByZWd1bGFyIGludGVydmFsIHRvIGF2b2lkIGV4cGlyYXRpb24gb2YgZmlyZXdhbGwgbmF0IG1hcHBpbmdzCiAgcHVuY2g6IHRydWUKCiAgIyByZXNwb25kIG1lYW5zIHRoYXQgYSBub2RlIHlvdSBhcmUgdHJ5aW5nIHRvIHJlYWNoIHdpbGwgY29ubmVjdCBiYWNrIG91dCB0byB5b3UgaWYgeW91ciBob2xlIHB1bmNoaW5nIGZhaWxzCiAgIyB0aGlzIGlzIGV4dHJlbWVseSB1c2VmdWwgaWYgb25lIG5vZGUgaXMgYmVoaW5kIGEgZGlmZmljdWx0IG5hdCwgc3VjaCBhcyBhIHN5bW1ldHJpYyBOQVQKICAjIERlZmF1bHQgaXMgZmFsc2UKICAjcmVzcG9uZDogdHJ1ZQoKICAjIGRlbGF5cyBhIHB1bmNoIHJlc3BvbnNlIGZvciBtaXNiZWhhdmluZyBOQVRzLCBkZWZhdWx0IGlzIDEgc2Vjb25kLgogICNkZWxheTogMXMKCiAgIyBzZXQgdGhlIGRlbGF5IGJlZm9yZSBhdHRlbXB0aW5nIHB1bmNoeS5yZXNwb25kLiBEZWZhdWx0IGlzIDUgc2Vjb25kcy4gcmVzcG9uZCBtdXN0IGJlIHRydWUgdG8gdGFrZSBlZmZlY3QuCiAgI3Jlc3BvbmRfZGVsYXk6IDVzCgojIENpcGhlciBhbGxvd3MgeW91IHRvIGNob29zZSBiZXR3ZWVuIHRoZSBhdmFpbGFibGUgY2lwaGVycyBmb3IgeW91ciBuZXR3b3JrLiBPcHRpb25zIGFyZSBjaGFjaGFwb2x5IG9yIGFlcwojIElNUE9SVEFOVDogdGhpcyB2YWx1ZSBtdXN0IGJlIGlkZW50aWNhbCBvbiBBTEwgTk9ERVMvTElHSFRIT1VTRVMuIFdlIGRvIG5vdC93aWxsIG5vdCBzdXBwb3J0IHVzZSBvZiBkaWZmZXJlbnQgY2lwaGVycyBzaW11bHRhbmVvdXNseSEKI2NpcGhlcjogYWVzCgojIFByZWZlcnJlZCByYW5nZXMgaXMgdXNlZCB0byBkZWZpbmUgYSBoaW50IGFib3V0IHRoZSBsb2NhbCBuZXR3b3JrIHJhbmdlcywgd2hpY2ggc3BlZWRzIHVwIGRpc2NvdmVyaW5nIHRoZSBmYXN0ZXN0CiMgcGF0aCB0byBhIG5ldHdvcmsgYWRqYWNlbnQgbmVidWxhIG5vZGUuCiMgTk9URTogdGhlIHByZXZpb3VzIG9wdGlvbiAibG9jYWxfcmFuZ2UiIG9ubHkgYWxsb3dlZCBkZWZpbml0aW9uIG9mIGEgc2luZ2xlIHJhbmdlCiMgYW5kIGhhcyBiZWVuIGRlcHJlY2F0ZWQgZm9yICJwcmVmZXJyZWRfcmFuZ2VzIgojcHJlZmVycmVkX3JhbmdlczogWyIxNzIuMTYuMC4wLzI0Il0KCiMgc3NoZCBjYW4gZXhwb3NlIGluZm9ybWF0aW9uYWwgYW5kIGFkbWluaXN0cmF0aXZlIGZ1bmN0aW9ucyB2aWEgc3NoIHRoaXMgaXMgYQojc3NoZDoKICAjIFRvZ2dsZXMgdGhlIGZlYXR1cmUKICAjZW5hYmxlZDogdHJ1ZQogICMgSG9zdCBhbmQgcG9ydCB0byBsaXN0ZW4gb24sIHBvcnQgMjIgaXMgbm90IGFsbG93ZWQgZm9yIHlvdXIgc2FmZXR5CiAgI2xpc3RlbjogMTI3LjAuMC4xOjIyMjIKICAjIEEgZmlsZSBjb250YWluaW5nIHRoZSBzc2ggaG9zdCBwcml2YXRlIGtleSB0byB1c2UKICAjIEEgZGVjZW50IHdheSB0byBnZW5lcmF0ZSBvbmU6IHNzaC1rZXlnZW4gLXQgZWQyNTUxOSAtZiBzc2hfaG9zdF9lZDI1NTE5X2tleSAtTiAiIiA8IC9kZXYvbnVsbAogICNob3N0X2tleTogLi9zc2hfaG9zdF9lZDI1NTE5X2tleQogICMgQSBmaWxlIGNvbnRhaW5pbmcgYSBsaXN0IG9mIGF1dGhvcml6ZWQgcHVibGljIGtleXMKICAjYXV0aG9yaXplZF91c2VyczoKICAgICMtIHVzZXI6IHN0ZWVlZXZlCiAgICAgICMga2V5cyBjYW4gYmUgYW4gYXJyYXkgb2Ygc3RyaW5ncyBvciBzaW5nbGUgc3RyaW5nCiAgICAgICNrZXlzOgogICAgICAgICMtICJzc2ggcHVibGljIGtleSBzdHJpbmciCgojIEVYUEVSSU1FTlRBTDogcmVsYXkgc3VwcG9ydCBmb3IgbmV0d29ya3MgdGhhdCBjYW4ndCBlc3RhYmxpc2ggZGlyZWN0IGNvbm5lY3Rpb25zLgpyZWxheToKICAjIFJlbGF5cyBhcmUgYSBsaXN0IG9mIE5lYnVsYSBJUCdzIHRoYXQgcGVlcnMgY2FuIHVzZSB0byByZWxheSBwYWNrZXRzIHRvIG1lLgogICMgSVBzIGluIHRoaXMgbGlzdCBtdXN0IGhhdmUgYW1fcmVsYXkgc2V0IHRvIHRydWUgaW4gdGhlaXIgY29uZmlncywgb3RoZXJ3aXNlCiAgIyB0aGV5IHdpbGwgcmVqZWN0IHJlbGF5IHJlcXVlc3RzLgogICNyZWxheXM6CiAgICAjLSAxOTIuMTY4LjEwMC4xCiAgICAjLSA8b3RoZXIgTmVidWxhIFZQTiBJUHMgb2YgaG9zdHMgdXNlZCBhcyByZWxheXMgdG8gYWNjZXNzIG1lPgogICMgU2V0IGFtX3JlbGF5IHRvIHRydWUgdG8gcGVybWl0IG90aGVyIGhvc3RzIHRvIGxpc3QgbXkgSVAgaW4gdGhlaXIgcmVsYXlzIGNvbmZpZy4gRGVmYXVsdCBmYWxzZS4KICBhbV9yZWxheTogZmFsc2UKICAjIFNldCB1c2VfcmVsYXlzIHRvIGZhbHNlIHRvIHByZXZlbnQgdGhpcyBpbnN0YW5jZSBmcm9tIGF0dGVtcHRpbmcgdG8gZXN0YWJsaXNoIGNvbm5lY3Rpb25zIHRocm91Z2ggcmVsYXlzLgogICMgZGVmYXVsdCB0cnVlCiAgdXNlX3JlbGF5czogdHJ1ZQoKIyBDb25maWd1cmUgdGhlIHByaXZhdGUgaW50ZXJmYWNlLiBOb3RlOiBhZGRyIGlzIGJha2VkIGludG8gdGhlIG5lYnVsYSBjZXJ0aWZpY2F0ZQp0dW46CiAgIyBXaGVuIHR1biBpcyBkaXNhYmxlZCwgYSBsaWdodGhvdXNlIGNhbiBiZSBzdGFydGVkIHdpdGhvdXQgYSBsb2NhbCB0dW4gaW50ZXJmYWNlIChhbmQgdGhlcmVmb3JlIHdpdGhvdXQgcm9vdCkKICBkaXNhYmxlZDogZmFsc2UKICAjIE5hbWUgb2YgdGhlIGRldmljZS4gSWYgbm90IHNldCwgYSBkZWZhdWx0IHdpbGwgYmUgY2hvc2VuIGJ5IHRoZSBPUy4KICAjIEZvciBtYWNPUzogaWYgc2V0LCBtdXN0IGJlIGluIHRoZSBmb3JtIGB1dHVuWzAtOV0rYC4KICBkZXY6IG5lYnVsYTEKICAjIFRvZ2dsZXMgZm9yd2FyZGluZyBvZiBsb2NhbCBicm9hZGNhc3QgcGFja2V0cywgdGhlIGFkZHJlc3Mgb2Ygd2hpY2ggZGVwZW5kcyBvbiB0aGUgaXAvbWFzayBlbmNvZGVkIGluIHBraS5jZXJ0CiAgZHJvcF9sb2NhbF9icm9hZGNhc3Q6IGZhbHNlCiAgIyBUb2dnbGVzIGZvcndhcmRpbmcgb2YgbXVsdGljYXN0IHBhY2tldHMKICBkcm9wX211bHRpY2FzdDogZmFsc2UKICAjIFNldHMgdGhlIHRyYW5zbWl0IHF1ZXVlIGxlbmd0aCwgaWYgeW91IG5vdGljZSBsb3RzIG9mIHRyYW5zbWl0IGRyb3BzIG9uIHRoZSB0dW4gaXQgbWF5IGhlbHAgdG8gcmFpc2UgdGhpcyBudW1iZXIuIERlZmF1bHQgaXMgNTAwCiAgdHhfcXVldWU6IDUwMAogICMgRGVmYXVsdCBNVFUgZm9yIGV2ZXJ5IHBhY2tldCwgc2FmZSBzZXR0aW5nIGlzIChhbmQgdGhlIGRlZmF1bHQpIDEzMDAgZm9yIGludGVybmV0IGJhc2VkIHRyYWZmaWMKICBtdHU6IDEzMDAKCiAgIyBSb3V0ZSBiYXNlZCBNVFUgb3ZlcnJpZGVzLCB5b3UgaGF2ZSBrbm93biB2cG4gaXAgcGF0aHMgdGhhdCBjYW4gc3VwcG9ydCBsYXJnZXIgTVRVcyB5b3UgY2FuIGluY3JlYXNlL2RlY3JlYXNlIHRoZW0gaGVyZQogIHJvdXRlczoKICAgICMtIG10dTogODgwMAogICAgIyAgcm91dGU6IDEwLjAuMC4wLzE2CgogICMgVW5zYWZlIHJvdXRlcyBhbGxvd3MgeW91IHRvIHJvdXRlIHRyYWZmaWMgb3ZlciBuZWJ1bGEgdG8gbm9uLW5lYnVsYSBub2RlcwogICMgVW5zYWZlIHJvdXRlcyBzaG91bGQgYmUgYXZvaWRlZCB1bmxlc3MgeW91IGhhdmUgaG9zdHMvc2VydmljZXMgdGhhdCBjYW5ub3QgcnVuIG5lYnVsYQogICMgTk9URTogVGhlIG5lYnVsYSBjZXJ0aWZpY2F0ZSBvZiB0aGUgInZpYSIgbm9kZSAqTVVTVCogaGF2ZSB0aGUgInJvdXRlIiBkZWZpbmVkIGFzIGEgc3VibmV0IGluIGl0cyBjZXJ0aWZpY2F0ZQogICMgYG10dWA6IHdpbGwgZGVmYXVsdCB0byB0dW4gbXR1IGlmIHRoaXMgb3B0aW9uIGlzIG5vdCBzcGVjaWZpZWQKICAjIGBtZXRyaWNgOiB3aWxsIGRlZmF1bHQgdG8gMCBpZiB0aGlzIG9wdGlvbiBpcyBub3Qgc3BlY2lmaWVkCiAgIyBgaW5zdGFsbGA6IHdpbGwgZGVmYXVsdCB0byB0cnVlLCBjb250cm9scyB3aGV0aGVyIHRoaXMgcm91dGUgaXMgaW5zdGFsbGVkIGluIHRoZSBzeXN0ZW1zIHJvdXRpbmcgdGFibGUuCiAgdW5zYWZlX3JvdXRlczoKICAgICMtIHJvdXRlOiAxNzIuMTYuMS4wLzI0CiAgICAjICB2aWE6IDE5Mi4xNjguMTAwLjk5CiAgICAjICBtdHU6IDEzMDAKICAgICMgIG1ldHJpYzogMTAwCiAgICAjICBpbnN0YWxsOiB0cnVlCgogICMgT24gbGludXggb25seSwgc2V0IHRvIHRydWUgdG8gbWFuYWdlIHVuc2FmZSByb3V0ZXMgZGlyZWN0bHkgb24gdGhlIHN5c3RlbSByb3V0ZSB0YWJsZSB3aXRoIGdhdGV3YXkgcm91dGVzIGluc3RlYWQgb2YKICAjIGluIG5lYnVsYSBjb25maWd1cmF0aW9uIGZpbGVzLiBEZWZhdWx0IGZhbHNlLCBub3QgcmVsb2FkYWJsZS4KICAjdXNlX3N5c3RlbV9yb3V0ZV90YWJsZTogZmFsc2UKCiMgVE9ETwojIENvbmZpZ3VyZSBsb2dnaW5nIGxldmVsCmxvZ2dpbmc6CiAgIyBwYW5pYywgZmF0YWwsIGVycm9yLCB3YXJuaW5nLCBpbmZvLCBvciBkZWJ1Zy4gRGVmYXVsdCBpcyBpbmZvCiAgbGV2ZWw6IGluZm8KICAjIGpzb24gb3IgdGV4dCBmb3JtYXRzIGN1cnJlbnRseSBhdmFpbGFibGUuIERlZmF1bHQgaXMgdGV4dAogIGZvcm1hdDogdGV4dAogICMgRGlzYWJsZSB0aW1lc3RhbXAgbG9nZ2luZy4gdXNlZnVsIHdoZW4gb3V0cHV0IGlzIHJlZGlyZWN0ZWQgdG8gbG9nZ2luZyBzeXN0ZW0gdGhhdCBhbHJlYWR5IGFkZHMgdGltZXN0YW1wcy4gRGVmYXVsdCBpcyBmYWxzZQogICNkaXNhYmxlX3RpbWVzdGFtcDogdHJ1ZQogICMgdGltZXN0YW1wIGZvcm1hdCBpcyBzcGVjaWZpZWQgaW4gR28gdGltZSBmb3JtYXQsIHNlZToKICAjICAgICBodHRwczovL2dvbGFuZy5vcmcvcGtnL3RpbWUvI3BrZy1jb25zdGFudHMKICAjIGRlZmF1bHQgd2hlbiBgZm9ybWF0OiBqc29uYDogIjIwMDYtMDEtMDJUMTU6MDQ6MDVaMDc6MDAiIChSRkMzMzM5KQogICMgZGVmYXVsdCB3aGVuIGBmb3JtYXQ6IHRleHRgOgogICMgICAgIHdoZW4gVFRZIGF0dGFjaGVkOiBzZWNvbmRzIHNpbmNlIGJlZ2lubmluZyBvZiBleGVjdXRpb24KICAjICAgICBvdGhlcndpc2U6ICIyMDA2LTAxLTAyVDE1OjA0OjA1WjA3OjAwIiAoUkZDMzMzOSkKICAjIEFzIGFuIGV4YW1wbGUsIHRvIGxvZyBhcyBSRkMzMzM5IHdpdGggbWlsbGlzZWNvbmQgcHJlY2lzaW9uLCBzZXQgdG86CiAgI3RpbWVzdGFtcF9mb3JtYXQ6ICIyMDA2LTAxLTAyVDE1OjA0OjA1LjAwMFowNzowMCIKCiNzdGF0czoKICAjdHlwZTogZ3JhcGhpdGUKICAjcHJlZml4OiBuZWJ1bGEKICAjcHJvdG9jb2w6IHRjcAogICNob3N0OiAxMjcuMC4wLjE6OTk5OQogICNpbnRlcnZhbDogMTBzCgogICN0eXBlOiBwcm9tZXRoZXVzCiAgI2xpc3RlbjogMTI3LjAuMC4xOjgwODAKICAjcGF0aDogL21ldHJpY3MKICAjbmFtZXNwYWNlOiBwcm9tZXRoZXVzbnMKICAjc3Vic3lzdGVtOiBuZWJ1bGEKICAjaW50ZXJ2YWw6IDEwcwoKICAjIGVuYWJsZXMgY291bnRlciBtZXRyaWNzIGZvciBtZXRhIHBhY2tldHMKICAjICAgZS5nLjogYG1lc3NhZ2VzLnR4LmhhbmRzaGFrZWAKICAjIE5PVEU6IGBtZXNzYWdlLnt0eCxyeH0ucmVjdl9lcnJvcmAgaXMgYWx3YXlzIGVtaXR0ZWQKICAjbWVzc2FnZV9tZXRyaWNzOiBmYWxzZQoKICAjIGVuYWJsZXMgZGV0YWlsZWQgY291bnRlciBtZXRyaWNzIGZvciBsaWdodGhvdXNlIHBhY2tldHMKICAjICAgZS5nLjogYGxpZ2h0aG91c2UucnguSG9zdFF1ZXJ5YAogICNsaWdodGhvdXNlX21ldHJpY3M6IGZhbHNlCgojIEhhbmRzaGFrZSBNYW5hZ2VyIFNldHRpbmdzCiNoYW5kc2hha2VzOgogICMgSGFuZHNoYWtlcyBhcmUgc2VudCB0byBhbGwga25vd24gYWRkcmVzc2VzIGF0IGVhY2ggaW50ZXJ2YWwgd2l0aCBhIGxpbmVhciBiYWNrb2ZmLAogICMgV2FpdCB0cnlfaW50ZXJ2YWwgYWZ0ZXIgdGhlIDFzdCBhdHRlbXB0LCAyICogdHJ5X2ludGVydmFsIGFmdGVyIHRoZSAybmQsIGV0YywgdW50aWwgdGhlIGhhbmRzaGFrZSBpcyBvbGRlciB0aGFuIHRpbWVvdXQKICAjIEEgMTAwbXMgaW50ZXJ2YWwgd2l0aCB0aGUgZGVmYXVsdCAxMCByZXRyaWVzIHdpbGwgZ2l2ZSBhIGhhbmRzaGFrZSA1LjUgc2Vjb25kcyB0byByZXNvbHZlIGJlZm9yZSB0aW1pbmcgb3V0CiAgI3RyeV9pbnRlcnZhbDogMTAwbXMKICAjcmV0cmllczogMjAKICAjIHRyaWdnZXJfYnVmZmVyIGlzIHRoZSBzaXplIG9mIHRoZSBidWZmZXIgY2hhbm5lbCBmb3IgcXVpY2tseSBzZW5kaW5nIGhhbmRzaGFrZXMKICAjIGFmdGVyIHJlY2VpdmluZyB0aGUgcmVzcG9uc2UgZm9yIGxpZ2h0aG91c2UgcXVlcmllcwogICN0cmlnZ2VyX2J1ZmZlcjogNjQKCgojIE5lYnVsYSBzZWN1cml0eSBncm91cCBjb25maWd1cmF0aW9uCmZpcmV3YWxsOgogICMgQWN0aW9uIHRvIHRha2Ugd2hlbiBhIHBhY2tldCBpcyBub3QgYWxsb3dlZCBieSB0aGUgZmlyZXdhbGwgcnVsZXMuCiAgIyBDYW4gYmUgb25lIG9mOgogICMgICBgZHJvcGAgKGRlZmF1bHQpOiBzaWxlbnRseSBkcm9wIHRoZSBwYWNrZXQuCiAgIyAgIGByZWplY3RgOiBzZW5kIGEgcmVqZWN0IHJlcGx5LgogICMgICAgIC0gRm9yIFRDUCwgdGhpcyB3aWxsIGJlIGEgUlNUICJDb25uZWN0aW9uIFJlc2V0IiBwYWNrZXQuCiAgIyAgICAgLSBGb3Igb3RoZXIgcHJvdG9jb2xzLCB0aGlzIHdpbGwgYmUgYW4gSUNNUCBwb3J0IHVucmVhY2hhYmxlIHBhY2tldC4KICBvdXRib3VuZF9hY3Rpb246IGRyb3AKICBpbmJvdW5kX2FjdGlvbjogZHJvcAoKICBjb25udHJhY2s6CiAgICB0Y3BfdGltZW91dDogMTJtCiAgICB1ZHBfdGltZW91dDogM20KICAgIGRlZmF1bHRfdGltZW91dDogMTBtCgogICMgVGhlIGZpcmV3YWxsIGlzIGRlZmF1bHQgZGVueS4gVGhlcmUgaXMgbm8gd2F5IHRvIHdyaXRlIGEgZGVueSBydWxlLgogICMgUnVsZXMgYXJlIGNvbXByaXNlZCBvZiBhIHByb3RvY29sLCBwb3J0LCBhbmQgb25lIG9yIG1vcmUgb2YgaG9zdCwgZ3JvdXAsIG9yIENJRFIKICAjIExvZ2ljYWwgZXZhbHVhdGlvbiBpcyByb3VnaGx5OiBwb3J0IEFORCBwcm90byBBTkQgKGNhX3NoYSBPUiBjYV9uYW1lKSBBTkQgKGhvc3QgT1IgZ3JvdXAgT1IgZ3JvdXBzIE9SIGNpZHIpCiAgIyAtIHBvcnQ6IFRha2VzIGAwYCBvciBgYW55YCBhcyBhbnksIGEgc2luZ2xlIG51bWJlciBgODBgLCBhIHJhbmdlIGAyMDAtOTAxYCwgb3IgYGZyYWdtZW50YCB0byBtYXRjaCBzZWNvbmQgYW5kIGZ1cnRoZXIgZnJhZ21lbnRzIG9mIGZyYWdtZW50ZWQgcGFja2V0cyAoc2luY2UgdGhlcmUgaXMgbm8gcG9ydCBhdmFpbGFibGUpLgogICMgICBjb2RlOiBzYW1lIGFzIHBvcnQgYnV0IG1ha2VzIG1vcmUgc2Vuc2Ugd2hlbiB0YWxraW5nIGFib3V0IElDTVAsIFRPRE86IHRoaXMgaXMgbm90IGN1cnJlbnRseSBpbXBsZW1lbnRlZCBpbiBhIHdheSB0aGF0IHdvcmtzLCB1c2UgYGFueWAKICAjICAgcHJvdG86IGBhbnlgLCBgdGNwYCwgYHVkcGAsIG9yIGBpY21wYAogICMgICBob3N0OiBgYW55YCBvciBhIGxpdGVyYWwgaG9zdG5hbWUsIGllIGB0ZXN0LWhvc3RgCiAgIyAgIGdyb3VwOiBgYW55YCBvciBhIGxpdGVyYWwgZ3JvdXAgbmFtZSwgaWUgYGRlZmF1bHQtZ3JvdXBgCiAgIyAgIGdyb3VwczogU2FtZSBhcyBncm91cCBidXQgYWNjZXB0cyBhIGxpc3Qgb2YgdmFsdWVzLiBNdWx0aXBsZSB2YWx1ZXMgYXJlIEFORCdkIHRvZ2V0aGVyIGFuZCBhIGNlcnRpZmljYXRlIHdvdWxkIGhhdmUgdG8gY29udGFpbiBhbGwgZ3JvdXBzIHRvIHBhc3MKICAjICAgY2lkcjogYSByZW1vdGUgQ0lEUiwgYDAuMC4wLjAvMGAgaXMgYW55LgogICMgICBsb2NhbF9jaWRyOiBhIGxvY2FsIENJRFIsIGAwLjAuMC4wLzBgIGlzIGFueS4gVGhpcyBjb3VsZCBiZSB1c2VkIHRvIGZpbHRlciBkZXN0aW5hdGlvbnMgd2hlbiB1c2luZyB1bnNhZmVfcm91dGVzLgogICMgICBjYV9uYW1lOiBBbiBpc3N1aW5nIENBIG5hbWUKICAjICAgY2Ffc2hhOiBBbiBpc3N1aW5nIENBIHNoYXN1bQoKICBvdXRib3VuZDoKICAgICMgQWxsb3cgYWxsIG91dGJvdW5kIHRyYWZmaWMgZnJvbSB0aGlzIG5vZGUKICAgIC0gcG9ydDogYW55CiAgICAgIHByb3RvOiBhbnkKICAgICAgaG9zdDogYW55CgogIGluYm91bmQ6CiAgICAjIEFsbG93IGljbXAgYmV0d2VlbiBhbnkgbmVidWxhIGhvc3RzCiAgICAtIHBvcnQ6IGFueQogICAgICBwcm90bzogaWNtcAogICAgICBob3N0OiBhbnkKCiAgICAjIEFsbG93IHNzaAogICAgLSBwb3J0OiAyMgogICAgICBwcm90bzogdGNwCiAgICAgIGhvc3Q6IGFueQoKICAgICMgQWxsb3cgdGNwLzQ0MyBmcm9tIGFueSBob3N0IHdpdGggQk9USCBsYXB0b3AgYW5kIGhvbWUgZ3JvdXAKICAgIC0gcG9ydDogNDQzCiAgICAgIHByb3RvOiB0Y3AKICAgICAgZ3JvdXBzOgogICAgICAgIC0gbGFwdG9wCiAgICAgICAgLSBob21l"
ansNebulaConfigEndpointDecode = base64.b64decode(ansNebulaEndpointConfig)
ansNebulaConfigEndpointDecode = ansNebulaConfigEndpointDecode.decode("utf-8")
ansNebulaEndpointConfig = open("ansible/playbooks/templates/nebula-endpoint.yml.j2", "w")
ansNebulaEndpointConfig.write(ansNebulaConfigEndpointDecode)
ansNebulaEndpointConfig.close()
# Write Nebula Lighthouse config template out to file from base64 version
# base64 of template to simplify storage
ansNebulaLighthouseConfig="IyBUaGlzIGlzIHRoZSBuZWJ1bGEgZXhhbXBsZSBjb25maWd1cmF0aW9uIGZpbGUuIFlvdSBtdXN0IGVkaXQsIGF0IGEgbWluaW11bSwgdGhlIHN0YXRpY19ob3N0X21hcCwgbGlnaHRob3VzZSwgYW5kIGZpcmV3YWxsIHNlY3Rpb25zCiMgU29tZSBvcHRpb25zIGluIHRoaXMgZmlsZSBhcmUgSFVQYWJsZSwgaW5jbHVkaW5nIHRoZSBwa2kgc2VjdGlvbi4gKEEgSFVQIHdpbGwgcmVsb2FkIGNyZWRlbnRpYWxzIGZyb20gZGlzayB3aXRob3V0IGFmZmVjdGluZyBleGlzdGluZyB0dW5uZWxzKQoKIyBQS0kgZGVmaW5lcyB0aGUgbG9jYXRpb24gb2YgY3JlZGVudGlhbHMgZm9yIHRoaXMgbm9kZS4gRWFjaCBvZiB0aGVzZSBjYW4gYWxzbyBiZSBpbmxpbmVkIGJ5IHVzaW5nIHRoZSB5YW1sICI6IHwiIHN5bnRheC4KcGtpOgogICMgVGhlIENBcyB0aGF0IGFyZSBhY2NlcHRlZCBieSB0aGlzIG5vZGUuIE11c3QgY29udGFpbiBvbmUgb3IgbW9yZSBjZXJ0aWZpY2F0ZXMgY3JlYXRlZCBieSAnbmVidWxhLWNlcnQgY2EnCiAgY2E6IC91c3IvbG9jYWwvYmluL25lYnVsYS9jYS5jcnQKICBjZXJ0OiAvdXNyL2xvY2FsL2Jpbi9uZWJ1bGEve3sgY2VydF9uYW1lIH19LmNydAogIGtleTogL3Vzci9sb2NhbC9iaW4vbmVidWxhL3t7IGNlcnRfbmFtZSB9fS5rZXkKICAjIGJsb2NrbGlzdCBpcyBhIGxpc3Qgb2YgY2VydGlmaWNhdGUgZmluZ2VycHJpbnRzIHRoYXQgd2Ugd2lsbCByZWZ1c2UgdG8gdGFsayB0bwogICNibG9ja2xpc3Q6CiAgIyAgLSBjOTlkNGU2NTA1MzNiOTIwNjFiMDk5MThlODM4YTVhMGE2YWFlZTIxZWVkMWQxMmZkOTM3NjgyODY1OTM2YzcyCiAgIyBkaXNjb25uZWN0X2ludmFsaWQgaXMgYSB0b2dnbGUgdG8gZm9yY2UgYSBjbGllbnQgdG8gYmUgZGlzY29ubmVjdGVkIGlmIHRoZSBjZXJ0aWZpY2F0ZSBpcyBleHBpcmVkIG9yIGludmFsaWQuCiAgI2Rpc2Nvbm5lY3RfaW52YWxpZDogZmFsc2UKCiMgVGhlIHN0YXRpYyBob3N0IG1hcCBkZWZpbmVzIGEgc2V0IG9mIGhvc3RzIHdpdGggZml4ZWQgSVAgYWRkcmVzc2VzIG9uIHRoZSBpbnRlcm5ldCAob3IgYW55IG5ldHdvcmspLgojIEEgaG9zdCBjYW4gaGF2ZSBtdWx0aXBsZSBmaXhlZCBJUCBhZGRyZXNzZXMgZGVmaW5lZCBoZXJlLCBhbmQgbmVidWxhIHdpbGwgdHJ5IGVhY2ggd2hlbiBlc3RhYmxpc2hpbmcgYSB0dW5uZWwuCiMgVGhlIHN5bnRheCBpczoKIyAgICJ7bmVidWxhIGlwfSI6IFsie3JvdXRhYmxlIGlwL2RucyBuYW1lfTp7cm91dGFibGUgcG9ydH0iXQojIEV4YW1wbGUsIGlmIHlvdXIgbGlnaHRob3VzZSBoYXMgdGhlIG5lYnVsYSBJUCBvZiAxOTIuMTY4LjEwMC4xIGFuZCBoYXMgdGhlIHJlYWwgaXAgYWRkcmVzcyBvZiAxMDAuNjQuMjIuMTEgYW5kIHJ1bnMgb24gcG9ydCA0MjQyOgpzdGF0aWNfaG9zdF9tYXA6CiAgInt7IGxpZ2h0aG91c2VfaXAgfX0iOiBbInt7IGxpZ2h0aG91c2VfaG9zdG5hbWUgfX06NDI0MiJdCgojIFRoZSBzdGF0aWNfbWFwIGNvbmZpZyBzdGFuemEgY2FuIGJlIHVzZWQgdG8gY29uZmlndXJlIGhvdyB0aGUgc3RhdGljX2hvc3RfbWFwIGJlaGF2ZXMuCiNzdGF0aWNfbWFwOgogICMgY2FkZW5jZSBkZXRlcm1pbmVzIGhvdyBmcmVxdWVudGx5IEROUyBpcyByZS1xdWVyaWVkIGZvciB1cGRhdGVkIElQIGFkZHJlc3NlcyB3aGVuIGEgc3RhdGljX2hvc3RfbWFwIGVudHJ5IGNvbnRhaW5zCiAgIyBhIEROUyBuYW1lLgogICNjYWRlbmNlOiAzMHMKCiAgIyBuZXR3b3JrIGRldGVybWluZXMgdGhlIHR5cGUgb2YgSVAgYWRkcmVzc2VzIHRvIGFzayB0aGUgRE5TIHNlcnZlciBmb3IuIFRoZSBkZWZhdWx0IGlzICJpcDQiIGJlY2F1c2Ugbm9kZXMgdHlwaWNhbGx5CiAgIyBkbyBub3Qga25vdyB0aGVpciBwdWJsaWMgSVB2NCBhZGRyZXNzLiBDb25uZWN0aW5nIHRvIHRoZSBMaWdodGhvdXNlIHZpYSBJUHY0IGFsbG93cyB0aGUgTGlnaHRob3VzZSB0byBkZXRlY3QgdGhlCiAgIyBwdWJsaWMgYWRkcmVzcy4gT3RoZXIgdmFsaWQgb3B0aW9ucyBhcmUgImlwNiIgYW5kICJpcCIgKHJldHVybnMgYm90aC4pCiAgI25ldHdvcms6IGlwNAoKICAjIGxvb2t1cF90aW1lb3V0IGlzIHRoZSBETlMgcXVlcnkgdGltZW91dC4KICAjbG9va3VwX3RpbWVvdXQ6IDI1MG1zCgpsaWdodGhvdXNlOgogICMgYW1fbGlnaHRob3VzZSBpcyB1c2VkIHRvIGVuYWJsZSBsaWdodGhvdXNlIGZ1bmN0aW9uYWxpdHkgZm9yIGEgbm9kZS4gVGhpcyBzaG91bGQgT05MWSBiZSB0cnVlIG9uIG5vZGVzCiAgIyB5b3UgaGF2ZSBjb25maWd1cmVkIHRvIGJlIGxpZ2h0aG91c2VzIGluIHlvdXIgbmV0d29yawogIGFtX2xpZ2h0aG91c2U6IHRydWUKICAjIHNlcnZlX2RucyBvcHRpb25hbGx5IHN0YXJ0cyBhIGRucyBsaXN0ZW5lciB0aGF0IHJlc3BvbmRzIHRvIHZhcmlvdXMgcXVlcmllcyBhbmQgY2FuIGV2ZW4gYmUKICAjIGRlbGVnYXRlZCB0byBmb3IgcmVzb2x1dGlvbgogICNzZXJ2ZV9kbnM6IGZhbHNlCiAgI2RuczoKICAgICMgVGhlIEROUyBob3N0IGRlZmluZXMgdGhlIElQIHRvIGJpbmQgdGhlIGRucyBsaXN0ZW5lciB0by4gVGhpcyBhbHNvIGFsbG93cyBiaW5kaW5nIHRvIHRoZSBuZWJ1bGEgbm9kZSBJUC4KICAgICNob3N0OiAwLjAuMC4wCiAgICAjcG9ydDogNTMKICAjIGludGVydmFsIGlzIHRoZSBudW1iZXIgb2Ygc2Vjb25kcyBiZXR3ZWVuIHVwZGF0ZXMgZnJvbSB0aGlzIG5vZGUgdG8gYSBsaWdodGhvdXNlLgogICMgZHVyaW5nIHVwZGF0ZXMsIGEgbm9kZSBzZW5kcyBpbmZvcm1hdGlvbiBhYm91dCBpdHMgY3VycmVudCBJUCBhZGRyZXNzZXMgdG8gZWFjaCBub2RlLgogIGludGVydmFsOiA2MAogICMgaG9zdHMgaXMgYSBsaXN0IG9mIGxpZ2h0aG91c2UgaG9zdHMgdGhpcyBub2RlIHNob3VsZCByZXBvcnQgdG8gYW5kIHF1ZXJ5IGZyb20KICAjIElNUE9SVEFOVDogVEhJUyBTSE9VTEQgQkUgRU1QVFkgT04gTElHSFRIT1VTRSBOT0RFUwogICMgSU1QT1JUQU5UMjogVEhJUyBTSE9VTEQgQkUgTElHSFRIT1VTRVMnIE5FQlVMQSBJUHMsIE5PVCBMSUdIVEhPVVNFUycgUkVBTCBST1VUQUJMRSBJUHMKICBob3N0czoKICAgIC0gInt7IGxpZ2h0aG91c2VfaXAgfX0iCgogICMgcmVtb3RlX2FsbG93X2xpc3QgYWxsb3dzIHlvdSB0byBjb250cm9sIGlwIHJhbmdlcyB0aGF0IHRoaXMgbm9kZSB3aWxsCiAgIyBjb25zaWRlciB3aGVuIGhhbmRzaGFraW5nIHRvIGFub3RoZXIgbm9kZS4gQnkgZGVmYXVsdCwgYW55IHJlbW90ZSBJUHMgYXJlCiAgIyBhbGxvd2VkLiBZb3UgY2FuIHByb3ZpZGUgQ0lEUnMgaGVyZSB3aXRoIGB0cnVlYCB0byBhbGxvdyBhbmQgYGZhbHNlYCB0bwogICMgZGVueS4gVGhlIG1vc3Qgc3BlY2lmaWMgQ0lEUiBydWxlIGFwcGxpZXMgdG8gZWFjaCByZW1vdGUuIElmIGFsbCBydWxlcyBhcmUKICAjICJhbGxvdyIsIHRoZSBkZWZhdWx0IHdpbGwgYmUgImRlbnkiLCBhbmQgdmljZS12ZXJzYS4gSWYgYm90aCAiYWxsb3ciIGFuZAogICMgImRlbnkiIElQdjQgcnVsZXMgYXJlIHByZXNlbnQsIHRoZW4geW91IE1VU1Qgc2V0IGEgcnVsZSBmb3IgIjAuMC4wLjAvMCIgYXMKICAjIHRoZSBkZWZhdWx0LiBTaW1pbGFybHkgaWYgYm90aCAiYWxsb3ciIGFuZCAiZGVueSIgSVB2NiBydWxlcyBhcmUgcHJlc2VudCwKICAjIHRoZW4geW91IE1VU1Qgc2V0IGEgcnVsZSBmb3IgIjo6LzAiIGFzIHRoZSBkZWZhdWx0LgogICNyZW1vdGVfYWxsb3dfbGlzdDoKICAgICMgRXhhbXBsZSB0byBibG9jayBJUHMgZnJvbSB0aGlzIHN1Ym5ldCBmcm9tIGJlaW5nIHVzZWQgZm9yIHJlbW90ZSBJUHMuCiAgICAjIjE3Mi4xNi4wLjAvMTIiOiBmYWxzZQoKICAgICMgQSBtb3JlIGNvbXBsaWNhdGVkIGV4YW1wbGUsIGFsbG93IHB1YmxpYyBJUHMgYnV0IG9ubHkgcHJpdmF0ZSBJUHMgZnJvbSBhIHNwZWNpZmljIHN1Ym5ldAogICAgIyIwLjAuMC4wLzAiOiB0cnVlCiAgICAjIjEwLjAuMC4wLzgiOiBmYWxzZQogICAgIyIxMC40Mi40Mi4wLzI0IjogdHJ1ZQoKICAjIEVYUEVSSU1FTlRBTDogVGhpcyBvcHRpb24gbWF5IGNoYW5nZSBvciBkaXNhcHBlYXIgaW4gdGhlIGZ1dHVyZS4KICAjIE9wdGlvbmFsbHkgYWxsb3dzIHRoZSBkZWZpbml0aW9uIG9mIHJlbW90ZV9hbGxvd19saXN0IGJsb2NrcwogICMgc3BlY2lmaWMgdG8gYW4gaW5zaWRlIFZQTiBJUCBDSURSLgogICNyZW1vdGVfYWxsb3dfcmFuZ2VzOgogICAgIyBUaGlzIHJ1bGUgd291bGQgb25seSBhbGxvdyBvbmx5IHByaXZhdGUgSVBzIGZvciB0aGlzIFZQTiByYW5nZQogICAgIyIxMC40Mi40Mi4wLzI0IjoKICAgICAgIyIxOTIuMTY4LjAuMC8xNiI6IHRydWUKCiAgIyBsb2NhbF9hbGxvd19saXN0IGFsbG93cyB5b3UgdG8gZmlsdGVyIHdoaWNoIGxvY2FsIElQIGFkZHJlc3NlcyB3ZSBhZHZlcnRpc2UKICAjIHRvIHRoZSBsaWdodGhvdXNlcy4gVGhpcyB1c2VzIHRoZSBzYW1lIGxvZ2ljIGFzIGByZW1vdGVfYWxsb3dfbGlzdGAsIGJ1dAogICMgYWRkaXRpb25hbGx5LCB5b3UgY2FuIHNwZWNpZnkgYW4gYGludGVyZmFjZXNgIG1hcCBvZiByZWd1bGFyIGV4cHJlc3Npb25zCiAgIyB0byBtYXRjaCBhZ2FpbnN0IGludGVyZmFjZSBuYW1lcy4gVGhlIHJlZ2V4cCBtdXN0IG1hdGNoIHRoZSBlbnRpcmUgbmFtZS4KICAjIEFsbCBpbnRlcmZhY2UgcnVsZXMgbXVzdCBiZSBlaXRoZXIgdHJ1ZSBvciBmYWxzZSAoYW5kIHRoZSBkZWZhdWx0IHdpbGwgYmUKICAjIHRoZSBpbnZlcnNlKS4gQ0lEUiBydWxlcyBhcmUgbWF0Y2hlZCBhZnRlciBpbnRlcmZhY2UgbmFtZSBydWxlcy4KICAjIERlZmF1bHQgaXMgYWxsIGxvY2FsIElQIGFkZHJlc3Nlcy4KICAjbG9jYWxfYWxsb3dfbGlzdDoKICAgICMgRXhhbXBsZSB0byBibG9jayB0dW4wIGFuZCBhbGwgZG9ja2VyIGludGVyZmFjZXMuCiAgICAjaW50ZXJmYWNlczoKICAgICAgI3R1bjA6IGZhbHNlCiAgICAgICMnZG9ja2VyLionOiBmYWxzZQogICAgIyBFeGFtcGxlIHRvIG9ubHkgYWR2ZXJ0aXNlIHRoaXMgc3VibmV0IHRvIHRoZSBsaWdodGhvdXNlLgogICAgIyIxMC4wLjAuMC84IjogdHJ1ZQoKICAjIGFkdmVydGlzZV9hZGRycyBhcmUgcm91dGFibGUgYWRkcmVzc2VzIHRoYXQgd2lsbCBiZSBpbmNsdWRlZCBhbG9uZyB3aXRoIGRpc2NvdmVyZWQgYWRkcmVzc2VzIHRvIHJlcG9ydCB0byB0aGUKICAjIGxpZ2h0aG91c2UsIHRoZSBmb3JtYXQgaXMgImlwOnBvcnQiLiBgcG9ydGAgY2FuIGJlIGAwYCwgaW4gd2hpY2ggY2FzZSB0aGUgYWN0dWFsIGxpc3RlbmluZyBwb3J0IHdpbGwgYmUgdXNlZCBpbiBpdHMKICAjIHBsYWNlLCB1c2VmdWwgaWYgYGxpc3Rlbi5wb3J0YCBpcyBzZXQgdG8gMC4KICAjIFRoaXMgb3B0aW9uIGlzIG1haW5seSB1c2VmdWwgd2hlbiB0aGVyZSBhcmUgc3RhdGljIGlwIGFkZHJlc3NlcyB0aGUgaG9zdCBjYW4gYmUgcmVhY2hlZCBhdCB0aGF0IG5lYnVsYSBjYW4gbm90CiAgIyB0eXBpY2FsbHkgZGlzY292ZXIgb24gaXRzIG93bi4gRXhhbXBsZXMgYmVpbmcgcG9ydCBmb3J3YXJkaW5nIG9yIG11bHRpcGxlIHBhdGhzIHRvIHRoZSBpbnRlcm5ldC4KICAjYWR2ZXJ0aXNlX2FkZHJzOgogICAgIy0gIjEuMS4xLjE6NDI0MiIKICAgICMtICIxLjIuMy40OjAiICMgcG9ydCB3aWxsIGJlIHJlcGxhY2VkIHdpdGggdGhlIHJlYWwgbGlzdGVuaW5nIHBvcnQKCiAgIyBFWFBFUklNRU5UQUw6IFRoaXMgb3B0aW9uIG1heSBjaGFuZ2Ugb3IgZGlzYXBwZWFyIGluIHRoZSBmdXR1cmUuCiAgIyBUaGlzIHNldHRpbmcgYWxsb3dzIHVzIHRvICJndWVzcyIgd2hhdCB0aGUgcmVtb3RlIG1pZ2h0IGJlIGZvciBhIGhvc3QKICAjIHdoaWxlIHdlIHdhaXQgZm9yIHRoZSBsaWdodGhvdXNlIHJlc3BvbnNlLgogICNjYWxjdWxhdGVkX3JlbW90ZXM6CiAgICAjIEZvciBhbnkgTmVidWxhIElQcyBpbiAxMC4wLjEwLjAvMjQsIHRoaXMgd2lsbCBhcHBseSB0aGUgbWFzayBhbmQgYWRkCiAgICAjIHRoZSBjYWxjdWxhdGVkIElQIGFzIGFuIGluaXRpYWwgcmVtb3RlICh3aGlsZSB3ZSB3YWl0IGZvciB0aGUgcmVzcG9uc2UKICAgICMgZnJvbSB0aGUgbGlnaHRob3VzZSkuIEJvdGggQ0lEUnMgbXVzdCBoYXZlIHRoZSBzYW1lIG1hc2sgc2l6ZS4KICAgICMgRm9yIGV4YW1wbGUsIE5lYnVsYSBJUCAxMC4wLjEwLjEyMyB3aWxsIGhhdmUgYSBjYWxjdWxhdGVkIHJlbW90ZSBvZgogICAgIyAxOTIuMTY4LjEuMTIzCiAgICAjMTAuMC4xMC4wLzI0OgogICAgICAjLSBtYXNrOiAxOTIuMTY4LjEuMC8yNAogICAgICAjICBwb3J0OiA0MjQyCgojIFBvcnQgTmVidWxhIHdpbGwgYmUgbGlzdGVuaW5nIG9uLiBUaGUgZGVmYXVsdCBoZXJlIGlzIDQyNDIuIEZvciBhIGxpZ2h0aG91c2Ugbm9kZSwgdGhlIHBvcnQgc2hvdWxkIGJlIGRlZmluZWQsCiMgaG93ZXZlciB1c2luZyBwb3J0IDAgd2lsbCBkeW5hbWljYWxseSBhc3NpZ24gYSBwb3J0IGFuZCBpcyByZWNvbW1lbmRlZCBmb3Igcm9hbWluZyBub2Rlcy4KbGlzdGVuOgogICMgVG8gbGlzdGVuIG9uIGJvdGggYW55IGlwdjQgYW5kIGlwdjYgdXNlICI6OiIKICBob3N0OiAwLjAuMC4wCiAgcG9ydDogNDI0MgogICMgU2V0cyB0aGUgbWF4IG51bWJlciBvZiBwYWNrZXRzIHRvIHB1bGwgZnJvbSB0aGUga2VybmVsIGZvciBlYWNoIHN5c2NhbGwgKHVuZGVyIHN5c3RlbXMgdGhhdCBzdXBwb3J0IHJlY3ZtbXNnKQogICMgZGVmYXVsdCBpcyA2NCwgZG9lcyBub3Qgc3VwcG9ydCByZWxvYWQKICAjYmF0Y2g6IDY0CiAgIyBDb25maWd1cmUgc29ja2V0IGJ1ZmZlcnMgZm9yIHRoZSB1ZHAgc2lkZSAob3V0c2lkZSksIGxlYXZlIHVuc2V0IHRvIHVzZSB0aGUgc3lzdGVtIGRlZmF1bHRzLiBWYWx1ZXMgd2lsbCBiZSBkb3VibGVkIGJ5IHRoZSBrZXJuZWwKICAjIERlZmF1bHQgaXMgbmV0LmNvcmUucm1lbV9kZWZhdWx0IGFuZCBuZXQuY29yZS53bWVtX2RlZmF1bHQgKC9wcm9jL3N5cy9uZXQvY29yZS9ybWVtX2RlZmF1bHQgYW5kIC9wcm9jL3N5cy9uZXQvY29yZS9ybWVtX2RlZmF1bHQpCiAgIyBNYXhpbXVtIGlzIGxpbWl0ZWQgYnkgbWVtb3J5IGluIHRoZSBzeXN0ZW0sIFNPX1JDVkJVRkZPUkNFIGFuZCBTT19TTkRCVUZGT1JDRSBpcyB1c2VkIHRvIGF2b2lkIGhhdmluZyB0byByYWlzZSB0aGUgc3lzdGVtIHdpZGUKICAjIG1heCwgbmV0LmNvcmUucm1lbV9tYXggYW5kIG5ldC5jb3JlLndtZW1fbWF4CiAgI3JlYWRfYnVmZmVyOiAxMDQ4NTc2MAogICN3cml0ZV9idWZmZXI6IDEwNDg1NzYwCiAgIyBCeSBkZWZhdWx0LCBOZWJ1bGEgcmVwbGllcyB0byBwYWNrZXRzIGl0IGhhcyBubyB0dW5uZWwgZm9yIHdpdGggYSAicmVjdl9lcnJvciIgcGFja2V0LiBUaGlzIHBhY2tldCBoZWxwcyBzcGVlZCB1cCByZWNvbm5lY3Rpb24KICAjIGluIHRoZSBjYXNlIHRoYXQgTmVidWxhIG9uIGVpdGhlciBzaWRlIGRpZCBub3Qgc2h1dCBkb3duIGNsZWFubHkuIFRoaXMgcmVzcG9uc2UgY2FuIGJlIGFidXNlZCBhcyBhIHdheSB0byBkaXNjb3ZlciBpZiBOZWJ1bGEgaXMgcnVubmluZwogICMgb24gYSBob3N0IHRob3VnaC4gVGhpcyBvcHRpb24gbGV0cyB5b3UgY29uZmlndXJlIGlmIHlvdSB3YW50IHRvIHNlbmQgInJlY3ZfZXJyb3IiIHBhY2tldHMgYWx3YXlzLCBuZXZlciwgb3Igb25seSB0byBwcml2YXRlIG5ldHdvcmsgcmVtb3Rlcy4KICAjIHZhbGlkIHZhbHVlczogYWx3YXlzLCBuZXZlciwgcHJpdmF0ZQogICMgVGhpcyBzZXR0aW5nIGlzIHJlbG9hZGFibGUuCiAgI3NlbmRfcmVjdl9lcnJvcjogYWx3YXlzCgojIFJvdXRpbmVzIGlzIHRoZSBudW1iZXIgb2YgdGhyZWFkIHBhaXJzIHRvIHJ1biB0aGF0IGNvbnN1bWUgZnJvbSB0aGUgdHVuIGFuZCBVRFAgcXVldWVzLgojIEN1cnJlbnRseSwgdGhpcyBkZWZhdWx0cyB0byAxIHdoaWNoIG1lYW5zIHdlIGhhdmUgMSB0dW4gcXVldWUgcmVhZGVyIGFuZCAxCiMgVURQIHF1ZXVlIHJlYWRlci4gU2V0dGluZyB0aGlzIGFib3ZlIG9uZSB3aWxsIHNldCBJRkZfTVVMVElfUVVFVUUgb24gdGhlIHR1bgojIGRldmljZSBhbmQgU09fUkVVU0VQT1JUIG9uIHRoZSBVRFAgc29ja2V0IHRvIGFsbG93IG11bHRpcGxlIHF1ZXVlcy4KIyBUaGlzIG9wdGlvbiBpcyBvbmx5IHN1cHBvcnRlZCBvbiBMaW51eC4KI3JvdXRpbmVzOiAxCgpwdW5jaHk6CiAgIyBDb250aW51ZXMgdG8gcHVuY2ggaW5ib3VuZC9vdXRib3VuZCBhdCBhIHJlZ3VsYXIgaW50ZXJ2YWwgdG8gYXZvaWQgZXhwaXJhdGlvbiBvZiBmaXJld2FsbCBuYXQgbWFwcGluZ3MKICBwdW5jaDogdHJ1ZQoKICAjIHJlc3BvbmQgbWVhbnMgdGhhdCBhIG5vZGUgeW91IGFyZSB0cnlpbmcgdG8gcmVhY2ggd2lsbCBjb25uZWN0IGJhY2sgb3V0IHRvIHlvdSBpZiB5b3VyIGhvbGUgcHVuY2hpbmcgZmFpbHMKICAjIHRoaXMgaXMgZXh0cmVtZWx5IHVzZWZ1bCBpZiBvbmUgbm9kZSBpcyBiZWhpbmQgYSBkaWZmaWN1bHQgbmF0LCBzdWNoIGFzIGEgc3ltbWV0cmljIE5BVAogICMgRGVmYXVsdCBpcyBmYWxzZQogICNyZXNwb25kOiB0cnVlCgogICMgZGVsYXlzIGEgcHVuY2ggcmVzcG9uc2UgZm9yIG1pc2JlaGF2aW5nIE5BVHMsIGRlZmF1bHQgaXMgMSBzZWNvbmQuCiAgI2RlbGF5OiAxcwoKICAjIHNldCB0aGUgZGVsYXkgYmVmb3JlIGF0dGVtcHRpbmcgcHVuY2h5LnJlc3BvbmQuIERlZmF1bHQgaXMgNSBzZWNvbmRzLiByZXNwb25kIG11c3QgYmUgdHJ1ZSB0byB0YWtlIGVmZmVjdC4KICAjcmVzcG9uZF9kZWxheTogNXMKCiMgQ2lwaGVyIGFsbG93cyB5b3UgdG8gY2hvb3NlIGJldHdlZW4gdGhlIGF2YWlsYWJsZSBjaXBoZXJzIGZvciB5b3VyIG5ldHdvcmsuIE9wdGlvbnMgYXJlIGNoYWNoYXBvbHkgb3IgYWVzCiMgSU1QT1JUQU5UOiB0aGlzIHZhbHVlIG11c3QgYmUgaWRlbnRpY2FsIG9uIEFMTCBOT0RFUy9MSUdIVEhPVVNFUy4gV2UgZG8gbm90L3dpbGwgbm90IHN1cHBvcnQgdXNlIG9mIGRpZmZlcmVudCBjaXBoZXJzIHNpbXVsdGFuZW91c2x5IQojY2lwaGVyOiBhZXMKCiMgUHJlZmVycmVkIHJhbmdlcyBpcyB1c2VkIHRvIGRlZmluZSBhIGhpbnQgYWJvdXQgdGhlIGxvY2FsIG5ldHdvcmsgcmFuZ2VzLCB3aGljaCBzcGVlZHMgdXAgZGlzY292ZXJpbmcgdGhlIGZhc3Rlc3QKIyBwYXRoIHRvIGEgbmV0d29yayBhZGphY2VudCBuZWJ1bGEgbm9kZS4KIyBOT1RFOiB0aGUgcHJldmlvdXMgb3B0aW9uICJsb2NhbF9yYW5nZSIgb25seSBhbGxvd2VkIGRlZmluaXRpb24gb2YgYSBzaW5nbGUgcmFuZ2UKIyBhbmQgaGFzIGJlZW4gZGVwcmVjYXRlZCBmb3IgInByZWZlcnJlZF9yYW5nZXMiCiNwcmVmZXJyZWRfcmFuZ2VzOiBbIjE3Mi4xNi4wLjAvMjQiXQoKIyBzc2hkIGNhbiBleHBvc2UgaW5mb3JtYXRpb25hbCBhbmQgYWRtaW5pc3RyYXRpdmUgZnVuY3Rpb25zIHZpYSBzc2ggdGhpcyBpcyBhCiNzc2hkOgogICMgVG9nZ2xlcyB0aGUgZmVhdHVyZQogICNlbmFibGVkOiB0cnVlCiAgIyBIb3N0IGFuZCBwb3J0IHRvIGxpc3RlbiBvbiwgcG9ydCAyMiBpcyBub3QgYWxsb3dlZCBmb3IgeW91ciBzYWZldHkKICAjbGlzdGVuOiAxMjcuMC4wLjE6MjIyMgogICMgQSBmaWxlIGNvbnRhaW5pbmcgdGhlIHNzaCBob3N0IHByaXZhdGUga2V5IHRvIHVzZQogICMgQSBkZWNlbnQgd2F5IHRvIGdlbmVyYXRlIG9uZTogc3NoLWtleWdlbiAtdCBlZDI1NTE5IC1mIHNzaF9ob3N0X2VkMjU1MTlfa2V5IC1OICIiIDwgL2Rldi9udWxsCiAgI2hvc3Rfa2V5OiAuL3NzaF9ob3N0X2VkMjU1MTlfa2V5CiAgIyBBIGZpbGUgY29udGFpbmluZyBhIGxpc3Qgb2YgYXV0aG9yaXplZCBwdWJsaWMga2V5cwogICNhdXRob3JpemVkX3VzZXJzOgogICAgIy0gdXNlcjogc3RlZWVldmUKICAgICAgIyBrZXlzIGNhbiBiZSBhbiBhcnJheSBvZiBzdHJpbmdzIG9yIHNpbmdsZSBzdHJpbmcKICAgICAgI2tleXM6CiAgICAgICAgIy0gInNzaCBwdWJsaWMga2V5IHN0cmluZyIKCiMgRVhQRVJJTUVOVEFMOiByZWxheSBzdXBwb3J0IGZvciBuZXR3b3JrcyB0aGF0IGNhbid0IGVzdGFibGlzaCBkaXJlY3QgY29ubmVjdGlvbnMuCnJlbGF5OgogICMgUmVsYXlzIGFyZSBhIGxpc3Qgb2YgTmVidWxhIElQJ3MgdGhhdCBwZWVycyBjYW4gdXNlIHRvIHJlbGF5IHBhY2tldHMgdG8gbWUuCiAgIyBJUHMgaW4gdGhpcyBsaXN0IG11c3QgaGF2ZSBhbV9yZWxheSBzZXQgdG8gdHJ1ZSBpbiB0aGVpciBjb25maWdzLCBvdGhlcndpc2UKICAjIHRoZXkgd2lsbCByZWplY3QgcmVsYXkgcmVxdWVzdHMuCiAgI3JlbGF5czoKICAgICMtIDE5Mi4xNjguMTAwLjEKICAgICMtIDxvdGhlciBOZWJ1bGEgVlBOIElQcyBvZiBob3N0cyB1c2VkIGFzIHJlbGF5cyB0byBhY2Nlc3MgbWU+CiAgIyBTZXQgYW1fcmVsYXkgdG8gdHJ1ZSB0byBwZXJtaXQgb3RoZXIgaG9zdHMgdG8gbGlzdCBteSBJUCBpbiB0aGVpciByZWxheXMgY29uZmlnLiBEZWZhdWx0IGZhbHNlLgogIGFtX3JlbGF5OiBmYWxzZQogICMgU2V0IHVzZV9yZWxheXMgdG8gZmFsc2UgdG8gcHJldmVudCB0aGlzIGluc3RhbmNlIGZyb20gYXR0ZW1wdGluZyB0byBlc3RhYmxpc2ggY29ubmVjdGlvbnMgdGhyb3VnaCByZWxheXMuCiAgIyBkZWZhdWx0IHRydWUKICB1c2VfcmVsYXlzOiB0cnVlCgojIENvbmZpZ3VyZSB0aGUgcHJpdmF0ZSBpbnRlcmZhY2UuIE5vdGU6IGFkZHIgaXMgYmFrZWQgaW50byB0aGUgbmVidWxhIGNlcnRpZmljYXRlCnR1bjoKICAjIFdoZW4gdHVuIGlzIGRpc2FibGVkLCBhIGxpZ2h0aG91c2UgY2FuIGJlIHN0YXJ0ZWQgd2l0aG91dCBhIGxvY2FsIHR1biBpbnRlcmZhY2UgKGFuZCB0aGVyZWZvcmUgd2l0aG91dCByb290KQogIGRpc2FibGVkOiBmYWxzZQogICMgTmFtZSBvZiB0aGUgZGV2aWNlLiBJZiBub3Qgc2V0LCBhIGRlZmF1bHQgd2lsbCBiZSBjaG9zZW4gYnkgdGhlIE9TLgogICMgRm9yIG1hY09TOiBpZiBzZXQsIG11c3QgYmUgaW4gdGhlIGZvcm0gYHV0dW5bMC05XStgLgogIGRldjogbmVidWxhMQogICMgVG9nZ2xlcyBmb3J3YXJkaW5nIG9mIGxvY2FsIGJyb2FkY2FzdCBwYWNrZXRzLCB0aGUgYWRkcmVzcyBvZiB3aGljaCBkZXBlbmRzIG9uIHRoZSBpcC9tYXNrIGVuY29kZWQgaW4gcGtpLmNlcnQKICBkcm9wX2xvY2FsX2Jyb2FkY2FzdDogZmFsc2UKICAjIFRvZ2dsZXMgZm9yd2FyZGluZyBvZiBtdWx0aWNhc3QgcGFja2V0cwogIGRyb3BfbXVsdGljYXN0OiBmYWxzZQogICMgU2V0cyB0aGUgdHJhbnNtaXQgcXVldWUgbGVuZ3RoLCBpZiB5b3Ugbm90aWNlIGxvdHMgb2YgdHJhbnNtaXQgZHJvcHMgb24gdGhlIHR1biBpdCBtYXkgaGVscCB0byByYWlzZSB0aGlzIG51bWJlci4gRGVmYXVsdCBpcyA1MDAKICB0eF9xdWV1ZTogNTAwCiAgIyBEZWZhdWx0IE1UVSBmb3IgZXZlcnkgcGFja2V0LCBzYWZlIHNldHRpbmcgaXMgKGFuZCB0aGUgZGVmYXVsdCkgMTMwMCBmb3IgaW50ZXJuZXQgYmFzZWQgdHJhZmZpYwogIG10dTogMTMwMAoKICAjIFJvdXRlIGJhc2VkIE1UVSBvdmVycmlkZXMsIHlvdSBoYXZlIGtub3duIHZwbiBpcCBwYXRocyB0aGF0IGNhbiBzdXBwb3J0IGxhcmdlciBNVFVzIHlvdSBjYW4gaW5jcmVhc2UvZGVjcmVhc2UgdGhlbSBoZXJlCiAgcm91dGVzOgogICAgIy0gbXR1OiA4ODAwCiAgICAjICByb3V0ZTogMTAuMC4wLjAvMTYKCiAgIyBVbnNhZmUgcm91dGVzIGFsbG93cyB5b3UgdG8gcm91dGUgdHJhZmZpYyBvdmVyIG5lYnVsYSB0byBub24tbmVidWxhIG5vZGVzCiAgIyBVbnNhZmUgcm91dGVzIHNob3VsZCBiZSBhdm9pZGVkIHVubGVzcyB5b3UgaGF2ZSBob3N0cy9zZXJ2aWNlcyB0aGF0IGNhbm5vdCBydW4gbmVidWxhCiAgIyBOT1RFOiBUaGUgbmVidWxhIGNlcnRpZmljYXRlIG9mIHRoZSAidmlhIiBub2RlICpNVVNUKiBoYXZlIHRoZSAicm91dGUiIGRlZmluZWQgYXMgYSBzdWJuZXQgaW4gaXRzIGNlcnRpZmljYXRlCiAgIyBgbXR1YDogd2lsbCBkZWZhdWx0IHRvIHR1biBtdHUgaWYgdGhpcyBvcHRpb24gaXMgbm90IHNwZWNpZmllZAogICMgYG1ldHJpY2A6IHdpbGwgZGVmYXVsdCB0byAwIGlmIHRoaXMgb3B0aW9uIGlzIG5vdCBzcGVjaWZpZWQKICAjIGBpbnN0YWxsYDogd2lsbCBkZWZhdWx0IHRvIHRydWUsIGNvbnRyb2xzIHdoZXRoZXIgdGhpcyByb3V0ZSBpcyBpbnN0YWxsZWQgaW4gdGhlIHN5c3RlbXMgcm91dGluZyB0YWJsZS4KICB1bnNhZmVfcm91dGVzOgogICAgIy0gcm91dGU6IDE3Mi4xNi4xLjAvMjQKICAgICMgIHZpYTogMTkyLjE2OC4xMDAuOTkKICAgICMgIG10dTogMTMwMAogICAgIyAgbWV0cmljOiAxMDAKICAgICMgIGluc3RhbGw6IHRydWUKCiAgIyBPbiBsaW51eCBvbmx5LCBzZXQgdG8gdHJ1ZSB0byBtYW5hZ2UgdW5zYWZlIHJvdXRlcyBkaXJlY3RseSBvbiB0aGUgc3lzdGVtIHJvdXRlIHRhYmxlIHdpdGggZ2F0ZXdheSByb3V0ZXMgaW5zdGVhZCBvZgogICMgaW4gbmVidWxhIGNvbmZpZ3VyYXRpb24gZmlsZXMuIERlZmF1bHQgZmFsc2UsIG5vdCByZWxvYWRhYmxlLgogICN1c2Vfc3lzdGVtX3JvdXRlX3RhYmxlOiBmYWxzZQoKIyBUT0RPCiMgQ29uZmlndXJlIGxvZ2dpbmcgbGV2ZWwKbG9nZ2luZzoKICAjIHBhbmljLCBmYXRhbCwgZXJyb3IsIHdhcm5pbmcsIGluZm8sIG9yIGRlYnVnLiBEZWZhdWx0IGlzIGluZm8KICBsZXZlbDogaW5mbwogICMganNvbiBvciB0ZXh0IGZvcm1hdHMgY3VycmVudGx5IGF2YWlsYWJsZS4gRGVmYXVsdCBpcyB0ZXh0CiAgZm9ybWF0OiB0ZXh0CiAgIyBEaXNhYmxlIHRpbWVzdGFtcCBsb2dnaW5nLiB1c2VmdWwgd2hlbiBvdXRwdXQgaXMgcmVkaXJlY3RlZCB0byBsb2dnaW5nIHN5c3RlbSB0aGF0IGFscmVhZHkgYWRkcyB0aW1lc3RhbXBzLiBEZWZhdWx0IGlzIGZhbHNlCiAgI2Rpc2FibGVfdGltZXN0YW1wOiB0cnVlCiAgIyB0aW1lc3RhbXAgZm9ybWF0IGlzIHNwZWNpZmllZCBpbiBHbyB0aW1lIGZvcm1hdCwgc2VlOgogICMgICAgIGh0dHBzOi8vZ29sYW5nLm9yZy9wa2cvdGltZS8jcGtnLWNvbnN0YW50cwogICMgZGVmYXVsdCB3aGVuIGBmb3JtYXQ6IGpzb25gOiAiMjAwNi0wMS0wMlQxNTowNDowNVowNzowMCIgKFJGQzMzMzkpCiAgIyBkZWZhdWx0IHdoZW4gYGZvcm1hdDogdGV4dGA6CiAgIyAgICAgd2hlbiBUVFkgYXR0YWNoZWQ6IHNlY29uZHMgc2luY2UgYmVnaW5uaW5nIG9mIGV4ZWN1dGlvbgogICMgICAgIG90aGVyd2lzZTogIjIwMDYtMDEtMDJUMTU6MDQ6MDVaMDc6MDAiIChSRkMzMzM5KQogICMgQXMgYW4gZXhhbXBsZSwgdG8gbG9nIGFzIFJGQzMzMzkgd2l0aCBtaWxsaXNlY29uZCBwcmVjaXNpb24sIHNldCB0bzoKICAjdGltZXN0YW1wX2Zvcm1hdDogIjIwMDYtMDEtMDJUMTU6MDQ6MDUuMDAwWjA3OjAwIgoKI3N0YXRzOgogICN0eXBlOiBncmFwaGl0ZQogICNwcmVmaXg6IG5lYnVsYQogICNwcm90b2NvbDogdGNwCiAgI2hvc3Q6IDEyNy4wLjAuMTo5OTk5CiAgI2ludGVydmFsOiAxMHMKCiAgI3R5cGU6IHByb21ldGhldXMKICAjbGlzdGVuOiAxMjcuMC4wLjE6ODA4MAogICNwYXRoOiAvbWV0cmljcwogICNuYW1lc3BhY2U6IHByb21ldGhldXNucwogICNzdWJzeXN0ZW06IG5lYnVsYQogICNpbnRlcnZhbDogMTBzCgogICMgZW5hYmxlcyBjb3VudGVyIG1ldHJpY3MgZm9yIG1ldGEgcGFja2V0cwogICMgICBlLmcuOiBgbWVzc2FnZXMudHguaGFuZHNoYWtlYAogICMgTk9URTogYG1lc3NhZ2Uue3R4LHJ4fS5yZWN2X2Vycm9yYCBpcyBhbHdheXMgZW1pdHRlZAogICNtZXNzYWdlX21ldHJpY3M6IGZhbHNlCgogICMgZW5hYmxlcyBkZXRhaWxlZCBjb3VudGVyIG1ldHJpY3MgZm9yIGxpZ2h0aG91c2UgcGFja2V0cwogICMgICBlLmcuOiBgbGlnaHRob3VzZS5yeC5Ib3N0UXVlcnlgCiAgI2xpZ2h0aG91c2VfbWV0cmljczogZmFsc2UKCiMgSGFuZHNoYWtlIE1hbmFnZXIgU2V0dGluZ3MKI2hhbmRzaGFrZXM6CiAgIyBIYW5kc2hha2VzIGFyZSBzZW50IHRvIGFsbCBrbm93biBhZGRyZXNzZXMgYXQgZWFjaCBpbnRlcnZhbCB3aXRoIGEgbGluZWFyIGJhY2tvZmYsCiAgIyBXYWl0IHRyeV9pbnRlcnZhbCBhZnRlciB0aGUgMXN0IGF0dGVtcHQsIDIgKiB0cnlfaW50ZXJ2YWwgYWZ0ZXIgdGhlIDJuZCwgZXRjLCB1bnRpbCB0aGUgaGFuZHNoYWtlIGlzIG9sZGVyIHRoYW4gdGltZW91dAogICMgQSAxMDBtcyBpbnRlcnZhbCB3aXRoIHRoZSBkZWZhdWx0IDEwIHJldHJpZXMgd2lsbCBnaXZlIGEgaGFuZHNoYWtlIDUuNSBzZWNvbmRzIHRvIHJlc29sdmUgYmVmb3JlIHRpbWluZyBvdXQKICAjdHJ5X2ludGVydmFsOiAxMDBtcwogICNyZXRyaWVzOiAyMAogICMgdHJpZ2dlcl9idWZmZXIgaXMgdGhlIHNpemUgb2YgdGhlIGJ1ZmZlciBjaGFubmVsIGZvciBxdWlja2x5IHNlbmRpbmcgaGFuZHNoYWtlcwogICMgYWZ0ZXIgcmVjZWl2aW5nIHRoZSByZXNwb25zZSBmb3IgbGlnaHRob3VzZSBxdWVyaWVzCiAgI3RyaWdnZXJfYnVmZmVyOiA2NAoKCiMgTmVidWxhIHNlY3VyaXR5IGdyb3VwIGNvbmZpZ3VyYXRpb24KZmlyZXdhbGw6CiAgIyBBY3Rpb24gdG8gdGFrZSB3aGVuIGEgcGFja2V0IGlzIG5vdCBhbGxvd2VkIGJ5IHRoZSBmaXJld2FsbCBydWxlcy4KICAjIENhbiBiZSBvbmUgb2Y6CiAgIyAgIGBkcm9wYCAoZGVmYXVsdCk6IHNpbGVudGx5IGRyb3AgdGhlIHBhY2tldC4KICAjICAgYHJlamVjdGA6IHNlbmQgYSByZWplY3QgcmVwbHkuCiAgIyAgICAgLSBGb3IgVENQLCB0aGlzIHdpbGwgYmUgYSBSU1QgIkNvbm5lY3Rpb24gUmVzZXQiIHBhY2tldC4KICAjICAgICAtIEZvciBvdGhlciBwcm90b2NvbHMsIHRoaXMgd2lsbCBiZSBhbiBJQ01QIHBvcnQgdW5yZWFjaGFibGUgcGFja2V0LgogIG91dGJvdW5kX2FjdGlvbjogZHJvcAogIGluYm91bmRfYWN0aW9uOiBkcm9wCgogIGNvbm50cmFjazoKICAgIHRjcF90aW1lb3V0OiAxMm0KICAgIHVkcF90aW1lb3V0OiAzbQogICAgZGVmYXVsdF90aW1lb3V0OiAxMG0KCiAgIyBUaGUgZmlyZXdhbGwgaXMgZGVmYXVsdCBkZW55LiBUaGVyZSBpcyBubyB3YXkgdG8gd3JpdGUgYSBkZW55IHJ1bGUuCiAgIyBSdWxlcyBhcmUgY29tcHJpc2VkIG9mIGEgcHJvdG9jb2wsIHBvcnQsIGFuZCBvbmUgb3IgbW9yZSBvZiBob3N0LCBncm91cCwgb3IgQ0lEUgogICMgTG9naWNhbCBldmFsdWF0aW9uIGlzIHJvdWdobHk6IHBvcnQgQU5EIHByb3RvIEFORCAoY2Ffc2hhIE9SIGNhX25hbWUpIEFORCAoaG9zdCBPUiBncm91cCBPUiBncm91cHMgT1IgY2lkcikKICAjIC0gcG9ydDogVGFrZXMgYDBgIG9yIGBhbnlgIGFzIGFueSwgYSBzaW5nbGUgbnVtYmVyIGA4MGAsIGEgcmFuZ2UgYDIwMC05MDFgLCBvciBgZnJhZ21lbnRgIHRvIG1hdGNoIHNlY29uZCBhbmQgZnVydGhlciBmcmFnbWVudHMgb2YgZnJhZ21lbnRlZCBwYWNrZXRzIChzaW5jZSB0aGVyZSBpcyBubyBwb3J0IGF2YWlsYWJsZSkuCiAgIyAgIGNvZGU6IHNhbWUgYXMgcG9ydCBidXQgbWFrZXMgbW9yZSBzZW5zZSB3aGVuIHRhbGtpbmcgYWJvdXQgSUNNUCwgVE9ETzogdGhpcyBpcyBub3QgY3VycmVudGx5IGltcGxlbWVudGVkIGluIGEgd2F5IHRoYXQgd29ya3MsIHVzZSBgYW55YAogICMgICBwcm90bzogYGFueWAsIGB0Y3BgLCBgdWRwYCwgb3IgYGljbXBgCiAgIyAgIGhvc3Q6IGBhbnlgIG9yIGEgbGl0ZXJhbCBob3N0bmFtZSwgaWUgYHRlc3QtaG9zdGAKICAjICAgZ3JvdXA6IGBhbnlgIG9yIGEgbGl0ZXJhbCBncm91cCBuYW1lLCBpZSBgZGVmYXVsdC1ncm91cGAKICAjICAgZ3JvdXBzOiBTYW1lIGFzIGdyb3VwIGJ1dCBhY2NlcHRzIGEgbGlzdCBvZiB2YWx1ZXMuIE11bHRpcGxlIHZhbHVlcyBhcmUgQU5EJ2QgdG9nZXRoZXIgYW5kIGEgY2VydGlmaWNhdGUgd291bGQgaGF2ZSB0byBjb250YWluIGFsbCBncm91cHMgdG8gcGFzcwogICMgICBjaWRyOiBhIHJlbW90ZSBDSURSLCBgMC4wLjAuMC8wYCBpcyBhbnkuCiAgIyAgIGxvY2FsX2NpZHI6IGEgbG9jYWwgQ0lEUiwgYDAuMC4wLjAvMGAgaXMgYW55LiBUaGlzIGNvdWxkIGJlIHVzZWQgdG8gZmlsdGVyIGRlc3RpbmF0aW9ucyB3aGVuIHVzaW5nIHVuc2FmZV9yb3V0ZXMuCiAgIyAgIGNhX25hbWU6IEFuIGlzc3VpbmcgQ0EgbmFtZQogICMgICBjYV9zaGE6IEFuIGlzc3VpbmcgQ0Egc2hhc3VtCgogIG91dGJvdW5kOgogICAgIyBBbGxvdyBhbGwgb3V0Ym91bmQgdHJhZmZpYyBmcm9tIHRoaXMgbm9kZQogICAgLSBwb3J0OiBhbnkKICAgICAgcHJvdG86IGFueQogICAgICBob3N0OiBhbnkKCiAgaW5ib3VuZDoKICAgICMgQWxsb3cgaWNtcCBiZXR3ZWVuIGFueSBuZWJ1bGEgaG9zdHMKICAgIC0gcG9ydDogYW55CiAgICAgIHByb3RvOiBpY21wCiAgICAgIGhvc3Q6IGFueQoKICAgICMgQWxsb3cgc3NoCiAgICAtIHBvcnQ6IDIyCiAgICAgIHByb3RvOiB0Y3AKICAgICAgaG9zdDogYW55CgogICAgIyBBbGxvdyB0Y3AvNDQzIGZyb20gYW55IGhvc3Qgd2l0aCBCT1RIIGxhcHRvcCBhbmQgaG9tZSBncm91cAogICAgLSBwb3J0OiA0NDMKICAgICAgcHJvdG86IHRjcAogICAgICBncm91cHM6CiAgICAgICAgLSBsYXB0b3AKICAgICAgICAtIGhvbWU="
ansNebulaConfigLighthouseDecode = base64.b64decode(ansNebulaLighthouseConfig)
ansNebulaConfigLighthouseDecode = ansNebulaConfigLighthouseDecode.decode("utf-8")
ansNebulaLighthouseConfig = open("ansible/playbooks/templates/nebula-lighthouse.yml.j2", "w")
ansNebulaLighthouseConfig.write(ansNebulaConfigLighthouseDecode)
ansNebulaLighthouseConfig.close()
def pullNebula(passedURL, update):
# Set file variables, concentrating on Linux for initial build
nebulaLinuxURL=passedURL
nebulaLinuxDL="nebula-linux-amd64.tar.gz"
nebulaLinuxCurrent="nebula-linux.tar.gz"
nebulaFile="nebula"
nebulaCertFile="nebula-cert"
# If Nebula download doesn't exist, download it.
if not os.path.exists(nebulaLinuxDL) or update == "yes":
response = requests.get(nebulaLinuxURL)
response.raw.decode_content = True
with open(nebulaLinuxDL, 'wb') as fileDL:
for block in response.iter_content(chunk_size=1024):
fileDL.write(block)
fileDL.close()
# If Nebula binary doesn't exist, extract the tar.
if not os.path.exists(nebulaFile) or update == "yes":
nebulaTar = tarfile.open(nebulaLinuxDL)
nebulaTar.extractall(filter='data')
nebulaTar.close()
# Display all clients in the DB
def listClients():
if not os.path.exists(NEBMANDB):
sys.exit("Database does not exist, exiting")
else:
dbConnect = sqlite3.connect(NEBMANDB)
dbCurser = dbConnect.cursor()
dbContent = dbCurser.execute("SELECT * FROM nebmanClients")
print(dbContent.fetchall())
dbConnect.close()
def addClient():
# add client to DB
newHostname = input("Please enter new hostname (FQDN): ")
newNetwork = input("Please enter network address (192.168.1): ")
newLighthouse = input("Is this new a lighthouse (y/n): ")
newOS = input("Please enter OS (Windows, Ubuntu, Fedora): ")
newServices = input("Please enter comma seperated list of services (ssh,http): ")
newVersion = CURRENTVERSION
# Set new ID value based on endpoint type
if newLighthouse == 'y':
newID = existingLighthouseID + 1
else:
newID = existingEndpointID + 1
# If DB doesn't exist, exit the app, otherwise create new entry in the DB
if not os.path.exists(NEBMANDB):
sys.exit("Database does not exist, exiting")
else:
dbConnect = sqlite3.connect(NEBMANDB)
dbCurser = dbConnect.cursor()
# pass inserted values into sqlite3 db
dbCurser.execute("INSERT OR IGNORE INTO nebmanClients(id, hostname, network, lighthouse, os, services, version) VALUES(?, ?, ?, ?, ?, ?, ?)",(newID, newHostname, newNetwork, newLighthouse, newOS, newServices, newVersion))
dbConnect.commit()
# Close DB connection
dbConnect.close()
def endpointCertGen(certType):
# make certs dir if it doesn't already exist
if not os.path.exists('certs'):
os.makedirs('certs')
# new endpoint cert generation
if certType == '1':
if existingNetwork == "notset":
print("No endpoints exist in the DB, please add at least one")
# check if ca eists and if it doesn't request that it be generated
elif not os.path.exists('certs/ca.crt') or not os.path.exists('certs/ca.key'):
print ("CA cert does not exist, please generate one first.")
else:
x = 0
y = 0
dbConnect = sqlite3.connect(NEBMANDB)
dbCurser = dbConnect.cursor()
dbContent = dbCurser.execute("SELECT * FROM nebmanClients")
print("Generating cert for endpoint")
print("----------------------------------")
for row in dbContent:
print(str(x) +" - "+row[1])
x+=1
# Close DB connection
dbConnect.close()
endpointSelection = input("Select an endpoint from list above (0, 1 ..): ")
dbConnect = sqlite3.connect(NEBMANDB)
dbCurser = dbConnect.cursor()
dbContent = dbCurser.execute("SELECT * FROM nebmanClients")
for row in dbContent:
if endpointSelection == str(y):
newEndpointCertCmd="./nebula-cert sign -ca-crt ./certs/ca.crt -ca-key ./certs/ca.key -out-crt ./certs/" +row[1]+ ".crt -out-key ./certs/" +row[1]+ ".key -name " +row[1]+ " -ip " + existingNetwork + "." + str(row[0]) + "/24"
subprocess.call(newEndpointCertCmd, shell=True)
break
else:
y+=1
# Close DB connection
dbConnect.close()
# new ca cert generation, this should only be done once in most cases
elif certType == '99':
# check if ca eists and if it does request that it be deleted
if os.path.exists('certs/ca.crt') or os.path.exists('certs/ca.key'):
print ("CA cert alrady exists, you need to manually delete CA cert and key first.")
else:
print("Generating initial CA cert for org")
print("----------------------------------")
orgName = input("Please enter org name: ")
newOrgCertCmd = "./nebula-cert ca -out-crt ./certs/ca.crt -out-key ./certs/ca.key -name \""+orgName+"\""
subprocess.call(newOrgCertCmd, shell=True)
else:
print("invalid choice")
def updateNebula():
# Ref global variable
global existingVersion
# Does nebula binary exist in Ansible folder and if so what's the version.
print("----------------------")
print("Update Nebula Binaries")
print("----------------------")
if os.path.exists('ansible/playbooks/files/nebula'):
getAnsVersion="./ansible/playbooks/files/nebula --version"
ansVersion = str(subprocess.check_output(getAnsVersion, shell=True))
ansVersion = str(ansVersion[11:16])
print("- Existing version found is: " + existingVersion)
if existingVersion == ansVersion:
print("- Ansible binary found is: " + bcolors.GREEN + ansVersion + bcolors.END)
else:
print("- Ansible binary found is: " + bcolors.ORANGE + ansVersion + bcolors.END)
else:
print("- Ansible binary found is: " + bcolors.RED + "Not found" + bcolors.END)
print("---------------------------------")
confirmChoice = input("Do you want to download an ubdated version (yes/ no): ")
if confirmChoice == "yes":
updatedURL = input("PLease paste the full download link from the Nebula releases page: ")
pullNebula(updatedURL, "yes")
## Cert purge, should only be used in event an entire new set of certs is going to be generated.
def purgeCerts():
if not os.path.exists('certs'):
print("No certs found, nothing to do here")
else:
print("## Warning, this is destructive, ALL CERTS WILL BE DELETED, inc CA ##")
confirmChoice = input("Please type yes to confirm you wish to proceed: ")
if confirmChoice == "yes":
certsDir = "certs/"
certFiles = os.listdir(certsDir)
# iterate through files and only delete .crt and .key files.
for certFile in certFiles:
if certFile.endswith(".crt") or certFile.endswith(".key"):
os.remove(os.path.join(certsDir, certFile))
else:
print("Not confirmed, exiting.")
if __name__ == "__main__":
initDB()
pullNebula("https://github.com/slackhq/nebula/releases/download/v1.9.5/nebula-linux-amd64.tar.gz", "no")
print("---------------------")
print("Current status of app")
print("---------------------")
checkState()
print("---------------------------------")
print("1 - View current clients in the DB")
print("2 - Add new client in the DB")
print("3 - Generate new CA cert for organisation")
print("4 - Generate certs for an endpoint in the DB")
print("5 - Generate Ansible inventory")
print("6 - Update Nebula version")
print("99 - Purge all certs")
print("---------------------------------")
menuChoice = input("Please select from the menu above: ")
if menuChoice == '1':
listClients()
elif menuChoice == '2':
addClient()
elif menuChoice == '3':
endpointCertGen("99")
elif menuChoice == '4':
endpointCertGen("1")
elif menuChoice == '5':
ansibleGen()
elif menuChoice == '6':
updateNebula()
elif menuChoice == '99':
purgeCerts()