import agent_util
import logging
from agent_util import float
try:
# Python 2.x
import httplib
except:
import http.client as httplib
try:
# Python 2.x
import urlparse
except:
import urllib.parse as urlpars
logger = logging.getLogger(__name__)
def execute_query(query):
ret, output = agent_util.execute_command(query)
return str(output)
class PHPFPMPlugin(agent_util.Plugin):
textkey = "phpfpm"
label = "PHP-FPM"
@classmethod
def get_metadata(self, config):
# Installation and config checks
installed = agent_util.which("php5-fpm") or agent_util.which("php-fpm")
configured = "console_url" in config
# if config is present, trust it and proceed
if configured:
self.log.info("console_url found in config. Marking plugin as supported")
status = agent_util.SUPPORTED
msg = None
# PHP-FPM is installed, but not configured, ask the user for more config assistance
elif installed and not configured:
self.log.info("PHP FPM binary found, but console_url is not in config")
status = agent_util.MISCONFIGURED
msg = "console_url is not in config"
return {}
# PHP-FPM does not appear to be installed and no config provided, disqualify the plugin
else:
self.log.info("No console_url provided and php-fpm binary not found")
status = agent_util.UNSUPPORTED
msg = "php-fpm binary not found"
return {}
# Generate options based on the number of entries in the config file.
options = config.get('console_url').split(',')
self.log.info('PHP-FPM is supported. Generating Metadata.')
# This is the metadata for the plugin.
data = {
"active processes": {
"label": "Active processes",
"options": options,
"status": status,
"error_message": msg
},
"idle processes": {
"label": "Idle processes",
"options": options,
"status": status,
"error_message": msg
},
"listen queue": {
"label": "Listen queue",
"options": options,
"status": status,
"error_message": msg
},
"listen queue len": {
"label": "Listen queue len",
"options": options,
"status": status,
"error_message": msg
},
"max active processes": {
"label": "Max active processes",
"options": options,
"status": status,
"error_message": msg
},
"max children reached": {
"label": "Children reached",
"options": options,
"status": status,
"error_message": msg
},
"max listen queue": {
"label": "Max listen queue",
"options": options,
"status": status,
"error_message": msg
},
"slow requests": {
"label": "Slow Requests",
"options": options,
"status": status,
"error_message": msg
},
"start since": {
"label": "Start since",
"options": options,
"status": status,
"error_message": msg
},
"start time": {
"label": "Start time",
"options": options,
"status": status,
"error_message": msg
},
"total processes": {
"label": "Total Processes",
"options": options,
"status": status,
"error_message": msg
},
}
return data
def check(self, textkey, data, config):
"""
Make a GET request to the console url and parse the output.
"""
if data.startswith('http'):
url = urlparse.urlparse(data + '?json&full')
if data.startswith('https:'):
connection = httplib.HTTPSConnection(
host=url.netloc, timeout=25
)
else:
connection = httplib.HTTPConnection(
host=url.netloc, timeout=25
)
connection.request('GET', '%s?%s' % (url.path, url.query))
resp = connection.getresponse()
if int(resp.status) != 200:
logging.error('Invalid response from %s/%s Reason: %s' % (
url.netloc, url.path, resp.reason
))
return
else:
output = resp.read().decode('utf-8')
connection.close()
else:
query = r'SCRIPT_NAME=/status SCRIPT_FILENAME=/status QUERY_STRING=json\&full REQUEST_METHOD=GET cgi-fcgi -bind -connect ' + data + ' |tail -1'
ret, output = agent_util.execute_command(query)
try:
statLines = agent_util.json_loads(output)
except Exception:
logging.exception('Unable to parse json output.')
return
metric = str(textkey).replace('_',' ')
if statLines.has_key(metric):
return float(statLines[metric])
else:
raise Exception('stats output did not contain metric ' + metric +". stats output: " + statLines)