网上尚未发现成熟方案,这是个人第一次尝试。
第一步,编辑解析模块 Parser.py
#!/usr/bin/env python
# encoding: utf-8
class Parser(object):
def __init__(self, offset_char=' '):
self._i = 0
self._config = ''
self._length = 0
self._data = []
self._off_char = offset_char
def __call__(self):
return self.gen_config()
def load(self, config):
self._config = config
self._length = len(config) - 1
self._i = 0
return self.parse_block()
def loadf(self, filename):
conf = ''
with open(filename, 'r') as f:
cnt = f.readlines()
temp=[i for i in cnt if not i.strip().startswith('#')]
conf = "".join(temp)
return self.load(conf)
# 块解析器
def parse_block(self):
data = []
param_name = None
param_value = None
buf = ''
while self._i < self._length:
# 换行符可能block换行或item之间的换行
if '\n' == self._config[self._i]:
if buf and param_name:
if param_value is None:
param_value = []
param_value.append(buf.strip())
buf = ''
elif ' ' == self._config[self._i]:
if not param_name and len(buf.strip()) > 0:
param_name = buf.strip()
buf = ''
else:
buf += self._config[self._i]
elif ';' == self._config[self._i]:
if isinstance(param_value, list):
# tag value
param_value.append(buf.strip())
else:
# tag value
param_value = buf.strip()
# tag
data.append({'name': param_name, 'value': param_value.split(' '), 'type': 'item'})
param_name = None
param_value = None
buf = ''
elif '{' == self._config[self._i]:
self._i += 1
block = self.parse_block()
data.append({'name': param_name, 'param': buf.strip(), 'value': block, 'type': 'block'})
param_name = None
param_value = None
buf = ''
elif '}' == self._config[self._i]:
self._i += 1
return data
elif '#' == self._config[self._i]: # skip comments
# 遇到#时,忽略下一字符为空格的注释
if ' ' == self._config[self._i + 1]:
while self._i < self._length and '\n' != self._config[self._i]:
self._i += 1
else:
buf += self._config[self._i]
else:
buf += self._config[self._i]
self._i += 1
return data
第二步,把nginx配置中的servers和upstream和upsync目录放在主目录下
第三步,执行nginx.py 开始解析
import requests
import json,os
from time import sleep
from parser import Parser
import random
#coding=utf-8
apisix_addr='http://127.0.0.1:80'
header={'X-API-KEY': 'xxxxxxxxxxxxxxxxxxxxxx'}
def getrand():
str_list=[]
for i in range(8):
str_list.append(random.choice('abcdefghifklmnopqrstuvwxyz123456789'))
return "".join(str_list)
#滚动发布的应用列表
upsync_list=['app1','app2','app3']
ups_map={}
def parsenginx(path):
#解析配置文件
try:
data=Parser().loadf(path)
except Exception as e:
print(e)
return False
for line in data:
if(line['name']=='upstream'):
upstream={}
name=line['param'] #upstream名称
upstream['type']='roundrobin'
upstream['scheme']='http'
upstream['timeout']={"connect":30,"send":30,"read":30}
upstream['name']=line['param']
upstream['retries']=3
content=line['value']
if(content[0]['name']=='upsync'): #发现配置滚动发布的应用
upsync_path=[i['value'] for i in content if i['name']=='upsync_dump_path'][0][0]
upsync_path=os.path.join('upsync',os.path.basename(upsync_path))
upsync_data=Parser().loadf(upsync_path)
hosts=[i['value'][0] for i in upsync_data]
else:
hosts=[i['value'][0] for i in content if not i['name'].startswith('#')] #后端列表
upstream['nodes']={i:100 for i in hosts}
for app in upsync_list: #滚动发布的应用列表的应用 默认接入dapr
if(app in name):
upstream['nodes']={"127.0.0.1:3500":100}
datapost=json.dumps(upstream)
url=apisix_addr+"/apisix/admin/upstreams"
res=requests.post(url,data=datapost,headers=header)
if(res.status_code not in [200,201]):
print(url,res.status_code)
print(upstream,res.json())
continue
else:
ups_map[name]=upstream
if(line['name']=='server'):
content=line['value']
portlist=[i['value'][0] for i in content if i['name']=='listen']
hosts_info=[i['value'] for i in content if i['name']=='server_name']
if not hosts_info: #没有域名的忽略
continue
hosts=[i['value'] for i in content if i['name']=='server_name'][0]
location_list=[i for i in content if i['name']=='location'] #location项目
for location_item in location_list: #每个location都是独立的路由
routes={}
randstr=getrand() #随机字符串
routes['methods']=["GET","POST","PUT","DELETE","PATCH","HEAD","OPTIONS","CONNECT","TRACE"]
routes['status']=1
routes['hosts']=hosts
routes['name']=routes['hosts'][0]+'-'+randstr #路由名称用随机字符串
loc_uri=location_item['param']
routes['uri']=location_item['param']+"*"
loc_cnt=location_item['value']
proxyinfo=[i for i in loc_cnt if i['name']=='proxy_pass']
if(not proxyinfo): #没有proxy_pass
continue
proxy_pass=proxyinfo[0]['value'][0].replace('$scheme://','').replace('http://','').replace('/','') #获取proxy_pass对象
if('.' in proxy_pass): #说明没有用到upstream后端
routes['upstream']={"type": "roundrobin","nodes": {proxy_pass: 100}}
else:
ifupsync=False
for app in upsync_list: #滚动发布的应用 默认接入dapr
if(app in proxy_pass):
ifupsync=True
routes["plugins"]={"proxy-rewrite":{"regex_uri":["(.*)","/v1.0/invoke/{}/method/$1".format(app)]}}
routes['upstream']={"type": "roundrobin","nodes": {"127.0.0.1:3500": 100}}
if not ifupsync:
routes['upstream']=ups_map.get(proxy_pass) #proxy_pass锁定upstream
datapost=json.dumps(routes)
url=apisix_addr+"/apisix/admin/routes"
res=requests.post(url,data=datapost,headers=header)
if(res.status_code not in [200,201]):
print(url)
print(routes,res.json())
#解析upstream
file_list=os.listdir('upstream')
conf_list=[i for i in file_list if i.endswith('.conf')]
for conf in conf_list: #遍历每个配置文件
path=os.path.join('upstream',conf)
parsenginx(path)
#解析servers
file_list=os.listdir('servers')
conf_list=[i for i in file_list if i.endswith('.conf')]
for conf in conf_list: #遍历每个配置文件
path=os.path.join('servers',conf)
parsenginx(path)