Two thread will be launched, with normal and administrative permissions.
'''
-__author__="Alfonso Tierno"
+__author__="Alfonso Tierno, Gerardo Garcia"
__date__ ="$10-jul-2014 12:07:15$"
import bottle
+import urlparse
import yaml
import json
import threading
import datetime
-import RADclass
+import hashlib
+import os
+import imp
+#import only if needed because not needed in test mode. To allow an easier installation import RADclass
from jsonschema import validate as js_v, exceptions as js_e
import host_thread as ht
from vim_schema import host_new_schema, host_edit_schema, tenant_new_schema, \
global my
global url_base
global config_dic
+global RADclass_module
+RADclass=None #RADclass module is charged only if not in test mode
url_base="/openvim"
HTTP_Service_Unavailable = 503
HTTP_Internal_Server_Error= 500
+def md5(fname):
+ hash_md5 = hashlib.md5()
+ with open(fname, "rb") as f:
+ for chunk in iter(lambda: f.read(4096), b""):
+ hash_md5.update(chunk)
+ return hash_md5.hexdigest()
+
+def md5_string(fname):
+ hash_md5 = hashlib.md5()
+ hash_md5.update(fname)
+ return hash_md5.hexdigest()
def check_extended(extended, allow_net_attach=False):
'''Makes and extra checking of extended input that cannot be done using jsonschema
except js_e.ValidationError:
return False
+
+def is_url(url):
+ '''
+ Check if string value is a well-wormed url
+ :param url: string url
+ :return: True if is a valid url, False if is not well-formed
+ '''
+
+ parsed_url = urlparse.urlparse(url)
+ return parsed_url
+
+
@bottle.error(400)
@bottle.error(401)
@bottle.error(404)
ip_name=host['ip_name']
user=host['user']
password=host.get('password', None)
+ if not RADclass_module:
+ try:
+ RADclass_module = imp.find_module("RADclass")
+ except (IOError, ImportError) as e:
+ raise ImportError("Cannot import RADclass.py Openvim not properly installed" +str(e))
#fill rad info
- rad = RADclass.RADclass()
+ rad = RADclass_module.RADclass()
(return_status, code) = rad.obtain_RAD(user, password, ip_name)
#return
sriov['source_name'] = index
index += 1
interfaces.append ({'pci':str(port_k), 'Mbps': port_v['speed']/1000000, 'sriovs': new_sriovs, 'mac':port_v['mac'], 'source_name':port_v['source_name']})
- #@TODO LA memoria devuelta por el RAD es incorrecta, almenos para IVY1, NFV100
memory=node['memory']['node_size'] / (1024*1024*1024)
#memory=get_next_2pow(node['memory']['hugepage_nr'])
host['numas'].append( {'numa_socket': node['id'], 'hugepages': node['memory']['hugepage_nr'], 'memory':memory, 'interfaces': interfaces, 'cores': cores } )
bottle.abort(result, content)
#obtain data
select_,where_,limit_ = filter_query_string(bottle.request.query, http2db_image,
- ('id','name','description','path','public') )
+ ('id','name','checksum','description','path','public') )
if tenant_id=='any':
from_ ='images'
+ where_or_ = None
else:
- from_ ='tenants_images inner join images on tenants_images.image_id=images.uuid'
- where_['tenant_id'] = tenant_id
- result, content = my.db.get_table(SELECT=select_, FROM=from_, WHERE=where_, LIMIT=limit_)
+ from_ ='tenants_images right join images on tenants_images.image_id=images.uuid'
+ where_or_ = {'tenant_id': tenant_id, 'public': 'yes'}
+ result, content = my.db.get_table(SELECT=select_, DISTINCT=True, FROM=from_, WHERE=where_, WHERE_OR=where_or_, WHERE_AND_OR="AND", LIMIT=limit_)
if result < 0:
print "http_get_images Error", content
bottle.abort(-result, content)
bottle.abort(result, content)
#obtain data
select_,where_,limit_ = filter_query_string(bottle.request.query, http2db_image,
- ('id','name','description','progress', 'status','path', 'created', 'updated','public') )
+ ('id','name','checksum','description','progress', 'status','path', 'created', 'updated','public') )
if tenant_id=='any':
from_ ='images'
+ where_or_ = None
else:
- from_ ='tenants_images as ti inner join images as i on ti.image_id=i.uuid'
- where_['tenant_id'] = tenant_id
+ from_ ='tenants_images as ti right join images as i on ti.image_id=i.uuid'
+ where_or_ = {'tenant_id': tenant_id, 'public': "yes"}
where_['uuid'] = image_id
- result, content = my.db.get_table(SELECT=select_, FROM=from_, WHERE=where_, LIMIT=limit_)
+ result, content = my.db.get_table(SELECT=select_, DISTINCT=True, FROM=from_, WHERE=where_, WHERE_OR=where_or_, WHERE_AND_OR="AND", LIMIT=limit_)
if result < 0:
print "http_get_images error %d %s" % (result, content)
metadata_dict = http_content['image'].pop('metadata', None)
if metadata_dict is not None:
http_content['image']['metadata'] = json.dumps(metadata_dict)
+ #calculate checksum
+ try:
+ image_file = http_content['image'].get('path',None)
+ parsed_url = urlparse.urlparse(image_file)
+ if parsed_url.scheme == "" and parsed_url.netloc == "":
+ # The path is a local file
+ if os.path.exists(image_file):
+ http_content['image']['checksum'] = md5(image_file)
+ else:
+ # The path is a URL. Code should be added to download the image and calculate the checksum
+ #http_content['image']['checksum'] = md5(downloaded_image)
+ pass
+ # Finally, only if we are in test mode and checksum has not been calculated, we calculate it from the path
+ host_test_mode = True if config_dic['mode']=='test' or config_dic['mode']=="OF only" else False
+ if host_test_mode:
+ if 'checksum' not in http_content['image']:
+ http_content['image']['checksum'] = md5_string(image_file)
+ else:
+ # At this point, if the path is a local file and no chechsum has been obtained yet, an error is sent back.
+ # If it is a URL, no error is sent. Checksum will be an empty string
+ if parsed_url.scheme == "" and parsed_url.netloc == "" and 'checksum' not in http_content['image']:
+ content = "Image file not found"
+ print "http_post_images error: %d %s" % (HTTP_Bad_Request, content)
+ bottle.abort(HTTP_Bad_Request, content)
+ except Exception as e:
+ print "ERROR. Unexpected exception: %s" % (str(e))
+ bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
#insert in data base
result, content = my.db.new_image(http_content['image'], tenant_id)
if result >= 0:
where_={'uuid': image_id}
if tenant_id=='any':
from_ ='images'
+ where_or_ = None
else:
- from_ ='tenants_images as ti inner join images as i on ti.image_id=i.uuid'
- where_['tenant_id'] = tenant_id
- result, content = my.db.get_table(SELECT=('public',), FROM=from_, WHERE=where_)
+ from_ ='tenants_images as ti right join images as i on ti.image_id=i.uuid'
+ where_or_ = {'tenant_id': tenant_id, 'public': 'yes'}
+ result, content = my.db.get_table(SELECT=('public',), DISTINCT=True, FROM=from_, WHERE=where_, WHERE_OR=where_or_, WHERE_AND_OR="AND")
if result==0:
text_error="Image '%s' not found" % image_id
if tenant_id!='any':
return
server['flavor']=content[0]
#check image valid and take info
- result, content = my.db.get_table(FROM='tenants_images as ti join images as i on ti.image_id=i.uuid',
- SELECT=('path','metadata'), WHERE={'uuid':server['image_id'], 'tenant_id':tenant_id, "status":"ACTIVE"})
+ result, content = my.db.get_table(FROM='tenants_images as ti right join images as i on ti.image_id=i.uuid',
+ SELECT=('path','metadata'), WHERE={'uuid':server['image_id'], "status":"ACTIVE"},
+ WHERE_OR={'tenant_id':tenant_id, 'public': 'yes'}, WHERE_AND_OR="AND", DISTINCT=True)
if result<=0:
bottle.abort(HTTP_Not_Found, 'image_id %s not found or not ACTIVE' % server['image_id'])
return
else: #result==1
image_id = content[0]['image_id']
- result, content = my.db.get_table(FROM='tenants_images as ti join images as i on ti.image_id=i.uuid',
- SELECT=('path','metadata'), WHERE={'uuid':image_id, 'tenant_id':tenant_id, "status":"ACTIVE"})
+ result, content = my.db.get_table(FROM='tenants_images as ti right join images as i on ti.image_id=i.uuid',
+ SELECT=('path','metadata'), WHERE={'uuid':image_id, "status":"ACTIVE"},
+ WHERE_OR={'tenant_id':tenant_id, 'public': 'yes'}, WHERE_AND_OR="AND", DISTINCT=True)
if result<=0:
bottle.abort(HTTP_Not_Found, 'image_id %s not found or not ACTIVE' % image_id)
return