commit f5b4f2a3a498492d86cbbfd96fbec56418a151a0
Author: Christos Stavrakakis <cstavr@grnet.gr>
Date:   Mon May 7 19:34:11 2012 +0300

    Use the Backend client instead of global RAPI
    
    Replace use of global RAPI client, with the cached client from the
    VirtualMachine or Backend model.
    
    Dispatch network actions to all backends.

diff --git a/snf-cyclades-app/synnefo/api/servers.py b/snf-cyclades-app/synnefo/api/servers.py
index dda73d4..23b4491 100644
--- a/snf-cyclades-app/synnefo/api/servers.py
+++ b/snf-cyclades-app/synnefo/api/servers.py
@@ -31,6 +31,8 @@
 # interpreted as representing official policies, either expressed
 # or implied, of GRNET S.A.
 
+import random
+
 from base64 import b64decode
 from logging import getLogger
 
@@ -43,7 +45,7 @@ from django.utils import simplejson as json
 from synnefo.api import faults, util
 from synnefo.api.actions import server_actions
 from synnefo.api.common import method_not_allowed
-from synnefo.db.models import VirtualMachine, VirtualMachineMetadata
+from synnefo.db.models import Backend, VirtualMachine, VirtualMachineMetadata
 from synnefo.logic.backend import create_instance, delete_instance
 from synnefo.logic.utils import get_rsapi_state
 from synnefo.util.rapi import GanetiApiError
@@ -251,10 +253,12 @@ def create_server(request):
     if count >= vms_limit_for_user:
         raise faults.OverLimit("Server count limit exceeded for your account.")
 
+    backend = random.choice(Backend.objects.all())
     # We must save the VM instance now, so that it gets a
     # valid vm.backend_vm_id.
     vm = VirtualMachine.objects.create(
         name=name,
+        backend=backend,
         userid=request.user_uniq,
         imageid=image_id,
         flavor=flavor)
diff --git a/snf-cyclades-app/synnefo/db/models.py b/snf-cyclades-app/synnefo/db/models.py
index bac2cf8..9eea50d 100644
--- a/snf-cyclades-app/synnefo/db/models.py
+++ b/snf-cyclades-app/synnefo/db/models.py
@@ -309,7 +309,7 @@ class VirtualMachine(models.Model):
 
     @property
     def client(self):
-        if not self.backend.offline:
+        if self.backend and not self.backend.offline:
             return get_client(self.backend_hash, self.backend_id)
         else:
             raise ServiceUnavailable
diff --git a/snf-cyclades-app/synnefo/logic/backend.py b/snf-cyclades-app/synnefo/logic/backend.py
index 917b965..ac06d85 100644
--- a/snf-cyclades-app/synnefo/logic/backend.py
+++ b/snf-cyclades-app/synnefo/logic/backend.py
@@ -34,18 +34,17 @@
 import json
 
 from logging import getLogger
-
 from django.conf import settings
 from django.db import transaction
 
-from synnefo.db.models import (VirtualMachine, Network, NetworkLink)
+from synnefo.db.models import (Backend, VirtualMachine, Network, NetworkLink)
 from synnefo.logic import utils
 from synnefo.util.rapi import GanetiRapiClient
 
 
+
 log = getLogger('synnefo.logic')
 
-rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO)
 
 _firewall_tags = {
     'ENABLED': settings.GANETI_FIREWALL_ENABLED_TAG,
@@ -282,28 +281,28 @@ def create_instance(vm, flavor, image, password, personality):
     # Defined in settings.GANETI_CREATEINSTANCE_KWARGS
     # kw['hvparams'] = dict(serial_console=False)
 
-    return rapi.CreateInstance(**kw)
+    return vm.client.CreateInstance(**kw)
 
 
 def delete_instance(vm):
     start_action(vm, 'DESTROY')
-    rapi.DeleteInstance(vm.backend_vm_id, dry_run=settings.TEST)
+    vm.client.DeleteInstance(vm.backend_vm_id, dry_run=settings.TEST)
 
 
 def reboot_instance(vm, reboot_type):
     assert reboot_type in ('soft', 'hard')
-    rapi.RebootInstance(vm.backend_vm_id, reboot_type, dry_run=settings.TEST)
+    vm.client.RebootInstance(vm.backend_vm_id, reboot_type, dry_run=settings.TEST)
     log.info('Rebooting instance %s', vm.backend_vm_id)
 
 
 def startup_instance(vm):
     start_action(vm, 'START')
-    rapi.StartupInstance(vm.backend_vm_id, dry_run=settings.TEST)
+    vm.client.StartupInstance(vm.backend_vm_id, dry_run=settings.TEST)
 
 
 def shutdown_instance(vm):
     start_action(vm, 'STOP')
-    rapi.ShutdownInstance(vm.backend_vm_id, dry_run=settings.TEST)
+    vm.client.ShutdownInstance(vm.backend_vm_id, dry_run=settings.TEST)
 
 
 def get_instance_console(vm):
@@ -320,7 +319,7 @@ def get_instance_console(vm):
     #
     console = {}
     console['kind'] = 'vnc'
-    i = rapi.GetInstance(vm.backend_vm_id)
+    i = vm.client.GetInstance(vm.backend_vm_id)
     if i['hvparams']['serial_console']:
         raise Exception("hv parameter serial_console cannot be true")
     console['host'] = i['pnode']
@@ -331,11 +330,7 @@ def get_instance_console(vm):
 
 
 def request_status_update(vm):
-    return rapi.GetInstanceInfo(vm.backend_vm_id)
-
-
-def get_job_status(jobid):
-    return rapi.GetJobStatus(jobid)
+    return vm.client.GetInstanceInfo(vm.backend_vm_id)
 
 
 def update_status(vm, status):
@@ -395,7 +390,7 @@ def delete_network(net):
 
 def connect_to_network(vm, net):
     nic = {'mode': 'bridged', 'link': net.link.name}
-    rapi.ModifyInstance(vm.backend_vm_id, nics=[('add', -1, nic)],
+    vm.client.ModifyInstance(vm.backend_vm_id, nics=[('add', -1, nic)],
                         hotplug=True, dry_run=settings.TEST)
 
 
@@ -404,7 +399,7 @@ def disconnect_from_network(vm, net):
     ops = [('remove', nic.index, {}) for nic in nics if nic.network == net]
     if not ops:  # Vm not connected to network
         return
-    rapi.ModifyInstance(vm.backend_vm_id, nics=ops[::-1],
+    vm.client.ModifyInstance(vm.backend_vm_id, nics=ops[::-1],
                         hotplug=True, dry_run=settings.TEST)
 
 
@@ -414,25 +409,42 @@ def set_firewall_profile(vm, profile):
     except KeyError:
         raise ValueError("Unsopported Firewall Profile: %s" % profile)
 
+    client = vm.client
     # Delete all firewall tags
     for t in _firewall_tags.values():
-        rapi.DeleteInstanceTags(vm.backend_vm_id, [t], dry_run=settings.TEST)
+        client.DeleteInstanceTags(vm.backend_vm_id, [t], dry_run=settings.TEST)
 
-    rapi.AddInstanceTags(vm.backend_vm_id, [tag], dry_run=settings.TEST)
+    client.AddInstanceTags(vm.backend_vm_id, [tag], dry_run=settings.TEST)
 
     # XXX NOP ModifyInstance call to force process_net_status to run
     # on the dispatcher
-    rapi.ModifyInstance(vm.backend_vm_id,
+    vm.client.ModifyInstance(vm.backend_vm_id,
                         os_name=settings.GANETI_CREATEINSTANCE_KWARGS['os'])
 
 
-def get_ganeti_instances():
-    return rapi.GetInstances()
+def get_ganeti_instances(backend=None, bulk=False):
+    Instances = [c.client.GetInstances(bulk=bulk) for c in get_backends(backend)]
+    return reduce(list.__add__, Instances, [])
+
+
+def get_ganeti_nodes(backend=None, bulk=False):
+    Nodes = [c.client.GetNodes(bulk=bulk) for c in get_backends(backend)]
+    return reduce(list.__add__, Nodes, [])
+
+
+def get_ganeti_jobs(backend=None, bulk=False):
+    Jobs = [c.client.GetJobs(bulk=bulk) for c in get_backends(backend)]
+    return reduce(list.__add__, Jobs, [])
+
+##
+##
+##
+def get_backends(backend=None):
+    if backend:
+        return [backend]
+    return Backend.objects.all()
+
 
 
-def get_ganeti_nodes():
-    return rapi.GetNodes()
 
 
-def get_ganeti_jobs():
-    return rapi.GetJobs()
diff --git a/snf-cyclades-app/synnefo/logic/management/commands/reconcile.py b/snf-cyclades-app/synnefo/logic/management/commands/reconcile.py
index 492af0a..26a85dc 100644
--- a/snf-cyclades-app/synnefo/logic/management/commands/reconcile.py
+++ b/snf-cyclades-app/synnefo/logic/management/commands/reconcile.py
@@ -44,7 +44,6 @@ from django.core.management.base import BaseCommand, CommandError
 
 from synnefo.db.models import VirtualMachine
 from synnefo.logic import reconciliation, backend
-from synnefo.util.rapi import GanetiRapiClient
 
 
 class Command(BaseCommand):
@@ -156,8 +155,8 @@ class Command(BaseCommand):
                 "Issuing OP_INSTANCE_REMOVE for %d Ganeti instances:" % \
                 len(orphans)
             for id in orphans:
-                rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO)
-                rapi.DeleteInstance('%s%s' %
+                vm = VirtualMachine.objects.get(pk=id)
+                vm.client.DeleteInstance('%s%s' %
                                     (settings.BACKEND_PREFIX_ID, str(id)))
             print >> sys.stderr, "    ...done"
 
diff --git a/snf-cyclades-app/synnefo/logic/reconciliation.py b/snf-cyclades-app/synnefo/logic/reconciliation.py
index 641ddd8..6a1d0f7 100755
--- a/snf-cyclades-app/synnefo/logic/reconciliation.py
+++ b/snf-cyclades-app/synnefo/logic/reconciliation.py
@@ -69,7 +69,7 @@ setup_environ(settings)
 
 from synnefo.db.models import VirtualMachine
 from synnefo.util.dictconfig import dictConfig
-from synnefo.util.rapi import GanetiRapiClient
+from synnefo.logic.backend import get_ganeti_instances
 
 
 log = logging.getLogger()
@@ -108,8 +108,7 @@ def get_servers_from_db():
 
 
 def get_instances_from_ganeti():
-    rapi = GanetiRapiClient(*settings.GANETI_CLUSTER_INFO)
-    ganeti_instances = rapi.GetInstances(bulk=True)
+    ganeti_instances = get_ganeti_instances(bulk=True)
     snf_instances = {}
 
     prefix = settings.BACKEND_PREFIX_ID
