Statistics
| Branch: | Revision:

root / snfOCCI / APIserver.py @ c1106cd7

History | View | Annotate | Download (7.4 kB)

1
#!/usr/bin/env python
2

    
3
import re
4
import sys
5
from optparse import OptionParser, OptionValueError
6
import string
7
import sqlite3
8

    
9
from snfOCCI.registry import snfRegistry
10
from snfOCCI.compute import ComputeBackend
11
from snfOCCI.config import SERVER_CONFIG, KAMAKI_CONFIG
12

    
13
from kamaki.clients.compute import ComputeClient
14
from kamaki.clients.cyclades import CycladesClient
15
from kamaki.config  import Config
16

    
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
22

    
23
from wsgiref.simple_server import make_server
24
from wsgiref.validate import validator
25

    
26
import voms
27

    
28
def parse_arguments(args):
29

    
30
    kw = {}
31
    kw["usage"] = "%prog [options]"
32
    kw["description"] = "OCCI interface to synnefo API"
33

    
34
    parser = OptionParser(**kw)
35
    parser.disable_interspersed_args()
36

    
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")
39

    
40
    (opts, args) = parser.parse_args(args)
41

    
42
    if opts.enable_voms and not opts.voms_db:
43
        print "--voms_db option required"
44
        parser.print_help()
45

    
46
    return (opts, args)
47

    
48
class MyAPP(Application):
49
    '''
50
    An OCCI WSGI application.
51
    '''
52

    
53
    def refresh_images(self, snf, client):
54

    
55
        images = snf.list_images()
56
        for image in 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())
60

    
61
    def refresh_flavors(self, snf, client):
62
        
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'],
70
                                 }
71
            FLAVOR = Mixin("http://schemas.ogf.org/occi/infrastructure#", str(flavor['name']), [RESOURCE_TEMPLATE], attributes = FLAVOR_ATTRIBUTES)
72
            self.register_backend(FLAVOR, MixinBackend())
73

    
74

    
75
    def refresh_compute_instances(self, snf):
76
        '''Syncing registry with cyclades resources'''
77

    
78
        servers = snf.list_servers()
79
        snf_keys = []
80
        for server in servers:
81
            snf_keys.append(str(server['id']))
82

    
83
        resources = self.registry.resources
84
        occi_keys = resources.keys()
85
        
86
        #Compute instances in synnefo not available in registry
87
        diff = [x for x in snf_keys if '/compute/'+x not in occi_keys]
88
        for key in diff:
89

    
90
            details = snf.get_server_details(int(key))
91
            flavor = snf.get_flavor_details(details['flavorRef'])
92
            image = snf.get_image_details(details['imageRef'])
93

    
94
            for i in self.registry.backends:
95
                if i.term == str(image['name']):
96
                    rel_image = i
97
                if i.term == str(flavor['name']):
98
                    rel_flavor = i
99

    
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)}
108

    
109
            self.registry.add_resource(key, resource, None)
110

    
111
        #Compute instances in registry not available in synnefo
112
        diff = [x for x in occi_keys if x[9:] not in snf_keys]
113
        for key in diff:
114
            self.registry.delete_resource(key, None)
115

    
116

    
117
    def __call__(self, environ, response):
118

    
119
        #Authorization
120

    
121
        if ENABLE_VOMS:
122

    
123
            global VOMS_DB
124
            conn = sqlite3.connect(VOMS_DB)
125

    
126
            ssl_dict = dict()
127
            
128
            #Regular expression in HTTP headers
129
            #raw environ[HTTP_SSL] contains PEM certificates in wrong format
130
        
131
            pem_re = r'^(-----BEGIN CERTIFICATE----- )(.*|\s]*)( -----END CERTIFICATE-----)'
132

    
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"])
135

    
136
            client_cert_list=[]
137
            client_chain_list=[]
138

    
139
            for i in range(1,4):
140
                client_cert_list.append(string.strip(client_cert.group(i)))
141

    
142
            for i in range(1,4):
143
                client_chain_list.append(string.strip(client_chain.group(i)))
144

    
145

    
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]
148

    
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
152

    
153
            (user_dn, user_vo, user_fqans) = voms.authenticate(ssl_dict)
154
            print (user_dn, user_vo, user_fqans)
155

    
156
            cursor = conn.cursor()
157
            query = "SELECT token FROM vo_map WHERE vo_name=?"
158
            cursor.execute(query,[(user_vo)])
159

    
160
            (token,) = cursor.fetchone()
161

    
162
            if token:
163
                compClient = ComputeClient(KAMAKI_CONFIG['compute_url'], token)
164
                cyclClient = CycladesClient(KAMAKI_CONFIG['compute_url'], token)
165

    
166
                self.refresh_images(compClient,cyclClient)
167
                self.refresh_flavors(compClient,cyclClient)
168
                self.refresh_compute_instances(compClient)
169

    
170

    
171
                return self._call_occi(environ, response, security = None, token = token, snf = compClient, client = cyclClient)
172
            else:
173
                raise HTTPError(404, "Unauthorized access")
174

    
175
        else:
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'])
179
            
180
            return self._call_occi(environ, response, security = None, token = environ['HTTP_AUTH_TOKEN'], snf = compClient, client = cyclClient)
181

    
182

    
183
def main():
184

    
185
    global ENABLE_VOMS, VOMS_DB
186
    (opts, args) = parse_arguments(sys.argv[1:])
187

    
188
    ENABLE_VOMS = opts.enable_voms
189
    VOMS_DB = opts.voms_db
190

    
191
    APP = MyAPP(registry = snfRegistry())
192

    
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())
201
 
202
    VALIDATOR_APP = validator(APP)
203
    HTTPD = make_server('', SERVER_CONFIG['port'], VALIDATOR_APP)
204
    HTTPD.serve_forever()
205