5 from optparse import OptionParser, OptionValueError
9 from snfOCCI.registry import snfRegistry
10 from snfOCCI.compute import ComputeBackend
11 from snfOCCI.config import SERVER_CONFIG, KAMAKI_CONFIG
13 from kamaki.clients.compute import ComputeClient
14 from kamaki.clients.cyclades import CycladesClient
15 from kamaki.config import Config
17 from occi.core_model import Mixin, Resource
18 from occi.backend import MixinBackend
19 from occi.extensions.infrastructure import COMPUTE, START, STOP, SUSPEND, RESTART, RESOURCE_TEMPLATE, OS_TEMPLATE
20 from occi.wsgi import Application
21 from occi.exceptions import HTTPError
23 from wsgiref.simple_server import make_server
24 from wsgiref.validate import validator
28 def parse_arguments(args):
31 kw["usage"] = "%prog [options]"
32 kw["description"] = "OCCI interface to synnefo API"
34 parser = OptionParser(**kw)
35 parser.disable_interspersed_args()
37 parser.add_option("--enable_voms", action="store_true", dest="enable_voms", default=False, help="Enable voms authorization")
38 parser.add_option("--voms_db", action="store", type="string", dest="voms_db", help="Path to sqlite database file")
40 (opts, args) = parser.parse_args(args)
42 if opts.enable_voms and not opts.voms_db:
43 print "--voms_db option required"
48 class MyAPP(Application):
50 An OCCI WSGI application.
53 def refresh_images(self, snf, client):
55 images = snf.list_images()
57 IMAGE_ATTRIBUTES = {'occi.core.id': str(image['id'])}
58 IMAGE = Mixin("http://schemas.ogf.org/occi/infrastructure#", str(image['name']), [OS_TEMPLATE], attributes = IMAGE_ATTRIBUTES)
59 self.register_backend(IMAGE, MixinBackend())
61 def refresh_flavors(self, snf, client):
63 flavors = snf.list_flavors()
64 for flavor in flavors:
65 details = snf.get_flavor_details(flavor['id'])
66 FLAVOR_ATTRIBUTES = {'occi.core.id': flavor['id'],
67 'occi.compute.cores': details['cpu'],
68 'occi.compute.memory': details['ram'],
69 'occi.storage.size': details['disk'],
71 FLAVOR = Mixin("http://schemas.ogf.org/occi/infrastructure#", str(flavor['name']), [RESOURCE_TEMPLATE], attributes = FLAVOR_ATTRIBUTES)
72 self.register_backend(FLAVOR, MixinBackend())
75 def refresh_compute_instances(self, snf):
76 '''Syncing registry with cyclades resources'''
78 servers = snf.list_servers()
80 for server in servers:
81 snf_keys.append(str(server['id']))
83 resources = self.registry.resources
84 occi_keys = resources.keys()
86 #Compute instances in synnefo not available in registry
87 diff = [x for x in snf_keys if '/compute/'+x not in occi_keys]
90 details = snf.get_server_details(int(key))
91 flavor = snf.get_flavor_details(details['flavorRef'])
92 image = snf.get_image_details(details['imageRef'])
94 for i in self.registry.backends:
95 if i.term == str(image['name']):
97 if i.term == str(flavor['name']):
100 resource = Resource(key, COMPUTE, [rel_flavor, rel_image])
101 resource.actions = [START]
102 resource.attributes['occi.core.id'] = key
103 resource.attributes['occi.compute.state'] = 'inactive'
104 resource.attributes['occi.compute.architecture'] = SERVER_CONFIG['compute_arch']
105 resource.attributes['occi.compute.cores'] = flavor['cpu']
106 resource.attributes['occi.compute.memory'] = flavor['ram']
107 resource.attributes['occi.compute.hostname'] = SERVER_CONFIG['hostname'] % {'id':int(key)}
109 self.registry.add_resource(key, resource, None)
111 #Compute instances in registry not available in synnefo
112 diff = [x for x in occi_keys if x[9:] not in snf_keys]
114 self.registry.delete_resource(key, None)
117 def __call__(self, environ, response):
124 conn = sqlite3.connect(VOMS_DB)
128 #Regular expression in HTTP headers
129 #raw environ[HTTP_SSL] contains PEM certificates in wrong format
131 pem_re = r'^(-----BEGIN CERTIFICATE----- )(.*|\s]*)( -----END CERTIFICATE-----)'
133 client_cert = re.search(pem_re, environ["HTTP_SSL_CLIENT_CERT"])
134 client_chain = re.search(pem_re, environ["HTTP_SSL_CLIENT_CERT_CHAIN_0"])
140 client_cert_list.append(string.strip(client_cert.group(i)))
143 client_chain_list.append(string.strip(client_chain.group(i)))
146 cert = client_cert_list[0]+"\n"+client_cert_list[1].replace(" "," \n")+"\n"+client_cert_list[2]
147 chain = client_chain_list[0]+"\n"+client_chain_list[1].replace(" "," \n")+"\n"+client_chain_list[2]
149 ssl_dict["SSL_CLIENT_S_DN"] = environ["HTTP_SSL_CLIENT_S_DN"]
150 ssl_dict["SSL_CLIENT_CERT"] = cert
151 ssl_dict["SSL_CLIENT_CERT_CHAIN_0"] = chain
153 (user_dn, user_vo, user_fqans) = voms.authenticate(ssl_dict)
154 print (user_dn, user_vo, user_fqans)
156 cursor = conn.cursor()
157 query = "SELECT token FROM vo_map WHERE vo_name=?"
158 cursor.execute(query,[(user_vo)])
160 (token,) = cursor.fetchone()
163 compClient = ComputeClient(KAMAKI_CONFIG['compute_url'], token)
164 cyclClient = CycladesClient(KAMAKI_CONFIG['compute_url'], token)
166 self.refresh_images(compClient,cyclClient)
167 self.refresh_flavors(compClient,cyclClient)
168 self.refresh_compute_instances(compClient)
171 return self._call_occi(environ, response, security = None, token = token, snf = compClient, client = cyclClient)
173 raise HTTPError(404, "Unauthorized access")
176 #Authorize with user token
177 compClient = ComputeClient(KAMAKI_CONFIG['compute_url'], environ['HTTP_AUTH_TOKEN'])
178 cyclClient = CycladesClient(KAMAKI_CONFIG['compute_url'], environ['HTTP_AUTH_TOKEN'])
180 return self._call_occi(environ, response, security = None, token = environ['HTTP_AUTH_TOKEN'], snf = compClient, client = cyclClient)
185 global ENABLE_VOMS, VOMS_DB
186 (opts, args) = parse_arguments(sys.argv[1:])
188 ENABLE_VOMS = opts.enable_voms
189 VOMS_DB = opts.voms_db
191 APP = MyAPP(registry = snfRegistry())
193 COMPUTE_BACKEND = ComputeBackend()
194 APP.register_backend(COMPUTE, COMPUTE_BACKEND)
195 APP.register_backend(START, COMPUTE_BACKEND)
196 APP.register_backend(STOP, COMPUTE_BACKEND)
197 APP.register_backend(RESTART, COMPUTE_BACKEND)
198 APP.register_backend(SUSPEND, COMPUTE_BACKEND)
199 APP.register_backend(RESOURCE_TEMPLATE, MixinBackend())
200 APP.register_backend(OS_TEMPLATE, MixinBackend())
202 VALIDATOR_APP = validator(APP)
203 HTTPD = make_server('', SERVER_CONFIG['port'], VALIDATOR_APP)
204 HTTPD.serve_forever()