Commit cb4d8aac authored by albert's avatar albert
Browse files

added fitcloud sfa

parent 9755fa8b
Pipeline #2434 failed with stage
import requests
import json
from myslice import settings
from myslice import db
import logging
import time
import myslice.db as db
from myslice.db import matchLeases
from urllib.parse import urlparse
logger = logging.getLogger(__name__)
class FitCloud(object):
......@@ -10,8 +14,8 @@ class FitCloud(object):
def __init__(self, endpoint, authentication):
self.authentication = authentication
self.endpoint = endpoint
self.server = self.endpoint.url
self.logs = []
if 'email' not in self.authentication or 'password' not in self.authentication:
raise InvalidLoginException('FitCloud : Missing login info')
......@@ -22,14 +26,75 @@ class FitCloud(object):
if self.cookies is None:
raise InvalidLoginException('FitCloud : Invalid login')
def _lease(self, id):
pass
def _lease(self, id=None):
result = requests.get(self.server + "/api/v1/leases/", cookies=self.cookies)
try:
leases = result.json()['result']
except Exception as e:
raise Exception('Can not retrieve leases from FitCloud Testbed {}'.format(e))
def _resource(self, id):
pass
return leases
def get(self, entity, id=None, raw=False):
pass
def _resource(self, id=None):
resources = []
if id is not None:
result = requests.get(self.server + "/api/v1/resources/"+id, cookies=self.cookies)
else:
result = requests.get(self.server + "/api/v1/resources/", cookies=self.cookies)
try:
resources = result.json()['result']
except Exception as e:
raise Exception('Can not retrieve resources from FitCloud Testbed {}'.format(e))
return resources
def get(self, entity, id=None):
try:
result = getattr(self, "_" + entity)(id)
except Exception as e:
result = []
# print(self.endpoint.name)
# traceback.print_exc()
self.logs.append({
'endpoint': self.endpoint.name,
'url': self.endpoint.url,
'protocol': self.endpoint.protocol,
'type': self.endpoint.type,
'exception': str(e)
})
return {'data': result, 'errors': self.logs}
def version(self, raw=False):
message = None
online = False
status = "offline"
try:
testbed = None
result = requests.get(self.server + "/api/v1/testbeds/", cookies=self.cookies).json()['result']
for t in result:
if t['url'] == self.endpoint.url:
testbed = t
break
status = 'online'
online = True
except Exception as e:
import traceback
traceback.print_exc()
message = str(e)
testbed = list(db.get(table='testbed', filter={'url': self.endpoint.url}, limit=1))[0]
testbed['status'] = status
testbed['connection']['online'] = online
return {
'data': [testbed],
'errors': [message],
}
def create(self, entity, id, data):
self.update(entity, id, data)
......@@ -38,70 +103,180 @@ class FitCloud(object):
pass
def update(self, entity, id, data):
if entity == 'slice':
if 'leases' in data and isinstance(data['leases'], list) and data['leases']:
result_leases = list()
result_resources = list()
try:
if entity == 'slice':
# For each lease,
# Create a POST Request to the instance of Myslice in charge of the deployment of OS instance
# Each lease can have multiple resources
if 'leases' in data and isinstance(data['leases'], list) and data['leases']:
reservation_method = self.get_testbed_reservation_method()
deployment_task = reservation_method['allocation']
deletion_task = reservation_method['deletion']
for lease in data['leases']:
logger.debug(lease)
if not self.is_unhandled_lease(id, lease):
continue
payload = dict()
# to be removed
payload['resources'] = []
if 'start_time' in lease:
# -60 or event will be scheduled on the testbed side
payload['start_time'] = lease['start_time'] -60
else:
payload['start_time'] = time.time()
if 'end_time' in lease:
payload['end_time'] = lease['end_time']
if 'duration' in lease:
payload['duration'] = lease['duration']
payload['slice_id'] = id
#payload['tasktype'] = 'deployment'
creation_tasks = []
deletion_tasks = []
for resource in lease['resources']:
args = {}
if 'extravars' in lease and lease['extravars']:
for res_data in lease['extravars']:
if res_data['resource_id'] == resource:
args = res_data
break
if 'os_name' not in args:
args['os_name'] = resource.split('+')[-1]
# Name of the resource will be SliceName (from slice_id) + ResourceName
args['os_name'] = id.split('+')[-1] + args['os_name']
payload['resources'].append(resource)
creation_tasks.append({'id': deployment_task, 'args': args})
deletion_tasks.append({'id': deletion_task, 'args': args})
payload['tasks'] = creation_tasks
#  creation of VMs per lease
#logger.debug(payload)
r1 = requests.post(self.server + "/api/v1/tasks/deployment",
headers={str('Content-Type'): 'application/json'},
data=json.dumps(payload), cookies=self.cookies)
if r1.status_code != 200:
raise Exception('Request Error : status not 200')
res = self.check_event(r1.json()['events'][0])
lease['resources'] = res['data']['resources']
logger.debug(lease['resources'])
logger.debug(type(lease['resources']))
logger.debug(type(result_resources))
result_leases.append(lease)
result_resources += list(set(lease['resources']) - set(result_resources))
# schedule VM deletion / Lease.end-time
payload['start_time'] = lease['end_time']
payload['tasks'] = deletion_tasks
payload.pop('end_time', None)
payload.pop('duration', None)
payload['lease_id'] = res['data']['lease_id']
r2 = requests.post(self.server + "/api/v1/tasks/deployment",
headers={str('Content-Type'): 'application/json'},
data=json.dumps(payload), cookies=self.cookies)
if r2.status_code != 200:
raise Exception('Request Error : status not 200')
# Retrieve the deployment and deletion tasks id
else:
raise NotImplementedError('FIT-Cloud : update not supported for {}'.format(entity))
try:
deployment_task = list(db.get(table='tasks', filter={'name': 'os_vm'}, limit=1))
deletion_task = list(db.get(table='tasks', filter={'name': 'os_vm_del'}, limit=1))
except Exception as e:
logger.error(self.endpoint.name)
logger.exception(e)
except:
raise Exception('FitCloud : Error retrieving predefined deployment tasks from rethinkdb')
self.logs.append({
'endpoint': self.endpoint.name,
'url': self.endpoint.url,
'protocol': self.endpoint.protocol,
'type': self.endpoint.type,
'exception': str(e)
})
if deployment_task and deletion_task:
deployment_task_id = deployment_task[0]['id']
deletion_task_id = deletion_task[0]['id']
else:
raise Exception('FitCloud : Error retrieving predefined deployment tasks from rethinkdb')
result = [{'resources': result_resources, 'leases': result_leases}]
logger.debug(result)
return {'data': result, 'errors': self.logs}
else:
raise Exception('FitCloud: Can not update {}, leases is empty')
def is_unhandled_lease(self, id, lease):
logger.debug(lease['testbed'])
if 'testbed' in lease and db.get(table='testbeds', id=lease['testbed'])['url'] == self.endpoint.url:
# For each lease,
# Create a POST Request to the instance of Myslice in charge of the deployment of OS instance
# Each lease can have multiple resources
slice = db.get(table='slices', id=id)
for lease in data['leases']:
payload = {}
#to be removed
payload['resources'] = []
if 'start_time' in lease:
payload['start_time'] = lease['start_time']
if not any(matchLeases(s_lease, lease) for s_lease in slice['leases']):
return True
payload['slice_id'] = id
payload['tasktype'] = 'deployment'
creation_tasks = []
deletion_tasks = []
return False
for resource in lease['resources']:
creation_tasks.append({'id': deployment_task_id, 'args': resource})
deletion_tasks.append({'id': deletion_task_id, 'args': resource})
# TODO : Resource availability check, Number of CPU cores availables at the time of the lease
# TODO : Return scheduled lease ?
payload['tasks'] = creation_tasks
# creation of VMs per lease
r1 = requests.post(self.server + "/api/v1/tasks", headers={str('Content-Type'): 'application/json'},
data=json.dumps(payload), cookies=self.cookies)
def get_testbed_reservation_method(self):
try:
result = requests.get(self.server + "/api/v1/testbeds/", cookies=self.cookies).json()['result']
except Exception as e:
raise Exception('Can not retrieve testbed info from rethinkdb')
# schedule VM deletion / Lease.end-time
payload['start_time'] = lease['end_time']
payload['tasks'] = deletion_tasks
if not result:
raise Exception('Testbed list is empty')
r2 = requests.post(self.server + "/api/v1/tasks", headers={str('Content-Type'): 'application/json'},
data=json.dumps(payload), cookies=self.cookies)
for r in result:
if r['url'] == self.endpoint.url:
return r['reservation']
return
def get_allocated_resources(self, lease):
else:
raise NotImplementedError('FIT-Cloud : update not supported for {}'.format(entity))
leases = getattr(self, "_lease")()
for l in leases:
if l['end_time'] < lease['start_time'] and l['start_time'] > lease['end_time']:
continue
def check_event(self, event):
timeout = self.endpoint.timeout
# TODO : change interval in settings
interval = settings.scheduler['interval']
max_retries = timeout / int(interval)
final_status = ['WAITING', 'SUCCESS', 'WARNING', 'ERROR', 'SCHEDULED']
while max_retries > 0:
res = requests.get(self.server + "/api/v1/activity/" + event, cookies=self.cookies)
if res.status_code == 200:
result = res.json()
if 'result' in result and result['result']:
result = result['result'][0]
if result['status'] == 'ERROR':
raise Exception('Reservation is not approved by the testbeds')
elif result['status'] in final_status:
return result
max_retries -= 1
time.sleep(int(interval))
raise Exception('Reservation timeout')
class InvalidLoginException (Exception):
......
......@@ -53,6 +53,9 @@ class Authentication(object):
self.hrn = hrn
self.private_key = private_key
if password:
self.password = password
if not certificate:
certificate = self.create_self_signed_cert(private_key)
if not isinstance(certificate, str):
......@@ -64,7 +67,7 @@ class Authentication(object):
self.credentials = credentials
def __repr__(self):
return "email: {}, hrn: {}, pkey: {}".format(self.email,self.hrn,self.private_key)
return "email: {}, hrn: {}, pkey: {}, password: {}".format(self.email,self.hrn,self.private_key,self.password)
def create_self_signed_cert(self, private_key=None):
if not private_key:
......
import xml.etree.ElementTree as ET
from myslicelib.api.sfa import SfaError
from myslicelib.api.sfa.sfa import SfaError
from myslicelib.util.sfabuilder import SfaBuilder
class Iotlab(SfaBuilder):
......
import uuid
import xml.etree.ElementTree as ET
from datetime import datetime
from pprint import pprint
from myslicelib.api.sfa import SfaError
from myslicelib.api.sfa.sfa import SfaError
from myslicelib.util.sfabuilder import SfaBuilder
NEW_LEASE_TAG = '<ol:lease client_id="%(client_id)s" valid_from="%(valid_from_iso)sZ" valid_until="%(valid_until_iso)sZ"/>'
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment