Update setup.py
[snf-occi] / snfOCCI / APIserver.py
1 #!/usr/bin/env python
2
3 import re
4 import string
5 import sqlite3
6
7 from snfOCCI.registry import snfRegistry
8 from snfOCCI.compute import ComputeBackend
9 from snfOCCI.config import SERVER_CONFIG, KAMAKI_CONFIG
10
11 from kamaki.clients.compute import ComputeClient
12 from kamaki.clients.cyclades import CycladesClient
13 from kamaki.config  import Config
14
15 from occi.core_model import Mixin, Resource
16 from occi.backend import MixinBackend
17 from occi.extensions.infrastructure import COMPUTE, START, STOP, SUSPEND, RESTART, RESOURCE_TEMPLATE, OS_TEMPLATE
18 from occi.wsgi import Application
19 from occi.exceptions import HTTPError
20
21 from wsgiref.simple_server import make_server
22 from wsgiref.validate import validator
23
24 import voms
25
26
27 conn = sqlite3.connect('/home/nemo/myWorkspace/snf-occi/snfOCCI/voms.db')
28
29 class MyAPP(Application):
30     '''
31     An OCCI WSGI application.
32     '''
33
34     def refresh_images(self, snf, client):
35
36         images = snf.list_images()
37         for image in images:
38             IMAGE_ATTRIBUTES = {'occi.core.id': str(image['id'])}
39             IMAGE = Mixin("http://schemas.ogf.org/occi/infrastructure#", str(image['name']), [OS_TEMPLATE], attributes = IMAGE_ATTRIBUTES)
40             self.register_backend(IMAGE, MixinBackend())
41
42     def refresh_flavors(self, snf, client):
43         
44         flavors = snf.list_flavors()
45         for flavor in flavors:
46             details = snf.get_flavor_details(flavor['id'])
47             FLAVOR_ATTRIBUTES = {'occi.core.id': flavor['id'],
48                                  'occi.compute.cores': details['cpu'],
49                                  'occi.compute.memory': details['ram'],
50                                  'occi.storage.size': details['disk'],
51                                  }
52             FLAVOR = Mixin("http://schemas.ogf.org/occi/infrastructure#", str(flavor['name']), [RESOURCE_TEMPLATE], attributes = FLAVOR_ATTRIBUTES)
53             self.register_backend(FLAVOR, MixinBackend())
54
55
56     def refresh_compute_instances(self, snf):
57         '''Syncing registry with cyclades resources'''
58
59         servers = snf.list_servers()
60         snf_keys = []
61         for server in servers:
62             snf_keys.append(str(server['id']))
63
64         resources = self.registry.resources
65         occi_keys = resources.keys()
66         
67         #Compute instances in synnefo not available in registry
68         diff = [x for x in snf_keys if '/compute/'+x not in occi_keys]
69         for key in diff:
70
71             details = snf.get_server_details(int(key))
72             flavor = snf.get_flavor_details(details['flavorRef'])
73             image = snf.get_image_details(details['imageRef'])
74
75             for i in self.registry.backends:
76                 if i.term == str(image['name']):
77                     rel_image = i
78                 if i.term == str(flavor['name']):
79                     rel_flavor = i
80
81             resource = Resource(key, COMPUTE, [rel_flavor, rel_image])
82             resource.actions = [START]
83             resource.attributes['occi.core.id'] = key
84             resource.attributes['occi.compute.state'] = 'inactive'
85             resource.attributes['occi.compute.architecture'] = SERVER_CONFIG['compute_arch']
86             resource.attributes['occi.compute.cores'] = flavor['cpu']
87             resource.attributes['occi.compute.memory'] = flavor['ram']
88             resource.attributes['occi.compute.hostname'] = SERVER_CONFIG['hostname'] % {'id':int(key)}
89
90             self.registry.add_resource(key, resource, None)
91
92         #Compute instances in registry not available in synnefo
93         diff = [x for x in occi_keys if x[9:] not in snf_keys]
94         for key in diff:
95             self.registry.delete_resource(key, None)
96
97
98     def __call__(self, environ, response):
99
100         #Authorization
101
102         ssl_dict = dict()
103
104         #Regular expression in HTTP headers
105         #raw environ[HTTP_SSL] contains PEM certificates in wrong format
106         
107         pem_re = r'^(-----BEGIN CERTIFICATE----- )(.*|\s]*)( -----END CERTIFICATE-----)'
108
109         client_cert = re.search(pem_re, environ["HTTP_SSL_CLIENT_CERT"])
110         client_chain = re.search(pem_re, environ["HTTP_SSL_CLIENT_CERT_CHAIN_0"])
111
112         client_cert_list=[]
113         client_chain_list=[]
114
115         for i in range(1,4):
116             client_cert_list.append(string.strip(client_cert.group(i)))
117
118         for i in range(1,4):
119             client_chain_list.append(string.strip(client_chain.group(i)))
120
121
122         cert = client_cert_list[0]+"\n"+client_cert_list[1].replace(" "," \n")+"\n"+client_cert_list[2]
123         chain = client_chain_list[0]+"\n"+client_chain_list[1].replace(" "," \n")+"\n"+client_chain_list[2]
124
125         ssl_dict["SSL_CLIENT_S_DN"] = environ["HTTP_SSL_CLIENT_S_DN"]
126         ssl_dict["SSL_CLIENT_CERT"] = cert
127         ssl_dict["SSL_CLIENT_CERT_CHAIN_0"] = chain
128
129         (user_dn, user_vo, user_fqans) = voms.authenticate(ssl_dict)
130         print (user_dn, user_vo, user_fqans)
131
132
133         cursor = conn.cursor()
134         query = "SELECT token FROM vo_map WHERE vo_name=?"
135         cursor.execute(query,[(user_vo)])
136
137         (token,) = cursor.fetchone()
138
139         if token:
140             compClient = ComputeClient(KAMAKI_CONFIG['compute_url'], token)
141             cyclClient = CycladesClient(KAMAKI_CONFIG['compute_url'], token)
142
143             self.refresh_images(compClient,cyclClient)
144             self.refresh_flavors(compClient,cyclClient)
145             self.refresh_compute_instances(compClient)
146
147
148             return self._call_occi(environ, response, security = None, token = token, snf = compClient, client = cyclClient)
149         else:
150             raise HTTPError(404, "Unauthorized access")
151
152
153
154 def main():
155
156     APP = MyAPP(registry = snfRegistry())
157     COMPUTE_BACKEND = ComputeBackend()
158
159     APP.register_backend(COMPUTE, COMPUTE_BACKEND)
160     APP.register_backend(START, COMPUTE_BACKEND)
161     APP.register_backend(STOP, COMPUTE_BACKEND)
162     APP.register_backend(RESTART, COMPUTE_BACKEND)
163     APP.register_backend(SUSPEND, COMPUTE_BACKEND)
164     APP.register_backend(RESOURCE_TEMPLATE, MixinBackend())
165     APP.register_backend(OS_TEMPLATE, MixinBackend())
166  
167     VALIDATOR_APP = validator(APP)
168     HTTPD = make_server('', SERVER_CONFIG['port'], VALIDATOR_APP)
169     HTTPD.serve_forever()
170