def __call__(self, req): resp = req.get_response(self.application) path_info = req.environ.get("PATH_INFO", "/") if not path_info.startswith("/images"): return resp method = req.environ.get("REQUEST_METHOD", "GET") if method == "PUT" or method == "POST": try: resp_json = json.loads(resp.body) img_id, img_size = resp_json["image"]["id"], resp_json[ "image"]["size"] except KeyError: return resp heart_request = {"name": img_id, "linear": img_size / (1024.0**3)} elif method == "DELETE": heart_request = { "name": path_info[len("/images/"):], "fixed": None } else: heart_request = None if heart_request is not None: heart_request["rtype"] = "glance/image" heart_request["account"] = req.headers["X-Tenant-Id"] heart_request["datetime"] = utils.datetime_to_str(utils.now()) try: self.billing_heart.event.create(heart_request) except: LOG.exception("cannot report image info for billing") return resp
def __call__(self, req): resp = req.get_response(self.application) path_info = req.environ.get("PATH_INFO", "/") if not path_info.startswith("/images"): return resp method = req.environ.get("REQUEST_METHOD", "GET") if method == "PUT" or method == "POST": try: resp_json = json.loads(resp.body) img_id, img_size = resp_json["image"]["id"], resp_json["image"]["size"] except KeyError: return resp heart_request = {"name": img_id, "linear": img_size / (1024.0 ** 3)} elif method == "DELETE": heart_request = {"name": path_info[len("/images/"):], "fixed": None} else: heart_request = None if heart_request is not None: heart_request["rtype"] = "glance/image" heart_request["account"] = req.headers["X-Tenant-Id"] heart_request["datetime"] = utils.datetime_to_str(utils.now()) try: self.billing_heart.event.create(heart_request) except: LOG.exception("cannot report image info for billing") return resp
def get_period(): if not request.args.has_key("time_period"): if "period_start" in request.args: period_start = utils.str_to_datetime(request.args["period_start"]) try: period_end = utils.str_to_datetime(request.args["period_end"]) except KeyError: raise BadRequest(description="period_end is request.ired") if not (period_start and period_end): raise BadRequest( description= "date should be in ISO 8601 format of YYYY-MM-DDThh:mm:ssZ" ) if period_start >= period_end: raise BadRequest( description="period_start must be less than period_end") return period_start, period_end else: now = utils.now() date_args = (now.year, now.month, 1) date_incr = 1 else: time_period_splitted = request.args["time_period"].split("-", 2) date_args = [1, 1, 1] for i in xrange(min(2, len(time_period_splitted))): try: date_args[i] = int(time_period_splitted[i]) except ValueError: raise BadRequest(description="invalid time_period `%s'" % request.args["time_period"]) date_incr = len(time_period_splitted) - 1 period_start = datetime.datetime(*date_args) if date_incr == 2: period_end = period_start + datetime.timedelta(days=1) else: year, month, day = date_args if date_incr == 1: month += 1 if month > 12: month = 1 year += 1 else: year += 1 period_end = datetime.datetime(year=year, month=month, day=day) return period_start, period_end
def get_period(): if not request.args.has_key("time_period"): if "period_start" in request.args: period_start = utils.str_to_datetime(request.args["period_start"]) try: period_end = utils.str_to_datetime(request.args["period_end"]) except KeyError: raise BadRequest(description="period_end is request.ired") if not (period_start and period_end): raise BadRequest( description="date should be in ISO 8601 format of YYYY-MM-DDThh:mm:ssZ") if period_start >= period_end: raise BadRequest( description="period_start must be less than period_end") return period_start, period_end else: now = utils.now() date_args = (now.year, now.month, 1) date_incr = 1 else: time_period_splitted = request.args["time_period"].split("-", 2) date_args = [1, 1, 1] for i in xrange(min(2, len(time_period_splitted))): try: date_args[i] = int(time_period_splitted[i]) except ValueError: raise BadRequest( description="invalid time_period `%s'" % request.args["time_period"]) date_incr = len(time_period_splitted) - 1 period_start = datetime.datetime(*date_args) if date_incr == 2: period_end = period_start + datetime.timedelta(days=1) else: year, month, day = date_args if date_incr == 1: month += 1 if month > 12: month = 1 year += 1 else: year += 1 period_end = datetime.datetime(year=year, month=month, day=day) return period_start, period_end
def get_event_datetime(self, body): return utils.now()
def __call__(self, req): """ Determine period start and stop, ask db api, and return JSON report. """ arg_dict = req.environ['wsgiorg.routing_args'][1] STATISTICS_NONE = 0 STATISTICS_SHORT = 1 STATISTICS_LONG = 2 queried_tenant_id = arg_dict.get("project_id", None) roles = [r.strip() for r in req.headers.get('X_ROLE', '').split(',')] is_admin = "Admin" in roles if not is_admin: if queried_tenant_id: if req.headers.get('X_TENANT_ID', '') != queried_tenant_id: raise webob.exc.HTTPUnauthorized() else: queried_tenant_id = req.headers.get('X_TENANT_ID', '-1') auth_token = req.headers.get('X_AUTH_TOKEN', '') period_start, period_end = self.get_period(req) statistics = {"instances": STATISTICS_NONE, "images": STATISTICS_NONE} try: include = req.GET["include"] except KeyError: statistics["instances"] = (STATISTICS_LONG if period_end - period_start <= datetime.timedelta(days=31) and queried_tenant_id else STATISTICS_SHORT) else: include = include.strip(",") for key in "images", "instances": if (key + "-long") in include: statistics[key] = STATISTICS_LONG elif key in include: statistics[key] = STATISTICS_SHORT if is_admin: tenants = keystone_utils.KeystoneTenants().\ get_tenants(auth_token) reported_projects = set([tenant.id for tenant in tenants]) if queried_tenant_id: if queried_tenant_id in reported_projects: reported_projects = set([queried_tenant_id]) else: raise webob.exc.HTTPNotFound() else: reported_projects = set([queried_tenant_id]) projects = {} for project_id in reported_projects: projects[project_id] = { "id": str(project_id), "url": "http://%s:%s/projects/%s" % (req.environ["SERVER_NAME"], req.environ["SERVER_PORT"], project_id), } now = utils.now() for statistics_key in "images", "instances": if not statistics[statistics_key]: continue show_items = statistics[statistics_key] == STATISTICS_LONG if statistics_key == "images": total_statistics = glance_utils.images_on_interval( period_start, period_end, auth_token, queried_tenant_id) else: total_statistics = db_api.instances_on_interval( period_start, period_end, queried_tenant_id) for project_id in projects: project_statistics = total_statistics.get(project_id, {}) project_dict = { "count": len(project_statistics), } project_usage = {} items = [] for item_id, item_statistics in project_statistics.items(): utils.dict_add(project_usage, item_statistics["usage"]) if show_items: lifetime = utils.total_seconds( min(item_statistics["destroyed_at"] or now, period_end) - max(item_statistics["created_at"], period_start)) item_dict = { "id": item_id, "lifetime_sec": lifetime, "usage": utils.usage_to_hours(item_statistics["usage"]), "name": item_statistics.get("name", None), } for key in "created_at", "destroyed_at": item_dict[key] = utils.datetime_to_str(item_statistics[key]) items.append(item_dict) if show_items: project_dict["items"] = items project_dict["usage"] = utils.usage_to_hours(project_usage) projects[project_id][statistics_key] = project_dict ans_dict = { "period_start": utils.datetime_to_str(period_start), "period_end": utils.datetime_to_str(period_end), "projects": projects.values(), } return webob.Response(json.dumps(ans_dict), content_type='application/json')
def images_on_interval(period_start, period_stop, auth_tok, tenant_id=None): """ Retrieve images statistics for the given interval [``period_start``, ``period_stop``]. ``tenant_id=None`` means all projects. Example of the returned value: .. code-block:: python { "1": { 12: { "created_at": datetime.datetime(2011, 1, 1), "destroyed_at": datetime.datetime(2011, 1, 2), "name": "Gentoo initrd", "usage": {"local_gb": 0.1}, }, 14: { "created_at": datetime.datetime(2011, 1, 4), "destroyed_at": datetime.datetime(2011, 2, 1), "name": "Ubuntu vmlinuz", "usage": {"local_gb": 2.5}, }, }, "2": { 24: { "created_at": datetime.datetime(2011, 1, 1), "destroyed_at": datetime.datetime(2011, 1, 2), "name": "RHEL vmlinuz", "usage": {"local_gb": 6.1}, }, } } :returns: a dictionary where keys are project ids and values are project statistics. """ glance_host, glance_port = pick_glance_api_server() client = glance_client.Client(glance_host, glance_port, auth_tok=auth_tok) images = client.get_images_detailed(filters={"is_public": "none"}) if tenant_id: images = [image for image in images if image["owner"] == tenant_id] else: images = [image for image in images if image["owner"] is not None] report_by_id = {} now = utils.now() for image in images: created_at = utils.str_to_datetime(image["created_at"]) if created_at >= period_stop: continue deleted_at = utils.str_to_datetime(image["deleted_at"]) if deleted_at and deleted_at <= period_start: continue lifetime = utils.total_seconds( min(deleted_at or now, period_stop) - max(created_at, period_start)) if lifetime < 0: lifetime = 0 try: tenant_statistics = report_by_id[image["owner"]] except KeyError: tenant_statistics = {} report_by_id[image["owner"]] = tenant_statistics tenant_statistics[image["id"]] = { "name": image["name"], "created_at": created_at, "destroyed_at": deleted_at, "usage": {"local_gb": image["size"] * lifetime / 2 ** 30} } return report_by_id