-
Notifications
You must be signed in to change notification settings - Fork 83
/
check-tf-plan.py
218 lines (167 loc) · 7.98 KB
/
check-tf-plan.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
#!/usr/bin/env python3
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
import json
import glob
import shutil
import requests
from python_terraform import Terraform
from urllib.parse import unquote
def main(PR):
TOKEN = os.getenv('GITHUB_TOKEN')
GITHUB_WORKSPACE = os.getenv('GITHUB_WORKSPACE')
GITHUB_REPOSITORY = os.getenv('GITHUB_REPOSITORY')
# Get Added / Modified files in PR
modified_files, modified_files_raw, removed_files = pr_files(GITHUB_REPOSITORY, PR)
# Get Working directories to run TF Plan on
working_directories = get_updated_modules(modified_files, removed_files)
# Loop through all the identified working directories
# Deleting added/modified & removed files
try:
for dir in working_directories:
print("----------> RUN FOR: " + dir)
try:
# IF MODULE EXISTS: Copying main directory in temp folder
shutil.copytree(GITHUB_WORKSPACE+'/'+dir, os.getcwd()+'/temp/'+dir)
# Deleting added/modified & removed files
for mfile in modified_files:
if os.path.exists(os.getcwd()+'/temp/'+mfile):
print("Deleting file: " + mfile)
os.remove(os.getcwd()+'/temp/'+mfile)
for rfile in removed_files:
if os.path.exists(os.getcwd()+'/temp/'+rfile):
print("Deleting file: " + rfile)
os.remove(os.getcwd()+'/temp/'+rfile)
except:
# IF MODULE DONOT EXISTS: Creating temp module folder
os.makedirs(os.getcwd()+'/temp/'+dir)
except requests.exceptions.RequestException as e:
print('No working directory with TF configs in PR.')
raise SystemExit(e)
# Loop through all the identified working directories
# Download added/modified files
try:
for dir in working_directories:
print("Module: " + dir)
# Download added/modified files
for file in modified_files:
if dir in file:
print("File: " + file)
for raw in modified_files_raw:
# print("Raw: " + raw)
# print("Raw Decoded: " + unquote(raw))
if file in unquote(raw):
print("Downloading file: " + unquote(raw))
downloadprfiles(unquote(raw), file, os.getcwd()+'/temp/'+os.path.dirname(file))
break
except requests.exceptions.RequestException as e:
print('No working directory with TF configs in PR.')
raise SystemExit(e)
# Loop through all the identified working directories
# Run Terraform Plan
try:
for dir in working_directories:
# print('****************************')
# print(glob.glob(os.getcwd() + '/temp/' + dir+'/*'))
# print('****************************')
# print(glob.glob(os.getcwd() + '/temp/' + dir+'/*/*'))
# Running Terraform Init & Terraform Plan
comment, status = tf(os.getcwd() + '/temp/' + dir)
comment = comment + ' for: **' + dir + '** !'
# Commenting on the PR
commentpr(GITHUB_REPOSITORY, PR, comment, TOKEN)
if(status == 'fail'):
sys.exit('Terraform Init or Terraform Plan FAILED for: '+ dir)
except requests.exceptions.RequestException as e:
print('No working directory with TF configs in PR.')
raise SystemExit(e)
def pr_files(GITHUB_REPOSITORY,pr):
removed_files = []
modified_files = []
modified_files_raw = []
try:
response = requests.get('https://api.github.com/repos/'+ GITHUB_REPOSITORY +'/pulls/'+ str(pr) +'/files')
for file in response.json():
if(file['status'] == 'removed'):
print("Removed File: " + file['filename'])
removed_files.append(file['filename'])
else:
print("Added/Modified File: " + file['filename'])
modified_files.append(file['filename'])
modified_files_raw.append(file['raw_url'])
return modified_files, modified_files_raw, removed_files
except requests.exceptions.RequestException as e:
raise SystemExit(e)
def downloadprfiles(raw, file, path):
# print(path)
if not os.path.exists(path):
os.makedirs(path)
# print('Beginning file download with requests')
r = requests.get(raw)
with open(path + '/' + os.path.basename(file), 'wb') as f:
f.write(r.content)
# Retrieve HTTP meta-data
# print(r.status_code)
# print(r.headers['content-type'])
# print(r.encoding)
def get_updated_modules(modified_files, removed_files):
modified_files_dir = []
removed_files_dir = []
for file in modified_files:
modified_files_dir.append(os.path.dirname(file))
for file in removed_files:
removed_files_dir.append(os.path.dirname(file))
working_directories = modified_files_dir + removed_files_dir
working_directories = list(set(working_directories))
# print("Working Directories:")
# print(working_directories)
modules = [x for x in working_directories if x.startswith('modules/')]
modules = [x for x in modules if x.count('/') == 1]
print("Modules Updated:")
print(modules)
return modules
def tf(dir):
tr = Terraform(working_dir=dir)
return_code_init, stdout_init, stderr_init = tr.init_cmd(capture_output=False)
if "secure_data_warehouse" in dir:
# Special case in SDW module as it require additional mandatory variables compared to any other modules.
return_code_plan, stdout_plan, stderr_plan = tr.plan_cmd(capture_output=False,var={'billing_account_id':'ABCD-EFGH-IJKL-MNOP', 'organization_id':'1234567890', 'random_id': '1234', 'data_analyst_group': '[email protected]', 'data_engineer_group': '[email protected]', 'security_administrator_group': '[email protected]', 'network_administrator_group': '[email protected]', 'security_analyst_group': '[email protected]', 'perimeter_additional_members': ['[email protected]','[email protected]'], 'secure_datawarehouse_service_acccount': '[email protected]'})
else:
return_code_plan, stdout_plan, stderr_plan = tr.plan_cmd(capture_output=False,var={'billing_account_id':'ABCD-EFGH-IJKL-MNOP', 'organization_id':'1234567890', 'random_id': '1234'})
path = os.getcwd()+'/temp/'
if(return_code_init == 1):
comment = 'Terraform Init FAILED'
status = 'fail'
if(return_code_plan == 1):
comment = 'Terraform Plan FAILED'
status = 'fail'
else:
comment = 'Terraform Init & Terraform Plan SUCCESSFUL'
status = 'pass'
return comment, status
def commentpr(GITHUB_REPOSITORY, pr, comment, TOKEN):
headers = {'Authorization': f'token {TOKEN}', 'Accept': 'application/vnd.github.v3+json'}
# print(comment)
data = {"body":comment}
try:
response = requests.post('https://api.github.com/repos/'+ GITHUB_REPOSITORY +'/issues/'+ str(pr) +'/comments', data=json.dumps(data), headers=headers)
# print(response.text)
except requests.exceptions.RequestException as e:
raise SystemExit(e)
if __name__ == '__main__':
if len(sys.argv) != 2:
raise SystemExit('No PR passed.')
main(sys.argv[1])