Skip to content

Commit 3e52724

Browse files
committed
Ceilometer extractor now extends nova information.
1 parent d9a6c46 commit 3e52724

File tree

1 file changed

+28
-122
lines changed

1 file changed

+28
-122
lines changed

caso/extract/ceilometer.py

Lines changed: 28 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,14 @@
1414
# License for the specific language governing permissions and limitations
1515
# under the License.
1616

17-
import datetime
18-
1917
import ceilometerclient.client
2018
import dateutil.parser
21-
from dateutil import tz
22-
import glanceclient.client
2319
from oslo.config import cfg
2420

25-
from caso.extract import base
21+
from caso.extract import nova
2622
from caso import log
27-
from caso import record
2823

2924
CONF = cfg.CONF
30-
CONF.import_opt("site_name", "caso.extract.manager")
3125
CONF.import_opt("user", "caso.extract.base", "extractor")
3226
CONF.import_opt("password", "caso.extract.base", "extractor")
3327
CONF.import_opt("endpoint", "caso.extract.base", "extractor")
@@ -36,7 +30,7 @@
3630
LOG = log.getLogger(__name__)
3731

3832

39-
class CeilometerExtractor(base.BaseExtractor):
33+
class CeilometerExtractor(nova.OpenStackExtractor):
4034
def _get_ceilometer_client(self, tenant):
4135
return ceilometerclient.client.get_client(
4236
'2',
@@ -46,18 +40,6 @@ def _get_ceilometer_client(self, tenant):
4640
os_tenant_name=tenant,
4741
insecure=CONF.extractor.insecure)
4842

