def update_template(template_id, body): logger.debug('In update_template') try: meta_template, msg = get_template(template_id) except Exception as e: msg = f" Template {template_id} NOT Found; exception: {e}" raise errors.ResourceError(msg=msg) logger.debug('UPDATING ... Kapacitor Template') template_body = {} template_body['id'] = template_id template_body['type'] = body['type'] template_body['script'] = body['script'] try: result, status_code = update_kapacitor_template( template_id, template_body) except Exception as e: msg = f" Not able to connect to Kapacitor for the template {body['template_id']} update; exception: {e}" raise errors.ResourceError(msg=msg) if status_code == 200: logger.debug("UPDATED ... Kapacitor template ") logger.debug("UPDATING ... template object in meta") meta_template['type'] = body['type'] meta_template['script'] = body['script'] meta_template['last_updated'] = str(datetime.datetime.utcnow()) result = {} result, message = meta.update_template(meta_template) else: msg = f" Could Not Find Template {template_id} with Template {body} " raise errors.ResourceError(msg=msg) return result, message
def update_channel(channel_id, req_body): logger.debug('Top of update_channel') req_body['channel_id'] = channel_id # Get channel information from Meta try: channel_result, msg = get_channel(channel_id) except Exception as e: msg = f" Channel {channel_id} NOT Found; exception: {e}" raise errors.ResourceError(msg=msg) # TODO check if Kapacitor Task exist logger.debug('UPDATING ... Kapacitor Task') task_id = channel_id task_body = { 'id': task_id, 'dbrps': [{ "db": "chords_ts_production", "rp": "autogen" }] } task_body['template-id'] = req_body['template_id'] vars = {} vars = convert_conditions_to_vars(req_body) task_body['vars'] = vars logger.debug('update_task request body: ' + str(task_body)) try: kapacitor_result, kapacitor_status_code = update_kapacitor_task( channel_id, task_body) except Exception as e: msg = f" Not able to connect to Kapacitor for the task {channel_id} update; exception: {e}" raise errors.ResourceError(msg=msg) if kapacitor_status_code == 200: logger.debug("UPDATED ... Kapacitor task ") logger.debug("UPDATING ... channel object in meta") if kapacitor_result['status'] == 'enabled': channel_result['status'] = 'ACTIVE' elif kapacitor_result['status'] == 'disabled': channel_result['status'] = 'INACTIVE' else: channel_result['status'] = 'ERROR' channel_result['last_updated'] = str(datetime.datetime.utcnow()) channel_result['template_id'] = kapacitor_result['template-id'] channel_result['channel_name'] = req_body['channel_name'] channel_result['triggers_with_actions'] = req_body[ 'triggers_with_actions'] meta_result = {} meta_result, meta_message = meta.update_channel(channel_result) else: str_response = kapacitor_result['error'] msg = f" Could Not Find Channel {channel_id} with Task ID {channel_result['channel_id']}: {str_response} " logger.debug(msg) raise errors.ResourceError(msg=msg) return meta_result, meta_message
def get_measurements(instrument_id, start="", end="", format="json"): #GET get all variables from chords service logger.debug("inside chords get measurement") if format is None: format = "json" path = "/instruments/" + instrument_id + "." + format + "?" #"api/v1/data.json"; #start, end, instruments logger.debug(start) logger.debug(end) if start is not None: if len(start) > 0: path = path + "&start=" + start if end is not None: if len(end) > 0: path = path + "&end=" + end res = create_get_request(path) if (res.status_code == 200): message = "Measurement found" else: raise errors.ResourceError(msg=f'Measurements not found') logger.debug(message) logger.debug(res.content) if format == "json": return json.loads(res.content.decode('utf-8')), message else: return res.content, message
def post(self): logger.debug("top of POST /tokens") # try: validator = RequestValidator(utils.spec) validated = validator.validate(FlaskOpenAPIRequest(request)) if validated.errors: raise errors.ResourceError( msg=f'Invalid POST data: {validated.errors}.') validated_body = validated.body # this raises an exception of the claims are invalid - if hasattr(validated_body, 'extra_claims'): check_extra_claims(validated_body.extra_claims) token_data = TapisAccessToken.get_derived_values(validated_body) access_token = TapisAccessToken(**token_data) access_token.sign_token() result = {} result['access_token'] = access_token.serialize # refresh token -- if hasattr(validated_body, 'generate_refresh_token' ) and validated_body.generate_refresh_token: refresh_token = TokensResource.get_refresh_from_access_token_data( token_data, access_token) result['refresh_token'] = refresh_token.serialize return utils.ok(result=result, msg="Token generation successful.")
def put(self): try: validator = RequestValidator(utils.spec) validated = validator.validate(FlaskOpenAPIRequest(request)) if validated.errors: raise errors.ResourceError( msg=f'Invalid PUT data: {validated.errors}.') refresh_token = validated.body.refresh_token refresh_token_data = auth.validate_token(refresh_token) token_data = refresh_token_data['access_token'] token_data.pop('token_type') token_data['exp'] = TapisAccessToken.compute_exp(token_data['ttl']) access_token = TapisAccessToken(**token_data) access_token.sign_token() refresh_token = TokensResource.get_refresh_from_access_token_data( token_data, access_token) result = { 'access_token': access_token.serialize, 'refres_token': refresh_token.serialize } return utils.ok(result=result, msg="Token generation successful.") except Exception as e: # return utils.ok(result="Got exception", msg=f"{refresh_token.serialize}") return utils.ok(result="Got exception", msg=f"Exception: {traceback.format_exc()}")
def create_instrument(instrument: ChordsIntrument): #TODO validate the instrument has all properties requirement and fields are correct postData = { 'email': conf.chords_user_email, 'api_key': conf.chords_api_key, 'instrument[site_id]': instrument.site_id, 'instrument[name]': instrument.name, #'instrument[sensor_id]': instrument.sensor_id, 'instrument[topic_category_id]': instrument.topic_category_id, 'instrument[description]': instrument.description, 'instrument[display_points]': instrument.display_points, 'instrument[plot_offset_value]': instrument.plot_offset_value, 'instrument[plot_offset_units]': instrument.plot_offset_units, 'instrument[sample_rate_seconds]': instrument.sample_rate_seconds } logger.debug(postData) res = create_post_request("/instruments.json", postData) logger.debug(res.content) if (res.status_code == 201): message = "Instrument created" else: raise errors.ResourceError(msg=f'Instrument not created') logger.debug(message) logger.debug(res) return json.loads(res.content.decode('utf-8')), message
def update_site(project_id, site_id, put_body): logger.debug("IN Update SITE META") #fetch site first and then replace existing fields/add fields to current site document site_result, site_bug = get_site(project_id, site_id) if len(site_result) > 0: for field in put_body: site_result[field] = put_body[field] site_result['last_updated'] = str(datetime.datetime.now()) #validate fields logger.debug(site_result) result = {} message = "" result, put_bug = t.meta.replaceDocument( db=conf.stream_db, collection=project_id, docId=site_result['_id']['$oid'], request_body=site_result, _tapis_debug=True) logger.debug(put_bug.response.status_code) if put_bug.response.status_code == 200: result = site_result message = 'Site Updated' else: raise errors.ResourceError(msg=f'Site Does Not Exist For Site ID:' + str(site_id)) return result, message
def update_project(project_id, put_body): logger.debug("IN Update Project META") proj_result, proj_bug = get_project(project_id) if len(proj_result) > 0: for field in put_body: proj_result[field] = put_body[field] proj_result['last_updated'] = str(datetime.datetime.now()) #validate fields logger.debug(proj_result) result = {} message = "" result, put_bug = t.meta.replaceDocument( db=conf.stream_db, collection='streams_project_metadata', docId=proj_result['_id']['$oid'], request_body=proj_result, _tapis_debug=True) logger.debug(put_bug.response.status_code) if put_bug.response.status_code == 200: result = proj_result message = 'Project Updated' else: raise errors.ResourceError( msg=f'Project Does Not Exist For Project ID:' + str(project_id)) return result, message
def create_alert(channel, req_data): actor_id = channel['triggers_with_actions'][0]['action']['actor_id'] logger.debug('actor_id:' + actor_id) abaco_base_url = channel['triggers_with_actions'][0]['action'][ 'abaco_base_url'] abaco_nonce = channel['triggers_with_actions'][0]['action']['nonces'] abaco_url = abaco_base_url + '/actors/v2/' + actor_id + '/messages?x-nonce=' + abaco_nonce logger.debug('abaco_url: ' + abaco_url) #prepare request for abaco headers = {'accept': 'application/json'} message_data = {} message_data['message'] = req_data message_data['message']['channel_id'] = channel['channel_id'] result = meta.fetch_instrument_index( channel["triggers_with_actions"][0]['inst_ids'][0]) message_data['message']['project_id'] = result[0]['project_id'] message_data['message']['site_id'] = result[0]['site_id'] message_data['message']['inst_id'] = result[0]['instrument_id'] cond_key = channel['triggers_with_actions'][0]['condition']['key'].split( ".") message_data['message']['var_id'] = cond_key[1] logger.debug('message_data: ' + str(message_data)) try: res = requests.post(abaco_url, json=message_data, headers=headers, verify=False) except Exception as e: msg = f"Got exception trying to post message to Abaco actor: {actor_id}; exception: {e}" raise errors.BaseTapyException(msg=msg, request=res.request) logger.debug('abaco response:' + res.text) logger.debug('abaco response status code:' + str(res.status_code)) if res.status_code == 200: abaco_res = json.loads(res.text) #TODO create alert summary and alert object with all details execution_id = abaco_res['result']['executionId'] alert = {} alert['alert_id'] = str(uuid.uuid4()) alert['channel_name'] = channel['channel_name'] alert['channel_id'] = channel['channel_id'] alert['actor_id'] = actor_id alert['execution_id'] = execution_id alert['message'] = req_data['message'] alert['create_time'] = str(datetime.datetime.utcnow()) logger.debug(alert) alert_result, msg = meta.create_alert(alert) logger.debug(alert_result) result = meta.strip_meta(alert_result) logger.debug(result) return result, msg else: msg = f"Abaco Actor: {actor_id} unable to perform the execution on the message: {message_data}. Check the Actor Status and the message" raise errors.ResourceError(msg=msg)
def create_project(body): logger.debug("IN CREATE PROJECT META") results = '' #create project metadata record req_body = body req_body['project_id'] = body['project_name'].replace(" ", "") req_body['permissions'] = {'users': [g.username]} logger.debug(req_body) #Check if project_id exists - if so add something to id to unique it. result, bug = t.meta.createDocument(db=conf.stream_db, collection='streams_project_metadata', request_body=req_body, _tapis_debug=True) if bug.response.status_code == 201: logger.debug('Created project metadata') #create project collection col_result, col_bug = t.meta.createCollection( db=conf.stream_db, collection=req_body['project_id'], _tapis_debug=True) logger.debug("Status_Code: " + str(col_bug.response.status_code)) logger.debug(col_result) if str(col_bug.response.status_code) == '201': message = "Project Created" index_result, index_bug = t.meta.createIndex( db=conf.stream_db, collection=req_body['project_id'], indexName=body['project_id'] + "_loc_index", request_body={"keys": { "location": "2dsphere" }}, _tapis_debug=True) #create location index logger.debug(index_result) results, bug = get_project(req_body['project_id']) else: #should remove project metadata record if this fails raise errors.ResourceError(msg=f'Project Creation Failed') results = bug.response else: raise errors.ResourceError(msg=f'Project Creation Failed') results = bug.response return results, message
def get(self, client_id): client = Client.query.filter_by(tenant_id=g.tenant_id, client_id=client_id).first() if not client: raise errors.ResourceError( msg=f'No client found with id {client_id}.') if not client.username == g.username: raise errors.PermissionsError("Not authorized for this client.") return utils.ok(result=client.serialize, msg='Client object retrieved successfully.')
def get_variable(id): #GET get a instrument from chords service res = create_get_request("/vars/" + id + ".json") if (res.status_code == 200): message = "Variable found" else: raise errors.ResourceError(msg=f'Variable not found') logger.debug(message) logger.debug(res) return json.loads(res.content.decode('utf-8')), message
def list_instruments(): #GET get a instrument from chords service res = create_get_request("/instruments.json") if (res.status_code == 200): message = "Instrument found" else: raise errors.ResourceError(msg=f'No instrument found') logger.debug(message) logger.debug(res) return json.loads(res.content.decode('utf-8')), message
def list_sites(project_id): logger.debug("Before") result = t.meta.listDocuments(db='StreamsTACCDB', collection=project_id) logger.debug("After") if len(result) > 0: message = "Sites found" else: raise errors.ResourceError(msg=f'No Site found') logger.debug(result) return json.loads(result.decode('utf-8')), message
def delete(self, client_id): client = Client.query.filter_by(tenant_id=g.tenant_id, client_id=client_id).first() if not client: raise errors.ResourceError( msg=f'No client found with id {client_id}.') if not client.username == g.username: raise errors.PermissionsError("Not authorized for this client.") db.session.delete(client) db.session.commit()
def get_site(id): #GET get a site from chords service res = create_get_request("/sites/" + id + ".json") if (res.status_code == 200): message = "Site found" else: raise errors.ResourceError(msg=f'No Site found') logger.debug(message) logger.debug(res) return json.loads(res.content.decode('utf-8')), message
def create_template(body): logger.debug("IN CREATE TEMPLATE") headers = {'content-type': "application/json"} json_req = {} json_req['id'] = body['template_id'] json_req['type'] = 'stream' json_req['script'] = body['script'] res = requests.post(conf.kapacitor_url + '/kapacitor/v1/templates', json=json_req, headers=headers, auth=HTTPBasicAuth(conf.kapacitor_username, conf.kapacitor_password), verify=False) logger.debug(res.content) logger.debug(res.status_code) if res.status_code == 200: body['create_time'] = str(datetime.datetime.utcnow()) body['last_updated'] = str(datetime.datetime.utcnow()) body['permissions'] = {'users': [g.username]} mtemplate_result, mtemplate_bug = t.meta.createDocument( db=conf.tenant[g.tenant_id]['stream_db'], collection='streams_templates_metadata', request_body=body, _tapis_debug=True) logger.debug("Status_Code: " + str(mtemplate_bug.response.status_code)) logger.debug(mtemplate_result) if str(mtemplate_bug.response.status_code) == '201': message = "Template Created in Meta" #get the newly created template object to return result, bug = get_template(body['template_id']) logger.debug(result) else: message = f'Template Creation in Meta Failed' #TODO Rollback- delete template in Kapacitor raise errors.ResourceError(msg=message) else: kapacitor_res_msg = res.content message = kapacitor_res_msg + f'Kapacitor Template Creation Failed' raise errors.ResourceError(msg=message) return result, message
def delete_site(id): path = "/sites/" + id + ".json" res = create_delete_request(path) #Chords returns a 204 so we can only return the response if (res.status_code == 204): message = "Site deleted" else: raise errors.ResourceError(msg=f'Site not deleted.') logger.debug(message) logger.debug(res) return res.content.decode('utf-8'), message
def get_measurements(instrument_id): #GET get all variables from chords service path = "/instruments/" + instrument_id + ".json" #"api/v1/data.json"; #start, end, instruments res = create_get_request(path) if (res.status_code == 200): message = "Measurement found" else: raise errors.ResourceError(msg=f'Measurements not found') logger.debug(message) logger.debug(res) return json.loads(res.content.decode('utf-8')), message
def post(self): validator = RequestValidator(utils.spec) result = validator.validate(FlaskOpenAPIRequest(request)) if result.errors: raise errors.ResourceError( msg=f'Invalid POST data: {result.errors}.') validated_body = result.body data = Client.get_derived_values(validated_body) client = Client(**data) db.session.add(client) db.session.commit() return utils.ok(result=client.serialize, msg="Client created successfully.")
def list_channels(): logger.debug('in Channel list ') result = t.meta.listDocuments(db=conf.tenant[g.tenant_id]['stream_db'], collection='streams_channel_metadata', filter='{"permissions.users":"' + g.username + '"}') logger.debug(result) if len(result.decode('utf-8')) > 0: message = "Channels found" else: raise errors.ResourceError(msg=f'No Channels found') logger.debug(result) return json.loads(result.decode('utf-8')), message
def get_token_from_callback(self, request): """ For the cii tenant, get the token directly from the callback URL. This function is only called by the CII tenant; other tenants do standard OAuth and pass an authorization code which is exchanged for the token. :param request: The request made to the Tapis callback URL. :return: """ if not self.ext_type == 'cii': msg = f'get_token_from_callback() called for a non-cii ext type; ext type: {self.ext_type}; ' \ f'This function should only be called by cii tenants. ' \ f'request: {request}.' logger.error(msg) raise errors.ResourceError( f"Program error; contact system administrators. " f"(Debug message: {msg})") # the CII OAuth server returns the access token in a URL query parameter, "token" self.access_token = request.args.get('token') if not self.access_token: msg = f"Did not get access token from CII callback. request args: {request.args}" raise errors.ResourceError() return self.access_token
def update_channel_status(channel_id, body): logger.debug('In update_channel_status') try: channel_result, msg = get_channel(channel_id) except Exception as e: msg = f" Channel {channel_id} NOT Found; exception: {e}" raise errors.ResourceError(msg=msg) logger.debug('UPDATING ... Kapacitor task status') result = {} meta_result = {} try: result, status_code = change_task_status(channel_result['channel_id'], body) except Exception as e: msg = f" Not able to connect to Kapacitor for the task {channel_result['channel_id']} status update; exception: {e}" raise errors.ResourceError(msg=msg) if status_code == 200: logger.debug("UPDATED ... Kapacitor task status ") logger.debug("UPDATING ... channel object in meta") logger.debug('status: ' + body['status']) # TODO Convert to Status Enum if result['status'] == 'enabled': channel_result['status'] = 'ACTIVE' elif result['status'] == 'disabled': channel_result['status'] = 'INACTIVE' else: channel_result['status'] = 'ERROR' channel_result['last_updated'] = str(datetime.datetime.utcnow()) meta_result, message = meta.update_channel(channel_result) else: str_result = result['error'] msg = f" Could Not Find Channel {channel_id} with Task {channel_result['channel_id']} kapacitor's response:{str_result} " logger.debug(msg) raise errors.ResourceError(msg=msg) return meta_result, message
def get(self): logger.debug('top of GET /ready') try: from service import models # if the service has no models at all, we assume the service is ready -- except ImportError: return utils.ok(result='', msg="Service is ready.") # any other exception though is likely a problem with the service -- except Exception as e: logger.error( f"Got exception in ready resource trying to import models; e: {e}." ) raise errors.ResourceError(msg=f'Service not ready') return utils.ok(result='', msg="Service is ready.")
def list_projects(): #get user role with permission ? logger.debug('in META list project') result = t.meta.listDocuments(db=conf.stream_db, collection='streams_project_metadata', filter='{"permissions.users":"' + g.username + '"}') logger.debug(result) if len(result.decode('utf-8')) > 0: message = "Projects found" else: raise errors.ResourceError(msg=f'No Projects found') logger.debug(result) return json.loads(result.decode('utf-8')), message
def get(self): try: status_kapacitor = kapacitor.ping() logger.debug('Kapacitor status') logger.debug(status_kapacitor) status_chords = chords.ping() logger.debug('Chords status') logger.debug(status_chords) status_influx = influx.ping() logger.debug('Influx status') logger.debug(status_influx) if (status_kapacitor == 204 and status_chords == 200 and status_influx == 204): return utils.ok(result='', msg=f'Service ready') except: raise errors.ResourceError(msg=f'Service not ready')
def get_template(template_id): logger.debug('In get_template') result = {} result = t.meta.listDocuments(db=conf.tenant[g.tenant_id]['stream_db'], collection='streams_templates_metadata', filter='{"template_id":"' + template_id + '"}') if len(result.decode('utf-8')) > 0: message = "Template found." template_result = json.loads(result.decode('utf-8'))[0] result = template_result logger.debug("TEMPLATE FOUND") else: logger.debug("NO TEMPLATE FOUND") raise errors.ResourceError(msg=f'No TEMPLATE found') return result, message
def get_channel(channel_id): logger.debug('In GET Channel' + channel_id) logger.debug(g.tenant_id) logger.debug(conf.tenant[g.tenant_id]['stream_db']) result = t.meta.listDocuments(db=conf.tenant[g.tenant_id]['stream_db'], collection='streams_channel_metadata', filter='{"channel_id":"' + channel_id + '"}') if len(result.decode('utf-8')) > 0: message = "Channel found." channel_result = json.loads(result.decode('utf-8'))[0] result = channel_result logger.debug("CHANNEL FOUND") else: logger.debug("NO CHANNEL FOUND") raise errors.ResourceError(msg=f'No Channel found') return result, message
def get_project(project_id): logger.debug('In GET Project') result = t.meta.listDocuments(db=conf.stream_db, collection='streams_project_metadata', filter='{"project_id":"' + project_id + '"}') logger.debug(result) if len(result.decode('utf-8')) > 0: logger.debug('PROJECT FOUND') message = "Project found." proj_result = json.loads(result.decode('utf-8'))[0] #proj_result.pop('_id') #proj_result.pop('_etag') result = proj_result else: logger.debug("NO PROJECT FOUND") raise errors.ResourceError(msg=f'No Project found') result = '' return result, message
def update_variable(id, variable: ChordsVariable): #TODO validate the variable has all properties requirement and fields are correct path = "/vars/" + str(id) + ".json" putData = { 'email': conf.chords_user_email, 'api_key': conf.chords_api_key, 'var[name]': variable.name, 'var[instrument_id]': variable.instrument_id, 'var[shortname]': variable.shortname } res = create_put_request(path, putData) if (res.status_code == 200): message = "Instrument updated" else: raise errors.ResourceError(msg=f'Variable not updated') logger.debug(message) logger.debug(res) return json.loads(res.content.decode('utf-8')), message