Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Gelencsér Szabolcs
/
circlestack
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
385ad3e3
authored
Apr 30, 2014
by
Kálmán Viktor
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master' into feature-template-wizard
parents
5912d4e8
d9fb045f
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
444 additions
and
13 deletions
+444
-13
circle/circle/settings/base.py
+3
-0
circle/common/operations.py
+1
-1
circle/dashboard/templates/dashboard/_vm-save.html
+21
-0
circle/dashboard/tests/test_mockedviews.py
+67
-0
circle/dashboard/views.py
+23
-4
circle/firewall/tests/test_firewall.py
+3
-0
circle/vm/migrations/0022_auto__del_unique_instancetemplate_n.py
+276
-0
circle/vm/models/instance.py
+4
-2
circle/vm/operations.py
+42
-2
circle/vm/tasks/local_periodic_tasks.py
+2
-2
circle/vm/tests/test_models.py
+2
-2
No files found.
circle/circle/settings/base.py
View file @
385ad3e3
...
...
@@ -400,3 +400,6 @@ LOGIN_REDIRECT_URL = "/"
LOCALE_PATHS
=
(
join
(
SITE_ROOT
,
'locale'
),
)
COMPANY_NAME
=
"BME IK 2014"
SOUTH_MIGRATION_MODULES
=
{
'taggit'
:
'taggit.south_migrations'
,
}
circle/common/operations.py
View file @
385ad3e3
...
...
@@ -134,8 +134,8 @@ class OperatedMixin(object):
"""Yield Operations that match permissions of user and preconditions.
"""
for
name
in
getattr
(
self
,
operation_registry_name
,
{}):
op
=
getattr
(
self
,
name
)
try
:
op
=
getattr
(
self
,
name
)
op
.
check_auth
(
user
)
op
.
check_precond
()
except
:
...
...
circle/dashboard/templates/dashboard/_vm-save.html
0 → 100644
View file @
385ad3e3
{% extends "dashboard/operate.html" %}
{% load i18n %}
{% load sizefieldtags %}
{% block question %}
<p>
{% blocktrans %}
Choose a name for the new template.
{% endblocktrans %}
</p>
<p
class=
"text-info"
>
{{op.name}}: {{op.description}}
</p>
{% endblock %}
{% block formfields %}
<div
class=
"form-group"
>
<label
for=
"input-name"
class=
"col-sm-4"
>
{% trans "Name of template" %}
</label>
<div
class=
"col-sm-8"
>
<input
type=
"text"
value=
"{{name}}"
name=
"name"
class=
"form-control"
/>
</div>
</div>
{% endblock %}
circle/dashboard/tests/test_mockedviews.py
View file @
385ad3e3
...
...
@@ -112,6 +112,73 @@ class VmOperationViewTestCase(unittest.TestCase):
self
.
assertEquals
(
view
.
as_view
()(
request
,
pk
=
1234
)
.
render
()
.
status_code
,
200
)
def
test_save_as_wo_name
(
self
):
request
=
FakeRequestFactory
(
POST
=
{})
view
=
vm_ops
[
'save_as_template'
]
with
patch
.
object
(
view
,
'get_object'
)
as
go
,
\
patch
(
'dashboard.views.messages'
)
as
msg
,
\
patch
(
'dashboard.views.get_object_or_404'
)
as
go4
:
inst
=
MagicMock
(
spec
=
Instance
)
inst
.
_meta
.
object_name
=
"Instance"
inst
.
save_as_template
=
Instance
.
_ops
[
'save_as_template'
](
inst
)
inst
.
save_as_template
.
async
=
MagicMock
()
inst
.
has_level
.
return_value
=
True
go
.
return_value
=
inst
go4
.
return_value
=
MagicMock
()
assert
view
.
as_view
()(
request
,
pk
=
1234
)[
'location'
]
assert
not
msg
.
error
.
called
def
test_save_as_w_name
(
self
):
request
=
FakeRequestFactory
(
POST
=
{
'name'
:
'foobar'
})
view
=
vm_ops
[
'save_as_template'
]
with
patch
.
object
(
view
,
'get_object'
)
as
go
,
\
patch
(
'dashboard.views.messages'
)
as
msg
,
\
patch
(
'dashboard.views.get_object_or_404'
)
as
go4
:
inst
=
MagicMock
(
spec
=
Instance
)
inst
.
_meta
.
object_name
=
"Instance"
inst
.
save_as_template
=
Instance
.
_ops
[
'save_as_template'
](
inst
)
inst
.
save_as_template
.
async
=
MagicMock
()
inst
.
has_level
.
return_value
=
True
go
.
return_value
=
inst
go4
.
return_value
=
MagicMock
()
assert
view
.
as_view
()(
request
,
pk
=
1234
)[
'location'
]
assert
not
msg
.
error
.
called
def
test_save_as_failed
(
self
):
request
=
FakeRequestFactory
(
POST
=
{})
view
=
vm_ops
[
'save_as_template'
]
with
patch
.
object
(
view
,
'get_object'
)
as
go
,
\
patch
(
'dashboard.views.messages'
)
as
msg
,
\
patch
(
'dashboard.views.get_object_or_404'
)
as
go4
:
inst
=
MagicMock
(
spec
=
Instance
)
inst
.
_meta
.
object_name
=
"Instance"
inst
.
save_as_template
=
Instance
.
_ops
[
'save_as_template'
](
inst
)
inst
.
save_as_template
.
async
=
MagicMock
()
inst
.
save_as_template
.
async
.
side_effect
=
Exception
inst
.
has_level
.
return_value
=
True
go
.
return_value
=
inst
go4
.
return_value
=
MagicMock
()
assert
view
.
as_view
()(
request
,
pk
=
1234
)[
'location'
]
assert
msg
.
error
.
called
def
test_save_as_template
(
self
):
request
=
FakeRequestFactory
()
view
=
vm_ops
[
'save_as_template'
]
with
patch
.
object
(
view
,
'get_object'
)
as
go
:
inst
=
MagicMock
(
spec
=
Instance
)
inst
.
_meta
.
object_name
=
"Instance"
inst
.
name
=
'foo'
inst
.
save_as_template
=
Instance
.
_ops
[
'save_as_template'
](
inst
)
inst
.
has_level
.
return_value
=
True
go
.
return_value
=
inst
rend
=
view
.
as_view
()(
request
,
pk
=
1234
)
.
render
()
self
.
assertEquals
(
rend
.
status_code
,
200
)
assert
'foo v1'
in
rend
.
content
def
FakeRequestFactory
(
*
args
,
**
kwargs
):
''' FakeRequestFactory, FakeMessages and FakeRequestContext are good for
...
...
circle/dashboard/views.py
View file @
385ad3e3
...
...
@@ -513,7 +513,7 @@ class VmMigrateView(VmOperationView):
template_name
=
'dashboard/_vm-migrate.html'
def
get_context_data
(
self
,
**
kwargs
):
ctx
=
super
(
Vm
Operation
View
,
self
)
.
get_context_data
(
**
kwargs
)
ctx
=
super
(
Vm
Migrate
View
,
self
)
.
get_context_data
(
**
kwargs
)
ctx
[
'nodes'
]
=
[
n
for
n
in
Node
.
objects
.
filter
(
enabled
=
True
)
if
n
.
state
==
"ONLINE"
]
return
ctx
...
...
@@ -528,6 +528,26 @@ class VmMigrateView(VmOperationView):
return
super
(
VmMigrateView
,
self
)
.
post
(
request
,
extra
,
*
args
,
**
kwargs
)
class
VmSaveView
(
VmOperationView
):
op
=
'save_as_template'
icon
=
'save'
template_name
=
'dashboard/_vm-save.html'
def
get_context_data
(
self
,
**
kwargs
):
ctx
=
super
(
VmSaveView
,
self
)
.
get_context_data
(
**
kwargs
)
ctx
[
'name'
]
=
self
.
get_op
()
.
_rename
(
self
.
object
.
name
)
return
ctx
def
post
(
self
,
request
,
extra
=
None
,
*
args
,
**
kwargs
):
if
extra
is
None
:
extra
=
{}
name
=
self
.
request
.
POST
.
get
(
"name"
)
if
name
:
extra
[
"name"
]
=
name
return
super
(
VmSaveView
,
self
)
.
post
(
request
,
extra
,
*
args
,
**
kwargs
)
vm_ops
=
{
'reset'
:
VmOperationView
.
factory
(
op
=
'reset'
,
icon
=
'bolt'
),
'deploy'
:
VmOperationView
.
factory
(
op
=
'deploy'
,
icon
=
'play'
),
...
...
@@ -535,8 +555,7 @@ vm_ops = {
'reboot'
:
VmOperationView
.
factory
(
op
=
'reboot'
,
icon
=
'refresh'
),
'shut_off'
:
VmOperationView
.
factory
(
op
=
'shut_off'
,
icon
=
'ban-circle'
),
'shutdown'
:
VmOperationView
.
factory
(
op
=
'shutdown'
,
icon
=
'off'
),
'save_as_template'
:
VmOperationView
.
factory
(
op
=
'save_as_template'
,
icon
=
'save'
),
'save_as_template'
:
VmSaveView
,
'destroy'
:
VmOperationView
.
factory
(
op
=
'destroy'
,
icon
=
'remove'
),
'sleep'
:
VmOperationView
.
factory
(
op
=
'sleep'
,
icon
=
'moon'
),
'wake_up'
:
VmOperationView
.
factory
(
op
=
'wake_up'
,
icon
=
'sun'
),
...
...
@@ -2342,7 +2361,7 @@ class DiskRemoveView(DeleteView):
disk
=
self
.
get_object
()
app
=
disk
.
get_appliance
()
app
.
disks
.
remove
(
disk
)
app
.
remove_disk
(
disk
=
disk
,
user
=
request
.
user
)
disk
.
destroy
()
next_url
=
request
.
POST
.
get
(
"next"
)
...
...
circle/firewall/tests/test_firewall.py
View file @
385ad3e3
...
...
@@ -231,6 +231,9 @@ class ReloadTestCase(TestCase):
self
.
rm
.
save
()
self
.
rt
.
save
()
def
tearDown
(
self
):
settings
[
"default_host_groups"
]
=
[]
def
test_bad_aaaa_record
(
self
):
self
.
assertRaises
(
AddrFormatError
,
ipv6_to_octal
,
self
.
rb
.
address
)
...
...
circle/vm/migrations/0022_auto__del_unique_instancetemplate_n.py
0 → 100644
View file @
385ad3e3
# -*- coding: utf-8 -*-
from
south.utils
import
datetime_utils
as
datetime
from
south.db
import
db
from
south.v2
import
SchemaMigration
from
django.db
import
models
class
Migration
(
SchemaMigration
):
def
forwards
(
self
,
orm
):
# Removing unique constraint on 'InstanceTemplate', fields ['name']
db
.
delete_unique
(
u'vm_instancetemplate'
,
[
'name'
])
def
backwards
(
self
,
orm
):
# Adding unique constraint on 'InstanceTemplate', fields ['name']
db
.
create_unique
(
u'vm_instancetemplate'
,
[
'name'
])
models
=
{
u'auth.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'80'
}),
'permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
u'auth.permission'
:
{
'Meta'
:
{
'ordering'
:
"(u'content_type__app_label', u'content_type__model', u'codename')"
,
'unique_together'
:
"((u'content_type', u'codename'),)"
,
'object_name'
:
'Permission'
},
'codename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['contenttypes.ContentType']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
},
u'auth.user'
:
{
'Meta'
:
{
'object_name'
:
'User'
},
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'symmetrical'
:
'False'
,
'related_name'
:
"u'user_set'"
,
'blank'
:
'True'
,
'to'
:
u"orm['auth.Group']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'is_staff'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'is_superuser'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'last_login'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'user_permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'symmetrical'
:
'False'
,
'related_name'
:
"u'user_set'"
,
'blank'
:
'True'
,
'to'
:
u"orm['auth.Permission']"
}),
'username'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'30'
})
},
u'contenttypes.contenttype'
:
{
'Meta'
:
{
'ordering'
:
"('name',)"
,
'unique_together'
:
"(('app_label', 'model'),)"
,
'object_name'
:
'ContentType'
,
'db_table'
:
"'django_content_type'"
},
'app_label'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'model'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
})
},
u'firewall.domain'
:
{
'Meta'
:
{
'object_name'
:
'Domain'
},
'created_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'modified_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'blank'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'40'
}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
}),
'ttl'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'600'
})
},
u'firewall.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
'created_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'modified_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'blank'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'20'
}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
,
'null'
:
'True'
,
'blank'
:
'True'
})
},
u'firewall.host'
:
{
'Meta'
:
{
'ordering'
:
"('normalized_hostname', 'vlan')"
,
'unique_together'
:
"(('hostname', 'vlan'),)"
,
'object_name'
:
'Host'
},
'comment'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'created_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'external_ipv4'
:
(
'firewall.fields.IPAddressField'
,
[],
{
'max_length'
:
'100'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'symmetrical'
:
'False'
,
'to'
:
u"orm['firewall.Group']"
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'hostname'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'40'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'ipv4'
:
(
'firewall.fields.IPAddressField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'100'
}),
'ipv6'
:
(
'firewall.fields.IPAddressField'
,
[],
{
'max_length'
:
'100'
,
'unique'
:
'True'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'location'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'mac'
:
(
'firewall.fields.MACAddressField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'17'
}),
'modified_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'blank'
:
'True'
}),
'normalized_hostname'
:
(
'common.models.HumanSortField'
,
[],
{
'default'
:
"''"
,
'maximum_number_length'
:
'4'
,
'max_length'
:
'80'
,
'monitor'
:
"'hostname'"
,
'blank'
:
'True'
}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
}),
'reverse'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'40'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'shared_ip'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'vlan'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['firewall.Vlan']"
})
},
u'firewall.vlan'
:
{
'Meta'
:
{
'object_name'
:
'Vlan'
},
'comment'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'created_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'dhcp_pool'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'domain'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['firewall.Domain']"
}),
'host_ipv6_prefixlen'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'112'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'ipv6_template'
:
(
'django.db.models.fields.TextField'
,
[],
{
'default'
:
"'2001:738:2001:4031:
%(b)
d:
%(c)
d:
%(d)
d:0'"
}),
'managed'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'modified_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'blank'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'20'
}),
'network4'
:
(
'firewall.fields.IPNetworkField'
,
[],
{
'max_length'
:
'100'
}),
'network6'
:
(
'firewall.fields.IPNetworkField'
,
[],
{
'max_length'
:
'100'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'network_type'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'portforward'"
,
'max_length'
:
'20'
}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'reverse_domain'
:
(
'django.db.models.fields.TextField'
,
[],
{
'default'
:
"'
%(d)
d.
%(c)
d.
%(b)
d.
%(a)
d.in-addr.arpa'"
}),
'snat_ip'
:
(
'django.db.models.fields.GenericIPAddressField'
,
[],
{
'max_length'
:
'39'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'snat_to'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'symmetrical'
:
'False'
,
'to'
:
u"orm['firewall.Vlan']"
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'vid'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'unique'
:
'True'
})
},
u'storage.datastore'
:
{
'Meta'
:
{
'ordering'
:
"[u'name']"
,
'object_name'
:
'DataStore'
},
'hostname'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'40'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'100'
}),
'path'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'200'
})
},
u'storage.disk'
:
{
'Meta'
:
{
'ordering'
:
"[u'name']"
,
'object_name'
:
'Disk'
},
'base'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"u'derivatives'"
,
'null'
:
'True'
,
'to'
:
u"orm['storage.Disk']"
}),
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'datastore'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['storage.DataStore']"
}),
'destroyed'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'None'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'dev_num'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"u'a'"
,
'max_length'
:
'1'
}),
'filename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'256'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
,
'blank'
:
'True'
}),
'size'
:
(
'sizefield.models.FileSizeField'
,
[],
{
'default'
:
'None'
,
'null'
:
'True'
}),
'type'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'10'
})
},
u'vm.instance'
:
{
'Meta'
:
{
'ordering'
:
"(u'pk',)"
,
'object_name'
:
'Instance'
},
'access_method'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'10'
}),
'active_since'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'arch'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'10'
}),
'boot_menu'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'destroyed_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'disks'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'related_name'
:
"u'instance_set'"
,
'symmetrical'
:
'False'
,
'to'
:
u"orm['storage.Disk']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'lease'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['vm.Lease']"
}),
'max_ram_size'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
,
'blank'
:
'True'
}),
'node'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"u'instance_set'"
,
'null'
:
'True'
,
'to'
:
u"orm['vm.Node']"
}),
'num_cores'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
}),
'priority'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'pw'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'20'
}),
'ram_size'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'raw_data'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'req_traits'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['vm.Trait']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'status'
:
(
'model_utils.fields.StatusField'
,
[],
{
'default'
:
"u'NOSTATE'"
,
'max_length'
:
'100'
,
u'no_check_for_status'
:
'True'
}),
'status_changed'
:
(
'model_utils.fields.MonitorField'
,
[],
{
'default'
:
'datetime.datetime.now'
,
u'monitor'
:
"u'status'"
}),
'system'
:
(
'django.db.models.fields.TextField'
,
[],
{}),
'template'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"u'instance_set'"
,
'null'
:
'True'
,
'on_delete'
:
'models.SET_NULL'
,
'to'
:
u"orm['vm.InstanceTemplate']"
}),
'time_of_delete'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'None'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'time_of_suspend'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'None'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'vnc_port'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'None'
,
'unique'
:
'True'
,
'null'
:
'True'
,
'blank'
:
'True'
})
},
u'vm.instanceactivity'
:
{
'Meta'
:
{
'ordering'
:
"[u'-finished', u'-started', u'instance', u'-id']"
,
'object_name'
:
'InstanceActivity'
},
'activity_code'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'finished'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'instance'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'related_name'
:
"u'activity_log'"
,
'to'
:
u"orm['vm.Instance']"
}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'parent'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"'children'"
,
'null'
:
'True'
,
'to'
:
u"orm['vm.InstanceActivity']"
}),
'result'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'resultant_state'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'20'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'started'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'succeeded'
:
(
'django.db.models.fields.NullBooleanField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'task_uuid'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
,
'unique'
:
'True'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
,
'null'
:
'True'
,
'blank'
:
'True'
})
},
u'vm.instancetemplate'
:
{
'Meta'
:
{
'ordering'
:
"(u'name',)"
,
'object_name'
:
'InstanceTemplate'
},
'access_method'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'10'
}),
'arch'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'10'
}),
'boot_menu'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'disks'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'related_name'
:
"u'template_set'"
,
'symmetrical'
:
'False'
,
'to'
:
u"orm['storage.Disk']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'lease'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['vm.Lease']"
}),
'max_ram_size'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'num_cores'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
}),
'parent'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['vm.InstanceTemplate']"
,
'null'
:
'True'
,
'on_delete'
:
'models.SET_NULL'
,
'blank'
:
'True'
}),
'priority'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'ram_size'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'raw_data'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'req_traits'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['vm.Trait']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'system'
:
(
'django.db.models.fields.TextField'
,
[],
{})
},
u'vm.interface'
:
{
'Meta'
:
{
'ordering'
:
"(u'-vlan__managed',)"
,
'object_name'
:
'Interface'
},
'host'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['firewall.Host']"
,
'null'
:
'True'
,
'blank'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'instance'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'related_name'
:
"u'interface_set'"
,
'to'
:
u"orm['vm.Instance']"
}),
'vlan'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'related_name'
:
"u'vm_interface'"
,
'to'
:
u"orm['firewall.Vlan']"
})
},
u'vm.interfacetemplate'
:
{
'Meta'
:
{
'object_name'
:
'InterfaceTemplate'
},
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'managed'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'template'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'related_name'
:
"u'interface_set'"
,
'to'
:
u"orm['vm.InstanceTemplate']"
}),
'vlan'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['firewall.Vlan']"
})
},
u'vm.lease'
:
{
'Meta'
:
{
'ordering'
:
"[u'name']"
,
'object_name'
:
'Lease'
},
'delete_interval_seconds'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'100'
}),
'suspend_interval_seconds'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
})
},
u'vm.namedbaseresourceconfig'
:
{
'Meta'
:
{
'object_name'
:
'NamedBaseResourceConfig'
},
'arch'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'10'
}),
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'max_ram_size'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'50'
}),
'num_cores'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'priority'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'ram_size'
:
(
'django.db.models.fields.IntegerField'
,
[],
{})
},
u'vm.node'
:
{
'Meta'
:
{
'ordering'
:
"(u'-enabled', u'normalized_name')"
,
'object_name'
:
'Node'
},
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'enabled'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'host'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['firewall.Host']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'50'
}),
'normalized_name'
:
(
'common.models.HumanSortField'
,
[],
{
'default'
:
"''"
,
'maximum_number_length'
:
'4'
,
'max_length'
:
'100'
,
'monitor'
:
"u'name'"
,
'blank'
:
'True'
}),
'overcommit'
:
(
'django.db.models.fields.FloatField'
,
[],
{
'default'
:
'1.0'
}),
'priority'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'traits'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['vm.Trait']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
u'vm.nodeactivity'
:
{
'Meta'
:
{
'object_name'
:
'NodeActivity'
},
'activity_code'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'finished'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'node'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'related_name'
:
"u'activity_log'"
,
'to'
:
u"orm['vm.Node']"
}),
'parent'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"'children'"
,
'null'
:
'True'
,
'to'
:
u"orm['vm.NodeActivity']"
}),
'result'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'started'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'succeeded'
:
(
'django.db.models.fields.NullBooleanField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'task_uuid'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
,
'unique'
:
'True'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
,
'null'
:
'True'
,
'blank'
:
'True'
})
},
u'vm.trait'
:
{
'Meta'
:
{
'object_name'
:
'Trait'
},
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
}
}
complete_apps
=
[
'vm'
]
circle/vm/models/instance.py
View file @
385ad3e3
...
...
@@ -111,8 +111,7 @@ class InstanceTemplate(AclBase, VirtualMachineDescModel, TimeStampedModel):
(
'operator'
,
_
(
'operator'
)),
(
'owner'
,
_
(
'owner'
)),
# superuser, can delete, delegate perms
)
name
=
CharField
(
max_length
=
100
,
unique
=
True
,
verbose_name
=
_
(
'name'
),
name
=
CharField
(
max_length
=
100
,
verbose_name
=
_
(
'name'
),
help_text
=
_
(
'Human readable name of template.'
))
description
=
TextField
(
verbose_name
=
_
(
'description'
),
blank
=
True
)
parent
=
ForeignKey
(
'self'
,
null
=
True
,
blank
=
True
,
...
...
@@ -166,6 +165,9 @@ class InstanceTemplate(AclBase, VirtualMachineDescModel, TimeStampedModel):
def
get_absolute_url
(
self
):
return
(
'dashboard.views.template-detail'
,
None
,
{
'pk'
:
self
.
pk
})
def
remove_disk
(
self
,
disk
,
**
kwargs
):
self
.
disks
.
remove
(
disk
)
class
Instance
(
AclBase
,
VirtualMachineDescModel
,
StatusModel
,
OperatedMixin
,
TimeStampedModel
):
...
...
circle/vm/operations.py
View file @
385ad3e3
...
...
@@ -80,6 +80,26 @@ class AddInterfaceOperation(InstanceOperation):
register_operation
(
AddInterfaceOperation
)
class
AddDiskOperation
(
InstanceOperation
):
activity_code_suffix
=
'add_disk'
id
=
'add_disk'
name
=
_
(
"add disk"
)
description
=
_
(
"Add the specified disk to the VM."
)
def
check_precond
(
self
):
super
(
AddDiskOperation
,
self
)
.
check_precond
()
# TODO remove check when hot-attach is implemented
if
self
.
instance
.
status
not
in
[
'STOPPED'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
activity
,
user
,
system
,
disk
):
# TODO implement with hot-attach when it'll be available
return
self
.
instance
.
disks
.
add
(
disk
)
register_operation
(
AddDiskOperation
)
class
DeployOperation
(
InstanceOperation
):
activity_code_suffix
=
'deploy'
id
=
'deploy'
...
...
@@ -217,6 +237,26 @@ class RemoveInterfaceOperation(InstanceOperation):
register_operation
(
RemoveInterfaceOperation
)
class
RemoveDiskOperation
(
InstanceOperation
):
activity_code_suffix
=
'remove_disk'
id
=
'remove_disk'
name
=
_
(
"remove disk"
)
description
=
_
(
"Remove the specified disk from the VM."
)
def
check_precond
(
self
):
super
(
RemoveDiskOperation
,
self
)
.
check_precond
()
# TODO remove check when hot-detach is implemented
if
self
.
instance
.
status
not
in
[
'STOPPED'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
activity
,
user
,
system
,
disk
):
# TODO implement with hot-detach when it'll be available
return
self
.
instance
.
disks
.
remove
(
disk
)
register_operation
(
RemoveDiskOperation
)
class
ResetOperation
(
InstanceOperation
):
activity_code_suffix
=
'reset'
id
=
'reset'
...
...
@@ -249,7 +289,7 @@ class SaveAsTemplateOperation(InstanceOperation):
v
=
1
return
"
%
s v
%
d"
%
(
name
,
v
)
def
_operation
(
self
,
activity
,
user
,
system
,
timeout
=
300
,
def
_operation
(
self
,
activity
,
user
,
system
,
timeout
=
300
,
name
=
None
,
with_shutdown
=
True
,
**
kwargs
):
if
with_shutdown
:
try
:
...
...
@@ -266,7 +306,7 @@ class SaveAsTemplateOperation(InstanceOperation):
'description'
:
self
.
instance
.
description
,
'lease'
:
self
.
instance
.
lease
,
# Can be problem in new VM
'max_ram_size'
:
self
.
instance
.
max_ram_size
,
'name'
:
self
.
_rename
(
self
.
instance
.
name
),
'name'
:
name
or
self
.
_rename
(
self
.
instance
.
name
),
'num_cores'
:
self
.
instance
.
num_cores
,
'owner'
:
user
,
'parent'
:
self
.
instance
.
template
,
# Can be problem
...
...
circle/vm/tasks/local_periodic_tasks.py
View file @
385ad3e3
...
...
@@ -27,7 +27,7 @@ def garbage_collector(timeout=15):
now
=
timezone
.
now
()
for
i
in
Instance
.
objects
.
filter
(
destroyed_at
=
None
)
.
all
():
if
i
.
time_of_delete
and
now
>
i
.
time_of_delete
:
i
.
destroy
.
async
()
i
.
destroy
.
async
(
system
=
True
)
logger
.
info
(
"Expired instance
%
d destroyed."
,
i
.
pk
)
try
:
i
.
owner
.
profile
.
notify
(
...
...
@@ -39,7 +39,7 @@ def garbage_collector(timeout=15):
i
.
pk
,
unicode
(
e
))
elif
(
i
.
time_of_suspend
and
now
>
i
.
time_of_suspend
and
i
.
state
==
'RUNNING'
):
i
.
sleep
.
async
()
i
.
sleep
.
async
(
system
=
True
)
logger
.
info
(
"Expired instance
%
d suspended."
%
i
.
pk
)
try
:
i
.
owner
.
profile
.
notify
(
...
...
circle/vm/tests/test_models.py
View file @
385ad3e3
...
...
@@ -39,8 +39,8 @@ class TemplateTestCase(TestCase):
class
InstanceTestCase
(
TestCase
):
def
test_is_running
(
self
):
inst
=
M
ock
(
state
=
'RUNNING'
)
assert
Instance
.
is_running
.
getter
(
inst
)
inst
=
M
agicMock
(
status
=
'RUNNING'
)
self
.
assertTrue
(
Instance
.
is_running
.
fget
(
inst
)
)
def
test_mon_stopped_while_activity_running
(
self
):
node
=
Mock
()
...
...
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