26 import urllib, urllib2 |
26 import urllib, urllib2 |
27 import simplejson |
27 import simplejson |
28 import posixpath |
28 import posixpath |
29 |
29 |
30 from cone.public import * |
30 from cone.public import * |
31 from cone.carbon import persistentjson, model |
31 from cone.carbon import persistentjson, model, resourcemapper |
32 from cone.storage import authenticate |
32 from cone.storage import authenticate |
33 |
33 |
34 class WebStorage(api.Storage): |
34 class WebStorage(api.Storage): |
35 """ |
35 """ |
36 A general base class for all storage type classes |
36 A general base class for all storage type classes |
53 """ |
53 """ |
54 # Test the path, whether it is a featurelist or configuration |
54 # Test the path, whether it is a featurelist or configuration |
55 try: |
55 try: |
56 object_type = object.meta.get('type') |
56 object_type = object.meta.get('type') |
57 except (TypeError,AttributeError): |
57 except (TypeError,AttributeError): |
58 logging.getLogger('cone').error('Cannot dump configuration %s to webstorage without a type.' % path) |
58 logging.getLogger('cone').info('Cannot dump configuration %s to webstorage without a type.' % path) |
59 return False |
59 return False |
60 carbonpath = persistentjson.CarbonResourceMapper().map_confml_resource(object_type, path) |
60 carbonpath = resourcemapper.CarbonResourceMapper().map_confml_resource(object_type, path) |
61 if object_type == 'featurelist': |
61 if object_type == 'featurelist': |
62 # Create a featurelist |
62 # Create a featurelist |
63 success = self.extapi.create_featurelist(carbonpath, object) |
63 success = self.extapi.create_featurelist(carbonpath, object) |
64 if success: |
64 if success: |
65 self.resource_cache.add_resource_link(path, carbonpath) |
65 self.resource_cache.add_resource_link(path, carbonpath) |
91 solution to link Configuration project concepts to Carbon storage |
91 solution to link Configuration project concepts to Carbon storage |
92 |
92 |
93 """ |
93 """ |
94 if not self._resource_cache: |
94 if not self._resource_cache: |
95 self._resource_cache = ResourceCache() |
95 self._resource_cache = ResourceCache() |
96 reslist = self.extapi.list_resources("/", True) |
96 try: |
|
97 reslist = self.extapi.list_resources("/", True) |
|
98 except urllib2.HTTPError, e: |
|
99 print e |
|
100 return [] |
97 # Append all resources to resource cache |
101 # Append all resources to resource cache |
98 for res in reslist: |
102 for res in reslist: |
99 self._resource_cache.add_resource(res) |
103 self._resource_cache.add_resource(res) |
100 # if isinstance(res, model.ConfigurationResource): |
104 # if isinstance(res, model.ConfigurationResource): |
101 # self._resource_cache.add_configuration(res) |
105 # self._resource_cache.add_configuration(res) |
102 # elif isinstance(res, model.FeatureListResource): |
106 # elif isinstance(res, model.FeatureListResource): |
103 # self._resource_cache.add_featurelist(res) |
107 # self._resource_cache.add_featurelist(res) |
104 return self._resource_cache |
108 return self._resource_cache |
105 |
109 |
106 def list_resources(self,path, recurse=False, empty_folders=False): |
110 def list_resources(self,path, **kwargs): |
107 """ |
111 """ |
108 find the resources under certain path/path |
112 find the resources under certain path/path |
109 @param path : reference to path where resources are searched |
113 @param path : reference to path where resources are searched |
110 @param recurse : defines whether to return resources directly under the path or does the listing recurse to subfolders. |
114 @param recurse : defines whether to return resources directly under the path or does the listing recurse to subfolders. |
111 Default value is False. Set to True to enable recursion. |
115 Default value is False. Set to True to enable recursion. |
112 @param empty_folders: parameters that defined whether empty folders are included. This parameter is ignored |
116 @param empty_folders: parameters that defined whether empty folders are included. This parameter is ignored |
113 in WebStorage. |
117 in WebStorage. |
114 """ |
118 """ |
115 return self.resource_cache.list_resources(path,recurse) |
119 return self.resource_cache.list_resources(path, kwargs.get('recurse', False)) |
116 |
120 |
117 |
121 |
118 def open_resource(self,path,mode="r"): |
122 def open_resource(self,path,mode="r"): |
119 path = utils.resourceref.remove_begin_slash(path) |
123 path = utils.resourceref.remove_begin_slash(path) |
120 if self.resource_cache.get_resource_object(path): |
124 if self.resource_cache.get_resource_object(path): |
139 return res |
143 return res |
140 except KeyError: |
144 except KeyError: |
141 raise exceptions.NotResource("The given resource is not found %s" % path) |
145 raise exceptions.NotResource("The given resource is not found %s" % path) |
142 |
146 |
143 def is_resource(self,path): |
147 def is_resource(self,path): |
144 return self.resource_cache.is_resource(path) |
148 ret= self.resource_cache.is_resource(path) |
|
149 if not ret: |
|
150 try: |
|
151 mapped = self.resource_cache.get_mapped_resource(path) |
|
152 ret = self.extapi.is_resource(mapped) |
|
153 except Exception: |
|
154 pass |
|
155 return ret |
145 # path = path.replace(".confml", ".configuration") |
156 # path = path.replace(".confml", ".configuration") |
146 # path = utils.resourceref.join_refs([self.get_current_path(), path]) |
157 # path = utils.resourceref.join_refs([self.get_current_path(), path]) |
147 # try: |
158 # try: |
148 # query = urllib.quote(self._get_action_url('is_resource', path)) |
159 # query = urllib.quote(self._get_action_url('is_resource', path)) |
149 # self.conn.request("GET", query) |
160 # self.conn.request("GET", query) |
189 raise exceptions.StorageException("Cannot dump object type %s" % object.__class__) |
200 raise exceptions.StorageException("Cannot dump object type %s" % object.__class__) |
190 # Skip the unload storing to storage if the storage is opened in read mode |
201 # Skip the unload storing to storage if the storage is opened in read mode |
191 if self.get_mode(self.mode) != api.Storage.MODE_READ: |
202 if self.get_mode(self.mode) != api.Storage.MODE_READ: |
192 if self.resource_cache.get_resource_link(path): |
203 if self.resource_cache.get_resource_link(path): |
193 path = self.resource_cache.get_resource_link(path) |
204 path = self.resource_cache.get_resource_link(path) |
|
205 elif self.is_resource(path): |
|
206 path = self.resource_cache.get_mapped_resource(path) |
194 else: |
207 else: |
195 """ otherwise create the new resource first before update""" |
208 """ otherwise create the new resource first before update""" |
196 if self._create_resource(path, object): |
209 if self._create_resource(path, object): |
197 path = self.resource_cache.get_resource_link(path) |
210 path = self.resource_cache.get_resource_link(path) |
198 else: |
211 else: |
199 # Creation failed |
212 # Creation failed |
200 logging.getLogger('cone').error('Creation of %s resource failed' % path) |
213 logging.getLogger('cone').info('Creation of %s resource failed' % path) |
201 return |
214 return |
202 data = persistentjson.dumps(object) |
215 data = persistentjson.dumps(object) |
203 self.extapi.update_resource(path, data) |
216 self.extapi.update_resource(path, data) |
204 else: |
217 else: |
205 raise exceptions.StorageException("Cannot dump object to readonly storage") |
218 raise exceptions.StorageException("Cannot dump object to readonly storage") |
206 return |
219 return |
|
220 |
|
221 |
207 |
222 |
208 def load(self, path): |
223 def load(self, path): |
209 """ |
224 """ |
210 Load resource from a path. |
225 Load resource from a path. |
211 """ |
226 """ |
296 pathelems = path.split('/',1) |
311 pathelems = path.split('/',1) |
297 self.server_path = pathelems[0] |
312 self.server_path = pathelems[0] |
298 if len(pathelems) > 1: |
313 if len(pathelems) > 1: |
299 self.service_path = pathelems[1] |
314 self.service_path = pathelems[1] |
300 self._username = kwargs.get('username', None) |
315 self._username = kwargs.get('username', None) |
301 self._password = kwargs.get('password', None) |
316 self._password = kwargs.get('password', None) |
302 authhandler = authenticate.CarbonAuthHandler() |
317 authhandler = authenticate.CarbonAuthHandler() |
303 authhandler.add_password(self.username, self.password) |
318 authhandler.add_username_func(self.get_username) |
|
319 authhandler.add_password_func(self.get_password) |
304 self.conn = urllib2.build_opener(urllib2.HTTPCookieProcessor, authhandler, urllib2.ProxyHandler({})) |
320 self.conn = urllib2.build_opener(urllib2.HTTPCookieProcessor, authhandler, urllib2.ProxyHandler({})) |
305 |
321 |
306 @property |
322 def get_username(self): |
307 def username(self): |
|
308 if self._username == None: |
323 if self._username == None: |
309 self._username = getpass.getuser() |
324 self._username = getpass.getuser() |
310 return self._username |
325 return self._username |
311 |
326 |
312 @property |
327 def get_password(self): |
313 def password(self): |
|
314 if self._password == None: |
328 if self._password == None: |
315 self._password = getpass.getpass() |
329 self._password = getpass.getpass("Password (%s):" % self._username) |
316 return self._password |
330 return self._password |
317 |
331 |
318 def checklogin(self): |
332 def checklogin(self): |
319 """ |
333 """ |
320 Checks that we are logged in by loading the main page. |
334 Checks that we are logged in by loading the main page. |
387 query = self._get_action_url('list_resources', path) |
401 query = self._get_action_url('list_resources', path) |
388 req = urllib2.Request(query) |
402 req = urllib2.Request(query) |
389 resp = self.conn.open(req) |
403 resp = self.conn.open(req) |
390 if resp.code == httplib.OK: |
404 if resp.code == httplib.OK: |
391 bytes = resp.read() |
405 bytes = resp.read() |
392 reslist = simplejson.loads(bytes) |
406 if bytes: |
393 return reslist.get('resources',[]) |
407 reslist = simplejson.loads(bytes) |
|
408 return reslist.get('resources',[]) |
394 else: |
409 else: |
395 return [] |
410 return [] |
396 except exceptions.NotFound: |
411 except exceptions.NotFound: |
397 return [] |
412 return [] |
398 |
413 |
399 |
414 def is_resource(self, path): |
|
415 try: |
|
416 query = self._get_action_url('is_resource', path) |
|
417 req = urllib2.Request(query) |
|
418 resp = self.conn.open(req) |
|
419 if resp.code == httplib.OK: |
|
420 reader = persistentjson.HasResourceReader() |
|
421 ret = resp.read() |
|
422 return reader.loads(ret) |
|
423 else: |
|
424 return False |
|
425 except exceptions.NotFound: |
|
426 return False |
|
427 |
|
428 |
400 def update_resource(self, path, data): |
429 def update_resource(self, path, data): |
401 """ |
430 """ |
402 Update a resource to carbon. The resource can be a CarbonConfiguration or FeatureList object. |
431 Update a resource to carbon. The resource can be a CarbonConfiguration or FeatureList object. |
403 @param object: The object which is dumped to dict with persistentjson and then updated to server. |
432 @param object: The object which is dumped to dict with persistentjson and then updated to server. |
404 """ |
433 """ |
415 respdata = simplejson.loads(bytes) |
444 respdata = simplejson.loads(bytes) |
416 success = respdata.get('success') == True |
445 success = respdata.get('success') == True |
417 if success: |
446 if success: |
418 logging.getLogger('cone').info('Carbon update succeeds to path %s.' % (respdata.get('path'))) |
447 logging.getLogger('cone').info('Carbon update succeeds to path %s.' % (respdata.get('path'))) |
419 else: |
448 else: |
420 logging.getLogger('cone').error('Carbon update %s failed %s' % (path,respdata.get('errors'))) |
449 logging.getLogger('cone').error('Carbon update %s failed!' % (path)) |
|
450 if respdata.get('errors'): |
|
451 formatted_err = "" |
|
452 for error in respdata.get('errors'): |
|
453 formatted_err += "%s: %s\n" % (error,respdata.get('errors')[error]) |
|
454 logging.getLogger('cone').info('Carbon update to path %s returned %s' % (respdata.get('path'),formatted_err)) |
421 return success |
455 return success |
422 else: |
456 else: |
423 logging.getLogger('cone').error('Carbon update %s failed %s: %s' % (path,resp.code, resp)) |
457 logging.getLogger('cone').error('Carbon update %s failed %s: %s' % (path,resp.code, resp)) |
424 return False |
458 return False |
425 except urllib2.HTTPError,e: |
459 except urllib2.HTTPError,e: |
556 |
590 |
557 def add_resource(self, resourcepath): |
591 def add_resource(self, resourcepath): |
558 """ |
592 """ |
559 Add a resource |
593 Add a resource |
560 """ |
594 """ |
561 confmlpath = persistentjson.CarbonResourceMapper().map_carbon_resource(resourcepath) |
595 confmlpath = resourcemapper.CarbonResourceMapper().map_carbon_resource(resourcepath) |
562 self._cache[confmlpath] = resourcepath |
596 self._cache[confmlpath] = resourcepath |
563 |
597 |
564 def list_resources(self, path, recurse=False): |
598 def list_resources(self, path, recurse=False): |
565 """ |
599 """ |
566 List ConE resources under certain path |
600 List ConE resources under certain path |
597 object_type = 'featurelist' |
631 object_type = 'featurelist' |
598 elif path.endswith('/root.confml'): |
632 elif path.endswith('/root.confml'): |
599 object_type = 'configurationlayer' |
633 object_type = 'configurationlayer' |
600 else: |
634 else: |
601 object_type = 'configurationroot' |
635 object_type = 'configurationroot' |
602 carbonpath = persistentjson.CarbonResourceMapper().map_confml_resource(object_type, path) |
636 carbonpath = resourcemapper.CarbonResourceMapper().map_confml_resource(object_type, path) |
603 return carbonpath |
637 return carbonpath |
604 |
638 |
605 def add_resource_link(self,link, path): |
639 def add_resource_link(self,link, path): |
606 """ |
640 """ |
607 Add a actual Carbon resource link. The link is the key which returns path when asked from get_resource_link. |
641 Add a actual Carbon resource link. The link is the key which returns path when asked from get_resource_link. |