import os import sys import requests import ast import json import datetime import yaml import newrelic.agent requests.packages.urllib3.disable_warnings() newrelic.agent.initialize( os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'veda_newrelic.ini' ) ) """ Send data to VAL, either Video ID data or endpoint URLs """ ''' "upload": _UPLOADING, "ingest": _IN_PROGRESS, "transcode_queue": _IN_PROGRESS, "transcode_active": _IN_PROGRESS, "file_delivered": _COMPLETE, "file_complete": _COMPLETE, "file_corrupt": _FAILED, "pipeline_error": _FAILED, "invalid_token": _INVALID_TOKEN, "duplicate" : _DUPLICATE, "imported": _IMPORTED, ''' from control_env import * from control.veda_utils import ErrorObject, Output class VALAPICall(): def __init__(self, video_proto, val_status, **kwargs): """VAL Data""" self.val_status = val_status self.platform_course_url = kwargs.get('platform_course_url', []) """VEDA Data""" self.video_proto = video_proto self.video_object = kwargs.get('video_object', None) self.encode_profile = kwargs.get('encode_profile', None) """if sending urls""" self.endpoint_url = kwargs.get('endpoint_url', None) self.encode_data = [] self.val_profile = None """Generated""" self.val_token = None self.val_data = None self.headers = None """Credentials""" self.auth_yaml = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'instance_config.yaml' ) self.auth_dict = self._AUTH() @newrelic.agent.background_task() def call(self): if self.auth_dict is None: print 'No AUTH' return None """ Errors covered in other methods """ if self.val_token is None: self.val_tokengen() if self.video_object is not None: self.send_object_data() if self.video_proto is not None: self.send_val_data() def _AUTH(self): if not os.path.exists(self.auth_yaml): ErrorObject.print_error( message='No Auth YAML' ) return None with open(self.auth_yaml, 'r') as stream: try: auth_dict = yaml.load(stream) return auth_dict except yaml.YAMLError as exc: ErrorObject.print_error( message='YAML READ ERROR' ) return None @newrelic.agent.background_task() def val_tokengen(self): """ Generate a API token for VAL """ payload = { 'grant_type': 'password', 'client_id': self.auth_dict['val_client_id'], 'client_secret': self.auth_dict['val_secret_key'], 'username': self.auth_dict['val_username'], 'password': self.auth_dict['val_password'], } r = requests.post(self.auth_dict['val_token_url'], data=payload, timeout=20) if r.status_code != 200: ErrorObject.print_error( message='Token Gen Fail: VAL\nCheck VAL Config' ) return None self.val_token = ast.literal_eval(r.text)['access_token'] self.headers = { 'Authorization': 'Bearer ' + self.val_token, 'content-type': 'application/json' } def send_object_data(self): """ Rather than rewrite the protocol to fit the veda models, we'll shoehorn the model into the VideoProto model """ class VideoProto(): platform_course_url = [] self.video_proto = VideoProto() self.video_proto.s3_filename = self.video_object.studio_id self.video_proto.veda_id = self.video_object.edx_id self.video_proto.client_title = self.video_object.client_title if self.video_proto.client_title is None: self.video_proto.client_title = '' self.video_proto.duration = self.video_object.video_orig_duration self.send_val_data() def send_val_data(self): """ VAL is very tetchy -- it needs a great deal of specific info or it will fail """ ''' sending_data = { encoded_videos = [{ url="https://testurl.mp4", file_size=8499040, bitrate=131, profile="override", }, {...},], client_video_id = "This is a VEDA-VAL Test", courses = [ "TEST", "..." ], duration = 517.82, edx_video_id = "TESTID", status = "transcode_active" } ## "POST" for new objects to 'video' root url ## "PUT" for extant objects to video/id -- cannot send duplicate course records ''' if self.val_token is None: return False if self.video_proto.s3_filename is None or \ len(self.video_proto.s3_filename) == 0: self.video_proto.val_id = self.video_proto.veda_id else: self.video_proto.val_id = self.video_proto.s3_filename if self.val_status != 'invalid_token': self.video_object = Video.objects.filter( edx_id=self.video_proto.veda_id ).latest() """ Data Cleaning """ if self.video_proto.platform_course_url is None: self.video_proto.platform_course_url = [] if not isinstance(self.video_proto.platform_course_url, list): self.video_proto.platform_course_url = [self.video_proto.platform_course_url] try: self.video_object.video_orig_duration except NameError: self.video_object.video_orig_duration = 0 self.video_object.duration = 0.0 if not isinstance(self.video_proto.duration, float): self.video_proto.duration = Output._seconds_from_string( duration=self.video_object.video_orig_duration ) """ Sort out courses """ val_courses = [] if self.val_status != 'invalid_token': for f in self.video_object.inst_class.local_storedir.split(','): if f.strip() not in val_courses: val_courses.append({f.strip(): None}) if len(val_courses) == 0: for g in self.video_proto.platform_course_url: if g.strip() not in val_courses: val_courses.append({g.strip(): None}) self.val_data = { 'client_video_id': self.video_proto.client_title, 'duration': self.video_proto.duration, 'edx_video_id': self.video_proto.val_id, 'courses': val_courses } r1 = requests.get( '/'.join(( self.auth_dict['val_api_url'], self.video_proto.val_id )), headers=self.headers, timeout=20 ) if r1.status_code != 200 and r1.status_code != 404: ErrorObject.print_error( message='R1 : VAL Communication Fail: VAL\nCheck VAL Config' ) return None if r1.status_code == 404: self.send_404() elif r1.status_code == 200: val_api_return = ast.literal_eval(r1.text.replace('null', 'None')) self.send_200(val_api_return) """ Update Status """ url_query = URL.objects.filter( videoID=Video.objects.filter( edx_id=self.video_proto.veda_id ) ) for u in url_query: URL.objects.filter(pk=u.pk).update(val_input=True) def profile_determiner(self, val_api_return): """ Determine VAL profile data, from return/encode submix """ if self.endpoint_url is not None: for p in self.auth_dict['val_profile_dict'][self.encode_profile]: self.encode_data.append(dict( url=self.endpoint_url, file_size=self.video_proto.filesize, bitrate=int(self.video_proto.bitrate.split(' ')[0]), profile=p )) test_list = [] if self.video_proto.veda_id is not None: url_query = URL.objects.filter( videoID=Video.objects.filter( edx_id=self.video_proto.veda_id ).latest() ) for u in url_query: final = URL.objects.filter( encode_profile=u.encode_profile, videoID=u.videoID ).latest() if final.encode_profile.product_spec == 'review': pass else: for p in self.auth_dict['val_profile_dict'][final.encode_profile.product_spec]: test_list.append(dict( url=str(final.encode_url), file_size=final.encode_size, bitrate=int(final.encode_bitdepth.split(' ')[0]), profile=str(p) )) for t in test_list: if t['profile'] not in [g['profile'] for g in self.encode_data]: self.encode_data.append(t) if len(val_api_return) == 0: return None """ All URL Records Deleted (for some reason) """ if len(self.encode_data) == 0: return None for i in val_api_return['encoded_videos']: if i['profile'] not in [g['profile'] for g in self.encode_data]: self.encode_data.append(i) return None def send_404(self): """ Generate new VAL ID """ self.profile_determiner(val_api_return=[]) self.val_data['status'] = self.val_status if len(self.encode_data) == 0 and self.val_status is 'file_complete': return None sending_data = dict( encoded_videos=self.encode_data, **self.val_data ) r2 = requests.post( self.auth_dict['val_api_url'] + '/', data=json.dumps(sending_data), headers=self.headers, timeout=20 ) if r2.status_code > 299: ErrorObject.print_error( message='%s\n %s\n %s\n' % ( 'R2 : VAL POST/PUT Fail: VAL', 'Check VAL Config', r2.status_code ) ) def send_200(self, val_api_return): """ VAL ID is previously extant just update --- VAL will not allow duped studio urls to be sent, so we must scrub the data """ for retrieved_course in val_api_return['courses']: for course in list(self.val_data['courses']): if retrieved_course.keys() == course.keys(): self.val_data['courses'].remove(course) self.profile_determiner(val_api_return=val_api_return) self.val_data['status'] = self.val_status """ Double check for profiles in case of overwrite """ sending_data = dict( encoded_videos=self.encode_data, **self.val_data ) """ Make Request, finally """ if len(self.encode_data) == 0 and self.val_status is 'file_complete': return None r4 = requests.put( '/'.join(( self.auth_dict['val_api_url'], self.video_proto.val_id, )), data=json.dumps(sending_data), headers=self.headers, timeout=20 ) if r4.status_code > 299: ErrorObject.print_error( message='%s\n %s\n %s\n' % ( 'R4 : VAL POST/PUT Fail: VAL', 'Check VAL Config', r4.status_code ) ) def main(): pass if __name__ == '__main__': sys.exit(main())