-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathhandler.py
More file actions
205 lines (167 loc) · 6.25 KB
/
handler.py
File metadata and controls
205 lines (167 loc) · 6.25 KB
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
from github import Github
from lookml import lookml, View, Dimension, DimensionGroup
import json
import os
import requests
def schema_table_search(event, context):
## lookml configs
lookml.DB_FIELD_DELIMITER_START = ''
lookml.DB_FIELD_DELIMITER_END = ''
lookml.INDENT = ' '*2
lookml.NEWLINE = '\n'
lookml.NEWLINEINDENT = ''.join([lookml.NEWLINE,lookml.INDENT])
lookml.TIMEFRAMES = [ 'raw', 'year', 'quarter', 'month', 'week', 'date', 'day_of_week', 'month_name' ]
## Error checking
queryStringParameters = validate_queryStringParameters(event)
# filename and project are required
if queryStringParameters == '':
return {
'statusCode': 401,
'body': 'filename and project_id query parameters are required'
}
looker_header_token = check_headers(event)
# looker header must be present
if looker_header_token == '':
return {
'statusCode': 401,
'body': 'invalid payload headers'
}
if 'project_config' in os.environ:
config = json.loads(os.environ['project_config'])
else:
return {
'statusCode': 401,
'body': 'project_config is missing'
}
if looker_header_token in config:
instance = config[looker_header_token]
else:
return {
'statusCode': 401,
'body': 'invalid project_config (instance webhook signature)'
}
if not ({'base_url','github_token','projects'} <= instance.keys() ):
return {
'statusCode': 401,
'body': 'instance missing variables (base_url, github_token, projects)'
}
if not (type(instance['projects']) is list and len(instance['projects']) > 0 ):
return {
'statusCode': 401,
'body': 'project is not list or length is 0'
}
body = check_body(event)
## body must be present
if body == '':
return {
'statusCode': 401,
'body': 'body missing from event'
}
# check for the fields key
if 'scheduled_plan' in body and 'query' in body['scheduled_plan'] and 'fields' in body['scheduled_plan']['query']:
fields = body['scheduled_plan']['query']['fields']
else:
return {
'statusCode': 401,
'body': 'selection not correct, check fields'
}
# check fo rthe necessary fields
required_fields = {'schema_table_search.table_schema', 'schema_table_search.table_name', 'schema_table_search.column_name', 'schema_table_search.type_convert', 'schema_table_search.comment'}
if not (required_fields <= set(fields)):
return {
'statusCode': 401,
'body': 'selection not correct, missing a required field'
}
# check for body.attachment.data
if 'attachment' in body and 'data' in body['attachment']:
data = json.loads(body['attachment']['data'])
# check that data has value
if not check_data(data):
return {
'statusCode': 401,
'body': 'No Attachment Data'
}
else:
return {
'statusCode': 401,
'body': 'No Attachment Data'
}
# work with lookml
fName = queryStringParameters['filename']+'.view.lkml'
vw = View(queryStringParameters['filename'])
vw.setSqlTableName(sql_table_name=str(data[0]['schema_table_search.table_name']),schema=str(data[0]['schema_table_search.table_schema']))
for row in data:
column = str(row['schema_table_search.column_name'])
if str(row['schema_table_search.type_convert']) == 'time':
dim = DimensionGroup(dbColumn=column)
else:
dim = Dimension(dbColumn=column)
dim.setType(str(row['schema_table_search.type_convert']))
if row['schema_table_search.comment'] is not None:
dim.setProperty('description', str(row['schema_table_search.comment']))
vw + dim
## GitHub API Section
print(" begin github ")
## find project in config
matched_project = {}
print(fName)
for project in instance['projects']:
if queryStringParameters['project_id'] == project['project_id']:
matched_project = project
if not ( {'repository', 'project_id'} <= matched_project.keys() ):
return {
'statusCode': 401,
'body': 'missing keys from project (X-Looker-Deploy-Secret, repository, project_id)'
}
git = Github(instance['github_token'])
# get github org
repo = git.get_repo(matched_project['repository'])
contents = repo.get_contents("")
matched_content = None
for content in contents:
if content.path == fName:
matched_content = content
if matched_content is not None:
repo.update_file(matched_content.path, "auto-update", str(vw), sha=matched_content.sha, branch="master")
else:
repo.create_file(fName, "new file", str(vw), branch="master")
# hit deploy webhook
if matched_project['X-Looker-Deploy-Secret'] is None or matched_project['X-Looker-Deploy-Secret'] == '':
headers = {}
else:
headers={"X-Looker-Deploy-Secret": matched_project['X-Looker-Deploy-Secret']}
r = requests.get(
instance['base_url']+'/webhooks/projects/'+matched_project['project_id']+'/deploy',
headers=headers)
return {
'statusCode': 200,
'body': json.dumps('Deployed: '+instance['base_url']+'/projects/'+matched_project['project_id']+ '/files/' + fName)
}
def check_headers(event):
if 'headers' in event and 'X-Looker-Webhook-Token' in event['headers']:
return event['headers']['X-Looker-Webhook-Token']
else:
return ''
def check_body(event):
if 'body' in event:
return json.loads(event['body'])
else:
return ''
def check_fields(body):
return True
def check_data(data):
if data is None:
return False
elif len(data) > 0:
return True
else:
return False
def validate_queryStringParameters(event):
# filename and project_id are required
if 'queryStringParameters' in event:
if {'filename', 'project_id'} <= event['queryStringParameters'].keys():
return event['queryStringParameters']
else:
return ''
else:
return ''