129 lines
4.6 KiB
Python
129 lines
4.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
from amplify.agent.common.context import context
|
|
|
|
|
|
__author__ = "Raymond Lau"
|
|
__copyright__ = "Copyright (C) Nginx, Inc. All rights reserved."
|
|
__license__ = ""
|
|
__maintainer__ = "Raymond Lau"
|
|
__email__ = "raymond.lau@nginx.com"
|
|
|
|
|
|
SUPPORTED_API_VERSIONS = [2]
|
|
|
|
|
|
def get_latest_supported_api(location_prefix, timeout=1, log=False):
|
|
"""
|
|
Hitting the location prefix for the API returns a list of supported API versions. This
|
|
function hits that endpoint and returns a URI to the current API version.
|
|
|
|
It's not mentioned in the api documentation if list of versions is guaranteed to be ordered
|
|
or if they can be 2.1, 2.2, etc. so doing some extra checking here to make sure
|
|
the actual latest version is taken, instead of just getting the value at the end of the list
|
|
:param location_prefix: str (ex. http://demo.nginx.com/api/)
|
|
:param timeout: Int
|
|
:param log: Boolean
|
|
:return: str
|
|
"""
|
|
api_versions_list = context.http_client.get(location_prefix, timeout=timeout, log=log)
|
|
supported_by_agent = set(api_versions_list).intersection(set(SUPPORTED_API_VERSIONS))
|
|
if len(supported_by_agent) == 0:
|
|
context.log.debug("No Nginx+ API versions %s are supported by this agent (%s)." % (api_versions_list, supported_by_agent))
|
|
return None
|
|
latest_supported_version = max(supported_by_agent)
|
|
api_uri = location_prefix
|
|
if api_uri[-1] != '/':
|
|
api_uri += '/'
|
|
api_uri += "%s" % latest_supported_version
|
|
return api_uri
|
|
|
|
|
|
def _traverse_versioned_plus_api(api_url, timeout=1, log=False, root_endpoints_to_skip=None):
|
|
"""
|
|
Get data from all of the Plus API endpoints and combine them into a
|
|
single dict, similar to how the now-deprecated plus status module would
|
|
return everything at once
|
|
|
|
ex. api_url=http://demo.nginx.com/api/2 returns a list of endpoints
|
|
["nginx","processes","connections", ...]
|
|
so we will call this func on /api/2/nginx, /api/2/processes,
|
|
/api/2/connections, and so on.
|
|
If it returns a json dictionary, we just take the output and return.
|
|
|
|
http://demo.nginx.com/api/2
|
|
:param api_url: str - base API endpoint
|
|
:return: dict containing aggregated responses of all the api endpoints
|
|
{
|
|
"processes" : { #output of /api/2/processes
|
|
"respawned: : 0
|
|
},
|
|
"nginx" : {...}, #output of /api/2/nginx
|
|
"connections" : {...},
|
|
"ssl" : {...},
|
|
"http" : {
|
|
"caches" : { #output of /api/2/http/caches
|
|
"http_cache" : {...},
|
|
...
|
|
},
|
|
"keyvals" : { #output of /api/2/http/keyvals
|
|
"nginx_plus_versions" : {...},
|
|
...
|
|
},
|
|
....
|
|
},
|
|
"stream" : {
|
|
"server_zones" : { #output of /api/2/stream/server_zones
|
|
"postgresql_loadbalancer" : {...},
|
|
...
|
|
},
|
|
...
|
|
},
|
|
"slabs" : {...}
|
|
...
|
|
}
|
|
|
|
"""
|
|
aggregated_responses = {}
|
|
|
|
try:
|
|
api_response = context.http_client.get(
|
|
api_url,
|
|
timeout=timeout,
|
|
log=log
|
|
)
|
|
except Exception as e:
|
|
context.log.error(
|
|
'Caught "%s" error during api traverse' % e.__class__.__name__
|
|
)
|
|
context.log.debug('additional info:', exc_info=True)
|
|
api_response = {}
|
|
|
|
if isinstance(api_response, list):
|
|
for endpoint in api_response:
|
|
if root_endpoints_to_skip is not None and endpoint in root_endpoints_to_skip:
|
|
aggregated_responses[endpoint] = {}
|
|
continue
|
|
api_response = _traverse_versioned_plus_api("%s/%s" % (api_url, endpoint), timeout=timeout, log=log)
|
|
aggregated_responses[endpoint] = api_response
|
|
elif isinstance(api_response, dict):
|
|
aggregated_responses = api_response
|
|
|
|
return aggregated_responses
|
|
|
|
|
|
def traverse_plus_api(location_prefix, timeout=1, log=False, root_endpoints_to_skip=None):
|
|
"""
|
|
Does basically the same thing as traverse_versioned_plus_api except that it gets the
|
|
current API from root endpoint before and traverses based on that
|
|
|
|
:param location_prefix: str (ex. http://demo.nginx.com/api/)
|
|
:param timeout:
|
|
:param log:
|
|
:param root_endpoints_to_skip: list of strings
|
|
:return: dict containing aggregated responses of all the api endpoints
|
|
"""
|
|
current_api = get_latest_supported_api(location_prefix, timeout, log)
|
|
if current_api is None:
|
|
return None
|
|
return _traverse_versioned_plus_api(current_api, timeout, log, root_endpoints_to_skip)
|