1414# License for the specific language governing permissions and limitations
1515# under the License.
1616
17- import datetime
18-
1917import ceilometerclient .client
2018import dateutil .parser
21- from dateutil import tz
22- import glanceclient .client
2319from oslo .config import cfg
2420
25- from caso .extract import base
21+ from caso .extract import nova
2622from caso import log
27- from caso import record
2823
2924CONF = cfg .CONF
30- CONF .import_opt ("site_name" , "caso.extract.manager" )
3125CONF .import_opt ("user" , "caso.extract.base" , "extractor" )
3226CONF .import_opt ("password" , "caso.extract.base" , "extractor" )
3327CONF .import_opt ("endpoint" , "caso.extract.base" , "extractor" )
3630LOG = 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