def __create_app(self): # name must be A-Za-z0-9 and <=32 chars app_name = self.entity.kind.term[0:4] + 'srvinst' + ''.join(random.choice('0123456789ABCDEF') for i in range(16)) heads = { 'Content-Type': 'text/occi', 'Category': 'app; scheme="http://schemas.ogf.org/occi/platform#", ' 'python-2.7; scheme="http://schemas.openshift.com/template/app#", ' 'small; scheme="http://schemas.openshift.com/template/app#"', 'X-OCCI-Attribute': 'occi.app.name=' + app_name } url = self.nburl + '/app/' LOG.debug('Requesting container to execute SO Bundle: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) r = http_retriable_request('POST', url, headers=heads, authenticate=True) loc = r.headers.get('Location', '') if loc == '': raise AttributeError("No OCCI Location attribute found in request") app_uri_path = urlparse(loc).path LOG.debug('SO container created: ' + app_uri_path) LOG.debug('Updating OCCI entity.identifier from: ' + self.entity.identifier + ' to: ' + app_uri_path.replace('/app/', self.entity.kind.location)) self.entity.identifier = app_uri_path.replace('/app/', self.entity.kind.location) LOG.debug('Setting occi.core.id to: ' + app_uri_path.replace('/app/', '')) self.entity.attributes['occi.core.id'] = app_uri_path.replace('/app/', '') # get git uri. this is where our bundle is pushed to return self.__git_uri(app_uri_path)
def run(self): # 1. dispose the active SO, essentially kills the STG/ITG # 2. dispose the resources used to run the SO # example request to the SO # curl -v -X DELETE http://localhost:8051/orchestrator/default \ # -H 'X-Auth-Token: '$KID \ # -H 'X-Tenant-Name: '$TENANT self.start_time = time.time() infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'destroy', 'phase_event': 'start', 'response_time': 0, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) url = HTTP + self.host + '/orchestrator/default' heads = { 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'] } occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info( 'Adding service-specific parameters to call... X-OCCI-Attribute:' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.info('Disposing service orchestrator with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('DELETE', url, headers=heads) url = self.nburl + self.entity.identifier.replace( '/' + self.entity.kind.term + '/', '/app/') heads = { 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'] } LOG.info('Disposing service orchestrator container via CC... ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('DELETE', url, headers=heads, authenticate=True) elapsed_time = time.time() - self.start_time infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'destroy', 'phase_event': 'done', 'response_time': elapsed_time, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) return self.entity, self.extras
def service_parameters(self, state='', content_type='text/occi'): # takes the internal parameters defined for the lifecycle phase... # and combines them with the client supplied parameters if content_type == 'text/occi': params = [] # get the state specific internal parameters try: params = self.service_params[state] except KeyError: # as err: LOG.warn('The requested states parameters are not available: "' + state + '"') # get the client supplied parameters if any try: for param in self.service_params['client_params']: params.append(param) except KeyError: # as err: LOG.info('No client params') header = '' for param in params: if param['type'] == 'string': value = '"' + param['value'] + '"' else: value = str(param['value']) header = header + param['name'] + '=' + value + ', ' return header[0:-2] else: LOG.error('Content type not supported: ' + content_type)
def deploy_complete(self, url): # XXX fugly - code copied from Resolver heads = { 'Content-type': 'text/occi', 'Accept': 'application/occi+json', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'], } LOG.info('checking service state at: ' + url) LOG.info('sending headers: ' + heads.__repr__()) r = http_retriable_request('GET', url, headers=heads) attrs = json.loads(r.content) if len(attrs['attributes']) > 0: attr_hash = attrs['attributes'] stack_state = '' try: stack_state = attr_hash['occi.mcn.stack.state'] except KeyError: pass LOG.info('Current service state: ' + str(stack_state)) if stack_state == 'CREATE_COMPLETE' or stack_state == 'UPDATE_COMPLETE': LOG.info('Stack is ready') return True elif stack_state == 'CREATE_FAILED': raise RuntimeError('Heat stack creation failed.') else: LOG.info('Stack is not ready. Current state state: ' + stack_state) return False
def __init_so(self): url = HTTP + self.host + '/orchestrator/default' heads = { 'Category': 'orchestrator; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'], 'X-OCCI-Attribute': 'occi.mcn.app.url="' + HTTP + self.host + '/orchestrator/default"' } occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info('Adding service-specific parameters to call... X-OCCI-Attribute: ' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Initialising SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('PUT', url, headers=heads) elapsed_time = time.time() - self.start_time infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'activate', 'phase_event': 'done', 'response_time': elapsed_time, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON)
def run(self): # Deployment is done without any control by the client... # otherwise we won't be able to hand back a working service! LOG.debug('Deploying the SO bundle...') url = HTTP + self.host + '/orchestrator/default' params = {'action': 'deploy'} heads = { 'Category': 'deploy; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'] } occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info( 'Adding service-specific parameters to call... X-OCCI-Attribute:' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Deploying SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads, params=params) self.entity.attributes['mcn.service.state'] = 'deploy' LOG.debug('SO Deployed ') return self.entity, self.extras
def register_service(self): self.srv_ep = util.services.get_service_endpoint(identifier=self.srv_type.term, token=self.token, endpoint=self.design_uri, tenant_name=self.tenant_name, url_type='public') if self.srv_ep is None or self.srv_ep == '': LOG.debug('Registering the service with the keystone service...') keystone = client.Client(token=self.token, tenant_name=self.tenant_name, auth_url=self.design_uri) # taken from the kind definition self.srv_ep = keystone.services.create( self.srv_type.scheme+self.srv_type.term, self.srv_type.scheme+self.srv_type.term, self.srv_type.title) internal_url = admin_url = public_url = self.service_endpoint self.ep = keystone.endpoints.create(self.region, self.srv_ep.id, public_url, admin_url, internal_url) LOG.info('Service is now registered with keystone: ' + 'Region: ' + self.ep.region + ' Public URL:' + self.ep.publicurl + ' Service ID: ' + self.srv_ep.id + ' Endpoint ID: ' + self.ep.id) else: LOG.info('Service is already registered with keystone. Service endpoint is: ' + self.srv_ep)
def run(self): # 1. dispose the active SO, essentially kills the STG/ITG # 2. dispose the resources used to run the SO # example request to the SO # curl -v -X DELETE http://localhost:8051/orchestrator/default \ # -H 'X-Auth-Token: '$KID \ # -H 'X-Tenant-Name: '$TENANT url = HTTP + self.host + '/orchestrator/default' heads = { 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'] } occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info( 'Adding service-specific parameters to call... X-OCCI-Attribute:' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.info('Disposing service orchestrator with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('DELETE', url, headers=heads) url = self.nburl + self.entity.identifier.replace( '/' + self.entity.kind.term + '/', '/app/') heads = { 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'] } LOG.info('Disposing service orchestrator container via CC... ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('DELETE', url, headers=heads, authenticate=True) return self.entity, self.extras
def run(self): self.app.register_backend(self.srv_type, self.service_backend) if self.reg_srv: self.register_service() # setup shutdown handler for de-registration of service for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGHUP, signal.SIGQUIT]: signal.signal(sig, self.shutdown_handler) up = urlparse(self.stg["service_endpoint"]) dep_port = CONFIG.get("general", "port") if dep_port != "": LOG.warn( "DEPRECATED: parameter general: port in service manager config. " "Service port number (" + str(up.port) + ") is taken from the service manifest" ) if self.DEBUG: from wsgiref.simple_server import make_server httpd = make_server("", int(up.port), self.app) httpd.serve_forever() else: container = wsgi.WSGIContainer(self.app) http_server = httpserver.HTTPServer(container) http_server.listen(int(up.port)) ioloop.IOLoop.instance().start() LOG.info("Service Manager running on interfaces, running on port: " + int(up.port))
def run(self): self.app.register_backend(self.srv_type, self.service_backend) if self.reg_srv: self.register_service() # setup shutdown handler for de-registration of service for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGHUP, signal.SIGQUIT]: signal.signal(sig, self.shutdown_handler) up = urlparse(self.stg['service_endpoint']) dep_port = CONFIG.get('general', 'port') if dep_port != '': LOG.warn('DEPRECATED: parameter general: port in service manager config. ' 'Service port number (' + str(up.port) + ') is taken from the service manifest') if self.DEBUG: LOG.debug('Using WSGI reference implementation') httpd = make_server('', int(up.port), self.app) httpd.serve_forever() else: LOG.debug('Using tornado implementation') container = wsgi.WSGIContainer(self.app) http_server = httpserver.HTTPServer(container) http_server.listen(int(up.port)) ioloop.IOLoop.instance().start() LOG.info('Service Manager running on interfaces, running on port: ' + str(up.port))
def run(self): # 1. dispose the active SO, essentially kills the STG/ITG # 2. dispose the resources used to run the SO # example request to the SO # curl -v -X DELETE http://localhost:8051/orchestrator/default \ # -H 'X-Auth-Token: '$KID \ # -H 'X-Tenant-Name: '$TENANT url = HTTP + self.host + '/orchestrator/default' heads = {'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info('Adding service-specific parameters to call... X-OCCI-Attribute:' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.info('Disposing service orchestrator with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('DELETE', url, headers=heads) url = self.nburl + self.entity.identifier.replace('/' + self.entity.kind.term + '/', '/app/') heads = {'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} LOG.info('Disposing service orchestrator container via CC... ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('DELETE', url, headers=heads, authenticate=True) return self.entity, self.extras
def __git_uri(self, app_uri_path): url = self.nburl + app_uri_path headers = {'Accept': 'text/occi'} LOG.debug('Requesting container\'s URL ' + url) LOG.info('Sending headers: ' + headers.__repr__()) r = http_retriable_request('GET', url, headers=headers, authenticate=True) attrs = r.headers.get('X-OCCI-Attribute', '') if attrs == '': raise AttributeError("No occi attributes found in request") repo_uri = '' for attr in attrs.split(', '): if attr.find('occi.app.repo') != -1: repo_uri = attr.split('=')[1][ 1:-1] # scrubs trailing wrapped quotes break elif attr.find('occi.app.url') != -1: repo_uri = attr.split('=')[1][ 1:-1] # scrubs trailing wrapped quotes break if repo_uri == '': raise AttributeError( "No occi.app.repo or occi.app.url attribute found in request") LOG.debug('SO container URL: ' + repo_uri) return repo_uri
def service_parameters(self, state='', content_type='text/occi'): # takes the internal parameters defined for the lifecycle phase... # and combines them with the client supplied parameters if content_type == 'text/occi': params = [] # get the state specific internal parameters try: params = self.service_params[state] except KeyError as err: LOG.warn( 'The requested states parameters are not available: "' + state + '"') # get the client supplied parameters if any try: for p in self.service_params['client_params']: params.append(p) except KeyError as err: LOG.info('No client params') header = '' for param in params: if param['type'] == 'string': value = '"' + param['value'] + '"' else: value = str(param['value']) header = header + param['name'] + '=' + value + ', ' return header[0:-2] else: LOG.error('Content type not supported: ' + content_type)
def __init_so(self): url = HTTP + self.host + '/orchestrator/default' heads = { 'Category': 'orchestrator; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'], } occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info( 'Adding service-specific parameters to call... X-OCCI-Attribute: ' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Initialising SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('PUT', url, headers=heads) elapsed_time = time.time() - self.start_time infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'activate', 'phase_event': 'done', 'response_time': elapsed_time, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON)
def run(self): # this can only run until the deployment has complete! # this will block until run() returns url = HTTP + self.host + '/orchestrator/default' # with stuff like this, we need to have a callback mechanism... this will block otherwise while not self.deploy_complete(url): time.sleep(13) params = {'action': 'provision'} heads = { 'Category': 'provision; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info('Adding service-specific parameters to call... X-OCCI-Attribute: ' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Provisioning SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads, params=params) self.entity.attributes['mcn.service.state'] = 'provision' return self.entity, self.extras
def __is_complete(self, url): # XXX copy/paste code - merge the two places! heads = { 'Content-type': 'text/occi', 'Accept': 'application/occi+json', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'], } LOG.info('Checking app state at: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) r = http_retriable_request('GET', url, headers=heads, authenticate=True) attrs = json.loads(r.content) if len(attrs['attributes']) > 0: attr_hash = attrs['attributes'] app_state = '' try: app_state = attr_hash['occi.app.state'] except KeyError: pass LOG.info('Current service state: ' + str(app_state)) if app_state == 'active': LOG.info('App is ready') return True else: LOG.info('App is not ready. Current state state: ' + app_state) return False
def __git_uri(self, app_uri_path): url = self.nburl + app_uri_path headers = {'Accept': 'text/occi'} LOG.debug('Requesting container\'s URL ' + url) LOG.info('Sending headers: ' + headers.__repr__()) r = http_retriable_request('GET', url, headers=headers, authenticate=True) attrs = r.headers.get('X-OCCI-Attribute', '') if attrs == '': raise AttributeError("No occi attributes found in request") repo_uri = '' for attr in attrs.split(', '): if attr.find('occi.app.repo') != -1: repo_uri = attr.split('=')[1][1:-1] # scrubs trailing wrapped quotes break elif attr.find('occi.app.url') != -1: repo_uri = attr.split('=')[1][1:-1] # scrubs trailing wrapped quotes break if repo_uri == '': raise AttributeError("No occi.app.repo or occi.app.url attribute found in request") LOG.debug('SO container URL: ' + repo_uri) return repo_uri
def run(self): # example request to the SO # curl -v -X GET http://localhost:8051/orchestrator/default \ # -H 'X-Auth-Token: '$KID \ # -H 'X-Tenant-Name: '$TENANT if self.entity.attributes['mcn.service.state'] in ['activate', 'deploy', 'provision', 'update']: heads = { 'Content-Type': 'text/occi', 'Accept': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} LOG.info('Getting state of service orchestrator with: ' + self.host + '/orchestrator/default') LOG.info('Sending headers: ' + heads.__repr__()) r = http_retriable_request('GET', HTTP + self.host + '/orchestrator/default', headers=heads) attrs = r.headers['x-occi-attribute'].split(', ') for attr in attrs: kv = attr.split('=') if kv[0] != 'occi.core.id': if kv[1].startswith('"') and kv[1].endswith('"'): kv[1] = kv[1][1:-1] # scrub off quotes self.entity.attributes[kv[0]] = kv[1] LOG.debug('OCCI Attribute: ' + kv[0] + ' --> ' + kv[1]) # Assemble the SIG svcinsts = '' try: svcinsts = self.entity.attributes['mcn.so.svcinsts'] del self.entity.attributes['mcn.so.svcinsts'] # remove this, not be be used anywhere else except KeyError: LOG.warn('There was no service instance endpoints - ignore if not a composition.') pass if self.registry is None: LOG.error('No registry!') if len(svcinsts) > 0: svcinsts = svcinsts.split() # all instance EPs for svc_loc in svcinsts: # TODO get the service instance resource representation # source resource is self.entity compos = svc_loc.split('/') key = '/' + compos[3] + '/' + compos[4] target = Resource(key, Resource.kind, []) # target resource target.attributes['mcn.sm.endpoint'] = svc_loc self.registry.add_resource(key, target, None) key = '/link/'+str(uuid.uuid4()) link = Link(key, Link.kind, [], self.entity, target) self.registry.add_resource(key, link, None) self.entity.links.append(link) else: LOG.debug('Cannot GET entity as it is not in the activated, deployed or provisioned, updated state') return self.entity, self.extras
def run(self): # Deployment is done without any control by the client... # otherwise we won't be able to hand back a working service! #LOG.debug('DEPLOY SO START') self.start_time = time.time() infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'deploy', 'phase_event': 'start', 'response_time': 0, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) #LOG.debug('Deploying the SO bundle...') url = HTTP + self.host + '/orchestrator/default' params = {'action': 'deploy'} heads = { 'Category': 'deploy; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'] } occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info( 'Adding service-specific parameters to call... X-OCCI-Attribute:' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Deploying SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads, params=params) # also sleep here to keep phases consistent during greenfield while not self.deploy_complete(url): time.sleep(7) self.entity.attributes['mcn.service.state'] = 'deploy' LOG.debug('SO Deployed ') elapsed_time = time.time() - self.start_time infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'deploy', 'phase_event': 'done', 'response_time': elapsed_time, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) #LOG.debug('DEPLOY SO DONE, elapsed: %f' % elapsed_time) return self.entity, self.extras
def run(self): # this can only run until the deployment has complete! # this will block until run() returns #LOG.debug('PROVISION SO START') self.start_time = time.time() infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'provision', 'phase_event': 'start', 'response_time': 0, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) url = HTTP + self.host + '/orchestrator/default' # with stuff like this, we need to have a callback mechanism... this will block otherwise while not self.deploy_complete(url): time.sleep(13) params = {'action': 'provision'} heads = { 'Category': 'provision; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'] } occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info( 'Adding service-specific parameters to call... X-OCCI-Attribute: ' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Provisioning SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads, params=params) elapsed_time = time.time() - self.start_time infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'provision', 'phase_event': 'done', 'response_time': elapsed_time, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) #LOG.debug('PROVISION SO DONE, elapsed: %f' % elapsed_time) self.entity.attributes['mcn.service.state'] = 'provision' return self.entity, self.extras
def __init__(self, entity, extras): Task.__init__(self, entity, extras, state='initialise') self.nburl = CONFIG.get('cloud_controller', 'nb_api', '') if self.nburl[-1] == '/': self.nburl = self.nburl[0:-1] LOG.info('CloudController Northbound API: ' + self.nburl) if len(entity.attributes) > 0: LOG.info('Client supplied parameters: ' + entity.attributes.__repr__()) # XXX check that these parameters are valid according to the kind specification self.extras['srv_prms'].add_client_params(entity.attributes) else: LOG.warn('No client supplied parameters.')
def run(self): # 1. dispose the active SO, essentially kills the STG/ITG # 2. dispose the resources used to run the SO # example request to the SO # curl -v -X DELETE http://localhost:8051/orchestrator/default \ # -H 'X-Auth-Token: '$KID \ # -H 'X-Tenant-Name: '$TENANT self.start_time = time.time() infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'destroy', 'phase_event': 'start', 'response_time': 0, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) url = HTTP + self.host + '/orchestrator/default' heads = {'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info('Adding service-specific parameters to call... X-OCCI-Attribute:' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.info('Disposing service orchestrator with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('DELETE', url, headers=heads) url = self.nburl + self.entity.identifier.replace('/' + self.entity.kind.term + '/', '/app/') heads = {'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} LOG.info('Disposing service orchestrator container via CC... ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('DELETE', url, headers=heads, authenticate=True) elapsed_time = time.time() - self.start_time infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'destroy', 'phase_event': 'done', 'response_time': elapsed_time, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) return self.entity, self.extras
def run(self): # Deployment is done without any control by the client... # otherwise we won't be able to hand back a working service! #LOG.debug('DEPLOY SO START') self.start_time = time.time() infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'deploy', 'phase_event': 'start', 'response_time': 0, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) #LOG.debug('Deploying the SO bundle...') url = HTTP + self.host + '/orchestrator/default' params = {'action': 'deploy'} heads = { 'Category': 'deploy; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info('Adding service-specific parameters to call... X-OCCI-Attribute:' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Deploying SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads, params=params) # also sleep here to keep phases consistent during greenfield while not self.deploy_complete(url): time.sleep(7) self.entity.attributes['mcn.service.state'] = 'deploy' LOG.debug('SO Deployed ') elapsed_time = time.time() - self.start_time infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'deploy', 'phase_event': 'done', 'response_time': elapsed_time, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) #LOG.debug('DEPLOY SO DONE, elapsed: %f' % elapsed_time) return self.entity, self.extras
def run(self): # this can only run until the deployment has complete! # this will block until run() returns #LOG.debug('PROVISION SO START') self.start_time = time.time() infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'provision', 'phase_event': 'start', 'response_time': 0, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) url = HTTP + self.host + '/orchestrator/default' # with stuff like this, we need to have a callback mechanism... this will block otherwise while not self.deploy_complete(url): time.sleep(13) params = {'action': 'provision'} heads = { 'Category': 'provision; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info('Adding service-specific parameters to call... X-OCCI-Attribute: ' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Provisioning SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads, params=params) elapsed_time = time.time() - self.start_time infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'provision', 'phase_event': 'done', 'response_time': elapsed_time, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) #LOG.debug('PROVISION SO DONE, elapsed: %f' % elapsed_time) self.entity.attributes['mcn.service.state'] = 'provision' return self.entity, self.extras
def deploy_complete(url, start_time, extras, entity): done = False while done == False: # XXX fugly - code copied from Resolver heads = { 'Content-type': 'text/occi', 'Accept': 'application/occi+json', 'X-Auth-Token': extras['token'], 'X-Tenant-Name': extras['tenant_name'], } LOG.info('checking service state at: ' + url) LOG.info('sending headers: ' + heads.__repr__()) r = http_retriable_request('GET', url, headers=heads) attrs = json.loads(r.content) if len(attrs['attributes']) > 0: attr_hash = attrs['attributes'] stack_state = '' try: stack_state = attr_hash['occi.mcn.stack.state'] except KeyError: pass LOG.info('Current service state: ' + str(stack_state)) if stack_state == 'CREATE_COMPLETE' or stack_state == 'UPDATE_COMPLETE': LOG.info('Stack is ready') elapsed_time = time.time() - start_time infoDict = { 'so_id': entity.attributes['occi.core.id'], 'sm_name': entity.kind.term, 'so_phase': 'update', 'phase_event': 'done', 'response_time': elapsed_time, 'tenant': extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) done = True else: LOG.info('Stack is not ready. Current state state: ' + stack_state) done = False time.sleep(3)
def __init_so(self): url = HTTP + self.host + '/orchestrator/default' heads = { 'Category': 'orchestrator; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'], } occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info('Adding service-specific parameters to call... X-OCCI-Attribute: ' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Initialising SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('PUT', url, headers=heads)
def run(self): url = HTTP + self.host + '/orchestrator/default' params = {'action': 'provision'} heads = { 'Category': 'provision; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info('Adding service-specific parameters to call... X-OCCI-Attribute: ' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Provisioning SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads, params=params) self.entity.attributes['mcn.service.state'] = 'provision' return self.entity, self.extras
def __create_app(self): # name must be A-Za-z0-9 and <=32 chars app_name = self.entity.kind.term[0:4] + 'srvinst' + ''.join( random.choice('0123456789ABCDEF') for i in range(16)) heads = { 'Content-Type': 'text/occi', 'Category': 'app; scheme="http://schemas.ogf.org/occi/platform#", ' 'python-2.7; scheme="http://schemas.openshift.com/template/app#", ' 'small; scheme="http://schemas.openshift.com/template/app#"', 'X-OCCI-Attribute': 'occi.app.name=' + app_name } url = self.nburl + '/app/' LOG.debug('Requesting container to execute SO Bundle: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) r = http_retriable_request('POST', url, headers=heads, authenticate=True) loc = r.headers.get('Location', '') if loc == '': raise AttributeError("No OCCI Location attribute found in request") app_uri_path = urlparse(loc).path LOG.debug('SO container created: ' + app_uri_path) LOG.debug('Updating OCCI entity.identifier from: ' + self.entity.identifier + ' to: ' + app_uri_path.replace('/app/', self.entity.kind.location)) self.entity.identifier = app_uri_path.replace( '/app/', self.entity.kind.location) LOG.debug('Setting occi.core.id to: ' + app_uri_path.replace('/app/', '')) self.entity.attributes['occi.core.id'] = app_uri_path.replace( '/app/', '') # get git uri. this is where our bundle is pushed to return self.__git_uri(app_uri_path)
def __init__(self, app, srv_type=None): # openstack objects tracking the keystone service and endpoint self.srv_ep = None self.ep = None self.DEBUG = True self.app = app self.service_backend = ServiceBackend(app) LOG.info('Using configuration file: ' + CONFIG_PATH) self.token, self.tenant_name = self.get_service_credentials() self.design_uri = CONFIG.get('service_manager', 'design_uri', '') if self.design_uri == '': LOG.fatal('No design_uri parameter supplied in sm.cfg') raise Exception('No design_uri parameter supplied in sm.cfg') self.stg = None stg_path = CONFIG.get('service_manager', 'manifest', '') if stg_path == '': raise RuntimeError('No STG specified in the configuration file.') with open(stg_path) as stg_content: self.stg = json.load(stg_content) stg_content.close() if not srv_type: srv_type = self.create_service_type() self.srv_type = srv_type self.reg_srv = CONFIG.getboolean('service_manager_admin', 'register_service') if self.reg_srv: self.region = CONFIG.get('service_manager_admin', 'region', '') if self.region == '': LOG.info( 'No region parameter specified in sm.cfg, defaulting to an OpenStack default: RegionOne' ) self.region = 'RegionOne' self.service_endpoint = CONFIG.get('service_manager_admin', 'service_endpoint') if self.service_endpoint != '': LOG.warn( 'DEPRECATED: service_endpoint parameter supplied in sm.cfg! Endpoint is now specified in ' 'service manifest as service_endpoint') LOG.info('Using ' + self.stg['service_endpoint'] + ' as the service_endpoint value ' 'from service manifest') up = urlparse(self.stg['service_endpoint']) self.service_endpoint = up.scheme + '://' + up.hostname + ':' + str( up.port) + '/' + str('mobaas') LOG.info(self.service_endpoint)
def run(self): # take parameters from EEU and send them down to the SO instance # Trigger update on SO + service instance: # # $ curl -v -X POST http://localhost:8051/orchestrator/default \ # -H 'Content-Type: text/occi' \ # -H 'X-Auth-Token: '$KID \ # -H 'X-Tenant-Name: '$TENANT \ # -H 'X-OCCI-Attribute: occi.epc.attr_1="foo"' url = HTTP + self.host + '/orchestrator/default' heads = { 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info('Adding service-specific parameters to call... X-OCCI-Attribute:' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs if len(self.new.attributes) > 0: LOG.info('Adding updated parameters... X-OCCI-Attribute: ' + self.new.attributes.__repr__()) for k, v in self.new.attributes.items(): occi_attrs = occi_attrs + ', ' + k + '=' + v self.entity.attributes[k] = v heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Updating (Provisioning) SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads) self.entity.attributes['mcn.service.state'] = 'update' return self.entity, self.extras
def run(self): # Deployment is done without any control by the client... # otherwise we won't be able to hand back a working service! LOG.debug('Deploying the SO bundle...') url = HTTP + self.host + '/orchestrator/default' params = {'action': 'deploy'} heads = { 'Category': 'deploy; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info('Adding service-specific parameters to call... X-OCCI-Attribute:' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Deploying SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads, params=params) self.entity.attributes['mcn.service.state'] = 'deploy' LOG.debug('SO Deployed ') return self.entity, self.extras
def run(self): url = HTTP + self.host + '/orchestrator/default' params = {'action': 'provision'} heads = { 'Category': 'provision; scheme="http://schemas.mobile-cloud-networking.eu/occi/service#"', 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'] } occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info( 'Adding service-specific parameters to call... X-OCCI-Attribute: ' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Provisioning SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads, params=params) self.entity.attributes['mcn.service.state'] = 'provision' return self.entity, self.extras
def run(self): # take parameters from EEU and send them down to the SO instance # Trigger update on SO + service instance: # # $ curl -v -X POST http://localhost:8051/orchestrator/default \ # -H 'Content-Type: text/occi' \ # -H 'X-Auth-Token: '$KID \ # -H 'X-Tenant-Name: '$TENANT \ # -H 'X-OCCI-Attribute: occi.epc.attr_1="foo"' self.start_time = time.time() infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'update', 'phase_event': 'start', 'response_time': 0, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) url = HTTP + self.host + '/orchestrator/default' heads = { 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'] } occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info( 'Adding service-specific parameters to call... X-OCCI-Attribute:' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs if len(self.new.attributes) > 0: LOG.info('Adding updated parameters... X-OCCI-Attribute: ' + self.new.attributes.__repr__()) for k, v in self.new.attributes.items(): occi_attrs = occi_attrs + ', ' + k + '=' + v self.entity.attributes[k] = v heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Updating (Provisioning) SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads) self.entity.attributes['mcn.service.state'] = 'update' #start thread here thread = Thread(target=deploy_complete, args=(url, self.start_time, self.extras, self.entity)) thread.start() return self.entity, self.extras
def __init__(self, app, srv_type=None): # openstack objects tracking the keystone service and endpoint self.srv_ep = None self.ep = None self.DEBUG = True self.app = app self.service_backend = ServiceBackend(app) LOG.info('Using configuration file: ' + CONFIG_PATH) self.token, self.tenant_name = self.get_service_credentials() self.design_uri = CONFIG.get('service_manager', 'design_uri', '') if self.design_uri == '': LOG.fatal('No design_uri parameter supplied in sm.cfg') raise Exception('No design_uri parameter supplied in sm.cfg') self.stg = None stg_path = CONFIG.get('service_manager', 'manifest', '') if stg_path == '': raise RuntimeError('No STG specified in the configuration file.') with open(stg_path) as stg_content: self.stg = json.load(stg_content) stg_content.close() if not srv_type: srv_type = self.create_service_type() self.srv_type = srv_type self.reg_srv = CONFIG.getboolean('service_manager_admin', 'register_service') if self.reg_srv: self.region = CONFIG.get('service_manager_admin', 'region', '') if self.region == '': LOG.info('No region parameter specified in sm.cfg, defaulting to an OpenStack default: RegionOne') self.region = 'RegionOne' self.service_endpoint = CONFIG.get('service_manager_admin', 'service_endpoint') if self.service_endpoint != '': LOG.warn('DEPRECATED: service_endpoint parameter supplied in sm.cfg! Endpoint is now specified in ' 'service manifest as service_endpoint') LOG.info('Using ' + self.stg['service_endpoint'] + ' as the service_endpoint value ' 'from service manifest') up = urlparse(self.stg['service_endpoint']) self.service_endpoint = up.scheme + '://' + up.hostname + ':' + str(up.port) + '/' + str('mobaas') LOG.info(self.service_endpoint)
def run(self): # take parameters from EEU and send them down to the SO instance # Trigger update on SO + service instance: # # $ curl -v -X POST http://localhost:8051/orchestrator/default \ # -H 'Content-Type: text/occi' \ # -H 'X-Auth-Token: '$KID \ # -H 'X-Tenant-Name: '$TENANT \ # -H 'X-OCCI-Attribute: occi.epc.attr_1="foo"' self.start_time = time.time() infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'update', 'phase_event': 'start', 'response_time': 0, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) url = HTTP + self.host + '/orchestrator/default' heads = { 'Content-Type': 'text/occi', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name']} occi_attrs = self.extras['srv_prms'].service_parameters(self.state) if len(occi_attrs) > 0: LOG.info('Adding service-specific parameters to call... X-OCCI-Attribute:' + occi_attrs) heads['X-OCCI-Attribute'] = occi_attrs if len(self.new.attributes) > 0: LOG.info('Adding updated parameters... X-OCCI-Attribute: ' + self.new.attributes.__repr__()) for k, v in self.new.attributes.items(): occi_attrs = occi_attrs + ', ' + k + '=' + v self.entity.attributes[k] = v heads['X-OCCI-Attribute'] = occi_attrs LOG.debug('Updating (Provisioning) SO with: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) http_retriable_request('POST', url, headers=heads) self.entity.attributes['mcn.service.state'] = 'update' #start thread here thread = Thread(target = deploy_complete, args = (url, self.start_time, self.extras, self.entity )) thread.start() return self.entity, self.extras
def __detect_ops_version(self): # make a call to the cloud controller and based on the app kind, heuristically select version version = 'v2' heads = { 'Content-Type': 'text/occi', 'Accept': 'text/occi' } url = self.nburl + '/-/' LOG.debug('Requesting CC Query Interface: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) r = http_retriable_request('GET', url, headers=heads, authenticate=True) if r.headers['category'].find('occi.app.image') > -1 and r.headers['category'].find('occi.app.env') > -1: LOG.info('Found occi.app.image and occi.app.env - this is OpenShift V3') version = 'v3' else: LOG.info('This is OpenShift V2') return version
def __init__(self, app, srv_type=None): # openstack objects tracking the keystone service and endpoint self.srv_ep = None self.ep = None self.DEBUG = True self.app = app self.service_backend = ServiceBackend(app) LOG.info("Using configuration file: " + CONFIG_PATH) self.token, self.tenant_name = self.get_service_credentials() self.design_uri = CONFIG.get("service_manager", "design_uri", "") if self.design_uri == "": LOG.fatal("No design_uri parameter supplied in sm.cfg") raise Exception("No design_uri parameter supplied in sm.cfg") self.stg = None stg_path = CONFIG.get("service_manager", "manifest", "") if stg_path == "": raise RuntimeError("No STG specified in the configuration file.") with open(stg_path) as stg_content: self.stg = json.load(stg_content) stg_content.close() if not srv_type: srv_type = self.create_service_type() self.srv_type = srv_type self.reg_srv = CONFIG.getboolean("service_manager_admin", "register_service") if self.reg_srv: self.region = CONFIG.get("service_manager_admin", "region", "") if self.region == "": LOG.info("No region parameter specified in sm.cfg, defaulting to an OpenStack default: RegionOne") self.region = "RegionOne" self.service_endpoint = CONFIG.get("service_manager_admin", "service_endpoint") if self.service_endpoint != "": LOG.warn( "DEPRECATED: service_endpoint parameter supplied in sm.cfg! Endpoint is now specified in " "service manifest as service_endpoint" ) LOG.info( "Using " + self.stg["service_endpoint"] + " as the service_endpoint value " "from service manifest" ) up = urlparse(self.stg["service_endpoint"]) self.service_endpoint = up.scheme + "://" + up.hostname + ":" + str(up.port)
def __create_app(self): # will generate an appname 24 chars long - compatible with v2 and v3 # e.g. soandycd009b39c28790f3 app_name = 'so' + self.entity.kind.term[0:4] + \ ''.join(random.choice('0123456789abcdef') for _ in range(16)) heads = {'Content-Type': 'text/occi'} url = self.nburl + '/app/' if self.entity.extras['ops_version'] == 'v2': heads['category'] = 'app; scheme="http://schemas.ogf.org/occi/platform#", ' \ 'python-2.7; scheme="http://schemas.openshift.com/template/app#", ' \ 'small; scheme="http://schemas.openshift.com/template/app#"' heads['X-OCCI-Attribute'] = str('occi.app.name=' + app_name) LOG.debug('Ensuring SM SSH Key...') self.__ensure_ssh_key() elif self.entity.extras['ops_version'] == 'v3': # for OpSv3 bundle location is the repo id of the container image bundle_loc = os.environ.get('BUNDLE_LOC', False) if not bundle_loc: bundle_loc = CONFIG.get('service_manager', 'bundle_location', '') if bundle_loc == '': LOG.error('No bundle_location parameter supplied in sm.cfg') raise Exception( 'No bundle_location parameter supplied in sm.cfg') if bundle_loc.startswith('/'): LOG.warn( 'Bundle location does not look like an image reference!') LOG.debug('Bundle to execute: ' + bundle_loc) design_uri = CONFIG.get('service_manager', 'design_uri', '') if design_uri == '': raise Exception('No design_uri parameter supplied in sm.cfg') LOG.debug('Design URI: ' + design_uri) heads[ 'category'] = 'app; scheme="http://schemas.ogf.org/occi/platform#"' # TODO provide a means to provide additional docker env params attrs = 'occi.app.name="' + app_name + '", ' + \ 'occi.app.image="' + bundle_loc + '", ' + \ 'occi.app.env="DESIGN_URI=' + design_uri + '"' heads['X-OCCI-Attribute'] = str(attrs) else: LOG.error('Unknown OpenShift version. ops_version: ' + self.entity.extras['ops_version']) raise Exception('Unknown OpenShift version. ops_version: ' + self.entity.extras['ops_version']) LOG.debug('Requesting container to execute SO Bundle: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) r = http_retriable_request('POST', url, headers=heads, authenticate=True) loc = r.headers.get('Location', '') if loc == '': LOG.error("No OCCI Location attribute found in request") raise AttributeError("No OCCI Location attribute found in request") self.entity.attributes['occi.so.url'] = loc app_uri_path = urlparse(loc).path LOG.debug('SO container created: ' + app_uri_path) LOG.debug('Updating OCCI entity.identifier from: ' + self.entity.identifier + ' to: ' + app_uri_path.replace('/app/', self.entity.kind.location)) self.entity.identifier = app_uri_path.replace( '/app/', self.entity.kind.location) LOG.debug('Setting occi.core.id to: ' + app_uri_path.replace('/app/', '')) self.entity.attributes['occi.core.id'] = app_uri_path.replace( '/app/', '') # its a bit wrong to put this here, but we do not have the required information before. # this keeps things consistent as the timing is done right infoDict = { 'so_id': self.entity.attributes['occi.core.id'].split('/'), 'sm_name': self.entity.kind.term, 'so_phase': 'init', 'phase_event': 'start', 'response_time': 0, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) # OpSv2 only: get git uri. this is where our bundle is pushed to # XXX this is fugly # TODO use the same name for the app URI if self.entity.extras['ops_version'] == 'v2': self.entity.extras['repo_uri'] = self.__git_uri(app_uri_path) elif self.entity.extras['ops_version'] == 'v3': self.entity.extras['loc'] = self.__git_uri(app_uri_path)
def __get_heat_template(self, attributes): randomstring = "-"+str(uuid.uuid1()) # this function will return the first of following values in the order # of occurrence: # - given by the user during instantiation # - set as a default value in the config file # - an empty string def getAttr(attrName): if(attrName in attributes): return attributes[attrName] else: try: retVal = config.get('cluster',attrName) return retVal except: return "" # the rootFolder is needed in order to load the config files self.rootFolder = CONFIG.get('disco','root_folder') if self.rootFolder=="": # if no rootFolder has been provided, take the path it's located # within the Docker image self.rootFolder = "data/" # setup parser for config file config = ConfigParser.RawConfigParser() config.read(os.path.join(self.rootFolder,'defaultSettings.cfg')) LOG.info("deploying stack...") # the needed variables for the Heat Orchestration Template will be set # on the following lines; the function getAttr() is returning the # appropriate value. As an empty value cannot be used for int/float # conversion, they have to be set within a try-except block. slaveCount = 1 try: slaveCount = int(getAttr('icclab.haas.slave.number')) except: pass masterImage = getAttr('icclab.haas.master.image') slaveImage = getAttr('icclab.haas.slave.image') masterFlavor = getAttr('icclab.haas.master.flavor') slaveFlavor = getAttr('icclab.haas.slave.flavor') slaveOnMaster = True #getAttr('icclab.haas.master.slaveonmaster').lower() in ['true', '1'] SSHPublicKeyName = getAttr('icclab.haas.master.sshkeyname') SSHMasterPublicKey = getAttr('icclab.haas.master.publickey') withFloatingIP = getAttr('icclab.haas.master.withfloatingip').lower() in ['true','1'] master_name = getAttr('icclab.haas.master.name')+randomstring slave_name = getAttr('icclab.haas.slave.name')+randomstring+"-" subnet_cidr = getAttr('icclab.haas.network.subnet.cidr') subnet_gw_ip = getAttr('icclab.haas.network.gw.ip') subnet_allocation_pool_start = getAttr('icclab.haas.network.subnet.allocpool.start') subnet_allocation_pool_end = getAttr('icclab.haas.network.subnet.allocpool.end') subnet_dns_servers = getAttr('icclab.haas.network.dnsservers') image_id = getAttr('icclab.haas.master.imageid') floatingIpId = getAttr('icclab.haas.master.attachfloatingipwithid') externalNetwork = getAttr('icclab.haas.network.external') noDeployment = getAttr('icclab.haas.debug.donotdeploy').lower() in ['true','1'] saveToLocalPath = getAttr('icclab.haas.debug.savetemplatetolocalpath') diskId = 'virtio-'+image_id[0:20] # masterSSHKeyEntry = '' def getFileContent(fileName): f = open(os.path.join(self.rootFolder, fileName)) retVal = f.read() f.close() return retVal # read all the necessary files for creating the Heat template clusterTemplate = getFileContent("cluster.yaml"); slaveTemplate = getFileContent("slave.yaml") masterBash = getFileContent("master_bash.sh") master_id_rsa = getFileContent("master.id_rsa").replace("\n","\\n") master_id_rsa_pub = getFileContent("master.id_rsa.pub").replace("\n","") yarn_site_xml = getFileContent("yarn-site.xml") core_site_xml = getFileContent("core-site.xml") mapred_site_xml = getFileContent("mapred-site.xml") hdfs_site_xml = getFileContent("hdfs-site.xml") hadoop_env_sh = getFileContent("hadoop-env.sh") jupyter_notebook_config_py = getFileContent("jupyter_notebook_config.py") slaves = "" hostFileContent = "" forLoopSlaves = "" paramsSlave = "" slavesFile = "" hostsListFile = "" slaveTemplate = slaveTemplate.replace("$master.id_rsa.pub$",master_id_rsa_pub) for i in xrange(1,slaveCount+1): slaves += slaveTemplate.replace("$slavenumber$",str(i)) hostFileContent += "$slave"+str(i)+"address$\t"+slave_name+str(i)+"\n" forLoopSlaves += " $slave"+str(i)+"address$" paramsSlave += " $slave"+str(i)+"address$: { get_attr: [hadoop_slave_"+str(i)+", first_address] }\n" slavesFile += slave_name+str(i)+"\n" hostsListFile += "$slave"+str(i)+"address$\n" # In the following section, the master's public SSH key will be setup. # This is done the following way: if no key name was provided for an # existing public SSH key, the same key will be used as was used for # the slaves as well. If a key name was provided but no public SSH key, # it's assumed that an existing public key is already registered in # keystone which should be used. If a key name and a public SSH key are # provided, a new public key entry will be created in keystone with the # give public key and the given name. masterSSHKeyResource = "" insertMasterPublicKey = "" if SSHPublicKeyName=="": masterSSHKeyEntry = "{ get_resource: sshpublickey }" else: insertMasterPublicKey = "su ubuntu -c \"cat /home/ubuntu/.ssh/id_rsa.pub >> /home/ubuntu/.ssh/authorized_keys\"\n" if SSHMasterPublicKey=="": masterSSHKeyEntry = SSHPublicKeyName else: masterSSHKeyResource = " users_public_key:\n" \ " type: OS::Nova::KeyPair\n" \ " properties:\n" \ " name: " + SSHPublicKeyName + "\n" \ " public_key: " + SSHMasterPublicKey + "\n\n" masterSSHKeyEntry = "{ get_resource: users_public_key }" # if master has to act as a slave as well, set variable accordingly masterasslave = "" if slaveOnMaster==True: masterasslave = master_name+"\n" # setup bash script for master (write replace{r,e}s into dictionary and # replace them one by one replaceDict = { "$master.id_rsa$": master_id_rsa, "$master.id_rsa.pub$": master_id_rsa_pub, "$yarn-site.xml$": yarn_site_xml, "$core-site.xml$": core_site_xml, "$mapred-site.xml$": mapred_site_xml, "$hdfs-site.xml$": hdfs_site_xml, "$hadoop-env.sh$": hadoop_env_sh, "$masternodeasslave$": masterasslave, "$slavesfile$": slavesFile, "$hostsfilecontent$": hostFileContent, "$forloopslaves$": forLoopSlaves, "$for_loop_slaves$": hostsListFile, "$insert_master_pub_key$": insertMasterPublicKey, "$disk_id$": diskId, "$jupyter_notebook_config.py$": jupyter_notebook_config_py } for key, value in replaceDict.iteritems(): masterBash = masterBash.replace(key, value) # add some spaces in front of each line because the bash script has to # be indented within the Heat template masterBashLines = masterBash.splitlines(True) masterbash = "" for line in masterBashLines: masterbash += ' '*14+line # does the user want to have a floating IP created? floatingIpResource = "" floatingIpAssoc = "" externalIpOutput = "" # if a floating IP is to be setup for the master, the variables have to be set accordingly if True == withFloatingIP: ipid = floatingIpId floatingIpAssoc = " floating_ip_assoc:\n" \ " type: OS::Neutron::FloatingIPAssociation\n" \ " properties:\n" \ " floatingip_id: " if floatingIpId=="": floatingIpResource = " hadoop_ip:\n" \ " type: OS::Neutron::FloatingIP\n" \ " properties:\n" \ " floating_network: \""+externalNetwork+"\"\n\n" floatingIpAssoc += "{ get_resource: hadoop_ip }" externalIpOutput = " external_ip:\n" \ " description: The IP address of the deployed master node\n" \ " value: { get_attr: [ hadoop_ip, floating_ip_address ] }\n\n" else: floatingIpAssoc = floatingIpAssoc+floatingIpId floatingIpAssoc += "\n port_id: { get_resource: hadoop_port }\n\n" memVals = self.__get_hadoop_memory_values(slaveFlavor) # the cluster's heat template will have to be configured replaceDict = {"$master_bash.sh$": masterbash, "$paramsslave$": paramsSlave, "$slaves$": slaves, "$master_image$": masterImage, "$slave_image$": slaveImage, "$masternode$": master_name, "$slavenode$": slave_name, "$master_flavor$": masterFlavor, "$slave_flavor$": slaveFlavor, "$master_ssh_key_entry$": masterSSHKeyEntry, "$users_ssh_public_key$": masterSSHKeyResource, "$floating_ip_resource$": floatingIpResource, "$floating_ip_assoc$": floatingIpAssoc, "$external_ip_output$": externalIpOutput, "$subnet_cidr$": subnet_cidr, "$subnet_gw_ip$": subnet_gw_ip, "$subnet_allocation_pool_start$": subnet_allocation_pool_start, "$subnet_allocation_pool_end$": subnet_allocation_pool_end, "$subnet_dns_servers$": subnet_dns_servers, "$ssh_cluster_pub_key$": "ssh_pub_key_"+randomstring, "$hadoop_security_group$": "security_group_"+randomstring, "$network_name$": "network_"+randomstring, "$external_network$": externalNetwork } # do basic configuration for key, value in replaceDict.iteritems(): clusterTemplate = clusterTemplate.replace(key, value) # insert memory values for key, value in memVals.iteritems(): clusterTemplate = clusterTemplate.replace(key, str(value)) # for debugging purposes, the template can be saved locally if saveToLocalPath is not "": try: f = open( saveToLocalPath,"w") f.write(clusterTemplate) f.close() except: LOG.info("Couldn't write to location "+saveToLocalPath) # debug output should be implemented as a parameter # LOG.debug(clusterTemplate) # self.deployTemplate = clusterTemplate # deploy the created template if not noDeployment: return clusterTemplate
def shutdown_handler(self, signum=None, frame=None): LOG.info('Service shutting down... ') if not self.DEBUG: ioloop.IOLoop.instance().add_callback(self.deregister_service()) else: self.deregister_service()
def shutdown_handler(self, signum = None, frame = None): LOG.info('Service shutting down... ') if self.reg_srv: self.deregister_service() sys.exit(0)
def shutdown_handler(self, signum=None, frame=None): LOG.info("Service shutting down... ") if self.reg_srv: self.deregister_service() sys.exit(0)
def __is_complete(self, url): # XXX copy/paste code - merge the two places! heads = { 'Content-type': 'text/occi', 'Accept': 'application/occi+json', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'], } LOG.info('Checking app state at: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) r = http_retriable_request('GET', url, headers=heads, authenticate=True) attrs = json.loads(r.content) if len(attrs['attributes']) > 0: attr_hash = attrs['attributes'] app_state = '' try: app_state = attr_hash['occi.app.state'] except KeyError: pass LOG.info('Current service state: ' + str(app_state)) if app_state == 'active': # check if it returns something valid instead of 503 try: tmpUrl = 'http://' + attr_hash['occi.app.url'] except KeyError: LOG.info(('App is not ready. app url is not yet set.')) return False r = http_retriable_request('GET', tmpUrl, headers=heads, authenticate=True) if r.status_code == 200: LOG.info('App is ready') elapsed_time = time.time() - self.extras['occi.init.starttime'] del self.extras['occi.init.starttime'] infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'init', 'phase_event': 'done', 'response_time': elapsed_time, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) return True else: LOG.info('App is not ready. app url returned: ' + r.status_code) else: LOG.info('App is not ready. Current state state: ' + app_state) return False
def __create_app(self): # will generate an appname 24 chars long - compatible with v2 and v3 # e.g. soandycd009b39c28790f3 app_name = 'so' + self.entity.kind.term[0:4] + \ ''.join(random.choice('0123456789abcdef') for _ in range(16)) heads = {'Content-Type': 'text/occi'} url = self.nburl + '/app/' if self.entity.extras['ops_version'] == 'v2': heads['category'] = 'app; scheme="http://schemas.ogf.org/occi/platform#", ' \ 'python-2.7; scheme="http://schemas.openshift.com/template/app#", ' \ 'small; scheme="http://schemas.openshift.com/template/app#"' heads['X-OCCI-Attribute'] = str('occi.app.name=' + app_name) LOG.debug('Ensuring SM SSH Key...') self.__ensure_ssh_key() elif self.entity.extras['ops_version'] == 'v3': # for OpSv3 bundle location is the repo id of the container image bundle_loc = CONFIG.get('service_manager', 'bundle_location', '') if bundle_loc == '': LOG.error('No bundle_location parameter supplied in sm.cfg') raise Exception('No bundle_location parameter supplied in sm.cfg') if bundle_loc.startswith('/'): LOG.warn('Bundle location does not look like an image reference!') LOG.debug('Bundle to execute: ' + bundle_loc) design_uri = CONFIG.get('service_manager', 'design_uri', '') if design_uri == '': raise Exception('No design_uri parameter supplied in sm.cfg') LOG.debug('Design URI: ' + design_uri) heads['category'] = 'app; scheme="http://schemas.ogf.org/occi/platform#"' # TODO provide a means to provide additional docker env params attrs = 'occi.app.name="' + app_name + '", ' + \ 'occi.app.image="' + bundle_loc + '", ' + \ 'occi.app.env="DESIGN_URI=' + design_uri + '"' heads['X-OCCI-Attribute'] = str(attrs) else: LOG.error('Unknown OpenShift version. ops_version: ' + self.entity.extras['ops_version']) raise Exception('Unknown OpenShift version. ops_version: ' + self.entity.extras['ops_version']) LOG.debug('Requesting container to execute SO Bundle: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) r = http_retriable_request('POST', url, headers=heads, authenticate=True) loc = r.headers.get('Location', '') if loc == '': LOG.error("No OCCI Location attribute found in request") raise AttributeError("No OCCI Location attribute found in request") self.entity.attributes['occi.so.url'] = loc app_uri_path = urlparse(loc).path LOG.debug('SO container created: ' + app_uri_path) LOG.debug('Updating OCCI entity.identifier from: ' + self.entity.identifier + ' to: ' + app_uri_path.replace('/app/', self.entity.kind.location)) self.entity.identifier = app_uri_path.replace('/app/', self.entity.kind.location) LOG.debug('Setting occi.core.id to: ' + app_uri_path.replace('/app/', '')) self.entity.attributes['occi.core.id'] = app_uri_path.replace('/app/', '') # its a bit wrong to put this here, but we do not have the required information before. # this keeps things consistent as the timing is done right infoDict = { 'so_id': self.entity.attributes['occi.core.id'].split('/'), 'sm_name': self.entity.kind.term, 'so_phase': 'init', 'phase_event': 'start', 'response_time': 0, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) # OpSv2 only: get git uri. this is where our bundle is pushed to # XXX this is fugly # TODO use the same name for the app URI if self.entity.extras['ops_version'] == 'v2': self.entity.extras['repo_uri'] = self.__git_uri(app_uri_path) elif self.entity.extras['ops_version'] == 'v3': self.entity.extras['loc'] = self.__git_uri(app_uri_path)
def __is_complete(self, url): # XXX copy/paste code - merge the two places! heads = { 'Content-type': 'text/occi', 'Accept': 'application/occi+json', 'X-Auth-Token': self.extras['token'], 'X-Tenant-Name': self.extras['tenant_name'], } LOG.info('Checking app state at: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) r = http_retriable_request('GET', url, headers=heads, authenticate=True) attrs = json.loads(r.content) if len(attrs['attributes']) > 0: attr_hash = attrs['attributes'] app_state = '' try: app_state = attr_hash['occi.app.state'] except KeyError: pass LOG.info('Current service state: ' + str(app_state)) if app_state == 'active': # check if it returns something valid instead of 503 try: tmpUrl = 'http://' + attr_hash['occi.app.url'] except KeyError: LOG.info(('App is not ready. app url is not yet set.')) return False r = http_retriable_request('GET', tmpUrl, headers=heads, authenticate=True) if r.status_code == 200: LOG.info('App is ready') elapsed_time = time.time( ) - self.extras['occi.init.starttime'] del self.extras['occi.init.starttime'] infoDict = { 'so_id': self.entity.attributes['occi.core.id'], 'sm_name': self.entity.kind.term, 'so_phase': 'init', 'phase_event': 'done', 'response_time': elapsed_time, 'tenant': self.extras['tenant_name'] } tmpJSON = json.dumps(infoDict) LOG.debug(tmpJSON) return True else: LOG.info('App is not ready. app url returned: ' + r.status_code) else: LOG.info('App is not ready. Current state state: ' + app_state) return False
def __create_app(self): # will generate an appname 24 chars long - compatible with v2 and v3 # e.g. soandycd009b39c28790f3 app_name = 'so' + self.entity.kind.term[0:4] + \ ''.join(random.choice('0123456789abcdef') for _ in range(16)) heads = {'Content-Type': 'text/occi'} url = self.nburl + '/app/' if self.entity.extras['ops_version'] == 'v2': heads['category'] = 'app; scheme="http://schemas.ogf.org/occi/platform#", ' \ 'python-2.7; scheme="http://schemas.openshift.com/template/app#", ' \ 'small; scheme="http://schemas.openshift.com/template/app#"' heads['X-OCCI-Attribute'] = str('occi.app.name=' + app_name) LOG.debug('Ensuring SM SSH Key...') self.__ensure_ssh_key() elif self.entity.extras['ops_version'] == 'v3': # for OpSv3 bundle location is the repo id of the container image bundle_loc = CONFIG.get('service_manager', 'bundle_location', '') if bundle_loc == '': LOG.error('No bundle_location parameter supplied in sm.cfg') raise Exception('No bundle_location parameter supplied in sm.cfg') if bundle_loc.startswith('/'): LOG.warn('Bundle location does not look like an image reference!') LOG.debug('Bundle to execute: ' + bundle_loc) design_uri = CONFIG.get('service_manager', 'design_uri', '') if design_uri == '': raise Exception('No design_uri parameter supplied in sm.cfg') LOG.debug('Design URI: ' + design_uri) heads['category'] = 'app; scheme="http://schemas.ogf.org/occi/platform#"' # TODO provide a means to provide additional docker env params attrs = 'occi.app.name="' + app_name + '", ' + \ 'occi.app.image="' + bundle_loc + '", ' + \ 'occi.app.env="DESIGN_URI=' + design_uri + '"' heads['X-OCCI-Attribute'] = str(attrs) else: LOG.error('Unknown OpenShift version. ops_version: ' + self.entity.extras['ops_version']) raise Exception('Unknown OpenShift version. ops_version: ' + self.entity.extras['ops_version']) LOG.debug('Requesting container to execute SO Bundle: ' + url) LOG.info('Sending headers: ' + heads.__repr__()) r = http_retriable_request('POST', url, headers=heads, authenticate=True) loc = r.headers.get('Location', '') if loc == '': LOG.error("No OCCI Location attribute found in request") raise AttributeError("No OCCI Location attribute found in request") app_uri_path = urlparse(loc).path LOG.debug('SO container created: ' + app_uri_path) LOG.debug('Updating OCCI entity.identifier from: ' + self.entity.identifier + ' to: ' + app_uri_path.replace('/app/', self.entity.kind.location)) self.entity.identifier = app_uri_path.replace('/app/', self.entity.kind.location) LOG.debug('Setting occi.core.id to: ' + app_uri_path.replace('/app/', '')) self.entity.attributes['occi.core.id'] = app_uri_path.replace('/app/', '') # OpSv2 only: get git uri. this is where our bundle is pushed to # XXX this is fugly # TODO use the same name for the app URI if self.entity.extras['ops_version'] == 'v2': self.entity.extras['repo_uri'] = self.__git_uri(app_uri_path) elif self.entity.extras['ops_version'] == 'v3': self.entity.extras['loc'] = self.__git_uri(app_uri_path) # wait until occi.app.state="active" - loop a GET # this may not be applicable to OpSv2 LOG.info('checking: ' + loc) while not self.__is_complete(loc): time.sleep(3)