49-
def _get_glance_client(self, ks_client):
50-
glance_ep = ks_client.service_catalog.get_endpoints(
51-
service_type='image',
52-
endpoint_type='public')
53-
glance_url = glance_ep['image'][0]['publicURL']
54-
# glance client does not seem to work with user/password
55-
return glanceclient.client.Client(
56-
'2',
57-
glance_url,
58-
token=ks_client.auth_token,
59-
insecure=CONF.extractor.insecure)
60-
6143
def _build_query(self, project_id=None, start_date=None, end_date=None):
6244
q = []
6345
if project_id:
@@ -80,19 +62,24 @@ def _fill_metric(self, metric_name, samples, records,
8062
"""
8163

8264
instance_timestamps = {}
83-
the_past = datetime.datetime(1, 1, 1)
8465
for sample in samples:
8566
instance_id = get_id(sample)
86-
r = records.get(instance_id)
87-
if not r:
88-
# XXX: there is a sample for a VM that has no instance sample?
89-
LOG.debug("VM with some usage info but no instance metric?!")
67+
try:
68+
r = records[instance_id]
69+
except KeyError:
9070
continue
91-
instance_ts = instance_timestamps.get(instance_id, the_past)
71+
# takes the maximum value from ceilometer
72+
sample_value = unit_conv(sample.counter_volume)
73+
instance_ts = instance_timestamps.get(instance_id, None)
74+
if instance_ts is None:
75+
r.__dict__[metric_name] = sample_value
76+
try:
77+
r.__dict__[metric_name] = max(r.__dict__[metric_name],
78+
sample_value)
79+
except KeyError:
80+
r.__dict__[metric_name] = sample_value
9281
sample_ts = dateutil.parser.parse(sample.timestamp)
93-
if sample_ts > instance_ts:
94-
r.__dict__[metric_name] = unit_conv(sample.counter_volume)
95-
instance_timestamps[instance_id] = sample_ts
82+
instance_timestamps[instance_id] = sample_ts
9683

9784
def _fill_cpu_metric(self, cpu_samples, records):
9885
self._fill_metric('cpu_duration', cpu_samples, records,
@@ -105,104 +92,23 @@ def _fill_net_metric(self, metric_name, net_samples, records):
10592
# convert bytes to GB
10693
unit_conv=lambda v: int(v / 2 ** 30))
10794

108-
def _get_time_field(self, metadata, fields=[]):
109-
for f in fields:
110-
t = metadata.get(f, None)
111-
if t:
112-
dateutil.parser.parse(t).replace(tzinfo=None)
113-
else:
114-
return None
115-
116-
def _build_record(self, instance, users, vo, images, now):
117-
metadata = instance.resource_metadata
118-
status = self.vm_status(metadata.get('state', ''))
119-
instance_image_id = metadata.get('image.id')
120-
if not instance_image_id:
121-
instance_image_id = metadata.get('image_meta.base_image_ref')
122-
image_id = None
123-
for image in images:
124-
if instance_image_id == image.id:
125-
image_id = image.get('vmcatcher_event_ad_mpuri', None)
126-
break
127-
else:
128-
image_id = instance_image_id
129-
r = record.CloudRecord(instance.resource_id,
130-
CONF.site_name,
131-
metadata.get('display_name'),
132-
instance.user_id,
133-
instance.project_id,
134-
vo,
135-
cpu_count=metadata.get('vcpus'),
136-
memory=metadata.get('memory_gb'),
137-
disk=metadata.get('disk_gb'),
138-
# this should contain "caso ceilometer vX"
139-
cloud_type="OpenStack",
140-
status=status,
141-
image_id=image_id,
142-
user_dn=users.get(instance.user_id, None))
143-
144-
start_time = self._get_time_field(metadata,
145-
('launched_at', 'created_at'))
146-
end_time = self._get_time_field(metadata,
147-
('terminated_at', 'deleted_at'))
148-
if start_time:
149-
r.start_time = int(start_time.strftime("%s"))
150-
if end_time:
151-
r.end_time = int(end_time.strftime("%s"))
152-
wall = end_time - start_time
153-
r.wall_duration = int(wall.total_seconds())
154-
else:
155-
wall = now - start_time
156-
r.wall_duration = int(wall.total_seconds())
157-
return r
158-
15995
def extract_for_tenant(self, tenant, lastrun):
160-
now = datetime.datetime.now(tz.tzutc())
161-
now.replace(tzinfo=None)
162-
96+
records = super(CeilometerExtractor,
97+
self).extract_for_tenant(tenant, lastrun)
16398
# Try and except here
164-
# Getting clients
165-
ks_client = self._get_keystone_client(tenant)
166-
client = self._get_ceilometer_client(tenant)
167-
glance_client = self._get_glance_client(ks_client)
168-
169-
# users
170-
users = self._get_keystone_users(ks_client)
171-
tenant_id = ks_client.tenant_id
172-
173-
search_query = self._build_query(tenant_id, lastrun)
174-
instances = client.samples.list('instance', search_query)
175-
176-
# XXX should we query glance for every VM or not?
177-
images = list(glance_client.images.list())
178-
179-
records = {}
180-
181-
vo = self.voms_map.get(tenant)
182-
183-
for instance in instances:
184-
# it seems the only event type with relevant metadata is
185-
# 'compute.instance.exists'
186-
ev_type = instance.resource_metadata.get('event_type', None)
187-
if ev_type != 'compute.instance.exists':
188-
continue
189-
# this assumes that records are returned with decreasing timestamp
190-
# so the status and dates are the last ones.
191-
if instance.resource_id in records:
192-
continue
193-
records[instance.resource_id] = self._build_record(instance,
194-
users,
195-
vo,
196-
images,
197-
now)
99+
ks_conn = self._get_keystone_client(tenant)
100+
conn = self._get_ceilometer_client(tenant)
101+
# See comment in nova.py, remove TZ from the dates.
102+
lastrun = lastrun.replace(tzinfo=None)
103+
search_query = self._build_query(ks_conn.tenant_id, lastrun)
198104

199-
cpu = client.samples.list(meter_name='cpu', q=search_query)
105+
cpu = conn.samples.list(meter_name='cpu', q=search_query)
200106
self._fill_cpu_metric(cpu, records)
201-
net_in = client.samples.list(meter_name='network.incoming.bytes',
202-
q=search_query)
107+
net_in = conn.samples.list(meter_name='network.incoming.bytes',
108+
q=search_query)
203109
self._fill_net_metric('network_in', net_in, records)
204-
net_out = client.samples.list(meter_name='network.outcoming.bytes',
205-
q=search_query)
110+
net_out = conn.samples.list(meter_name='network.outcoming.bytes',
111+
q=search_query)
206112
self._fill_net_metric('network_out', net_out, records)
207113

208114
return records

0 commit comments

Comments
 (0)