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
1138a614
authored
Sep 12, 2014
by
Őry Máté
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature-wait-for-agent' into 'master'
Feature Wait For Agent closes
#280
parents
8045b135
d932325c
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
364 additions
and
24 deletions
+364
-24
circle/common/models.py
+8
-0
circle/dashboard/forms.py
+1
-1
circle/dashboard/templates/dashboard/template-edit.html
+1
-0
circle/vm/migrations/0027_auto__add_field_instance_has_agent__add_field_instancetemplate_has_age.py
+300
-0
circle/vm/models/activity.py
+19
-10
circle/vm/models/instance.py
+6
-1
circle/vm/operations.py
+16
-6
circle/vm/tasks/local_agent_tasks.py
+11
-6
circle/vm/tests/test_models.py
+2
-0
No files found.
circle/common/models.py
View file @
1138a614
...
...
@@ -214,6 +214,14 @@ class ActivityModel(TimeStampedModel):
self
.
result_data
=
None
if
value
is
None
else
value
.
to_dict
()
@classmethod
def
construct_activity_code
(
cls
,
code_suffix
,
sub_suffix
=
None
):
code
=
join_activity_code
(
cls
.
ACTIVITY_CODE_BASE
,
code_suffix
)
if
sub_suffix
:
return
join_activity_code
(
code
,
sub_suffix
)
else
:
return
code
@celery.task
()
def
compute_cached
(
method
,
instance
,
memcached_seconds
,
...
...
circle/dashboard/forms.py
View file @
1138a614
...
...
@@ -481,7 +481,7 @@ class TemplateForm(forms.ModelForm):
else
:
self
.
allowed_fields
=
(
'name'
,
'access_method'
,
'description'
,
'system'
,
'tags'
,
'arch'
,
'lease'
)
'arch'
,
'lease'
,
'has_agent'
)
if
(
self
.
user
.
has_perm
(
'vm.change_template_resources'
)
or
not
self
.
instance
.
pk
):
self
.
allowed_fields
+=
tuple
(
set
(
self
.
fields
.
keys
())
-
...
...
circle/dashboard/templates/dashboard/template-edit.html
View file @
1138a614
...
...
@@ -51,6 +51,7 @@
{{ form.req_traits|as_crispy_field }}
{{ form.description|as_crispy_field }}
{{ form.system|as_crispy_field }}
{{ form.has_agent|as_crispy_field }}
</fieldset>
<fieldset>
<legend>
{% trans "External resources" %}
</legend>
...
...
circle/vm/migrations/0027_auto__add_field_instance_has_agent__add_field_instancetemplate_has_age.py
0 → 100644
View file @
1138a614
# -*- 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
):
# Adding field 'Instance.has_agent'
db
.
add_column
(
u'vm_instance'
,
'has_agent'
,
self
.
gf
(
'django.db.models.fields.BooleanField'
)(
default
=
True
),
keep_default
=
False
)
# Adding field 'InstanceTemplate.has_agent'
db
.
add_column
(
u'vm_instancetemplate'
,
'has_agent'
,
self
.
gf
(
'django.db.models.fields.BooleanField'
)(
default
=
True
),
keep_default
=
False
)
# Adding field 'InstanceActivity.interruptible'
db
.
add_column
(
u'vm_instanceactivity'
,
'interruptible'
,
self
.
gf
(
'django.db.models.fields.BooleanField'
)(
default
=
False
),
keep_default
=
False
)
def
backwards
(
self
,
orm
):
# Deleting field 'Instance.has_agent'
db
.
delete_column
(
u'vm_instance'
,
'has_agent'
)
# Deleting field 'InstanceTemplate.has_agent'
db
.
delete_column
(
u'vm_instancetemplate'
,
'has_agent'
)
# Deleting field 'InstanceActivity.interruptible'
db
.
delete_column
(
u'vm_instanceactivity'
,
'interruptible'
)
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'
}),
'is_ready'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'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'
}),
'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']"
}),
'has_agent'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_base'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'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']"
}),
'interruptible'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'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']"
}),
'readable_name_data'
:
(
'jsonfield.fields.JSONField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'result_data'
:
(
'jsonfield.fields.JSONField'
,
[],
{
'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']"
}),
'has_agent'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
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']"
}),
'readable_name_data'
:
(
'jsonfield.fields.JSONField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'result_data'
:
(
'jsonfield.fields.JSONField'
,
[],
{
'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/activity.py
View file @
1138a614
...
...
@@ -24,7 +24,7 @@ from celery.signals import worker_ready
from
celery.contrib.abortable
import
AbortableAsyncResult
from
django.core.urlresolvers
import
reverse
from
django.db.models
import
CharField
,
ForeignKey
from
django.db.models
import
CharField
,
ForeignKey
,
BooleanField
from
django.utils
import
timezone
from
django.utils.translation
import
ugettext_lazy
as
_
,
ugettext_noop
...
...
@@ -70,6 +70,8 @@ class InstanceActivity(ActivityModel):
help_text
=
_
(
'Instance this activity works on.'
),
verbose_name
=
_
(
'instance'
))
resultant_state
=
CharField
(
blank
=
True
,
max_length
=
20
,
null
=
True
)
interruptible
=
BooleanField
(
default
=
False
,
help_text
=
_
(
'Other activities can interrupt this one.'
))
class
Meta
:
app_label
=
'vm'
...
...
@@ -91,24 +93,30 @@ class InstanceActivity(ActivityModel):
@classmethod
def
create
(
cls
,
code_suffix
,
instance
,
task_uuid
=
None
,
user
=
None
,
concurrency_check
=
True
,
readable_name
=
None
,
resultant_state
=
None
):
resultant_state
=
None
,
interruptible
=
False
):
readable_name
=
_normalize_readable_name
(
readable_name
,
code_suffix
)
# Check for concurrent activities
active_activities
=
instance
.
activity_log
.
filter
(
finished__isnull
=
True
)
if
concurrency_check
and
active_activities
.
exists
():
raise
ActivityInProgressError
.
create
(
active_activities
[
0
])
activity_code
=
join_activity_code
(
cls
.
ACTIVITY_CODE_BASE
,
code_suffix
)
for
i
in
active_activities
:
if
i
.
interruptible
:
i
.
finish
(
False
,
result
=
ugettext_noop
(
"Interrupted by other activity."
))
else
:
raise
ActivityInProgressError
.
create
(
i
)
activity_code
=
cls
.
construct_activity_code
(
code_suffix
)
act
=
cls
(
activity_code
=
activity_code
,
instance
=
instance
,
parent
=
None
,
resultant_state
=
resultant_state
,
started
=
timezone
.
now
(),
readable_name_data
=
readable_name
.
to_dict
(),
task_uuid
=
task_uuid
,
user
=
user
)
task_uuid
=
task_uuid
,
user
=
user
,
interruptible
=
interruptible
)
act
.
save
()
return
act
def
create_sub
(
self
,
code_suffix
,
task_uuid
=
None
,
concurrency_check
=
True
,
readable_name
=
None
,
resultant_state
=
None
):
readable_name
=
None
,
resultant_state
=
None
,
interruptible
=
False
):
readable_name
=
_normalize_readable_name
(
readable_name
,
code_suffix
)
# Check for concurrent activities
...
...
@@ -119,7 +127,7 @@ class InstanceActivity(ActivityModel):
act
=
InstanceActivity
(
activity_code
=
join_activity_code
(
self
.
activity_code
,
code_suffix
),
instance
=
self
.
instance
,
parent
=
self
,
resultant_state
=
resultant_state
,
resultant_state
=
resultant_state
,
interruptible
=
interruptible
,
readable_name_data
=
readable_name
.
to_dict
(),
started
=
timezone
.
now
(),
task_uuid
=
task_uuid
,
user
=
self
.
user
)
act
.
save
()
...
...
@@ -183,13 +191,14 @@ class InstanceActivity(ActivityModel):
@contextmanager
def
sub_activity
(
self
,
code_suffix
,
on_abort
=
None
,
on_commit
=
None
,
readable_name
=
None
,
task_uuid
=
None
,
concurrency_check
=
True
):
concurrency_check
=
True
,
interruptible
=
False
):
"""Create a transactional context for a nested instance activity.
"""
if
not
readable_name
:
warn
(
"Set readable_name"
,
stacklevel
=
3
)
act
=
self
.
create_sub
(
code_suffix
,
task_uuid
,
concurrency_check
,
readable_name
=
readable_name
)
readable_name
=
readable_name
,
interruptible
=
interruptible
)
return
activitycontextimpl
(
act
,
on_abort
=
on_abort
,
on_commit
=
on_commit
)
def
get_operation
(
self
):
...
...
circle/vm/models/instance.py
View file @
1138a614
...
...
@@ -123,6 +123,10 @@ class VirtualMachineDescModel(BaseResourceConfigModel):
'format like "
%
s".'
)
%
'Ubuntu 12.04 LTS Desktop amd64'
))
tags
=
TaggableManager
(
blank
=
True
,
verbose_name
=
_
(
"tags"
))
has_agent
=
BooleanField
(
verbose_name
=
_
(
'has agent'
),
default
=
True
,
help_text
=
_
(
'If the machine has agent installed, and '
'the manager should wait for its start.'
))
class
Meta
:
abstract
=
True
...
...
@@ -424,7 +428,8 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
# prepare parameters
common_fields
=
[
'name'
,
'description'
,
'num_cores'
,
'ram_size'
,
'max_ram_size'
,
'arch'
,
'priority'
,
'boot_menu'
,
'raw_data'
,
'lease'
,
'access_method'
,
'system'
]
'raw_data'
,
'lease'
,
'access_method'
,
'system'
,
'has_agent'
]
params
=
dict
(
template
=
template
,
owner
=
owner
,
pw
=
pwgen
())
params
.
update
([(
f
,
getattr
(
template
,
f
))
for
f
in
common_fields
])
params
.
update
(
kwargs
)
# override defaults w/ user supplied values
...
...
circle/vm/operations.py
View file @
1138a614
...
...
@@ -299,16 +299,20 @@ class DeployOperation(InstanceOperation):
"deploy network"
)):
self
.
instance
.
deploy_net
()
try
:
self
.
instance
.
renew
(
parent_activity
=
activity
)
except
:
pass
# Resume vm
with
activity
.
sub_activity
(
'booting'
,
readable_name
=
ugettext_noop
(
"boot virtual machine"
)):
self
.
instance
.
resume_vm
(
timeout
=
timeout
)
try
:
self
.
instance
.
renew
(
parent_activity
=
activity
)
except
:
pass
if
self
.
instance
.
has_agent
:
activity
.
sub_activity
(
'os_boot'
,
readable_name
=
ugettext_noop
(
"wait operating system loading"
),
interruptible
=
True
)
register_operation
(
DeployOperation
)
...
...
@@ -425,8 +429,11 @@ class RebootOperation(InstanceOperation):
required_perms
=
()
accept_states
=
(
'RUNNING'
,
)
def
_operation
(
self
,
timeout
=
5
):
def
_operation
(
self
,
activity
,
timeout
=
5
):
self
.
instance
.
reboot_vm
(
timeout
=
timeout
)
if
self
.
instance
.
has_agent
:
activity
.
sub_activity
(
'os_boot'
,
readable_name
=
ugettext_noop
(
"wait operating system loading"
),
interruptible
=
True
)
register_operation
(
RebootOperation
)
...
...
@@ -499,8 +506,11 @@ class ResetOperation(InstanceOperation):
required_perms
=
()
accept_states
=
(
'RUNNING'
,
)
def
_operation
(
self
,
timeout
=
5
):
def
_operation
(
self
,
activity
,
timeout
=
5
):
self
.
instance
.
reset_vm
(
timeout
=
timeout
)
if
self
.
instance
.
has_agent
:
activity
.
sub_activity
(
'os_boot'
,
readable_name
=
ugettext_noop
(
"wait operating system loading"
),
interruptible
=
True
)
register_operation
(
ResetOperation
)
...
...
circle/vm/tasks/local_agent_tasks.py
View file @
1138a614
...
...
@@ -85,16 +85,22 @@ def agent_started(vm, version=None):
from
vm.models
import
Instance
,
instance_activity
,
InstanceActivity
instance
=
Instance
.
objects
.
get
(
id
=
int
(
vm
.
split
(
'-'
)[
-
1
]))
queue
=
instance
.
get_remote_queue_name
(
"agent"
)
initialized
=
InstanceActivity
.
objects
.
filter
(
instance
=
instance
,
activity_code
=
'vm.Instance.agent.cleanup'
)
.
exists
()
initialized
=
instance
.
activity_log
.
filter
(
activity_code
=
'vm.Instance.agent.cleanup'
)
.
exists
()
with
instance_activity
(
code_suffix
=
'agent'
,
readable_name
=
ugettext_noop
(
'agent'
),
concurrency_check
=
False
,
instance
=
instance
)
as
act
:
with
act
.
sub_activity
(
'starting'
,
readable_name
=
ugettext_noop
(
'starting'
)):
pass
for
i
in
InstanceActivity
.
objects
.
filter
(
instance
=
instance
,
activity_code__endswith
=
'.os_boot'
,
finished__isnull
=
True
):
i
.
finish
(
True
)
if
version
and
version
!=
settings
.
AGENT_VERSION
:
try
:
update_agent
(
instance
,
act
)
...
...
@@ -108,10 +114,9 @@ def agent_started(vm, version=None):
send_init_commands
(
instance
,
act
)
send_networking_commands
(
instance
,
act
)
with
act
.
sub_activity
(
'start_access_server'
,
readable_name
=
ugettext_noop
(
'start access server'
)
):
with
act
.
sub_activity
(
'start_access_server'
,
readable_name
=
ugettext_noop
(
'start access server'
)):
start_access_server
.
apply_async
(
queue
=
queue
,
args
=
(
vm
,
))
...
...
circle/vm/tests/test_models.py
View file @
1138a614
...
...
@@ -217,6 +217,8 @@ class InstanceActivityTestCase(TestCase):
def
test_create_concurrency_check
(
self
):
instance
=
MagicMock
(
spec
=
Instance
)
instance
.
activity_log
.
filter
.
return_value
.
__iter__
.
return_value
=
iter
(
[
MagicMock
(
spec
=
InstanceActivity
,
interruptible
=
False
)])
instance
.
activity_log
.
filter
.
return_value
.
exists
.
return_value
=
True
with
self
.
assertRaises
(
ActivityInProgressError
):
...
...
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