cloudinfo: Add Azure metadata support

This commit is contained in:
Oleksii Shevchuk 2019-11-08 10:25:06 +02:00
parent de6eb8f246
commit 80603d13d3
1 changed files with 106 additions and 42 deletions

View File

@ -8,32 +8,87 @@ import string
is_dict = re.compile(r'^(\d+)=([^/]+)$') is_dict = re.compile(r'^(\d+)=([^/]+)$')
def get(path, version='latest', section='meta-data'):
if path == '/': METADATA_SERVER = 'http://169.254.169.254'
path = '' METADATA_PROVIDER = None
METADATA_ROOT = None
METADATA_HEADERS = []
METADATA_PARAMS = ''
def _probe():
global METADATA_ROOT
global METADATA_PROVIDER
global METADATA_HEADERS
global METADATA_PARAMS
if get('', 'latest/meta-data'):
METADATA_PROVIDER = 'EC2'
METADATA_ROOT = 'latest'
elif get('', 'metadata/v1'):
METADATA_PROVIDER = 'DO'
METADATA_ROOT = 'metadata/v1'
else:
result = get('', 'metadata', [('Metadata', 'true')], 400)
if not result:
raise ValueError('Unknown metadata implementation')
error = json.loads(result)
version = error['newest-versions'][0]
METADATA_PROVIDER = 'MS'
METADATA_HEADERS = [('Metadata', 'true')]
METADATA_ROOT = 'metadata/instance'
METADATA_PARAMS = '?api-version={}&format=json'.format(version)
return METADATA_PROVIDER, METADATA_ROOT, METADATA_HEADERS
def get(path, root=None, headers=None, code=200):
opener = urllib2.build_opener()
opener.addheaders = \
METADATA_HEADERS if headers is None else headers
path = '/'.join([x for x in path.split('/') if x])
uri = '/'.join([
METADATA_SERVER,
METADATA_ROOT if root is None else root,
path or ''
]) + METADATA_PARAMS
try: try:
return urllib2.urlopen('http://169.254.169.254/{}/{}/{}'.format( response = opener.open(uri, timeout=2)
version, section, path), timeout=2 if response.code != code:
).read() return None
except: except urllib2.HTTPError as e:
return None if e.code == code:
return e.fp.read()
else:
return None
def dir(path, version='latest', section='meta-data'): return response.read()
path = '/'.join([x for x in path.split('/') if x]) + '/'
data = get(path, version, section)
def metadir(path):
data = get(path)
if data: if data:
return [x for x in data.split('\n') if x] return [x for x in data.split('\n') if x]
else: else:
return data return data
def list(path, version='latest', section='meta-data'):
result = {} def isint(x):
for item in dir(path, version, section): try:
result[item] = get('/'.join(path, item)) int(x)
return result return True
except:
return False
def valueconv(x): def valueconv(x):
try: try:
@ -59,7 +114,7 @@ def valueconv(x):
except: except:
pass pass
if x == 'none': if x is None or x == 'none':
return None return None
elif x.endswith('\n'): elif x.endswith('\n'):
return x return x
@ -68,54 +123,63 @@ def valueconv(x):
return x return x
def as_dict(path='', version='latest', section='meta-data'):
def as_dict(path=''):
result = {} result = {}
dirs = dir(path, version, section) dirs = metadir(path)
if not dirs: if not dirs:
return None return None
for item in dirs: for item in dirs:
if item.endswith('/'): if item.endswith('/'):
records = as_dict(path+item, version, section) records = as_dict('/'.join([path, item]))
if records: if records:
result[item[:-1]] = records result[item[:-1]] = records
elif is_dict.match(item): elif is_dict.match(item):
idx, name = is_dict.match(item).groups() idx, name = is_dict.match(item).groups()
records = as_dict(path+idx+'/', version, section) records = as_dict('/'.join([path, idx + '/']))
if records: if records:
result[name] = records result[name] = records
else: else:
result[item] = valueconv(get(path+item, version, section)) result[item] = valueconv(get('/'.join([path, item])))
if isinstance(result, dict) and all(
(isint(key) and int(key) < len(result)) for key in result):
as_list = [None] * len(result)
for key, value in result.iteritems():
as_list[int(key)] = value
result = as_list
return result return result
def metadata(): def metadata():
result = as_dict() if METADATA_PROVIDER is None:
if result: try:
_probe()
except ValueError:
return None
if METADATA_PROVIDER == 'EC2':
result = { result = {
'meta-data': result 'meta-data': as_dict('meta-data'),
'dynamic': as_dict('dynamic'),
} }
user_data = get('', section='user-data') user_data = as_dict('user-data')
if user_data: if user_data:
try: try:
result.update({ result['user-data'] = dict(
'user-data': dict(x.split('=', 1) for x in user_data.split(';')) x.split('=', 1) for x in user_data.split(';')
}) )
except: except:
result.update({ result['user-data'] = user_data
'user-data': user_data
})
result.update({ elif METADATA_PROVIDER == 'MS':
'dynamic': as_dict('/', section='dynamic') result = json.loads(get(''))
}) else:
return 'EC2', result result = as_dict()
result = as_dict('', 'metadata', 'v1') return METADATA_PROVIDER, result
if result:
return 'DO', result
return None, None