diff --git a/devops/driver/dummy/dummy_driver.py b/devops/driver/dummy/dummy_driver.py index 2b65df30..b2bdbd3d 100644 --- a/devops/driver/dummy/dummy_driver.py +++ b/devops/driver/dummy/dummy_driver.py @@ -1,2 +1,3 @@ class DevopsDriver(object): - pass + def get_allocated_networks(self): + return [] \ No newline at end of file diff --git a/devops/helpers/helpers.py b/devops/helpers/helpers.py index a09d01b4..e87e70e0 100644 --- a/devops/helpers/helpers.py +++ b/devops/helpers/helpers.py @@ -86,12 +86,13 @@ def wait(predicate, interval=5, timeout=None): def _wait(raising_predicate, expected=Exception, interval=5, timeout=None): start_time = time.time() - try: - return raising_predicate() - except expected: - if timeout and start_time + timeout < time.time(): - raise - time.sleep(interval) + while True: + try: + return raising_predicate() + except expected: + if timeout and start_time + timeout < time.time(): + raise + time.sleep(interval) def http(host='localhost', port=80, method='GET', url='/', waited_code=200): diff --git a/devops/manager.py b/devops/manager.py index 141a67ce..ef756ed7 100644 --- a/devops/manager.py +++ b/devops/manager.py @@ -1,7 +1,7 @@ import json import os - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "devops.settings") +from django.db import IntegrityError, transaction import ipaddr from devops.helpers.helpers import generate_mac from devops.helpers.network import IpNetworksPool @@ -46,6 +46,26 @@ class Manager(object): prefix=24) return self.default_pool + @transaction.commit_on_success + def _safe_create_network( + self, name, environment=None, pool=None, + has_dhcp_server=True, has_pxe_server=False, + forward='nat'): + allocated_pool = pool or self._get_default_pool() + while True: + try: + ip_network = allocated_pool.next() + if not Network.objects.filter(ip_network=str(ip_network)).exists(): + return Network.objects.create( + environment=environment, + name=name, + ip_network=ip_network, + has_pxe_server=has_pxe_server, + has_dhcp_server=has_dhcp_server, + forward=forward) + except IntegrityError: + transaction.rollback() + def network_create( self, name, environment=None, ip_network=None, pool=None, has_dhcp_server=True, has_pxe_server=False, @@ -54,13 +74,22 @@ class Manager(object): """ :rtype : Network """ - allocated_network = ip_network or ExternalModel.allocate_network( - pool or self._get_default_pool()) - return Network.objects.create( - environment=environment, name=name, - ip_network=ip_network or allocated_network, - has_pxe_server=has_pxe_server, has_dhcp_server=has_dhcp_server, - forward=forward) + if ip_network: + return Network.objects.create( + environment=environment, + name=name, + ip_network=ip_network, + has_pxe_server=has_pxe_server, + has_dhcp_server=has_dhcp_server, + forward=forward + ) + return self._safe_create_network( + environment=environment, + forward=forward, + has_dhcp_server=has_dhcp_server, + has_pxe_server=has_pxe_server, + name=name, + pool=pool) def node_create(self, name, environment=None, role=None, vcpu=1, memory=1024, has_vnc=True, metadata=None, hypervisor='kvm', diff --git a/devops/models.py b/devops/models.py index 18204b41..949bff26 100644 --- a/devops/models.py +++ b/devops/models.py @@ -63,7 +63,7 @@ class Environment(models.Model): for node in nodes or self.nodes: node.start() - def destroy(self, verbose=True): + def destroy(self, verbose=False): for node in self.nodes: node.destroy(verbose=verbose) @@ -76,13 +76,13 @@ class Environment(models.Model): volume.erase() self.delete() - def suspend(self, verbose=True): + def suspend(self, verbose=False): for node in self.nodes: node.suspend(verbose) - def resume(self): + def resume(self, verbose=False): for node in self.nodes: - node.resume() + node.resume(verbose) def snapshot(self, name=None, description=None, force=False): for node in self.nodes: @@ -127,13 +127,6 @@ class ExternalModel(models.Model): def get_allocated_networks(cls): return cls.get_driver().get_allocated_networks() - @classmethod - def allocate_network(cls, pool): - while True: - ip_network = pool.next() - if not Network.objects.filter(ip_network=str(ip_network)).exists(): - return ip_network - class Network(ExternalModel): _iterhosts = None @@ -166,7 +159,9 @@ class Network(ExternalModel): ip = self._iterhosts.next() if ip < self.ip_pool_start or ip > self.ip_pool_end: continue - if not Address.objects.filter(interface__network=self, ip_address=str(ip)).exists(): + if not Address.objects.filter( + interface__network=self, + ip_address=str(ip)).exists(): return ip def bridge_name(self): @@ -179,7 +174,7 @@ class Network(ExternalModel): def start(self): self.create(verbose=False) - def create(self, verbose=True): + def create(self, verbose=False): if verbose or not self.driver.network_active(self): self.driver.network_create(self) @@ -189,7 +184,7 @@ class Network(ExternalModel): def erase(self): self.remove(verbose=False) - def remove(self, verbose=True): + def remove(self, verbose=False): if verbose or self.uuid: if verbose or self.driver.network_exists(self): if self.driver.network_active(self): @@ -260,18 +255,18 @@ class Node(ExternalModel): def start(self): self.create(verbose=False) - def create(self, verbose=True): + def create(self, verbose=False): if verbose or not self.driver.node_active(self): self.driver.node_create(self) - def destroy(self, verbose=True): + def destroy(self, verbose=False): if verbose or self.driver.node_active(self): self.driver.node_destroy(self) def erase(self): self.remove(verbose=False) - def remove(self, verbose=True): + def remove(self, verbose=False): if verbose or self.uuid: if verbose or self.driver.node_exists(self): self.destroy(verbose=False) @@ -279,12 +274,13 @@ class Node(ExternalModel): self.driver.node_undefine(self) self.delete() - def suspend(self, verbose=True): + def suspend(self, verbose=False): if verbose or self.driver.node_active(self): self.driver.node_suspend(self) - def resume(self): - self.driver.node_resume(self) + def resume(self, verbose=False): + if verbose or self.driver.node_active(self): + self.driver.node_resume(self) def has_snapshot(self, name): return self.driver.node_snapshot_exists(node=self, name=name) @@ -313,7 +309,7 @@ class Volume(ExternalModel): def erase(self): self.remove(verbose=False) - def remove(self, verbose=True): + def remove(self, verbose=False): if verbose or self.uuid: if verbose or self.driver.volume_exists(self): self.driver.volume_delete(self) diff --git a/devops/shell.py b/devops/shell.py index 5a28c79b..4d12b5d3 100644 --- a/devops/shell.py +++ b/devops/shell.py @@ -38,10 +38,10 @@ class Shell(object): self.manager.environment_get(self.params.name).destroy(verbose=False) def do_suspend(self): - self.manager.environment_get(self.params.name).suspend() + self.manager.environment_get(self.params.name).suspend(verbose=False) def do_resume(self): - self.manager.environment_get(self.params.name).resume() + self.manager.environment_get(self.params.name).resume(verbose=False) def do_revert(self): self.manager.environment_get(self.params.name).revert( diff --git a/devops/tests/test_models.py b/devops/tests/test_models.py index 56f47a02..159326f1 100644 --- a/devops/tests/test_models.py +++ b/devops/tests/test_models.py @@ -1,5 +1,13 @@ +import random from django.utils import unittest -from devops.models import double_tuple +import threading +from devops.manager import Manager +from devops.models import double_tuple, Network + + +class MyThread(threading.Thread): + def run(self): + Manager().network_create(str(random.randint(1, 5000))) class TestModels(unittest.TestCase): diff --git a/src/devops/driver/dummy/__init__.py b/src/devops/driver/dummy/__init__.py new file mode 100644 index 00000000..e69de29b