root / core / management / commands / parse_csv.py @ 04733cdb
History | View | Annotate | Download (6.6 kB)
1 |
# -*- coing: utf-8 -*- vim:encoding=utf-8:
|
---|---|
2 |
# vim: tabstop=4:shiftwidth=4:softtabstop=4:expandtab
|
3 |
|
4 |
# Copyright 2013 Leonidas Poulopoulos
|
5 |
#
|
6 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
7 |
# you may not use this file except in compliance with the License.
|
8 |
# You may obtain a copy of the License at
|
9 |
#
|
10 |
# http://www.apache.org/licenses/LICENSE-2.0
|
11 |
#
|
12 |
# Unless required by applicable law or agreed to in writing, software
|
13 |
# distributed under the License is distributed on an "AS IS" BASIS,
|
14 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15 |
# See the License for the specific language governing permissions and
|
16 |
# limitations under the License.
|
17 |
|
18 |
from django.core.management.base import BaseCommand, CommandError |
19 |
from django.conf import settings |
20 |
from core.models import * |
21 |
from graphs.models import * |
22 |
import csv |
23 |
import time |
24 |
|
25 |
import json |
26 |
from __genrgconfig__ import * |
27 |
from __dbfuncs__ import * |
28 |
|
29 |
# for file listing
|
30 |
from stat import S_ISREG, ST_CTIME, ST_MODE |
31 |
import os, sys, time, datetime |
32 |
|
33 |
class Command(BaseCommand): |
34 |
help = "Populates the lun series measurements from a csv file" \
|
35 |
"It assumes that the meassurement file is formatted like:\n" \
|
36 |
"<unix_timestamp>\n"\
|
37 |
"LUNID, METRIC_A, METRIC_B, METRIC_C, METRIC_D\n"\
|
38 |
"1, 0, 2, 2, 1\n"\
|
39 |
"2, 0, 0, 0, 0\n" \
|
40 |
"...\n" \
|
41 |
"N, 1, 2, 3, 1 \n" \
|
42 |
|
43 |
args = ""
|
44 |
label = ''
|
45 |
|
46 |
def handle(self, *args, **options): |
47 |
for statsfile in self.get_files_listing(): |
48 |
self.getgraph(statsfile)
|
49 |
print "Finished!" |
50 |
|
51 |
def get_files_listing(self): |
52 |
|
53 |
# path to the directory (relative or absolute)
|
54 |
dirpath = '/srv/emc-stats/incoming'
|
55 |
|
56 |
# get all entries in the directory w/ stats
|
57 |
entries = (os.path.join(dirpath, fn) for fn in os.listdir(dirpath)) |
58 |
entries = ((os.stat(path), path) for path in entries) |
59 |
|
60 |
# leave only regular files, insert creation date
|
61 |
entries = ((stat[ST_CTIME], path) |
62 |
for stat, path in entries if S_ISREG(stat[ST_MODE])) |
63 |
#NOTE: on Windows `ST_CTIME` is a creation date
|
64 |
# but on Unix it could be something else
|
65 |
#NOTE: use `ST_MTIME` to sort by a modification date
|
66 |
statfiles = [] |
67 |
for cdate, path in sorted(entries): |
68 |
statfiles.append("%s/%s"%('/srv/emc-stats/incoming',os.path.basename(path))) |
69 |
return statfiles
|
70 |
|
71 |
def getgraph(self, statsfile): |
72 |
# We assume that the following is received
|
73 |
# 1380622204
|
74 |
# LUN,Blocks Read,Blocks Write,Read Reqs,Write Reqs,
|
75 |
# 10,7346,8149,5311,9510,
|
76 |
# 20,4581,3879,2894,9419,
|
77 |
|
78 |
f = open(statsfile)
|
79 |
#print statsfile
|
80 |
# get first line. This is the timestamp
|
81 |
timestamp = "%s" %f.readline().replace('\n', '') |
82 |
reader = csv.reader(self.remove_last_char(f))
|
83 |
timestamp = self.round_to_5(int(timestamp)) |
84 |
out = {} |
85 |
luns = [] |
86 |
for i,serieslist in enumerate(reader): |
87 |
#print serieslist
|
88 |
lundict = {} |
89 |
if i == 0: |
90 |
#those are headers, ignore (for the time)
|
91 |
continue
|
92 |
lundict['lun_name'] = serieslist[0] |
93 |
lundict['timestamp'] = timestamp
|
94 |
lundict['blocksread'] = serieslist[1] |
95 |
lundict['blockswrite'] = serieslist[2] |
96 |
lundict['readreq'] = serieslist[3] |
97 |
lundict['writereq'] = serieslist[4] |
98 |
lun, created = Lun.objects.get_or_create(name="%s"%lundict['lun_name']) |
99 |
if created:
|
100 |
types = settings.LUN_GRAPH_TYPES |
101 |
for type in types: |
102 |
self.dbupdate(lun, type) |
103 |
lundict['lun_id'] = lun.pk
|
104 |
luns.append(lundict) |
105 |
self.update_graphs(luns)
|
106 |
f.close() |
107 |
print "Done with %s" %statsfile |
108 |
|
109 |
def update_graphs(self, lunslist): |
110 |
for lundict in lunslist: |
111 |
self.update_graph(lundict)
|
112 |
|
113 |
|
114 |
def update_graph(self, lundict): |
115 |
# Try to automate once proof of concept is done
|
116 |
#print "updating Lun %s"%(lundict['lun_name'])
|
117 |
dss_block = DataSource.objects.values('rrdfile').filter(tags__name="lun:%s"%lundict['lun_id']).filter(tags__name="type:blocksiostats").distinct() |
118 |
# This should return a single element list
|
119 |
if len(dss_block) != 1: |
120 |
print "ERROR: It appears that there are %s blocksiostats datasources for lun %s" %(len(dss_block), lundict['lun_name']) |
121 |
else:
|
122 |
rrdfile = dss_block[0]['rrdfile'] |
123 |
try:
|
124 |
rrdtool.update( |
125 |
str('%s'%(RrdFile.objects.get(pk=rrdfile).path)), |
126 |
str('--template'), str('ds0:ds1'), |
127 |
str(lundict['timestamp']+":" +lundict['blocksread']+":"+lundict['blockswrite'])) |
128 |
except Exception as e: |
129 |
#print e
|
130 |
pass
|
131 |
|
132 |
dss_req = DataSource.objects.values('rrdfile').filter(tags__name="lun:%s"%lundict['lun_id']).filter(tags__name="type:requeststats").distinct() |
133 |
# This should return a single element list
|
134 |
if len(dss_req) != 1: |
135 |
print "ERROR: It appears that there are %s requeststats datasources for lun %s" %(len(dss_req), lundict['lun_name']) |
136 |
else:
|
137 |
rrdfile = dss_req[0]['rrdfile'] |
138 |
try:
|
139 |
rrdtool.update( |
140 |
str('%s'%(RrdFile.objects.get(pk=rrdfile).path)), |
141 |
str('--template'), str('ds0:ds1'), |
142 |
str(lundict['timestamp']+":" +lundict['readreq']+":"+lundict['writereq'])) |
143 |
except Exception as e: |
144 |
#print e
|
145 |
pass
|
146 |
|
147 |
def round_to_5(self, timestamp): |
148 |
|
149 |
tm = datetime.datetime.fromtimestamp(timestamp) |
150 |
tm = tm - datetime.timedelta(minutes=tm.minute % 5,
|
151 |
seconds=tm.second, |
152 |
microseconds=tm.microsecond) |
153 |
return tm.strftime("%s") |
154 |
|
155 |
def remove_last_char(self, fileobj): |
156 |
for line in fileobj: |
157 |
yield line.strip()[:-1] |
158 |
|
159 |
def dbupdate(self, device, type): |
160 |
# Ok. A couple of hacks here. Instead of a if then elif then elif.... for each type
|
161 |
# we get first from the settings dictionnary the confdir and then the function used
|
162 |
# for this type from the globals() dictionary
|
163 |
try:
|
164 |
# dir = getattr(settings,'RG_%s_CONFDIR' % type.upper())
|
165 |
# self.checkdir(dir)
|
166 |
|
167 |
func = globals()['%s_genconfig' % type] |
168 |
func(device) |
169 |
except AttributeError as e: |
170 |
print "%s is not going to be configured because %s" % (type, e) |
171 |
return
|
172 |
|
173 |
|