056839e3bac9c499fedda7cee301f37d2db4e94e
[snf-occi] / snfOCCI / APIserver.py
1 #!/usr/bin/env python
2
3 from snfOCCI.registry import snfRegistry
4 from snfOCCI.compute import ComputeBackend
5 from snfOCCI.network import NetworkBackend, IpNetworkBackend, IpNetworkInterfaceBackend, NetworkInterfaceBackend
6
7 from snfOCCI.config import SERVER_CONFIG, KAMAKI_CONFIG
8
9 from kamaki.clients.compute import ComputeClient
10 from kamaki.clients.cyclades import CycladesClient
11 from kamaki.clients import ClientError
12
13 from occi.core_model import Mixin, Resource
14 from occi.backend import MixinBackend, KindBackend
15 from occi.extensions.infrastructure import COMPUTE, START, STOP, SUSPEND, RESTART, RESOURCE_TEMPLATE, OS_TEMPLATE, NETWORK, IPNETWORK, NETWORKINTERFACE,IPNETWORKINTERFACE 
16 from occi.wsgi import Application
17 from occi.exceptions import HTTPError
18 from occi import core_model
19
20 from wsgiref.simple_server import make_server
21 from wsgiref.validate import validator
22 import uuid
23
24 class MyAPP(Application):
25     '''
26     An OCCI WSGI application.
27     '''
28
29     def refresh_images(self, snf, client):
30
31         images = snf.list_images()
32         for image in images:
33             IMAGE_ATTRIBUTES = {'occi.core.id': str(image['id'])}
34             IMAGE = Mixin("http://schemas.ogf.org/occi/infrastructure#", str(image['name']), [OS_TEMPLATE], attributes = IMAGE_ATTRIBUTES)
35             self.register_backend(IMAGE, MixinBackend())
36
37     def refresh_flavors(self, snf, client):
38         
39         flavors = snf.list_flavors()
40         print "Retrieving details for each image id"
41         for flavor in flavors:
42             details = snf.get_flavor_details(flavor['id'])
43             FLAVOR_ATTRIBUTES = {'occi.core.id': flavor['id'],
44                                  'occi.compute.cores': str(details['vcpus']),
45                                  'occi.compute.memory': str(details['ram']),
46                                  'occi.storage.size': str(details['disk']),
47                                  }
48             FLAVOR = Mixin("http://schemas.ogf.org/occi/infrastructure#", str(flavor['name']), [RESOURCE_TEMPLATE], attributes = FLAVOR_ATTRIBUTES)
49             self.register_backend(FLAVOR, MixinBackend())
50             
51     def refresh_flavors_norecursive(self, snf, client):
52         flavors = snf.list_flavors(True)
53         print "Retrieving details for each image id"
54         for flavor in flavors:
55             # details = snf.get_flavor_details(flavor['id'])
56             FLAVOR_ATTRIBUTES = {'occi.core.id': flavor['id'],
57                                  'occi.compute.cores': str(flavor['vcpus']),
58                                  'occi.compute.memory': str(flavor['ram']),
59                                  'occi.storage.size': str(flavor['disk']),
60                                  }
61              
62             FLAVOR = Mixin("http://schemas.ogf.org/occi/infrastructure#", str(flavor['name']), [RESOURCE_TEMPLATE], attributes = FLAVOR_ATTRIBUTES)
63             self.register_backend(FLAVOR, MixinBackend())
64             
65        
66     def refresh_network_instances(self,client):
67         networks =client.networks_get(command = 'detail')
68         network_details = networks.json['networks']
69         resources = self.registry.resources
70         occi_keys = resources.keys()
71          
72         for network in network_details:
73             if '/network/'+str(network['id']) not in occi_keys:
74                 netID = '/network/'+str(network['id'])   
75                 snf_net = core_model.Resource(netID,
76                                            NETWORK,
77                                            [IPNETWORK])
78                 
79                 snf_net.attributes['occi.core.id'] = str(network['id']) 
80                
81                 #This info comes from the network details
82                 snf_net.attributes['occi.network.state'] = str(network['status'])
83                 snf_net.attributes['occi.network.gateway'] = str(network['gateway'])
84                
85                 if network['public'] == True:
86                     snf_net.attributes['occi.network.type'] = "Public = True"
87                 else:
88                     snf_net.attributes['occi.network.type'] = "Public = False"
89                     
90                 self.registry.add_resource(netID, snf_net, None)       
91             
92         
93             
94     def refresh_compute_instances(self, snf, client):
95         '''Syncing registry with cyclades resources'''
96         
97         servers = snf.list_servers()
98         snf_keys = []
99         for server in servers:
100             snf_keys.append(str(server['id']))
101
102         resources = self.registry.resources
103         occi_keys = resources.keys()
104         
105         print resources.keys()
106         
107         for serverID in occi_keys:
108             if '/compute/' in serverID and resources[serverID].attributes['occi.compute.hostname'] == "":
109                 self.registry.delete_resource(serverID, None)
110         
111         occi_keys = resources.keys()
112         
113             
114         #Compute instances in synnefo not available in registry
115         diff = [x for x in snf_keys if '/compute/'+x not in occi_keys]
116         for key in diff:
117
118             details = snf.get_server_details(int(key))
119             flavor = snf.get_flavor_details(details['flavor']['id'])
120             
121             try:
122                 print "line 65:Finished getting image details for VM with ID" + str(details['flavor']['id'])
123                 image = snf.get_image_details(details['image']['id'])
124                 
125                 for i in self.registry.backends:
126                     if i.term == str(image['name']):
127                         rel_image = i
128                     if i.term == str(flavor['name']):
129                         rel_flavor = i
130                         
131                 resource = Resource(key, COMPUTE, [rel_flavor, rel_image])
132                 resource.actions = [START]
133                 resource.attributes['occi.core.id'] = key
134                 resource.attributes['occi.compute.state'] = 'inactive'
135                 resource.attributes['occi.compute.architecture'] = SERVER_CONFIG['compute_arch']
136                 resource.attributes['occi.compute.cores'] = str(flavor['vcpus'])
137                 resource.attributes['occi.compute.memory'] = str(flavor['ram'])
138                 resource.attributes['occi.core.title'] = str(details['name'])
139                 networkIDs = details['addresses'].keys()
140                 if len(networkIDs)>0: 
141                     #resource.attributes['occi.compute.hostname'] = SERVER_CONFIG['hostname'] % {'id':int(key)}
142                     resource.attributes['occi.compute.hostname'] =  str(details['addresses'][networkIDs[0]][0]['addr'])
143                     #resource.attributes['occi.networkinterface.address'] = str(details['addresses'][networkIDs[0]][0]['addr'])
144                 else:
145                     resource.attributes['occi.compute.hostname'] = ""
146                     
147                 self.registry.add_resource(key, resource, None)  
148                 
149                 for netKey in networkIDs:
150                     link_id = str(uuid.uuid4())
151                     NET_LINK = core_model.Link("http://schemas.ogf.org/occi/infrastructure#networkinterface" + link_id,
152                                                NETWORKINTERFACE,
153                                                [IPNETWORKINTERFACE], resource,
154                                                self.registry.resources['/network/'+str(netKey)])
155                     
156                     for version in details['addresses'][netKey]:
157                         if version['version']==4:
158                             ip4address = str(version['addr'])
159                             allocheme = str(version['OS-EXT-IPS:type'])
160                         elif version['version']==6:
161                             ip6address = str(version['addr'])
162                    
163                     if 'attachments' in details.keys():
164                         for item in details['attachments']:
165                             NET_LINK.attributes ={'occi.core.id':link_id,
166                                           'occi.networkinterface.allocation' : allocheme,
167                                           'occi.networking.interface': str(item['id']),
168                                           'occi.networkinterface.mac' : str(item['mac_address']),
169                                           'occi.networkinterface.ip4' : ip4address,
170                                           'occi.networkinterface.ip6' :  ip6address                      
171                                       }
172                     elif  len(details['addresses'][netKey])>0:
173                         NET_LINK.attributes ={'occi.core.id':link_id,
174                                           'occi.networkinterface.allocation' : allocheme,
175                                           'occi.networking.interface': '',
176                                           'occi.networkinterface.mac' : '',
177                                           'occi.networkinterface.ip4' : ip4address,
178                                           'occi.networkinterface.ip6' :  ip6address                      
179                                       }
180     
181                     else:
182                         NET_LINK.attributes ={'occi.core.id':link_id,
183                                           'occi.networkinterface.allocation' : '',
184                                           'occi.networking.interface': '',
185                                           'occi.networkinterface.mac' : '',
186                                           'occi.networkinterface.ip4' :'',
187                                           'occi.networkinterface.ip6' : '' }
188                                       
189                     resource.links.append(NET_LINK)
190                     self.registry.add_resource(link_id, NET_LINK, None)
191                      
192                 
193             except ClientError as ce:
194                 if ce.status == 404:
195                     print('Image not found, sorry!!!')
196                     continue
197                 else:
198                     raise ce
199                   
200         #Compute instances in registry not available in synnefo
201         diff = [x for x in occi_keys if x[9:] not in snf_keys]
202         for key in diff:
203             if '/network/' not in key:
204                 self.registry.delete_resource(key, None)
205
206     
207     def __call__(self, environ, response):
208         
209             compClient = ComputeClient(KAMAKI_CONFIG['compute_url'], environ['HTTP_AUTH_TOKEN'])
210             cyclClient = CycladesClient(KAMAKI_CONFIG['compute_url'], environ['HTTP_AUTH_TOKEN'])
211
212             #Up-to-date flavors and images
213             print "@refresh_images"
214             self.refresh_images(compClient,cyclClient)
215             print "@refresh_flavors"
216             self.refresh_flavors_norecursive(compClient,cyclClient)
217             self.refresh_network_instances(cyclClient)
218             print "@refresh_compute_instances"
219             self.refresh_compute_instances(compClient,cyclClient)
220            
221             # token will be represented in self.extras
222             return self._call_occi(environ, response, security = None, token = environ['HTTP_AUTH_TOKEN'], snf = compClient, client = cyclClient)
223
224
225 def main():
226
227     APP = MyAPP(registry = snfRegistry())
228     COMPUTE_BACKEND = ComputeBackend()
229     NETWORK_BACKEND = NetworkBackend() 
230     NETWORKINTERFACE_BACKEND = NetworkInterfaceBackend()
231     IPNETWORK_BACKEND = IpNetworkBackend()
232     IPNETWORKINTERFACE_BACKEND = IpNetworkInterfaceBackend()
233       
234     APP.register_backend(COMPUTE, COMPUTE_BACKEND)
235     APP.register_backend(START, COMPUTE_BACKEND)
236     APP.register_backend(STOP, COMPUTE_BACKEND)
237     APP.register_backend(RESTART, COMPUTE_BACKEND)
238     APP.register_backend(SUSPEND, COMPUTE_BACKEND)
239     APP.register_backend(RESOURCE_TEMPLATE, MixinBackend())
240     APP.register_backend(OS_TEMPLATE, MixinBackend())
241  
242     # Network related backends
243     APP.register_backend(NETWORK, NETWORK_BACKEND)
244     APP.register_backend(IPNETWORK, IPNETWORK_BACKEND)
245     APP.register_backend(NETWORKINTERFACE,NETWORKINTERFACE_BACKEND)
246     APP.register_backend(IPNETWORKINTERFACE, IPNETWORKINTERFACE_BACKEND)
247      
248     VALIDATOR_APP = validator(APP)
249   
250     HTTPD = make_server('', SERVER_CONFIG['port'], VALIDATOR_APP)
251     HTTPD.serve_forever()
252