Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
CIRCLE
/
cloud
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
94
Merge Requests
10
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
c60d95ab
authored
Jun 10, 2016
by
Tamás
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Error handling, output handling not perfect.
parent
b69cd81e
Pipeline
#99
failed with stage
in 0 seconds
Changes
1
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
467 additions
and
0 deletions
+467
-0
circle/accounting.py
+467
-0
No files found.
circle/accounting.py
0 → 100644
View file @
c60d95ab
#!/usr/env/bin python
# coding=utf-8
# vim: set fileencoding=utf-8
###########################################################
#
# Accounting modul for Circle cloud.
#
# Created by Csatlós Tamás Péter
#
#
############################################################
from
django.contrib.auth.models
import
User
from
django.db.models
import
Q
from
datetime
import
datetime
from
datetime
import
timedelta
from
operator
import
itemgetter
import
json
ACC_DATE_FORMAT
=
'
%
Y.
%
m.
%
d
%
H:
%
M:
%
S.
%
f'
# const to the dates
ACC_FILE_NAME
=
'acc_out.json'
# Collect every data for accounting
class
ResourceCollector
():
name
=
'resource_collector'
def
__init__
(
self
,
delta_time
=
7
,
start
=
None
,
end
=
None
):
self
.
activities
=
dict
()
self
.
is_collection_successfull
=
False
if
start
is
None
:
if
delta_time
is
None
or
delta_time
<
1
:
raise
Exception
(
'End date is missing!'
)
if
end
is
None
:
temp_date
=
datetime
.
now
()
self
.
end_date
=
datetime
(
temp_date
.
year
,
temp_date
.
month
,
temp_date
.
day
,
temp_date
.
hour
+
(
23
-
temp_date
.
hour
),
temp_date
.
minute
+
(
59
-
temp_date
.
minute
),
temp_date
.
second
+
(
59
-
temp_date
.
second
)
)
else
:
assert
isinstance
(
end
,
datetime
)
self
.
end_date
=
end
self
.
dt
=
delta_time
self
.
start_date
=
self
.
end_date
-
timedelta
(
days
=
delta_time
,
hours
=
self
.
end_date
.
hour
,
minutes
=
self
.
end_date
.
minute
,
seconds
=
self
.
end_date
.
second
)
else
:
if
end
is
None
:
raise
Exception
(
'End date is missing!'
)
assert
isinstance
(
start
,
datetime
)
assert
isinstance
(
end
,
datetime
)
delta_time
=
end
-
start
if
delta_time
.
days
<
1
:
raise
Exception
(
'Least one day time interval!'
)
self
.
start_date
=
start
self
.
end_date
=
end
self
.
dt
=
delta_time
.
days
def
get_time_interval
(
self
):
return
{
'start'
:
self
.
start_date
,
'end'
:
self
.
end_date
}
# Collect every user's data.
def
collect_data
(
self
):
try
:
# get every user from the db (db conn. #1)
users
=
User
.
objects
.
all
()
for
user
in
users
:
temp_list
=
self
.
collect_user_data
(
self
.
start_date
,
self
.
end_date
,
user
)
self
.
activities
[
user
.
get_username
()]
=
temp_list
self
.
is_collection_successfull
=
True
return
True
except
Exception
as
ex
:
print
ex
.
message
return
False
def
write_data
(
self
,
filename
=
ACC_FILE_NAME
):
try
:
if
self
.
is_collection_successfull
:
with
open
(
filename
,
'w'
)
as
file
:
json
.
dump
(
self
.
activities
,
file
,
indent
=
4
,
separators
=
(
','
,
': '
)
)
return
True
else
:
return
False
except
Exception
:
return
False
def
write_given_resource_data
(
self
,
resources
,
filename
):
try
:
if
(
not
resources
==
{}
or
not
filename
==
''
):
with
open
(
filename
,
'w'
)
as
file
:
json
.
dump
(
resources
,
file
,
indent
=
4
,
separators
=
(
','
,
': '
)
)
return
True
else
:
return
False
except
Exception
:
return
False
def
collect_user_data
(
self
,
start_time
,
end_time
,
user
):
if
user
is
None
:
return
None
temp_list
=
[]
usr_acts
=
user
.
instanceactivity_set
.
filter
(
Q
(
started__range
=
(
start_time
,
end_time
)),
Q
(
finished__range
=
(
start_time
,
end_time
)),
Q
(
succeeded__exact
=
True
),
Q
(
activity_code__exact
=
'vm.Instance.deploy'
)
|
Q
(
activity_code__exact
=
'vm.Instance.create'
)
|
Q
(
activity_code__exact
=
'vm.Instance.destroy'
)
|
Q
(
activity_code__exact
=
'vm.Instance.sleep'
)
|
Q
(
activity_code__exact
=
'vm.Instance.wake_up'
)
|
Q
(
activity_code__exact
=
'vm.Instance.sleep'
)
|
Q
(
activity_code__exact
=
'vm.Instance.renew'
)
|
Q
(
activity_code__startswith
=
'vm.Instance.shut'
)
)
.
order_by
(
'instance_id'
,
'started'
)
.
values
(
'id'
,
'instance_id'
,
'user_id'
,
'started'
,
'finished'
,
'activity_code'
)
.
all
()
for
act
in
usr_acts
:
useful_data_chunk
=
dict
(
id
=
act
[
'id'
],
# Activity ID
activity_code
=
act
[
'activity_code'
],
# What?
started
=
act
[
'started'
]
.
strftime
(
ACC_DATE_FORMAT
),
# When?
finished
=
act
[
'finished'
]
.
strftime
(
ACC_DATE_FORMAT
),
user_id
=
act
[
'user_id'
],
# Who did that?
instance_id
=
act
[
'instance_id'
]
)
instances
=
user
.
instance_set
.
filter
(
Q
(
id__exact
=
act
[
'instance_id'
]),
Q
(
owner_id__exact
=
act
[
'user_id'
])
)
.
all
()
if
instances
:
ins
=
instances
[
0
]
useful_data_chunk
[
'ram'
]
=
ins
.
ram_size
useful_data_chunk
[
'cores'
]
=
ins
.
num_cores
useful_data_chunk
[
'core_prio'
]
=
ins
.
priority
useful_data_chunk
[
'disks'
]
=
[]
# Get all disks
ins_disks
=
ins
.
disks
.
all
()
.
values
(
'size'
,
'id'
)
for
disk
in
ins_disks
:
useful_data_chunk
[
'disks'
]
.
append
(
{
'size'
:
disk
[
'size'
],
'id'
:
disk
[
'id'
]}
)
else
:
# Sharaed machine
useful_data_chunk
[
'ram'
]
=
-
1
useful_data_chunk
[
'cores'
]
=
-
1
useful_data_chunk
[
'core_prio'
]
=
-
1
useful_data_chunk
[
'is_running'
]
=
None
useful_data_chunk
[
'disks'
]
=
[]
temp_list
.
append
(
useful_data_chunk
)
return
temp_list
def
get_one_users_data
(
self
,
user
=
u'admin'
):
if
self
.
is_collection_successfull
:
return
self
.
activities
[
user
]
else
:
return
None
def
get_data
(
self
):
if
self
.
is_collection_successfull
:
return
self
.
activities
else
:
return
None
def
is_successfull
(
self
):
return
self
.
is_collection_successfull
# Makes report about the resource usage
class
ReportMaker
():
name
=
'report_maker'
# create report maker object
# start, end has to be datetime objects
def
__init__
(
self
,
start
,
end
,
collected_data
=
None
):
try
:
self
.
data
=
None
self
.
is_data_avaiable
=
False
if
collected_data
is
None
:
self
.
read_data
()
else
:
self
.
data
=
collected_data
assert
isinstance
(
start
,
datetime
)
assert
isinstance
(
end
,
datetime
)
self
.
start_date
=
start
self
.
end_date
=
end
self
.
is_data_avaiable
=
True
except
Exception
:
self
.
data
=
None
self
.
is_data_avaiable
=
False
def
set_data
(
self
,
new_data
):
self
.
data
=
new_data
def
get_time_interval
(
self
):
return
{
'start'
:
self
.
start_date
,
'end'
:
self
.
end_date
}
def
read_data
(
self
,
filename
=
ACC_FILE_NAME
):
try
:
self
.
is_data_avaiable
=
False
with
open
(
filename
,
'r'
)
as
file
:
self
.
data
=
json
.
load
(
file
)
self
.
is_data_avaiable
=
True
return
True
except
Exception
:
self
.
is_data_avaiable
=
False
return
False
def
make_report_about_everyone
(
self
):
if
self
.
is_data_avaiable
:
for
user
in
self
.
data
.
keys
():
file_name
=
user
+
'.txt'
if
self
.
data
[
user
]
==
[]:
users_bill
=
None
else
:
users_bill
=
self
.
billing
(
user
,
self
.
data
[
user
])
# start and end is datetime, not serializable
interval
=
{
'start'
:
self
.
start_date
.
strftime
(
ACC_DATE_FORMAT
),
'end'
:
self
.
end_date
.
strftime
(
ACC_DATE_FORMAT
)}
with
open
(
file_name
,
'w'
)
as
file
:
json
.
dump
(
interval
,
file
)
json
.
dump
(
users_bill
,
file
,
indent
=
4
,
separators
=
(
','
,
': '
)
)
return
True
raise
Exception
(
'Error occured while making report about everyone!'
)
def
billing
(
self
,
user
,
activity_list
):
# the usage of the resources
bill
=
dict
()
# every machine ID which used by the user
machines
=
self
.
get_machines
(
activity_list
)
# every activity for one machine
activity_by_machines
=
self
.
get_acts
(
activity_list
)
# iterate over the user's machines
for
ins
in
machines
:
run_state
=
{
'started'
:
''
,
'ended'
:
''
,
'renewed_times'
:
0
,
'created'
:
False
}
total_usage
=
{
'total_run_time'
:
0
,
'total_used_cores'
:
0
,
'total_used_ram'
:
0
,
'total_used_disk'
:
0
,
'total_cost'
:
0
}
bill
[
ins
]
=
[]
for
act
in
activity_by_machines
[
ins
]:
# calculating usage
if
'create'
in
act
[
'activity_code'
]:
run_state
[
'created'
]
=
True
elif
(
'deploy'
in
act
[
'activity_code'
]
or
'wake_up'
in
act
[
'activity_code'
]):
run_state
[
'started'
]
=
act
[
'finished'
]
elif
'renew'
in
act
[
'activity_code'
]:
run_state
[
'renewed_times'
]
+=
1
elif
(
'sleep'
in
act
[
'activity_code'
]
or
'shut'
in
act
[
'activity_code'
]
or
'destroy'
in
act
[
'activity_code'
]):
run_state
[
'ended'
]
=
act
[
'started'
]
# end of running
# stopped, but did not start during T
# so the start of the runing is the begining of the T
if
run_state
[
'started'
]
==
''
:
if
run_state
[
'created'
]:
# létrejött, de nem tudott futni (create-->destroy)
break
else
:
run_state
[
'started'
]
=
self
.
start_date
.
strftime
(
ACC_DATE_FORMAT
)
# datetime -> str
bill
[
ins
]
.
append
(
self
.
construct_bill
(
act
=
act
,
begin
=
run_state
[
'started'
],
end
=
run_state
[
'ended'
],
rt
=
run_state
[
'renewed_times'
]
)
)
# reset the helper dictionary
run_state
=
{
'started'
:
''
,
'ended'
:
''
,
'renewed_times'
:
0
,
'created'
:
False
}
# end of activity loop
# T alatt elkezdődött, de nem befejezett futás
if
(
run_state
[
'ended'
]
==
''
and
not
run_state
[
'started'
]
==
''
):
run_state
[
'ended'
]
=
self
.
end_date
.
strftime
(
ACC_DATE_FORMAT
)
bill
[
ins
]
.
append
(
self
.
construct_bill
(
act
=
act
,
begin
=
run_state
[
'started'
],
end
=
run_state
[
'ended'
],
rt
=
run_state
[
'renewed_times'
]
)
)
# calculate total used time, and resources
for
act
in
bill
[
ins
]:
total_usage
[
'total_used_cores'
]
+=
act
[
'used_cores'
]
total_usage
[
'total_used_ram'
]
+=
act
[
'used_ram'
]
for
disk
in
act
[
'disks'
]:
total_usage
[
'total_used_disk'
]
+=
disk
[
'size'
]
if
total_usage
[
'total_run_time'
]
==
0
:
total_usage
[
'total_run_time'
]
=
act
[
'run_time'
]
else
:
total_usage
[
'total_run_time'
]
+=
act
[
'run_time'
]
act
[
'run_time'
]
=
str
(
act
[
'run_time'
])
# deltatime -> str
total_usage
[
'total_run_time'
]
=
str
(
# deltatime -> str
total_usage
[
'total_run_time'
]
)
bill
[
ins
]
.
append
(
total_usage
)
return
bill
def
construct_bill
(
self
,
act
,
begin
,
end
,
rt
):
temp_dict
=
{
'run_time'
:
datetime
.
strptime
(
end
,
ACC_DATE_FORMAT
)
-
datetime
.
strptime
(
begin
,
ACC_DATE_FORMAT
),
# deltatime
'used_ram'
:
act
[
'ram'
],
'used_cores'
:
act
[
'cores'
],
'cost'
:
0
,
'cores_priority'
:
act
[
'core_prio'
],
'renewed'
:
rt
,
'disks'
:
act
[
'disks'
],
'started'
:
begin
,
# str
'finished'
:
end
# str as well
}
return
temp_dict
def
get_machines
(
self
,
activity_list
):
if
len
(
activity_list
)
==
0
:
return
None
machines
=
set
()
for
act
in
activity_list
:
machines
.
add
(
act
[
'instance_id'
])
return
list
(
machines
)
def
get_acts
(
self
,
activity_list
):
if
len
(
activity_list
)
==
0
:
return
None
machines_acts
=
{
activity_list
[
0
][
'instance_id'
]:
[]}
for
act
in
activity_list
:
if
act
[
'instance_id'
]
in
machines_acts
.
keys
():
machines_acts
[
act
[
'instance_id'
]]
.
append
(
act
)
machines_acts
[
act
[
'instance_id'
]]
=
sorted
(
machines_acts
[
act
[
'instance_id'
]],
key
=
itemgetter
(
'started'
)
)
else
:
machines_acts
[
act
[
'instance_id'
]]
=
[]
machines_acts
[
act
[
'instance_id'
]]
.
append
(
act
)
return
machines_acts
# Wrapper class in order to use accounting easily
class
Accounter
():
name
=
'accounter'
def
billing_everyone
(
self
,
t0
,
t1
):
try
:
collector
=
ResourceCollector
(
start
=
t0
,
end
=
t1
)
if
collector
.
collect_data
():
maker
=
ReportMaker
(
t0
,
t1
,
collector
.
activities
)
if
maker
.
make_report_about_everyone
():
return
True
raise
Exception
(
'Billing failed!'
)
raise
Exception
(
'Data collection failed!'
)
except
Exception
as
e
:
print
e
return
None
def
billing_user
(
self
,
user
,
t0
,
t1
):
try
:
user_data_list
=
ResourceCollector
.
collect_user_data
(
t0
,
t1
,
user
)
if
not
user_data_list
is
None
:
maker
=
ReportMaker
(
t0
,
t1
)
bill
=
maker
.
billing
(
user
,
user_data_list
)
return
bill
except
Exception
as
e
:
print
e
return
None
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment