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
c08afb10
authored
3 months ago
by
Szeberényi Imre
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Form batman:
two-factor fix vm-details fix storage model (duisk types?)
parent
2a3a6018
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
141 additions
and
47 deletions
+141
-47
circle/circle/settings/base.py
+38
-3
circle/dashboard/forms.py
+6
-3
circle/dashboard/templates/dashboard/enable-two-factor.html
+5
-2
circle/dashboard/templates/dashboard/vm-detail.html
+1
-3
circle/dashboard/urls.py
+5
-2
circle/dashboard/views/user.py
+0
-1
circle/dashboard/views/vm.py
+47
-1
circle/storage/models.py
+2
-1
circle/vm/operations.py
+32
-28
circle/vm/tasks/local_periodic_tasks.py
+5
-3
No files found.
circle/circle/settings/base.py
View file @
c08afb10
...
...
@@ -333,7 +333,7 @@ DJANGO_APPS = (
'django.contrib.auth'
,
'django.contrib.contenttypes'
,
'django.contrib.sessions'
,
'django.contrib.sites'
,
#
'django.contrib.sites',
'django.contrib.messages'
,
'django.contrib.staticfiles'
,
...
...
@@ -357,6 +357,7 @@ THIRD_PARTY_APPS = (
'statici18n'
,
'django_sshkey'
,
'pipeline'
,
'qrcode2'
,
)
...
...
@@ -413,7 +414,7 @@ LOGGING = {
'address'
:
'/dev/log'
,
# 'socktype': SOCK_STREAM,
# 'address': ('host', '514'),
}
}
,
},
'loggers'
:
{
'django.request'
:
{
...
...
@@ -531,6 +532,7 @@ LOGIN_REDIRECT_URL = "/"
AGENT_DIR
=
get_env_variable
(
'DJANGO_AGENT_DIR'
,
join
(
unicode
(
expanduser
(
"~"
)),
'agent'
))
# AGENT_DIR is the root directory for the agent.
# The directory structure SHOULD be:
# /home/username/agent
...
...
@@ -542,12 +544,45 @@ AGENT_DIR = get_env_variable(
#
try
:
git_env
=
{
'GIT_DIR'
:
join
(
join
(
AGENT_DIR
,
"agent
-linux"
),
'.git'
)}
git_env
=
{
'GIT_DIR'
:
join
(
join
(
AGENT_DIR
,
"agent
"
),
".git"
)}
AGENT_VERSION
=
check_output
(
(
'git'
,
'log'
,
'-1'
,
r'--pretty=format:
%
h'
,
'HEAD'
),
env
=
git_env
)
except
:
AGENT_VERSION
=
None
print
(
"LEGACY VERSION:
%
s ------"
%
AGENT_VERSION
)
#### NEW ####
####
# AGENT_VERSIONS is a dict eg: { "Linux" : "vers1" , "Windows" : "vers2", .... }
# Normally it is fetched from Jason fromatted AGENT_DIR/wersions.txt file
#
# The dir namings ha changed:
# The same, but the dir names are lowercase and generated like this:
# agent-(agent_system)-(version). Eg: agent-linux-vers1, agent-window-vers2
try
:
with
open
(
"
%
s/versions.txt"
%
AGENT_DIR
,
"r"
)
as
f
:
AGENT_VERSIONS
=
loads
(
f
.
read
())
print
(
"-----KONWN VERSIONS-----"
)
print
(
AGENT_VERSIONS
)
except
:
print
(
"Format ERROR in versions.txt !!!! "
)
# TODO more error reposrting
AGENT_VERSIONS
=
None
## PUBLIC function for getting the latest version ad the DIR
def
GET_AGENT_VERSION_BY_SYSTEM
(
agent_system
):
if
agent_system
is
None
:
return
None
,
None
if
type
(
AGENT_VERSIONS
)
is
not
dict
:
# legacy naming
return
AGENT_VERSION
,
AGENT_DIR
+
"/agent-"
+
agent_system
.
lower
()
ret
=
AGENT_VERSIONS
.
get
(
agent_system
)
if
ret
is
None
:
return
None
,
None
return
ret
,
AGENT_DIR
+
"/agent-"
+
agent_system
.
lower
()
+
"-"
+
ret
LOCALE_PATHS
=
(
join
(
SITE_ROOT
,
'locale'
),
)
COMPANY_NAME
=
get_env_variable
(
"COMPANY_NAME"
,
"BME IK 2015"
)
...
...
This diff is collapsed.
Click to expand it.
circle/dashboard/forms.py
View file @
c08afb10
...
...
@@ -543,7 +543,7 @@ class TemplateForm(forms.ModelForm):
else
:
self
.
allowed_fields
=
(
'name'
,
'access_method'
,
'description'
,
'system'
,
'tags'
,
'arch'
,
'lease'
,
'has_agent'
)
'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
())
-
...
...
@@ -972,11 +972,14 @@ class VmImportDiskForm(OperationForm):
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
user
=
kwargs
.
pop
(
'user'
)
super
(
VmImportDiskForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
allowed
=
()
allowed
=
allowed
+
Disk
.
EXPORT_FORMATS
print
(
allowed
)
disk_paths
=
Store
(
self
.
user
)
.
get_files_with_exts
(
[
f
[
0
]
for
f
in
Disk
.
EXPORT_FORMATS
]
[
f
[
0
]
for
f
in
allowed
]
)
disk_filenames
=
[
os
.
path
.
basename
(
item
)
for
item
in
disk_paths
]
#raise Error(disk_filenames)
self
.
choices
=
zip
(
disk_paths
,
disk_filenames
)
self
.
fields
[
'name'
]
=
forms
.
CharField
(
max_length
=
100
,
label
=
_
(
'Name'
))
...
...
This diff is collapsed.
Click to expand it.
circle/dashboard/templates/dashboard/enable-two-factor.html
View file @
c08afb10
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load qrcode2 %}
{% block content %}
<div
class=
"row"
>
...
...
@@ -27,8 +29,9 @@
Your secret key is:
<strong>
{{ secret }}
</strong>
{% endblocktrans %}
</span>
<img
src=
"//chart.googleapis.com/chart?chs=255x255&chld=L|0&cht=qr&chl={{ uri }}"
/>
<small><a
href=
"{{ uri }}"
>
{{ uri }}
</a></small>
{#
<img
src=
"//chart.googleapis.com/chart?chs=255x255&chld=L|0&cht=qr&chl={{ uri }}"
/>
#}
<img
src=
"{{ uri | qrcode_src }}"
with=
"300"
i
height=
300
alt=
"{{ uri }}"
>
{#
<small><a
href=
"{{ uri }}"
>
{{ uri }}
</a></small>
#}
</div>
<hr
/>
<div
id=
"two-factor-confirm"
>
...
...
This diff is collapsed.
Click to expand it.
circle/dashboard/templates/dashboard/vm-detail.html
View file @
c08afb10
...
...
@@ -112,15 +112,13 @@
<dd>
{{ instance.access_method|upper }}
</dd>
<dt>
{% trans "Host" %}
</dt>
<dd>
{% if instance.get_connect_port %}
{{ instance.get_connect_host }}:
<strong>
{{ instance.get_connect_port }}
</strong>
{% if instance.get_connect_port %}{{ instance.get_connect_host }}:
<strong>
{{ instance.get_connect_port }}
</strong>
{% elif instance.interface_set.count
<
1
%}
<
strong
>
{% trans "The VM doesn't have any network interface." %}
</strong>
{% else %}
<strong>
{% trans "The required port for this protocol is not forwarded." %}
</strong>
{% endif %}
</dd>
{% if instance.ipv6 and instance.get_connect_port %}
<dt>
{% trans "Host (IPv6)" %}
</dt>
<dd>
{{ ipv6_host }}:
<strong>
{{ ipv6_port }}
</strong></dd>
...
...
This diff is collapsed.
Click to expand it.
circle/dashboard/urls.py
View file @
c08afb10
...
...
@@ -58,7 +58,8 @@ from .views import (
MessageList
,
MessageDetail
,
MessageCreate
,
MessageDelete
,
EnableTwoFactorView
,
DisableTwoFactorView
,
AclUserGroupAutocomplete
,
AclUserAutocomplete
,
RescheduleView
,
GroupImportView
,
GroupExportView
RescheduleView
,
GroupImportView
,
GroupExportView
,
start_instance
,
shutdown_instance
,
get_instance
)
from
.views.node
import
node_ops
from
.views.vm
import
vm_ops
,
vm_mass_ops
...
...
@@ -78,7 +79,9 @@ urlpatterns = [
name
=
"dashboard.views.lease-delete"
),
url
(
r'^lease/(?P<pk>\d+)/acl/$'
,
LeaseAclUpdateView
.
as_view
(),
name
=
"dashboard.views.lease-acl"
),
url
(
r'^vmstart/(?P<pk>\d+)'
,
start_instance
),
url
(
r'^vmshutdown/(?P<pk>\d+)'
,
shutdown_instance
),
url
(
r'^vmget/(?P<pk>\d+)'
,
get_instance
),
url
(
r'^template/create/$'
,
TemplateCreate
.
as_view
(),
name
=
"dashboard.views.template-create"
),
url
(
r'^template/choose/$'
,
TemplateChoose
.
as_view
(),
...
...
This diff is collapsed.
Click to expand it.
circle/dashboard/views/user.py
View file @
c08afb10
...
...
@@ -723,7 +723,6 @@ if hasattr(settings, 'SAML_ORG_ID_ATTRIBUTE'):
# authenticate the remote user
session_info
=
response
.
session_info
()
if
callable
(
attribute_mapping
):
attribute_mapping
=
attribute_mapping
()
if
callable
(
create_unknown_user
):
...
...
This diff is collapsed.
Click to expand it.
circle/dashboard/views/vm.py
View file @
c08afb10
...
...
@@ -36,7 +36,7 @@ from django.template.loader import render_to_string
from
django.utils.translation
import
(
ugettext
as
_
,
ugettext_noop
,
ungettext_lazy
,
)
from
django.views.decorators.http
import
require_GET
from
django.views.decorators.http
import
require_GET
,
require_POST
from
django.views.generic
import
(
UpdateView
,
ListView
,
TemplateView
)
...
...
@@ -70,6 +70,7 @@ from ..forms import (
VmRemoveInterfaceForm
,
VmRenameForm
,
)
from
vm.operations
import
DeployOperation
,
ShutdownOperation
from
request.models
import
TemplateAccessType
,
LeaseType
from
request.forms
import
LeaseRequestForm
,
TemplateRequestForm
from
..models
import
Favourite
...
...
@@ -1266,6 +1267,51 @@ def get_disk_download_status(request, pk):
content_type
=
"application/json"
,
)
from
django.views.decorators.csrf
import
csrf_exempt
@csrf_exempt
@require_POST
def
start_instance
(
request
,
pk
):
instance
=
Instance
.
objects
.
get
(
pk
=
pk
)
DeployOperation
(
instance
)
.
call
(
node
=
None
,
user
=
request
.
user
)
return
HttpResponse
(
json
.
dumps
({
'id'
:
pk
,
'op'
:
'deploy'
}),
content_type
=
"application/json"
,
)
@csrf_exempt
@require_POST
def
shutdown_instance
(
request
,
pk
):
instance
=
Instance
.
objects
.
get
(
pk
=
pk
)
ShutdownOperation
(
instance
)
.
call
(
user
=
request
.
user
)
return
HttpResponse
(
json
.
dumps
({
'id'
:
pk
,
'op'
:
'shutdown'
}),
content_type
=
"application/json"
,
)
@require_GET
def
get_instance
(
request
,
pk
):
instance
=
Instance
.
objects
.
get
(
pk
=
pk
)
if
instance
.
owner
!=
request
.
user
:
raise
PermissionDenied
()
return
HttpResponse
(
json
.
dumps
({
'id'
:
pk
,
'name'
:
instance
.
name
,
'status'
:
instance
.
status
,
'pw'
:
instance
.
pw
,
'ipv4'
:
str
(
instance
.
ipv4
),
'hostipv4'
:
instance
.
get_connect_host
(
use_ipv6
=
False
),
'sshport'
:
instance
.
get_connect_port
(
use_ipv6
=
False
)
}),
content_type
=
"application/json"
,
)
class
ClientCheck
(
LoginRequiredMixin
,
TemplateView
):
...
...
This diff is collapsed.
Click to expand it.
circle/storage/models.py
View file @
c08afb10
...
...
@@ -126,7 +126,8 @@ class Disk(TimeStampedModel):
EXPORT_FORMATS
=
((
'qcow2'
,
_
(
'QEMU disk image'
)),
(
'vmdk'
,
_
(
'VMware disk image'
)),
(
'vdi'
,
_
(
'VirtualBox disk image'
)),
(
'vpc'
,
_
(
'HyperV disk image'
)))
(
'vpc'
,
_
(
'HyperV disk image'
)),
(
'iso'
,
'ISO image'
))
name
=
CharField
(
blank
=
True
,
max_length
=
100
,
verbose_name
=
_
(
"name"
))
filename
=
CharField
(
max_length
=
256
,
unique
=
True
,
verbose_name
=
_
(
"filename"
))
...
...
This diff is collapsed.
Click to expand it.
circle/vm/operations.py
View file @
c08afb10
...
...
@@ -873,7 +873,7 @@ class ShutdownOperation(AbortableRemoteOperationMixin,
remote_queue
=
(
"vm"
,
"slow"
)
remote_timeout
=
180
def
_operation
(
self
,
task
):
def
_operation
(
self
,
task
=
vm_tasks
.
shutdown
):
super
(
ShutdownOperation
,
self
)
.
_operation
(
task
=
task
)
self
.
instance
.
yield_node
()
...
...
@@ -1575,19 +1575,6 @@ class AgentStartedOperation(InstanceOperation):
self
.
instance
.
_change_ip
(
parent_activity
=
activity
)
self
.
instance
.
_restart_networking
(
parent_activity
=
activity
)
new_version
=
settings
.
AGENT_VERSION
if
new_version
and
old_version
and
new_version
!=
old_version
:
try
:
self
.
instance
.
update_agent
(
parent_activity
=
activity
,
agent_system
=
agent_system
)
except
TimeoutError
:
pass
else
:
activity
.
sub_activity
(
'agent_wait'
,
readable_name
=
ugettext_noop
(
"wait agent restarting"
),
interruptible
=
True
)
return
# agent is going to restart
if
not
self
.
initialized
:
try
:
self
.
measure_boot_time
()
...
...
@@ -1600,6 +1587,20 @@ class AgentStartedOperation(InstanceOperation):
self
.
instance
.
_set_time
(
parent_activity
=
activity
)
self
.
instance
.
_set_hostname
(
parent_activity
=
activity
)
new_version
=
settings
.
GET_AGENT_VERSION_BY_SYSTEM
(
agent_system
)[
0
]
# if agent_system and new_version and (old_version is None or ("NOAGENTUPDATE" not in old_version and new_version != old_version)) :
if
agent_system
and
new_version
and
old_version
and
"NOAGENTUPDATE"
not
in
old_version
and
new_version
!=
old_version
:
try
:
self
.
instance
.
update_agent
(
parent_activity
=
activity
,
agent_system
=
agent_system
)
except
TimeoutError
:
pass
else
:
activity
.
sub_activity
(
'agent_wait'
,
readable_name
=
ugettext_noop
(
"wait agent restarting"
),
interruptible
=
True
)
return
# agent is going to restart
@register_operation
class
CleanupOperation
(
SubOperationMixin
,
RemoteAgentOperation
):
id
=
'_cleanup'
...
...
@@ -1658,11 +1659,12 @@ class UpdateAgentOperation(RemoteAgentOperation):
def
get_activity_name
(
self
,
kwargs
):
return
create_readable
(
ugettext_noop
(
'update agent to
%(version)
s'
),
version
=
settings
.
AGENT_VERSION
)
ugettext_noop
(
'update agent'
))
# ugettext_noop('update agent to %(version)s'),
# version=settings.GET_AGENT_VERSION_BY_SYSTEM(agent_system)[0])
@staticmethod
def
create_linux_tar
():
def
create_linux_tar
(
agent_system
):
def
exclude
(
tarinfo
):
ignored
=
(
'./.'
,
'./misc'
,
'./windows'
)
if
any
(
tarinfo
.
name
.
startswith
(
x
)
for
x
in
ignored
):
...
...
@@ -1670,13 +1672,14 @@ class UpdateAgentOperation(RemoteAgentOperation):
else
:
return
tarinfo
_vers
,
_dir
=
settings
.
GET_AGENT_VERSION_BY_SYSTEM
(
agent_system
)
f
=
StringIO
()
with
TarFile
.
open
(
fileobj
=
f
,
mode
=
'w:gz'
)
as
tar
:
agent_path
=
os
.
path
.
join
(
settings
.
AGENT_DIR
,
"agent-linux"
)
agent_path
=
_dir
tar
.
add
(
agent_path
,
arcname
=
'.'
,
filter
=
exclude
)
version_fileobj
=
StringIO
(
settings
.
AGENT_VERSION
)
version_fileobj
=
StringIO
(
_vers
)
version_info
=
TarInfo
(
name
=
'version.txt'
)
version_info
.
size
=
len
(
version_fileobj
.
buf
)
tar
.
addfile
(
version_info
,
version_fileobj
)
...
...
@@ -1684,14 +1687,15 @@ class UpdateAgentOperation(RemoteAgentOperation):
return
encodestring
(
f
.
getvalue
())
.
replace
(
'
\n
'
,
''
)
@staticmethod
def
create_windows_tar
():
def
create_windows_tar
(
agent_system
):
_vers
,
_dir
=
settings
.
GET_AGENT_VERSION_BY_SYSTEM
(
agent_system
)
f
=
StringIO
()
agent_path
=
os
.
path
.
join
(
settings
.
AGENT_DIR
,
"agent-win"
)
agent_path
=
_dir
with
TarFile
.
open
(
fileobj
=
f
,
mode
=
'w|gz'
)
as
tar
:
tar
.
add
(
agent_path
,
arcname
=
'.'
)
version_fileobj
=
StringIO
(
settings
.
AGENT_VERSION
)
version_fileobj
=
StringIO
(
_vers
)
version_info
=
TarInfo
(
name
=
'version.txt'
)
version_info
.
size
=
len
(
version_fileobj
.
buf
)
tar
.
addfile
(
version_info
,
version_fileobj
)
...
...
@@ -1699,15 +1703,15 @@ class UpdateAgentOperation(RemoteAgentOperation):
return
encodestring
(
f
.
getvalue
())
.
replace
(
'
\n
'
,
''
)
def
_operation
(
self
,
user
,
activity
,
agent_system
):
_vers
,
_dir
=
settings
.
GET_AGENT_VERSION_BY_SYSTEM
(
agent_system
)
queue
=
self
.
_get_remote_queue
()
instance
=
self
.
instance
if
agent_system
==
"Windows"
:
executable
=
os
.
listdir
(
os
.
path
.
join
(
settings
.
AGENT_DIR
,
"agent-win"
))[
0
]
data
=
self
.
create_windows_tar
()
executable
=
sorted
(
os
.
listdir
(
_dir
))[
0
]
data
=
self
.
create_windows_tar
(
agent_system
)
elif
agent_system
==
"Linux"
:
executable
=
""
data
=
self
.
create_linux_tar
()
data
=
self
.
create_linux_tar
(
agent_system
)
else
:
# Legacy update method
executable
=
""
...
...
@@ -1720,7 +1724,7 @@ class UpdateAgentOperation(RemoteAgentOperation):
chunk_size
=
1024
*
1024
chunk_number
=
0
index
=
0
filename
=
settings
.
AGENT_VERSION
+
".tar"
filename
=
_vers
+
".tar"
while
True
:
chunk
=
data
[
index
:
index
+
chunk_size
]
if
chunk
:
...
...
@@ -1734,7 +1738,7 @@ class UpdateAgentOperation(RemoteAgentOperation):
agent_tasks
.
update
.
apply_async
(
queue
=
queue
,
args
=
(
instance
.
vm_name
,
filename
,
executable
,
checksum
)
)
.
get
(
timeout
=
6
0
)
)
.
get
(
timeout
=
12
0
)
break
...
...
This diff is collapsed.
Click to expand it.
circle/vm/tasks/local_periodic_tasks.py
View file @
c08afb10
...
...
@@ -50,17 +50,19 @@ def garbage_collector(offset=timezone.timedelta(seconds=20)):
for
i
in
Instance
.
objects
.
filter
(
destroyed_at
=
None
)
.
all
():
logger
.
debug
(
"Garbage_collector work_package:
%
d
%
s:
%
s:"
,
work_package
,
i
.
pk
,
now
>
i
.
time_of_delete
)
if
i
.
time_of_delete
and
now
>
i
.
time_of_delete
+
grace_period
and
work_package
>
0
:
logger
.
debug
(
"Garbage_collector delete"
)
work_package
-=
1
i
.
destroy
.
async
(
system
=
True
)
logger
.
debug
(
"Garbage_collector delete"
)
logger
.
info
(
"Expired instance
%
d destroyed."
,
i
.
pk
)
try
:
i
.
destroy
.
async
(
system
=
True
)
i
.
owner
.
profile
.
notify
(
ugettext_noop
(
'
%(instance)
s destroyed'
),
ugettext_noop
(
'Your instance <a href="
%(url)
s">
%(instance)
s</a> '
'has been destroyed due to expiration.'
),
instance
=
i
.
name
,
url
=
i
.
get_absolute_url
())
except
ActivityInProgressError
:
logger
.
error
(
"Expired instance
%
d can't be destroyed due the AtctivityInPorgressError."
,
i
.
pk
)
except
Exception
as
e
:
logger
.
debug
(
'Could not notify owner of instance
%
d .
%
s'
,
i
.
pk
,
unicode
(
e
))
...
...
@@ -78,7 +80,7 @@ def garbage_collector(offset=timezone.timedelta(seconds=20)):
'You can resume or destroy it.'
),
instance
=
i
.
name
,
url
=
i
.
get_absolute_url
())
except
ActivityInProgressError
:
logger
.
error
(
"Expired instance
%
d can't be
destroy
ed due the AtctivityInPorgressError."
,
i
.
pk
)
logger
.
error
(
"Expired instance
%
d can't be
suspend
ed due the AtctivityInPorgressError."
,
i
.
pk
)
except
Exception
as
e
:
logger
.
info
(
'Could not notify owner of instance
%
d .
%
s'
,
i
.
pk
,
unicode
(
e
))
...
...
This diff is collapsed.
Click to expand it.
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