Skip to content

Instantly share code, notes, and snippets.

@magzim21
Last active July 16, 2020 09:28
Show Gist options
  • Select an option

  • Save magzim21/78df23de1b42d95fd0441e5552e3051e to your computer and use it in GitHub Desktop.

Select an option

Save magzim21/78df23de1b42d95fd0441e5552e3051e to your computer and use it in GitHub Desktop.
It scans nginx.conf with included configs and outputs (creates redirects.csv) all redirects in a short, handy form.
import crossplane, re, csv
# !!! CHANGE include /opt/nginx/conf/conf.d/*.conf; . /conf.d/*.conf;
payload = crossplane.parse('nginx.conf')
# In order to understand structure go to https://codebeautify.org/python-formatter-beautifier and paste result of print(payload['config'])
# print(payload['config'])
# print(payload)
files = payload['config']
# FINDING ALL UPSTREAMS
upstreams ={} #
for file in files: # ITERATING THROUGH EACH FILE
# print(file['file']) # config file path
# servers = [] # how did I want to use it?
for directive1 in file['parsed']: # ITERATING THROUGH FILE LINES
if directive1['directive'] == 'upstream': # UPSTREAM CONTEXT
upstream = directive1
upstream_name = upstream["args"][0]
upstreams[upstream_name] = []
# print(f'upstream {upstream_name}')
# breakpoint()
for directive2 in upstream["block"]:
if directive2['directive'] == 'server':
server = directive2
server_addr = server["args"][0]
# servers.append(server_addr)
upstreams[upstream_name].append(server_addr)
# print(f'server {server_addr}')
with open('redirects.csv', 'w', newline='') as csvfile:
fieldnames = ['FROM', 'WHERE']
csv.register_dialect("tabs",delimiter=",")
writer = csv.DictWriter(csvfile, fieldnames=fieldnames, dialect='tabs' )
writer.writeheader()
for file in files: # ITERATING THROUGH EACH FILE
# UNCOMMENT TO FIND LINES OF EACH CONFIG
# print(file['file']) # config file path
# if file['file'] == "./conf.d/6056.qbreport.conf": DEBUGGINNG
# breakpoint()
writer.writerow({'FROM': 'config file: ' + file['file'], 'WHERE': '-------------'})
# DEBUGGING BLOCK
# if file['file'] == '././conf.d/zabbix.minfin.local.conf':
# breakpoint()
for directive1 in file['parsed']: # ITERATING
# THROUGH FILE LINES
if directive1['directive'] == 'server': # SERVER CONTEXT
server=directive1
for directive2 in server['block']:
if directive2['directive'] == 'listen':
listen = directive2["args"][0]
# print(f'listen on {listen}') # listen on
if directive2['directive'] == 'location':
location = directive2["args"]
# print(f'location: {location}') # location specified
for directive3 in directive2['block']:
if directive3['directive'] == 'proxy_pass':
where = directive3["args"][0]
# regex to find ip in a proxy pass (?<=http://)[\d|\.|:]+
# regex to find upstream in a proxy pass (?<=http://)[a-zA-Z_-]+
# print(f'proxy_pass {proxy_pass}') # proxy pass
regex=r'(?<=://)[^/:]+' # !!! WORKS WITH HTTP ONLY !!!
if 'https://' in where:
print('UPSTREAM CONTAINS HTTPS! REFACTOR YOUR CODE.', file['file'])
# breakpoint()
# exit(1)
# print(proxy_pass)
# breakpoint()
matches = re.findall(regex, where, re.DOTALL)
# print(upstreams)
if matches and matches[0] in upstreams: # in case upstream name is present in a proxy pass
# .join may result few servers to pe printed in one line, if there are few servers in a upstream
# print(" ".join(upstreams[matches[0]]))
# print(file['file'])
where = re.sub(regex, " ".join(upstreams[matches[0]]), where, 0, re.MULTILINE) # " ".join(upstreams[matches[0]]) is a list of upstream's servers
elif directive3['directive'] == 'fastcgi_pass':
where = directive3["args"][0]
# breakpoint()
elif directive3['directive'] == 'root':
where = directive3["args"][0]
# breakpoint()
try:
# .join may result few location args to pe printed in one line, if there are few arags e.g " = / "
map = f'{listen}{" ".join(location)} -> {where}'
writer.writerow({'FROM': listen + " ".join(location), 'WHERE': where})
# print(map)
del where
except NameError:
# IF "proxy_pass" , "root", "fastcgi_pass" were not found in "location" it will be skipped
# IF configuration is not based on location context - this script will pass it
pass
# print('\n')
@magzim21
Copy link
Author

magzim21 commented Apr 29, 2020

README

This is a handy script to parse large nginx config.

This script scans nginx config (as well as "include" statements) and saves the output in a human readable text file 'redirects.csv'
The format is :

nginx_host:port/location -> upstream:port/location
example:
10.100.174.36:2203/,http://10.100.174.22:2203

Dependencies: crossplane

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment