Minor changes
[snf-occi] / snfOCCI / compute.py
index 279498f..d6f815b 100644 (file)
@@ -1,28 +1,55 @@
-from snfOCCI.config import SERVER_CONFIG
+# Copyright 2012-2013 GRNET S.A. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+#   1. Redistributions of source code must retain the above
+#     copyright notice, this list of conditions and the following
+#     disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above
+#     copyright notice, this list of conditions and the following
+#     disclaimer in the documentation and/or other materials
+#     provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and
+# documentation are those of the authors and should not be
+# interpreted as representing official policies, either expressed
+# or implied, of GRNET S.A.
+
 
 
-from kamaki.clients.compute import ComputeClient
-from kamaki.clients.cyclades import CycladesClient
-from kamaki.config  import Config
+from snfOCCI.config import SERVER_CONFIG
 
 from occi.backend import ActionBackend, KindBackend
 
 from occi.backend import ActionBackend, KindBackend
-from occi.extensions.infrastructure import COMPUTE, START, STOP, SUSPEND, RESTART
+from occi.extensions import infrastructure
+from occi.exceptions import HTTPError
 
 
 #Compute Backend for snf-occi-server
 
 class MyBackend(KindBackend, ActionBackend):
 
 
 #Compute Backend for snf-occi-server
 
 class MyBackend(KindBackend, ActionBackend):
-    '''
-    An very simple abstract backend which handles update and replace for
-    attributes. Support for links and mixins would need to added.
-    '''
 
 
-    # Update and Replace compute instances not supported by Cyclades
+    # Updating and Replacing compute instances not supported by Cyclades
 
     def update(self, old, new, extras):
 
     def update(self, old, new, extras):
-        raise AttributeError("This action is currently no applicable.")
+        raise HTTPError(501, "Update is currently no applicable")
 
     def replace(self, old, new, extras):
 
     def replace(self, old, new, extras):
-        raise AttributeError("This action is currently no applicable.")
+        raise HTTPError(501, "Replace is currently no applicable")
 
 
 class ComputeBackend(MyBackend):
 
 
 class ComputeBackend(MyBackend):
@@ -31,40 +58,52 @@ class ComputeBackend(MyBackend):
     '''
 
     def create(self, entity, extras):
     '''
 
     def create(self, entity, extras):
-    
-        for mixin in entity.mixins:
-            if mixin.related[0].term == 'os_tpl':
-                image = mixin
-                image_id = mixin.attributes['occi.core.id']
-            if mixin.related[0].term == 'resource_tpl':
-                flavor = mixin
-                flavor_id = mixin.attributes['occi.core.id']
-                
-        entity.attributes['occi.compute.state'] = 'inactive'
-        entity.actions = [START]
-
-        #Registry identifier is the uuid key occi.handler assigns
-        #attribute 'occi.core.id' will be the snf-server id
-
-        conf = Config()
-        conf.set('token',extras['token'])
-        snf = ComputeClient(conf)
 
 
-        vm_name = entity.attributes['occi.compute.hostname']
-        info = snf.create_server(vm_name, flavor_id, image_id)
-        entity.attributes['occi.core.id'] = str(info['id'])
-        entity.attributes['occi.compute.architecture'] = SERVER_CONFIG['compute_arch']
-        entity.attributes['occi.compute.cores'] = flavor.attributes['occi.compute.cores']
-        entity.attributes['occi.compute.memory'] = flavor.attributes['occi.compute.memory']
-        entity.attributes['occi.compute.hostname'] = SERVER_CONFIG['hostname'] % {'id':info['id']}
+        #Creating new compute instance
+        
+        try:
+
+            snf = extras['snf']
+
+            for mixin in entity.mixins:
+                if mixin.related[0].term == 'os_tpl':
+                    image_id = mixin.attributes['occi.core.id']
+                if mixin.related[0].term == 'resource_tpl':
+                    flavor = mixin
+                    flavor_id = mixin.attributes['occi.core.id']
+
+            vm_name = entity.attributes['occi.core.title']
+            info = snf.create_server(vm_name, flavor_id, image_id)
+           
+            entity.attributes['occi.compute.state'] = 'inactive'
+            entity.attributes['occi.core.id'] = str(info['id'])
+            entity.attributes['occi.compute.architecture'] = SERVER_CONFIG['compute_arch']
+            entity.attributes['occi.compute.cores'] = flavor.attributes['occi.compute.cores']
+            entity.attributes['occi.compute.memory'] = flavor.attributes['occi.compute.memory']
+           
+            entity.actions = [infrastructure.STOP,
+                               infrastructure.SUSPEND,
+                               infrastructure.RESTART]
+
+            # entity.attributes['occi.compute.hostname'] = SERVER_CONFIG['hostname'] % {'id':info['id']}
+            info['adminPass']= ""
+            print info
+            networkIDs = info['addresses'].keys()
+                #resource.attributes['occi.compute.hostname'] = SERVER_CONFIG['hostname'] % {'id':int(key)}
+            if len(networkIDs)>0:    
+                entity.attributes['occi.compute.hostname'] =  str(info['addresses'][networkIDs[0]][0]['addr'])
+            else:
+                entity.attributes['occi.compute.hostname'] = ""
+               
+        except (UnboundLocalError, KeyError) as e:
+            raise HTTPError(406, 'Missing details about compute instance')
+            
 
     def retrieve(self, entity, extras):
         
 
     def retrieve(self, entity, extras):
         
-        # triggering cyclades to retrieve up to date information
+        #Triggering cyclades to retrieve up to date information
 
 
-        conf = Config()
-        conf.set('token',extras['token'])
-        snf = ComputeClient(conf)
+        snf = extras['snf']
 
         vm_id = int(entity.attributes['occi.core.id'])
         vm_info = snf.get_server_details(vm_id)
 
         vm_id = int(entity.attributes['occi.core.id'])
         vm_info = snf.get_server_details(vm_id)
@@ -72,56 +111,96 @@ class ComputeBackend(MyBackend):
         
         status_dict = {'ACTIVE' : 'active',
                        'STOPPED' : 'inactive',
         
         status_dict = {'ACTIVE' : 'active',
                        'STOPPED' : 'inactive',
+                       'REBOOT' : 'inactive',
                        'ERROR' : 'inactive',
                        'BUILD' : 'inactive',
                        'DELETED' : 'inactive',
                        'ERROR' : 'inactive',
                        'BUILD' : 'inactive',
                        'DELETED' : 'inactive',
+                       'UNKNOWN' : 'inactive'
                        }
         
         entity.attributes['occi.compute.state'] = status_dict[vm_state]
                        }
         
         entity.attributes['occi.compute.state'] = status_dict[vm_state]
+                
+        if vm_state == 'ERROR':
+            raise HTTPError(500, 'ERROR building the compute instance')
 
 
-        if entity.attributes['occi.compute.state'] == 'inactive':
-            entity.actions = [START]
-        if entity.attributes['occi.compute.state'] == 'active': 
-            entity.actions = [STOP, SUSPEND, RESTART]
-        if entity.attributes['occi.compute.state'] == 'suspended':
-            entity.actions = [START]
+        else:
+            if entity.attributes['occi.compute.state'] == 'inactive':
+                entity.actions = [infrastructure.START]
+            if entity.attributes['occi.compute.state'] == 'active': 
+                entity.actions = [infrastructure.STOP, infrastructure.SUSPEND, infrastructure.RESTART]
 
 
     def delete(self, entity, extras):
 
 
 
     def delete(self, entity, extras):
 
-        # delete vm with vm_id = entity.attributes['occi.core.id']
-        conf = Config()
-        conf.set('token',extras['token'])
-        snf = ComputeClient(conf)
-
+        #Deleting compute instance
+        print "Deleting VM" + str(vm_id)
+        snf = extras['snf']
         vm_id = int(entity.attributes['occi.core.id'])
         snf.delete_server(vm_id)
 
 
         vm_id = int(entity.attributes['occi.core.id'])
         snf.delete_server(vm_id)
 
 
-    def action(self, entity, action, extras):
+    def get_vm_actions(self, entity ,vm_state):
+        
+        actions = []
+        
+        status_dict = {'ACTIVE' : 'active',
+                       'STOPPED' : 'inactive',
+                       'REBOOT' : 'inactive',
+                       'ERROR' : 'inactive',
+                       'BUILD' : 'inactive',
+                       'DELETED' : 'inactive',
+                       'UNKNOWN' : 'inactive'
+                       }
+
+        if vm_state in status_dict:
+            
+            entity.attributes['occi.compute.state'] = status_dict[vm_state]
+            if vm_state == 'ACTIVE':
+                actions.append(infrastructure.STOP)
+                actions.append(infrastructure.RESTART)
+            elif vm_state in ('STOPPED'):
+                actions.append(infrastructure.START)
+                
+            return actions
+        else:
+            raise HTTPError(500, 'Undefined status of the VM')
 
 
-        conf = Config()
-        conf.set('token',extras['token'])
-        client = CycladesClient(conf)
+    def action(self, entity, action, attributes, extras):
 
 
-        vm_id = int(entity.attributes['occi.core.id'])
+        #Triggering action to compute instances
 
 
-        if action not in entity.actions:
-            raise AttributeError("This action is currently no applicable.")
+        client = extras['client']
+        snf = extras['snf']
 
 
-        elif action == START:
-            print "Starting VM"
-            client.start_server(vm_id)
+        vm_id = int(entity.attributes['occi.core.id'])
+        vm_info = snf.get_server_details(vm_id)
+        vm_state = vm_info['status']
+        
+        # Define the allowed actions depending on the state of the VM
+        entity.actions = self.get_vm_actions(entity,vm_state)
+        
 
 
+        if vm_state == 'ERROR':
+            raise HTTPError(500, 'ERROR building the compute instance')
 
 
-        elif action == STOP:
-            print "Stopping VM"
-            client.shutdown_server(vm_id)
+        else:
+            if action not in entity.actions:
+                raise AttributeError("This action is currently no applicable in the current status of the VM (CURRENT_STATE = " + str(vm_state)+ ").")
             
             
-        elif action == RESTART:
-            print "Restarting VM"
-            snf.reboot_server(vm_id)
+            elif action == infrastructure.START:
+                print "Starting VM" + str(vm_id)
+                client.start_server(vm_id)
+                
+            elif action == infrastructure.STOP:
+                print "Stopping VM"  + str(vm_id)
+                client.shutdown_server(vm_id)
+    
+            elif action == infrastructure.RESTART:
+                print "Restarting VM" + str(vm_id)
+                snf.reboot_server(vm_id)
 
 
+            elif action == infrastructure.SUSPEND:
+                raise HTTPError(501, "This actions is currently no applicable")
+            
+            
 
 
-        elif action == SUSPEND:
-            raise AttributeError("This actions is currently no applicable")