-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add options #5
base: master
Are you sure you want to change the base?
add options #5
Changes from 8 commits
fe4db9a
e856762
7eaa0c8
e90112e
021cddf
d603a1f
8469579
fb5e27b
28cd55d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
*.pyc | ||
dynamodb_create_cloudwatch_alarms.egg-info | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,15 +15,15 @@ If set as a cron job - updates existing alarms if | |
Read/Write Capacity Units DynamoDB table parameters changed. | ||
|
||
Usage: | ||
dynamodb_create_cloudwatch_alarms [options] | ||
dynamodb_create_cloudwatch_alarms [-h | --help] | ||
dynamodb-create-cloudwatch-alarms (-s <sns_topic_arn>) [-r <region>] [-p <prefix>] [--debug] | ||
dynamodb-create-cloudwatch-alarms [-h | --help] | ||
|
||
Options: | ||
--debug Don't send data to AWS | ||
|
||
Examples: | ||
dynamodb_create_cloudwatch_alarms | ||
dynamodb_create_cloudwatch_alarms --debug | ||
-s <sns_topic_arn> For sending alarm ( require ) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if it's required, don't make it an option, but make it an argument. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you also give a usage example so people know what to put as an sns topic arn? |
||
-r <region> AWS region | ||
-p <prefix> DynamoDB name prefix | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain what it's about for the user? |
||
--debug Don't send data to AWS | ||
|
||
``` | ||
|
||
# Install | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,40 +8,75 @@ | |
|
||
|
||
Usage: | ||
dynamodb-create-cloudwatch-alarms [options] | ||
dynamodb-create-cloudwatch-alarms (-s <sns_topic_arn>) [options] | ||
dynamodb-create-cloudwatch-alarms [-h | --help] | ||
|
||
Options: | ||
--debug Don't send data to AWS | ||
-s <sns_topic_arn> For sending alarm ( require ) | ||
-r <region> AWS region | ||
-p <prefix> DynamoDB name prefix | ||
--debug Don't send data to AWS | ||
|
||
""" | ||
import boto | ||
import boto.ec2 | ||
import boto.dynamodb | ||
import boto.dynamodb2 | ||
from docopt import docopt | ||
from boto.ec2.cloudwatch import MetricAlarm | ||
|
||
DEBUG = False | ||
AWS_REGION = u'ap-northeast-1' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather not put any default. Make it so it uses the default region configured in boto, and if use the region specified if one is specified. |
||
AWS_SNS_ARN = u'' | ||
DYNAMO_PREF = u'' | ||
|
||
DDB_METRICS = frozenset([u'ConsumedReadCapacityUnits', | ||
u'ConsumedWriteCapacityUnits']) | ||
ALARM_PERIOD = 300 | ||
ALARM_EVALUATION_PERIOD = 12 | ||
ALARM_EVALUATION_PERIOD = 6 | ||
RATE = 0.8 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a comment to explain what this RATE is? |
||
|
||
|
||
def get_ddb_tables(): | ||
def _get_ddb_tables_list(ddb_connection): | ||
""" | ||
Retrieves all DynamoDB table names | ||
|
||
Returns: | ||
(set) Of valid DynamoDB table names | ||
""" | ||
ddb_connection = boto.connect_dynamodb() | ||
|
||
ddb_tables_list_all = [] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's supposed to return a set, not point using a list here. |
||
|
||
ddb_tables_list = ddb_connection.list_tables() | ||
while u'LastEvaluatedTableName' in ddb_tables_list: | ||
ddb_tables_list_all.extend(ddb_tables_list[u'TableNames']) | ||
ddb_tables_list = ddb_connection.list_tables( | ||
exclusive_start_table_name=ddb_tables_list | ||
[u'LastEvaluatedTableName']) | ||
else: | ||
ddb_tables_list_all.extend(ddb_tables_list[u'TableNames']) | ||
|
||
return ddb_tables_list_all | ||
|
||
|
||
def get_ddb_tables(): | ||
""" | ||
Retrieves all DynamoDB table describe | ||
|
||
Returns: | ||
(set) Of valid DynamoDB table describe list | ||
""" | ||
|
||
ddb_connection = boto.dynamodb2.connect_to_region(AWS_REGION) | ||
ddb_tables_list = _get_ddb_tables_list(ddb_connection) | ||
|
||
ddb_tables = set() | ||
for ddb_table in ddb_tables_list: | ||
|
||
if DYNAMO_PREF and not ddb_table.startswith(DYNAMO_PREF): | ||
continue | ||
|
||
ddb_table_attributes = ddb_connection.describe_table(ddb_table) | ||
|
||
# creating a variable for each unit to satisfy flake8 | ||
ddb_tablename = ddb_table_attributes[u'Table'][u'TableName'] | ||
ddb_rcu = (ddb_table_attributes | ||
|
@@ -50,6 +85,17 @@ def get_ddb_tables(): | |
[u'Table'][u'ProvisionedThroughput'][u'WriteCapacityUnits']) | ||
ddb_tables.add((ddb_tablename, ddb_rcu, ddb_wcu)) | ||
|
||
# check GlobalSecondaryIndexes | ||
if u'GlobalSecondaryIndexes' not in ddb_table_attributes[u'Table']: | ||
continue | ||
|
||
gsi_list = ddb_table_attributes[u'Table'][u'GlobalSecondaryIndexes'] | ||
for gsi in gsi_list: | ||
ddb_indexname = gsi[u'IndexName'] | ||
ddb_rcu = (gsi[u'ProvisionedThroughput'][u'ReadCapacityUnits']) | ||
ddb_wcu = (gsi[u'ProvisionedThroughput'][u'WriteCapacityUnits']) | ||
ddb_tables.add((ddb_tablename, ddb_rcu, ddb_wcu, ddb_indexname)) | ||
|
||
return ddb_tables | ||
|
||
|
||
|
@@ -84,8 +130,9 @@ def get_existing_alarm_names(aws_cw_connect): | |
|
||
for existing_alarm in existing_alarms: | ||
if existing_alarm.namespace == u'AWS/DynamoDB': | ||
existing_alarm_names.update({existing_alarm.name: | ||
existing_alarm.threshold}) | ||
existing_alarm_names.update({existing_alarm.name: { | ||
u'threshold': existing_alarm.threshold, | ||
u'alarm_actions': existing_alarm.alarm_actions}}) | ||
|
||
return existing_alarm_names | ||
|
||
|
@@ -121,29 +168,43 @@ def get_ddb_alarms_to_create(ddb_tables, aws_cw_connect): | |
# initiate a MetricAlarm object for each DynamoDb table. | ||
# for the threshold we calculate the 80 percent | ||
# from the tables ProvisionedThroughput values | ||
if len(table) > 3: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain in a comment why this |
||
alarm_name = u'{0}-{1}-BasicAlarm'.format( | ||
table[0] + u'-' + table[3], | ||
metric.replace('Consumed', '') + 'Limit') | ||
alarm_dimensions = { | ||
u'TableName': table[0], | ||
u'GlobalSecondaryIndexName': table[3]} | ||
else: | ||
alarm_name = u'{0}-{1}-BasicAlarm'.format( | ||
table[0], | ||
metric.replace('Consumed', '') + 'Limit') | ||
alarm_dimensions = {u'TableName': table[0]} | ||
|
||
ddb_table_alarm = MetricAlarm( | ||
name=u'{}-{}-BasicAlarm'.format(table[0], | ||
(metric. | ||
replace('Consumed', | ||
'') + 'Limit')), | ||
name=alarm_name, | ||
namespace=u'AWS/DynamoDB', | ||
metric=u'{}'.format(metric), statistic='Sum', | ||
metric=u'{0}'.format(metric), statistic='Sum', | ||
comparison=u'>=', | ||
threshold=0.8*threshold*ALARM_PERIOD, | ||
threshold=RATE*threshold*ALARM_PERIOD, | ||
period=ALARM_PERIOD, | ||
evaluation_periods=ALARM_EVALUATION_PERIOD, | ||
# Below insert the actions appropriate. | ||
alarm_actions=[u'some_action'], | ||
dimensions={u'TableName': table[0]}) | ||
alarm_actions=[AWS_SNS_ARN], | ||
dimensions=alarm_dimensions) | ||
|
||
# we create an Alarm metric for each new DDB table | ||
if ddb_table_alarm.name not in existing_alarms.iterkeys(): | ||
alarms_to_create.add(ddb_table_alarm) | ||
# checking the existing alarms thresholds | ||
# update them if there are changes | ||
for key, value in existing_alarms.iteritems(): | ||
if (key == ddb_table_alarm.name | ||
and value != ddb_table_alarm.threshold): | ||
if key != ddb_table_alarm.name: | ||
continue | ||
|
||
if str(value[u'threshold']) != str(ddb_table_alarm.threshold): | ||
alarms_to_update.add(ddb_table_alarm) | ||
elif value[u'alarm_actions'] != ddb_table_alarm.alarm_actions: | ||
alarms_to_update.add(ddb_table_alarm) | ||
|
||
return (alarms_to_create, alarms_to_update) | ||
|
@@ -153,12 +214,23 @@ def main(): | |
args = docopt(__doc__) | ||
|
||
global DEBUG | ||
global AWS_REGION | ||
global AWS_SNS_ARN | ||
global DYNAMO_PREF | ||
|
||
AWS_SNS_ARN = args['-s'] | ||
|
||
if args['--debug']: | ||
DEBUG = True | ||
|
||
if args['-r']: | ||
AWS_REGION = args['-r'] | ||
|
||
if args['-p']: | ||
DYNAMO_PREF = args['-p'] | ||
|
||
ddb_tables = get_ddb_tables() | ||
aws_cw_connect = boto.connect_cloudwatch() | ||
aws_cw_connect = boto.ec2.cloudwatch.connect_to_region(AWS_REGION) | ||
|
||
(alarms_to_create, | ||
alarms_to_update) = get_ddb_alarms_to_create(ddb_tables, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefix with
/
?