...
 
Commits (11)
...@@ -162,7 +162,7 @@ class ConnectCommand(Model): ...@@ -162,7 +162,7 @@ class ConnectCommand(Model):
validators=[connect_command_template_validator]) validators=[connect_command_template_validator])
class Meta: class Meta:
ordering = ('id', ) ordering = ('id',)
def __unicode__(self): def __unicode__(self):
return self.template return self.template
...@@ -218,7 +218,7 @@ class Profile(Model): ...@@ -218,7 +218,7 @@ class Profile(Model):
'id': command.id, 'id': command.id,
'cmd': command.template % { 'cmd': command.template % {
'port': instance.get_connect_port(use_ipv6=use_ipv6), 'port': instance.get_connect_port(use_ipv6=use_ipv6),
'host': instance.get_connect_host(use_ipv6=use_ipv6), 'host': instance.get_connect_host(use_ipv6=use_ipv6),
'password': instance.pw, 'password': instance.pw,
'username': 'cloud', 'username': 'cloud',
}} for command in commands] }} for command in commands]
...@@ -263,7 +263,7 @@ class Profile(Model): ...@@ -263,7 +263,7 @@ class Profile(Model):
super(Profile, self).save(*args, **kwargs) super(Profile, self).save(*args, **kwargs)
class Meta: class Meta:
ordering = ('id', ) ordering = ('id',)
permissions = ( permissions = (
('use_autocomplete', _('Can use autocomplete.')), ('use_autocomplete', _('Can use autocomplete.')),
) )
...@@ -275,7 +275,7 @@ class FutureMember(Model): ...@@ -275,7 +275,7 @@ class FutureMember(Model):
group = ForeignKey(Group) group = ForeignKey(Group)
class Meta: class Meta:
ordering = ('id', ) ordering = ('id',)
unique_together = ('org_id', 'group') unique_together = ('org_id', 'group')
def __unicode__(self): def __unicode__(self):
...@@ -295,7 +295,7 @@ class GroupProfile(AclBase): ...@@ -295,7 +295,7 @@ class GroupProfile(AclBase):
description = TextField(blank=True) description = TextField(blank=True)
class Meta: class Meta:
ordering = ('id', ) ordering = ('id',)
def __unicode__(self): def __unicode__(self):
return self.group.name return self.group.name
...@@ -331,7 +331,11 @@ def create_profile(user): ...@@ -331,7 +331,11 @@ def create_profile(user):
profile, created = Profile.objects.get_or_create(user=user) profile, created = Profile.objects.get_or_create(user=user)
try: try:
Store(user).create_user(profile.smb_password, None, profile.disk_quota) store = Store(user)
if store.user_exist():
profile.disk_quota = store.get_quota()['soft']
profile.save()
store.create_user(profile.smb_password, None, profile.disk_quota)
except: except:
logger.exception("Can't create user %s", unicode(user)) logger.exception("Can't create user %s", unicode(user))
return created return created
......
...@@ -44,9 +44,19 @@ class NoStoreException(StoreApiException): ...@@ -44,9 +44,19 @@ class NoStoreException(StoreApiException):
pass pass
class NoOrgIdException(StoreApiException):
pass
class Store(object): class Store(object):
def __init__(self, user, default_timeout=0.5): def __init__(self, user, default_timeout=0.5):
self.store_url = settings.STORE_URL
if not self.store_url:
raise NoStoreException
if not user.profile.org_id:
raise NoOrgIdException
self.username = 'u-%s' % user.profile.org_id
self.request_args = {'verify': settings.STORE_VERIFY_SSL} self.request_args = {'verify': settings.STORE_VERIFY_SSL}
if settings.STORE_SSL_AUTH: if settings.STORE_SSL_AUTH:
self.request_args['cert'] = (settings.STORE_CLIENT_CERT, self.request_args['cert'] = (settings.STORE_CLIENT_CERT,
...@@ -54,18 +64,15 @@ class Store(object): ...@@ -54,18 +64,15 @@ class Store(object):
if settings.STORE_BASIC_AUTH: if settings.STORE_BASIC_AUTH:
self.request_args['auth'] = (settings.STORE_CLIENT_USER, self.request_args['auth'] = (settings.STORE_CLIENT_USER,
settings.STORE_CLIENT_PASSWORD) settings.STORE_CLIENT_PASSWORD)
self.username = "u-%d" % user.pk
self.default_timeout = default_timeout self.default_timeout = default_timeout
self.store_url = settings.STORE_URL
if not self.store_url:
raise NoStoreException
def _request(self, url, method=get, timeout=None, def _request(self, url, method=get, timeout=None,
raise_status_code=True, **kwargs): raise_status_code=True, **kwargs):
url = urljoin(self.store_url, url) url = urljoin(self.store_url, url)
if timeout is None: if timeout is None:
timeout = self.default_timeout timeout = self.default_timeout
payload = json.dumps(kwargs) if kwargs else None kwargs['USER'] = self.username
payload = json.dumps(kwargs)
try: try:
headers = {'content-type': 'application/json'} headers = {'content-type': 'application/json'}
response = method(url, data=payload, headers=headers, response = method(url, data=payload, headers=headers,
...@@ -83,7 +90,7 @@ class Store(object): ...@@ -83,7 +90,7 @@ class Store(object):
return response return response
def _request_cmd(self, cmd, **kwargs): def _request_cmd(self, cmd, **kwargs):
return self._request(self.username, post, CMD=cmd, **kwargs) return self._request("/user/", post, CMD=cmd, **kwargs)
def list(self, path, process=True): def list(self, path, process=True):
r = self._request_cmd("LIST", PATH=path) r = self._request_cmd("LIST", PATH=path)
...@@ -119,7 +126,7 @@ class Store(object): ...@@ -119,7 +126,7 @@ class Store(object):
self._request_cmd("RENAME", PATH=old_path, NEW_NAME=new_name) self._request_cmd("RENAME", PATH=old_path, NEW_NAME=new_name)
def get_quota(self): # no CMD? :o def get_quota(self): # no CMD? :o
r = self._request(self.username) r = self._request("/user/")
quota = r.json() quota = r.json()
quota.update({ quota.update({
'readable_used': filesizeformat(float(quota['used'])), 'readable_used': filesizeformat(float(quota['used'])),
...@@ -129,17 +136,17 @@ class Store(object): ...@@ -129,17 +136,17 @@ class Store(object):
return quota return quota
def set_quota(self, quota): def set_quota(self, quota):
self._request("/quota/" + self.username, post, QUOTA=quota) self._request("/quota/", post, QUOTA=quota)
def user_exist(self): def user_exist(self):
try: try:
self._request(self.username) self._request("/user/")
return True return True
except NotOkException: except NotOkException:
return False return False
def create_user(self, password, keys, quota): def create_user(self, password, keys, quota):
self._request("/new/" + self.username, method=post, self._request("/new/", method=post,
SMBPASSWD=password, KEYS=keys, QUOTA=quota) SMBPASSWD=password, KEYS=keys, QUOTA=quota)
@staticmethod @staticmethod
......
...@@ -35,7 +35,8 @@ from django.views.generic import TemplateView ...@@ -35,7 +35,8 @@ from django.views.generic import TemplateView
from braces.views import LoginRequiredMixin from braces.views import LoginRequiredMixin
from ..store_api import Store, NoStoreException, NotOkException from ..store_api import (Store, NoStoreException,
NotOkException, NoOrgIdException)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -70,6 +71,11 @@ class StoreList(LoginRequiredMixin, TemplateView): ...@@ -70,6 +71,11 @@ class StoreList(LoginRequiredMixin, TemplateView):
return super(StoreList, self).get(*args, **kwargs) return super(StoreList, self).get(*args, **kwargs)
except NoStoreException: except NoStoreException:
messages.warning(self.request, _("No store.")) messages.warning(self.request, _("No store."))
except NoOrgIdException:
messages.warning(self.request,
_("Your organization ID is not set."
" To use the store, you need a"
" unique organization ID."))
except NotOkException: except NotOkException:
messages.warning(self.request, _("Store has some problems now." messages.warning(self.request, _("Store has some problems now."
" Try again later.")) " Try again later."))
......
...@@ -39,7 +39,7 @@ def _apply_once(name, tasks, queues, task, data): ...@@ -39,7 +39,7 @@ def _apply_once(name, tasks, queues, task, data):
data = data() data = data()
for queue in queues: for queue in queues:
try: try:
task.apply_async(args=data, queue=queue, expires=60).get(timeout=2) task.apply_async(args=data, queue=queue, expires=60).get(timeout=5)
logger.info("%s configuration is reloaded. (queue: %s)", logger.info("%s configuration is reloaded. (queue: %s)",
name, queue) name, queue)
except TimeoutError as e: except TimeoutError as e:
...@@ -76,8 +76,14 @@ def reloadtask_worker(): ...@@ -76,8 +76,14 @@ def reloadtask_worker():
logger.info("reloadtask_worker: Reload %s", ", ".join(tasks)) logger.info("reloadtask_worker: Reload %s", ", ".join(tasks))
firewall_queues = get_firewall_queues() firewall_queues = get_firewall_queues()
dns_queues = [("%s.dns" % i) for i in
settings.get('dns_queues', [gethostname()])] dns_queues = settings.get('dns_queues', [gethostname()])
if isinstance(dns_queues, (str, unicode)):
dns_queues = [dns_queues]
dns_queues = [("%s.dns" % i) for i in dns_queues]
# dns_queues = [("%s.dns" % i) for i in
# settings.get('dns_queues', [gethostname()])]
_apply_once('dns', tasks, dns_queues, reload_dns, _apply_once('dns', tasks, dns_queues, reload_dns,
lambda: (dns(), )) lambda: (dns(), ))
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
from celery import Celery from celery import Celery
from celery.signals import worker_ready from celery.signals import worker_ready
from datetime import timedelta from datetime import timedelta
from celery.schedules import crontab
from kombu import Queue, Exchange from kombu import Queue, Exchange
from os import getenv from os import getenv
...@@ -52,7 +53,7 @@ celery.conf.update( ...@@ -52,7 +53,7 @@ celery.conf.update(
'dashboard.send_email_notifications': { 'dashboard.send_email_notifications': {
'task': 'dashboard.tasks.local_periodic_tasks.' 'task': 'dashboard.tasks.local_periodic_tasks.'
'send_email_notifications', 'send_email_notifications',
'schedule': timedelta(hours=24), 'schedule': crontab(minute=10, hour=1),
'options': {'queue': 'localhost.man'} 'options': {'queue': 'localhost.man'}
}, },
} }
......
...@@ -86,7 +86,7 @@ class DataStore(Model): ...@@ -86,7 +86,7 @@ class DataStore(Model):
args=[self.path], queue=q).get(timeout=timeout) args=[self.path], queue=q).get(timeout=timeout)
@method_cache(30) @method_cache(30)
def get_orphan_disks(self, timeout=15): def get_orphan_disks(self, timeout=25):
"""Disk image files without Disk object in the database. """Disk image files without Disk object in the database.
""" """
queue_name = self.get_remote_queue_name('storage', "slow") queue_name = self.get_remote_queue_name('storage', "slow")
...@@ -101,7 +101,7 @@ class DataStore(Model): ...@@ -101,7 +101,7 @@ class DataStore(Model):
return orphans return orphans
@method_cache(30) @method_cache(30)
def get_missing_disks(self, timeout=15): def get_missing_disks(self, timeout=25):
"""Disk objects without disk image files. """Disk objects without disk image files.
""" """
queue_name = self.get_remote_queue_name('storage', "slow") queue_name = self.get_remote_queue_name('storage', "slow")
...@@ -111,7 +111,7 @@ class DataStore(Model): ...@@ -111,7 +111,7 @@ class DataStore(Model):
return disks.exclude(filename__in=files) return disks.exclude(filename__in=files)
@method_cache(120) @method_cache(120)
def get_file_statistics(self, timeout=30): def get_file_statistics(self, timeout=90):
queue_name = self.get_remote_queue_name('storage', "slow") queue_name = self.get_remote_queue_name('storage', "slow")
data = storage_tasks.get_file_statistics.apply_async( data = storage_tasks.get_file_statistics.apply_async(
args=[self.path], queue=queue_name).get(timeout=timeout) args=[self.path], queue=queue_name).get(timeout=timeout)
......
...@@ -349,7 +349,7 @@ class Node(OperatedMixin, TimeStampedModel): ...@@ -349,7 +349,7 @@ class Node(OperatedMixin, TimeStampedModel):
continue continue
value = target['datapoints'][-2][0] value = target['datapoints'][-2][0]
retval[metric] = float(value) retval[metric] = float(value)
except (KeyError, IndexError, ValueError): except (KeyError, IndexError, ValueError, TypeError):
continue continue
return retval return retval
......
...@@ -58,9 +58,9 @@ def garbage_collector(timeout=15): ...@@ -58,9 +58,9 @@ def garbage_collector(timeout=15):
i.pk, unicode(e)) i.pk, unicode(e))
elif (i.time_of_suspend and now > i.time_of_suspend and elif (i.time_of_suspend and now > i.time_of_suspend and
i.state == 'RUNNING'): i.state == 'RUNNING'):
i.sleep.async(system=True)
logger.info("Expired instance %d suspended." % i.pk) logger.info("Expired instance %d suspended." % i.pk)
try: try:
i.sleep.async(system=True)
i.owner.profile.notify( i.owner.profile.notify(
ugettext_noop('%(instance)s suspended'), ugettext_noop('%(instance)s suspended'),
ugettext_noop( ugettext_noop(
...@@ -68,8 +68,10 @@ def garbage_collector(timeout=15): ...@@ -68,8 +68,10 @@ def garbage_collector(timeout=15):
'has been suspended due to expiration. ' 'has been suspended due to expiration. '
'You can resume or destroy it.'), 'You can resume or destroy it.'),
instance=i.name, url=i.get_absolute_url()) 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: except Exception as e:
logger.debug('Could not notify owner of instance %d .%s', logger.info('Could not notify owner of instance %d .%s',
i.pk, unicode(e)) i.pk, unicode(e))
elif i.is_expiring(): elif i.is_expiring():
logger.debug("Instance %d expires soon." % i.pk) logger.debug("Instance %d expires soon." % i.pk)
......