Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 8 commits
  • 9 files changed
  • 0 commit comments
  • 3 contributors
Commits on May 15, 2012
Zhongyue Luo Fix dough api
Add query_monthly_report
dd8e37a
Commits on Jun 05, 2012
Zhongyue Luo Fix dough api
Resolve start of month time bug in query_monthly_report
f01c260
=Cheng Hui Fix dough api
Resolve bug in find_timeframe function
1d3de2d
Zhongyue Luo Fix dough api
Add order_size to query_usage_report response
59c1eec
Zhongyue Luo Merge branch 'master' of https://github.com/lzyeval/dough 0cd745e
Commits on Jun 12, 2012
Peng Yuwei pyw's discovery c0a1044
Commits on Jun 15, 2012
Peng Yuwei add bill detail interface: query_report() 90d3e78
Peng Yuwei Merge branch 'dev'
Conflicts:
	dough/api.py
7523869
8 bin/dough-api
View
@@ -6,9 +6,9 @@ import sys
import zmq
+from nova import utils
from nova import flags
from nova import log as logging
-from nova import utils
from dough import api
from dough import context as dough_context
@@ -25,6 +25,7 @@ if __name__ == '__main__':
# Socket to receive messages on
handler = zmq_context.socket(zmq.REP)
handler.bind("tcp://%s:%s" % (FLAGS.api_listen, FLAGS.api_listen_port))
+ print "listen:", FLAGS.api_listen, FLAGS.api_listen_port
poller = zmq.Poller()
poller.register(handler, zmq.POLLIN)
@@ -40,8 +41,13 @@ if __name__ == '__main__':
method = msg_body['method']
args = msg_body['args']
context = dough_context.get_context(**args)
+ print "-"*60
+ print "\033[0;31m" + method + "\033[0m:"
+ print args
method_func = getattr(api, method)
response = method_func(context, **args)
+ print "response:"
+ print response
except Exception, e:
print traceback.format_exc()
cli_msg['code'] = 500
101 bin/dough-client
View
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 Sina Corporation
+# All Rights Reserved.
+# Author: YuWei Peng <pengyuwei@gmail.com>
+#
+# 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.
+
+import sys
+import time
+import ConfigParser
+import json
+import zmq
+from collections import OrderedDict
+from dough.client.dough_client import *
+
+def show_usage():
+ print "usage:"
+ print "\tdough_client"
+ print "\tdough_client <param> <tenant_id> <time_from> [time_to] [period_hours]"
+ print "param:"
+ print "\t -m : query_monthly_report"
+ print "\t -d : query_report"
+ print "./dough-client -d 1adfb274fee24dbd96ea89b57d110fc5 2012-06-01T00:00:00 2012-07-01T00:00:00 days network resource_name"
+
+def show_result(data):
+ print data
+
+def show_report(data):
+# print "ID=", data['data']['id']
+ data = data['data']['default']
+ line_total_sum = 0
+ quantity_sum = 0
+ count = 0
+
+ rs = OrderedDict(sorted(data.items(), key=lambda t: t[0]))
+ for k, i in rs.iteritems():
+ count += 1
+ print '-' * 60, count
+ print k
+ for kk, ii in i.iteritems():
+ print "\t", kk, ii
+ if kk == 'line_total':
+ line_total_sum += ii
+ elif kk == 'quantity':
+ quantity_sum += ii
+ print "total[", count, "] = ", line_total_sum
+
+def main():
+ if len(sys.argv) == 2:
+ show_usage()
+ return
+ if len(sys.argv) == 3:
+ if sys.argv[2] in ['--help', "-h", "?"]:
+ show_usage()
+ return
+
+ data = None
+ client = DoughClient()
+
+ if len(sys.argv) > 8:
+ tenant_id = sys.argv[3]
+ time_from = sys.argv[4]
+ time_to = sys.argv[5]
+ period = sys.argv[6]
+ item_name = sys.argv[7]
+ resource_name = sys.argv[8]
+ if sys.argv[2] == '-d':
+ data = client.query_report(tenant_id, time_from, time_to, period,
+ item_name, resource_name)
+ else:
+ pass
+
+ show_report(data)
+ elif len(sys.argv) > 6:
+ return
+ elif len(sys.argv) > 5:
+ tenant_id = sys.argv[3]
+ time_from = sys.argv[4]
+ time_to = sys.argv[5]
+ if sys.argv[2] == '-m':
+ data = client.query_monthly_report(tenant_id, time_from, time_to)
+ else:
+ pass
+ show_result(data)
+ else:
+ pass
+
+if __name__ == '__main__':
+ main()
1  bin/dough-farmer
View
@@ -29,6 +29,7 @@ if __name__ == '__main__':
context = dough_context.get_admin_context()
while True:
current_time = utils.utcnow()
+ print "-" * 50, str(current_time)
subscriptions = list()
_subscriptions = db.subscription_get_all(context)
for sub in _subscriptions:
134 bin/dough-manager
View
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 Sina Corporation
+# All Rights Reserved.
+# Author: YuWei Peng <pengyuwei@gmail.com>
+#
+# 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.
+import datetime
+import sys
+import time
+import traceback
+
+#from dateutil.relativedelta import relativedelta
+#import zmq
+
+from nova import flags
+from nova import log as logging
+from nova import utils
+
+#from dough import billing
+# from dough.billing import api
+from dough import context as dough_context
+from dough import db
+from dough import api
+from nova.openstack.common import cfg
+#from dough import exception
+
+utils.default_flagfile(filename='/etc/dough/dough.conf')
+FLAGS = flags.FLAGS
+#logging.setup()
+
+manager_opts = [
+ cfg.StrOpt('resource_name',
+ short='r',
+ default='name1',
+ help='resource_name.'),
+ cfg.StrOpt('purchase',
+ short='p',
+ default='name1',
+ help='purchase.'),
+ cfg.StrOpt('help',
+ short='?',
+ default='',
+ help='help'),
+ ]
+
+FLAGS.register_cli_opts(manager_opts)
+flags.FLAGS(sys.argv)
+
+def show_usage():
+ print "dough-mansger -n <resource_name>"
+
+def get_subs(context, param):
+ print "filter: resource_name=", param
+ try:
+ sub = db.subscription_get_byname(context, resource_name=param)
+ subscription_id = sub['id']
+ status = sub['status']
+ tenant_id = sub['project_id']
+ resource_uuid = sub['resource_uuid']
+ created_at = sub['created_at']
+ updated_at = sub['updated_at']
+ expires_at = sub['expires_at']
+ order_unit = sub['product']['order_unit']
+ order_size = sub['product']['order_size']
+ price = sub['product']['price']
+ currency = sub['product']['currency']
+
+ region_name = sub['product']['region']['name']
+ item_name = sub['product']['item']['name']
+ pay_type = sub['product']['payment_type']
+ interval_unit = pay_type['interval_unit']
+ interval_size = pay_type['interval_size']
+ is_prepaid = pay_type['is_prepaid']
+ print '-'*60
+ print "%24s : %s" % ("subscription_id", str(subscription_id))
+ print "%24s : %s" % ("tenant_id", str(tenant_id))
+ print "%24s : %s" % ("expires_at", str(expires_at))
+ print "%24s : %s" % ("price", str(price))
+ print "%24s : %s" % ("region_name", str(region_name))
+ print "%24s : %s" % ("item_name", str(item_name))
+# print "%24s : %s" % ("pay_type", str(pay_type))
+ print "%24s : %s" % ("created_at", str(created_at))
+ except Exception, e:
+ print Exception, e
+
+def query_report(tenant_id, timestamp_from, timestamp_to):
+ datetime_from = iso8601.parse_date(timestamp_from)
+ datetime_to = iso8601.parse_date(timestamp_to)
+ context = dough_context.get_context(tenant_id=self.tenant_id)
+ data = api.query_report(self.context,
+ timestamp_from,
+ timestamp_to)
+ return data
+
+"""
+select id, subscription_id, created_at, quantity from purchases where subscription_id =151 and created_at>"2012-06-03 00:00:00";
+"""
+
+def main():
+ baselen = 2
+ context = dough_context.get_admin_context()
+ if len(sys.argv) == baselen:
+ get_subs(context, sys.argv)
+ return
+ if len(sys.argv) == baselen:
+ if sys.argv[baselen-1] in ['--help', "-h", "?"]:
+ show_usage()
+ return
+
+ if len(sys.argv) == baselen + 2:
+ param = sys.argv[baselen + 1]
+ if sys.argv[baselen][:2] == '-r':
+ get_subs(context, param)
+ elif len(sys.argv) == baselen + 4:
+ tenant_id = sys.argv[baselen + 1]
+ timestamp_from = sys.argv[baselen + 2]
+ timestamp_to = sys.argv[baselen + 3]
+ print query_report(tenant_id, timestamp_from, timestamp_to)
+
+
+if __name__ == '__main__':
+ main()
106 dough/api.py
View
@@ -166,9 +166,9 @@ def query_usage_report(context, timestamp_from=None,
# TODO(lzyeval): remove
#assert (line_total_sum == quantity_sum * price)
usage_datum = (resource_uuid, resource_name, item_type_name,
- order_unit, price, currency, quantity_sum,
- line_total_sum, created_at.isoformat(),
- expires_at.isoformat())
+ order_unit, order_size, price,
+ currency, quantity_sum, line_total_sum,
+ created_at.isoformat(), expires_at.isoformat())
region_usage = usage_report.setdefault(region_name, dict())
item_usage = region_usage.setdefault(item_name, list())
item_usage.append(usage_datum)
@@ -180,12 +180,16 @@ def query_monthly_report(context, timestamp_from=None,
def find_timeframe(start_time, end_time, target):
target_utc = target.replace(tzinfo=UTC_TIMEZONE)
current_frame = start_time
+ month_cnt = 1
while current_frame < end_time:
- next_frame = current_frame + relativedelta(months=1)
+ # 2012-05-10 00:00:00+00:00-->2012-06-10 00:00:00+00:00
+ next_frame = start_time + relativedelta(months=month_cnt)
if current_frame <= target_utc < next_frame:
break
+ month_cnt += 1
current_frame = next_frame
assert(current_frame < end_time)
+
return current_frame.isoformat()
monthly_report = dict()
@@ -216,3 +220,97 @@ def find_timeframe(start_time, end_time, target):
monthly_usage.setdefault(item_name, 0)
monthly_usage[item_name] += line_total
return {'data': monthly_report}
+
+def query_report(context, timestamp_from=None, timestamp_to=None,
+ period=None, item_name=None, resource_name=None, **kwargs):
+ """period='days' or 'hours'"""
+ print "query_report", timestamp_from, timestamp_to, item_name, resource_name
+# period = int(period)
+
+ if not period in ['days', 'hours', 'months']:
+ return {'data': None}
+
+ def find_timeframe(start_time, end_time, target):
+ target_utc = target.replace(tzinfo=UTC_TIMEZONE)
+ current_frame = start_time
+ cnt = 1
+ while current_frame < end_time:
+ foo = {period: cnt}
+ next_frame = start_time + relativedelta(**foo)
+ if current_frame <= target_utc < next_frame:
+ break
+ cnt += 1
+ current_frame = next_frame
+ assert(current_frame < end_time)
+ return current_frame.isoformat()
+
+ monthly_report = dict()
+ usage_report = dict()
+ datetime_from = iso8601.parse_date(timestamp_from)
+ datetime_to = iso8601.parse_date(timestamp_to)
+ subscriptions = list()
+ _subscriptions = list()
+
+ __subscriptions = db.subscription_get_all_by_project(context,
+ context.project_id)
+ if not __subscriptions:
+ return {'data': None}
+# print "context.project_id", context.project_id
+ for subscription in __subscriptions:
+# print subscription['id'], subscription['resource_name'], subscription['product']['item']['name']
+ if subscription['resource_name'] != resource_name:
+ continue
+ elif subscription['product']['item']['name'] != item_name:
+ continue
+ _subscriptions.append(subscription)
+
+ for subscription in _subscriptions:
+ subscription_id = subscription['id']
+ resource_uuid = subscription['resource_uuid']
+ resource_name = subscription['resource_name']
+ created_at = subscription['created_at']
+ expires_at = subscription['expires_at']
+ region_name = subscription['product']['region']['name']
+ item_name = subscription['product']['item']['name']
+ item_type_name = subscription['product']['item_type']['name']
+ order_unit = subscription['product']['order_unit']
+ order_size = subscription['product']['order_size']
+ price = subscription['product']['price']
+ currency = subscription['product']['currency']
+ subscriptions.append([subscription_id, resource_uuid, resource_name,
+ created_at, expires_at,
+ region_name, item_name, item_type_name,
+ order_unit, order_size, price, currency])
+ for (subscription_id, resource_uuid, resource_name, created_at, expires_at,
+ region_name, item_name, item_type_name,
+ order_unit, order_size, price, currency) in subscriptions:
+ purchases = db.purchase_get_all_by_subscription_and_timeframe(context,
+ subscription_id,
+ datetime_from,
+ datetime_to)
+ if not purchases:
+ continue
+ i = 0
+ for purchase in purchases:
+ line_total = purchase['line_total']
+ quantity = purchase['quantity']
+ timeframe = find_timeframe(datetime_from,
+ datetime_to,
+ purchase['created_at'])
+# print timeframe
+ i += 1
+ usage_datum = (resource_uuid, resource_name, item_type_name,
+ order_unit, order_size, price,
+ currency, quantity, line_total,
+ created_at.isoformat(), expires_at.isoformat())
+ region_usage = monthly_report.setdefault(region_name, dict())
+ monthly_usage = region_usage.setdefault(timeframe, dict())
+ item = monthly_usage.setdefault(item_name, 0)
+ monthly_usage[item_name] = usage_datum
+ item = monthly_usage.setdefault("quantity", 0)
+ monthly_usage.setdefault("line_total", 0)
+ monthly_usage["quantity"] += quantity
+ monthly_usage["line_total"] += line_total
+ print "total:", i
+ return {'data': monthly_report}
+
6 dough/billing/api.py
View
@@ -42,6 +42,8 @@ def creating(context, subscription_id, tenant_id, resource_uuid,
quantity = conn.get_usage(resource_uuid,
expires_at - relativedelta(**interval_info),
expires_at, order_size)
+ print "creating", tenant_id, subscription_id, \
+ quantity, order_size, "\033[1;33m", price, "\033[0m"
charge(context, tenant_id, subscription_id, quantity,
order_size, price)
db.subscription_extend(context, subscription_id,
@@ -67,6 +69,8 @@ def deleting(context, subscription_id, tenant_id, resource_uuid,
quantity = conn.get_usage(resource_uuid,
expires_at - relativedelta(**interval_info),
expires_at, order_size)
+ print "deleting", tenant_id, subscription_id, \
+ quantity, order_size, "\033[1;33m", price, "\033[0m"
charge(context, tenant_id, subscription_id, quantity,
order_size, price)
@@ -85,6 +89,8 @@ def verified(context, subscription_id, tenant_id, resource_uuid,
quantity = conn.get_usage(resource_uuid,
expires_at - relativedelta(**interval_info),
expires_at, order_size)
+ print "verified", tenant_id, subscription_id, \
+ quantity, order_size, "\033[1;33m", price, "\033[0m"
charge(context, tenant_id, subscription_id, quantity, order_size, price)
db.subscription_extend(context, subscription_id,
expires_at + relativedelta(**interval_info))
0  dough/client/__init__.py
View
No changes.
110 dough/client/dough_client.py
View
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 Sina Corporation
+# All Rights Reserved.
+# Author: YuWei Peng <pengyuwei@gmail.com>
+#
+# 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.
+
+import sys
+import time
+from md5 import md5
+import json
+import zmq
+import urllib2
+import datetime
+import base64
+from collections import OrderedDict
+
+from nova import utils
+from nova import flags
+from nova.openstack.common import cfg
+from nova import log as logging
+
+utils.default_flagfile(filename='/etc/dough/dough.conf')
+logging.setup()
+
+api_opts = [
+ cfg.StrOpt('api_host',
+ default='127.0.0.1',
+ help='IP address of dough API.'),
+ cfg.IntOpt('api_port',
+ default=8783,
+ help='Port of dough api.'),
+# cfg.StrOpt('monthly_report',
+# short='m',
+# default='name1',
+# help='monthly_report.'),
+ ]
+
+cli_opts = [
+ cfg.StrOpt('monthly_report',
+ short='m',
+ default='name1',
+ help='monthly_report.'),
+ ]
+
+FLAGS = flags.FLAGS
+FLAGS.register_cli_opts(cli_opts)
+FLAGS.register_opts(api_opts)
+flags.FLAGS(sys.argv)
+
+STANDARD_PROTOCOL = {
+ 'method': 'query_report',
+ 'args': {
+ 'user_id': '864bbc5d23ea47799ae2a702927920e9',
+ 'tenant_id': '864bbc5d23ea47799ae2a702927920e9',
+ 'timestamp_from': '2012-03-01T00:00:00',
+ 'timestamp_to': '2012-03-02T00:00:00',
+ }
+ }
+
+class DoughClient():
+
+ def __init__(self):
+ context = zmq.Context()
+ self.socket = context.socket(zmq.REQ)
+ connstr = "tcp://%(api_host)s:%(api_port)s" % FLAGS
+ # print connstr
+ self.socket.connect(connstr)
+
+ def invoke(self, param):
+ self.socket.send_multipart (["client", "1", json.dumps(param)])
+ msg_type, uuid, message = self.socket.recv_multipart()
+ return json.loads(message)
+
+ def query_monthly_report(self, tenant_id, time_from, time_to):
+ request = STANDARD_PROTOCOL
+ request["method"] = "query_monthly_report"
+ request["args"]["tenant_id"] = tenant_id
+ request["args"]["timestamp_from"] = time_from
+ request["args"]["timestamp_to"] = time_to
+
+ data = self.invoke(request)
+ return data
+
+ def query_report(self, tenant_id, time_from, time_to, period,
+ item_name, resource_name):
+ request = STANDARD_PROTOCOL
+ request["method"] = "query_report"
+ request["args"]["tenant_id"] = tenant_id
+ request["args"]["timestamp_from"] = time_from
+ request["args"]["timestamp_to"] = time_to
+ request["args"]["period"] = period
+ request["args"]["item_name"] = item_name
+ request["args"]["resource_name"] = resource_name
+
+ data = self.invoke(request)
+ return data
+
10 dough/db/sqlalchemy/api.py
View
@@ -241,6 +241,15 @@ def payment_type_get_by_name(context, payment_type_name):
# products
+def subscription_get_byname(context, resource_name):
+ result = model_query(context, models.Subscription).\
+ filter_by(resource_name=resource_name).\
+ first()
+ if not result:
+ return None
+ return result
+
+
def product_get(context, product_id):
result = model_query(context, models.Product).\
filter_by(id=product_id).\
@@ -352,6 +361,7 @@ def subscription_get_all_by_resource_uuid(context, resource_uuid):
def subscription_get_all(context, filters=None):
+ """filters={project_id:1}"""
filters = filters or dict()
filters = dict(filter(lambda (x, y): x in ['project_id',
'product_id',

No commit comments for this range

Something went wrong with that request. Please try again.