170 lines
5.4 KiB
Python
170 lines
5.4 KiB
Python
#!/usr/bin/env python
|
|
# 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.
|
|
|
|
DOCUMENTATION = '''
|
|
---
|
|
module: ara_graphite
|
|
version_added: "1.0"
|
|
short_description: Send ARA stats to graphite
|
|
description:
|
|
- Python ansible module to send ARA stats to graphite
|
|
options:
|
|
graphite_host:
|
|
description:
|
|
- The hostname of the Graphite server with optional port:
|
|
graphite.example.com:2004. The default port is 2003
|
|
required: True
|
|
ara_mapping:
|
|
description:
|
|
- Mapping task names to Graphite paths
|
|
required: True
|
|
ara_data:
|
|
description:
|
|
- List of ARA results: ara result list --all -f json
|
|
required: True
|
|
ara_only_successful:
|
|
description:
|
|
- Whether to send only successful tasks, ignoring skipped and failed,
|
|
by default True.
|
|
required: True
|
|
'''
|
|
|
|
EXAMPLES = '''
|
|
- name: Get ARA json data
|
|
shell: "{{ local_working_dir }}/bin/ara task list --all -f json"
|
|
register: ara_data
|
|
|
|
- ara_graphite:
|
|
graphite_host: 10.2.2.2
|
|
ara_data: "{{ ara_task_output.stdout }}"
|
|
ara_mapping:
|
|
- "Name of task that deploys overcloud": overcloud.deploy.seconds
|
|
'''
|
|
import ast
|
|
import datetime
|
|
import socket
|
|
|
|
|
|
def stamp(x):
|
|
'''Convert ISO timestamp to Unix timestamp
|
|
|
|
:param x: string with timestamp
|
|
:return: string with Unix timestamp
|
|
'''
|
|
return datetime.datetime.strptime(x, "%Y-%m-%d %H:%M:%S").strftime('%s')
|
|
|
|
|
|
def task_length(x):
|
|
'''Calculate task length in seconds from "%H:%M:%S" format
|
|
|
|
:param x: datetime string
|
|
:return: number of seconds spent for task
|
|
'''
|
|
t = datetime.datetime.strptime(x, "%H:%M:%S")
|
|
return datetime.timedelta(hours=t.hour, minutes=t.minute,
|
|
seconds=t.second).total_seconds()
|
|
|
|
|
|
def translate(mapping, json_data, only_ok):
|
|
'''Create data to send to Graphite server in format:
|
|
|
|
GraphitePath Timestamp TaskDuration
|
|
GraphitePath is taken from mapping dictionary according to task name.
|
|
|
|
:param mapping: dictionary of mapping task names to graphite paths
|
|
:param json_data: JSON data with tasks and times
|
|
:return: list of graphite data
|
|
'''
|
|
items = []
|
|
data = ast.literal_eval(json_data)
|
|
for task in data:
|
|
if not only_ok or (only_ok and task['Status'] in ['changed', 'ok']):
|
|
if task['Name'] in mapping:
|
|
timestamp, duration = stamp(task['Time Start']), task_length(
|
|
task['Duration'])
|
|
items.append([mapping[task['Name']], duration, timestamp])
|
|
return items
|
|
|
|
|
|
def send(data, gr_host, gr_port, prefix):
|
|
'''Actual sending of data to Graphite server via network
|
|
|
|
:param data: list of items to send to Graphite
|
|
:param gr_host: Graphite host (with optional port)
|
|
:param prefix: prefix to append before Graphite path
|
|
:return: True if sent successfully, otherwise False
|
|
'''
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s.settimeout(3.0)
|
|
try:
|
|
s.connect((gr_host, gr_port))
|
|
except Exception as e:
|
|
return False, str(e)
|
|
for content in data:
|
|
s.send(prefix + " ".join([str(i) for i in content]) + "\n")
|
|
s.close()
|
|
return True, ''
|
|
|
|
|
|
def send_stats(gr_host, gr_port, mapping, json_data, prefix, only_ok):
|
|
'''Send ARA statistics to Graphite server
|
|
|
|
:param gr_host: Graphite host (with optional port)
|
|
:param mapping: dictionary of mapping task names to graphite paths
|
|
:param json_data: JSON data with tasks and times
|
|
:param prefix: prefix to append before Graphite path
|
|
:return: JSON ansible result
|
|
'''
|
|
data2send = translate(mapping, json_data, only_ok)
|
|
response, reason = send(data2send, gr_host, gr_port, prefix)
|
|
if not response:
|
|
return {
|
|
'changed': False,
|
|
'failed': True,
|
|
'graphite_host': gr_host,
|
|
'msg': "Can't connect to Graphite: %s" % reason
|
|
}
|
|
return {
|
|
'changed': True,
|
|
'graphite_host': gr_host,
|
|
'sent_data': data2send,
|
|
}
|
|
|
|
|
|
def main():
|
|
module = AnsibleModule( # noqa
|
|
argument_spec=dict(
|
|
graphite_host=dict(required=True, type='str'),
|
|
graphite_port=dict(required=False, type='int', default=2003),
|
|
ara_mapping=dict(required=True, type='dict'),
|
|
ara_data=dict(required=True, type='str'),
|
|
graphite_prefix=dict(required=False, type='str', default=''),
|
|
only_successful_tasks=dict(required=False, type='bool',
|
|
default=True)
|
|
)
|
|
)
|
|
result = send_stats(module.params['graphite_host'],
|
|
module.params['graphite_port'],
|
|
module.params['ara_mapping'],
|
|
module.params['ara_data'],
|
|
module.params['graphite_prefix'],
|
|
module.params['only_successful_tasks'])
|
|
module.exit_json(**result)
|
|
|
|
|
|
from ansible.module_utils.basic import * # noqa
|
|
|
|
if __name__ == "__main__":
|
|
main()
|