51dc63bb07
Implements new client to demonstrate new Cloudwatch API Currently only provides options for DescribeAlarms, ListMetrics, PutMetricData and SetAlarmState Signed-off-by: Steven Hardy <shardy@redhat.com> Change-Id: I3963a07694cec9af96d9d7369cc7d18d629fcd2d
282 lines
8.6 KiB
Python
Executable File
282 lines
8.6 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
"""
|
|
This is the administration program for heat-api-cloudwatch.
|
|
It is simply a command-line interface for adding, modifying, and retrieving
|
|
information about the cloudwatch alarms and metrics belonging to a user.
|
|
It is a convenience application that talks to the heat Cloudwatch API server.
|
|
"""
|
|
|
|
import gettext
|
|
import optparse
|
|
import os
|
|
import os.path
|
|
import sys
|
|
import time
|
|
import json
|
|
import logging
|
|
|
|
from urlparse import urlparse
|
|
# If ../heat/__init__.py exists, add ../ to Python search path, so that
|
|
# it will override what happens to be installed in /usr/(local/)lib/python...
|
|
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
|
|
os.pardir,
|
|
os.pardir))
|
|
if os.path.exists(os.path.join(possible_topdir, 'heat', '__init__.py')):
|
|
sys.path.insert(0, possible_topdir)
|
|
|
|
scriptname = os.path.basename(sys.argv[0])
|
|
|
|
gettext.install('heat', unicode=1)
|
|
|
|
from heat import boto_client_cloudwatch as heat_client
|
|
from heat import version
|
|
from heat.common import config
|
|
from heat.common import exception
|
|
from heat import utils
|
|
|
|
DEFAULT_PORT=8003
|
|
|
|
@utils.catch_error('alarm-describe')
|
|
def alarm_describe(options, arguments):
|
|
'''
|
|
Describe detail for specified alarm, or all alarms
|
|
if no AlarmName is specified
|
|
'''
|
|
parameters={}
|
|
try:
|
|
parameters['AlarmName'] = arguments.pop(0)
|
|
except IndexError:
|
|
logging.info("No AlarmName passed, getting results for ALL alarms")
|
|
|
|
c = heat_client.get_client(options.port)
|
|
result = c.describe_alarm(**parameters)
|
|
print c.format_metric_alarm(result)
|
|
|
|
@utils.catch_error('alarm-set-state')
|
|
def alarm_set_state(options, arguments):
|
|
'''
|
|
Temporarily set state for specified alarm
|
|
'''
|
|
usage = ('''Usage:
|
|
%s alarm-set-state AlarmName StateValue [StateReason]''' %
|
|
(scriptname))
|
|
|
|
parameters={}
|
|
try:
|
|
parameters['AlarmName'] = arguments.pop(0)
|
|
parameters['StateValue'] = arguments.pop(0)
|
|
except IndexError:
|
|
logging.error("Must specify AlarmName and StateValue")
|
|
print usage
|
|
print "StateValue must be one of %s, %s or %s" % (
|
|
heat_client.BotoCWClient.ALARM_STATES)
|
|
return utils.FAILURE
|
|
try:
|
|
parameters['StateReason'] = arguments.pop(0)
|
|
except IndexError:
|
|
parameters['StateReason'] = ""
|
|
|
|
# We don't handle attaching data to state via this cli tool (yet)
|
|
parameters['StateReasonData'] = None
|
|
|
|
c = heat_client.get_client(options.port)
|
|
result = c.set_alarm_state(**parameters)
|
|
print result
|
|
|
|
|
|
@utils.catch_error('metric-list')
|
|
def metric_list(options, arguments):
|
|
'''
|
|
List all metric data for a given metric (or all metrics if none specified)
|
|
'''
|
|
parameters={}
|
|
try:
|
|
parameters['MetricName'] = arguments.pop(0)
|
|
except IndexError:
|
|
logging.info("No MetricName passed, getting results for ALL alarms")
|
|
|
|
c = heat_client.get_client(options.port)
|
|
result = c.list_metrics(**parameters)
|
|
print c.format_metric(result)
|
|
|
|
|
|
@utils.catch_error('metric-put-data')
|
|
def metric_put_data(options, arguments):
|
|
'''
|
|
Create a datapoint for a specified metric
|
|
'''
|
|
usage = ('''Usage:
|
|
%s metric-put-data AlarmName Namespace MetricName Units MetricValue
|
|
e.g
|
|
%s metric-put-data HttpFailureAlarm system/linux ServiceFailure Count 1
|
|
''' % (scriptname, scriptname))
|
|
|
|
# NOTE : we currently only support metric datapoints associated with a
|
|
# specific AlarmName, due to the current engine/db cloudwatch
|
|
# implementation, we should probably revisit this so we can support
|
|
# more generic metric data collection
|
|
parameters={}
|
|
try:
|
|
parameters['AlarmName'] = arguments.pop(0)
|
|
parameters['Namespace'] = arguments.pop(0)
|
|
parameters['MetricName'] = arguments.pop(0)
|
|
parameters['MetricUnit'] = arguments.pop(0)
|
|
parameters['MetricValue'] = arguments.pop(0)
|
|
except IndexError:
|
|
logging.error("Please specify the alarm, metric, unit and value")
|
|
print usage
|
|
return utils.FAILURE
|
|
|
|
c = heat_client.get_client(options.port)
|
|
result = c.put_metric_data(**parameters)
|
|
print result
|
|
|
|
|
|
def create_options(parser):
|
|
"""
|
|
Sets up the CLI and config-file options that may be
|
|
parsed and program commands.
|
|
|
|
:param parser: The option parser
|
|
"""
|
|
parser.add_option('-v', '--verbose', default=False, action="store_true",
|
|
help="Print more verbose output")
|
|
parser.add_option('-d', '--debug', default=False, action="store_true",
|
|
help="Print more verbose output")
|
|
parser.add_option('-p', '--port', dest="port", type=int,
|
|
default=DEFAULT_PORT,
|
|
help="Port the heat API host listens on. "
|
|
"Default: %default")
|
|
|
|
|
|
def parse_options(parser, cli_args):
|
|
"""
|
|
Returns the parsed CLI options, command to run and its arguments, merged
|
|
with any same-named options found in a configuration file
|
|
|
|
:param parser: The option parser
|
|
"""
|
|
if not cli_args:
|
|
cli_args.append('-h') # Show options in usage output...
|
|
|
|
(options, args) = parser.parse_args(cli_args)
|
|
|
|
# HACK(sirp): Make the parser available to the print_help method
|
|
# print_help is a command, so it only accepts (options, args); we could
|
|
# one-off have it take (parser, options, args), however, for now, I think
|
|
# this little hack will suffice
|
|
options.__parser = parser
|
|
|
|
if not args:
|
|
parser.print_usage()
|
|
sys.exit(0)
|
|
|
|
command_name = args.pop(0)
|
|
command = lookup_command(parser, command_name)
|
|
|
|
if options.debug:
|
|
logging.basicConfig(format='%(levelname)s:%(message)s',
|
|
level=logging.DEBUG)
|
|
logging.debug("Debug level logging enabled")
|
|
elif options.verbose:
|
|
logging.basicConfig(format='%(levelname)s:%(message)s',
|
|
level=logging.INFO)
|
|
else:
|
|
logging.basicConfig(format='%(levelname)s:%(message)s',
|
|
level=logging.WARNING)
|
|
|
|
return (options, command, args)
|
|
|
|
|
|
def print_help(options, args):
|
|
"""
|
|
Print help specific to a command
|
|
"""
|
|
parser = options.__parser
|
|
|
|
if not args:
|
|
parser.print_usage()
|
|
|
|
subst = {'prog': os.path.basename(sys.argv[0])}
|
|
docs = [lookup_command(parser, cmd).__doc__ % subst for cmd in args]
|
|
print '\n\n'.join(docs)
|
|
|
|
|
|
def lookup_command(parser, command_name):
|
|
base_commands = {'help': print_help}
|
|
|
|
watch_commands = {
|
|
'describe': alarm_describe,
|
|
'set-state': alarm_set_state,
|
|
'metric-list': metric_list,
|
|
'metric-put-data': metric_put_data}
|
|
|
|
commands = {}
|
|
for command_set in (base_commands, watch_commands):
|
|
commands.update(command_set)
|
|
|
|
try:
|
|
command = commands[command_name]
|
|
except KeyError:
|
|
parser.print_usage()
|
|
sys.exit("Unknown command: %s" % command_name)
|
|
|
|
return command
|
|
|
|
|
|
def main():
|
|
'''
|
|
'''
|
|
usage = """
|
|
%prog <command> [options] [args]
|
|
|
|
Commands:
|
|
|
|
help <command> Output help for one of the commands below
|
|
|
|
describe Describe a specified alarm (or all alarms)
|
|
|
|
set-state Temporarily set the state of an alarm
|
|
|
|
metric-list List data-points for specified metric
|
|
|
|
metric-put-data Publish data-point for specified metric
|
|
|
|
"""
|
|
oparser = optparse.OptionParser(version='%%prog %s'
|
|
% version.version_string(),
|
|
usage=usage.strip())
|
|
create_options(oparser)
|
|
(opts, cmd, args) = parse_options(oparser, sys.argv[1:])
|
|
|
|
try:
|
|
start_time = time.time()
|
|
result = cmd(opts, args)
|
|
end_time = time.time()
|
|
logging.debug("Completed in %-0.4f sec." % (end_time - start_time))
|
|
sys.exit(result)
|
|
except (RuntimeError,
|
|
NotImplementedError,
|
|
exception.ClientConfigurationError), ex:
|
|
oparser.print_usage()
|
|
logging.error("ERROR: %s" % ex)
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|