Merge "Send ARA statistics to Graphite server"
This commit is contained in:
commit
78b4acba4c
|
@ -116,3 +116,13 @@ artcl_logstash_files:
|
|||
- /home/*/yum_mirror.log
|
||||
- /home/*/tempest_output.log
|
||||
- /var/log/bootstrap-subnodes.log
|
||||
#ara_graphite_server: graphite.tripleo.org
|
||||
ara_graphite_prefix: "tripleo.{{ lookup('env', 'STABLE_RELEASE')|default('master', true) }}.{{ lookup('env', 'TOCI_JOBTYPE') }}."
|
||||
ara_only_successful_tasks: true
|
||||
ara_tasks_map:
|
||||
"overcloud-deploy : Deploy the overcloud": overcloud.deploy.seconds
|
||||
"undercloud-deploy : Install the undercloud": undercloud.install.seconds
|
||||
"build-images : run the image build script (direct)": overcloud.images.seconds
|
||||
"overcloud-prep-images : Prepare the overcloud images for deploy": prepare_images.seconds
|
||||
"validate-simple : Validate the overcloud": overcloud.ping_test.seconds
|
||||
"validate-tempest : Execute tempest": overcloud.tempest.seconds
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
#!/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']], timestamp, duration])
|
||||
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()
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
- name: Get ARA json data
|
||||
shell: "{{ local_working_dir }}/bin/ara result list --all -f json"
|
||||
register: ara_data
|
||||
|
||||
- name: Send to graphite
|
||||
ara_graphite:
|
||||
graphite_host: "{{ ara_graphite_server }}"
|
||||
ara_mapping: "{{ ara_tasks_map }}"
|
||||
ara_data: "{{ ara_data.stdout }}"
|
||||
graphite_prefix: "{{ ara_graphite_prefix }}"
|
||||
only_successful_tasks: "{{ ara_only_successful_tasks }}"
|
|
@ -23,6 +23,9 @@
|
|||
command: cp -a {{ local_working_dir }}/ara {{ artcl_collect_dir }}/ara
|
||||
ignore_errors: "yes"
|
||||
|
||||
- include: ara_graphite.yml
|
||||
when: ara_graphite_server is defined
|
||||
|
||||
- name: fetch stackviz results to the root of the collect_dir
|
||||
shell: >
|
||||
if [ -d {{ artcl_collect_dir }}/undercloud/var/log/extra/stackviz/data ]; then
|
||||
|
|
Loading…
Reference in New Issue