def __init__(self, lambda_dir=None, env_file=None, env_vars=None, role=None): if not env_file or env_file == self.DEFAULT_ENV_FILE: env_file = os.getenv('LAMBDA_ENV_FILE', '.env') yaep.populate_env(env_file) if not lambda_dir or lambda_dir == self.DEFAULT_LAMBDA_DIR: lambda_dir = yaep.env('LAMBDA_DIRECTORY', self.DEFAULT_LAMBDA_DIR) if not env_vars: # If there were no env_vars passed, look for them # in the ENV_VARS environment variable, and return # an empty list if they aren't there. env_vars = map( lambda x: x.strip(), filter( None, yaep.env('LAMBDA_ENV_VARS', '').split(',') ) ) self.env_vars = env_vars self.lambda_dir = lambda_dir self.client = boto3.client('lambda') self.role = role if role else yaep.env('LAMBDA_ROLE')
def test_populate_env(self): env_file = io.BytesIO('foo = bar\nbaz = biz\nBOO = FAR') with monkey_patch(yaep.yaep, 'open', lambda fn: env_file): yaep.yaep.populate_env() assert (yaep.env('foo') == 'bar') assert (yaep.env('baz') == 'biz') assert (yaep.env('BOO') == 'FAR')
def verify_appid(appid=None): if env('SKILL_APPID') and appid: try: print "Verifying application ID..." verifier.verify_application_id(appid, env('SKILL_APPID')) except verifier.VerificationError as e: print e.args[0] raise
def verify_application_id(candidate): if env('SKILL_APPID'): try: print "Verifying application ID..." if candidate not in env('SKILL_APPID'): raise ValueError("Application ID verification failed") except ValueError as e: print e.args[0] raise
def run_cases(self, test_cases, boolean_map=None): for given, expected in test_cases: try: assert (yaep.env('YAEP_TEST_NOT_THERE', given, boolean_map) == expected) except AssertionError: print 'Error testing {} - expected {}, but got {}'.format( given, str(expected), str(yaep.env('YAEP_TEST_NOT_THERE', given))) raise
def verify_application_id(candidate): """ verify app id """ if env('SKILL_APPID'): try: print "Verifying application ID..." if candidate not in env('SKILL_APPID'): raise ValueError("Application ID verification failed") else: print "Application ID succesfully verified." except ValueError as e: print e.args[0] raise
def deploy(self, *lambdas): """Deploys lambdas to AWS""" if not self.role: logger.error('Missing AWS Role') raise ArgumentsError('Role required') logger.debug('Deploying lambda {}'.format(self.lambda_name)) zfh = self.package() if self.lambda_name in self.get_function_names(): logger.info('Updating {} lambda'.format(self.lambda_name)) response = self.client.update_function_code( FunctionName=self.lambda_name, ZipFile=zfh.getvalue(), Publish=True) else: logger.info('Adding new {} lambda'.format(self.lambda_name)) response = self.client.create_function( FunctionName=self.lambda_name, Runtime=yaep.env('LAMBDA_RUNTIME', 'python2.7'), Role=self.role, Handler=yaep.env('LAMBDA_HANDLER', 'lambda_function.lambda_handler'), Code={ 'ZipFile': zfh.getvalue(), }, Description=yaep.env( 'LAMBDA_DESCRIPTION', 'Lambda code for {}'.format(self.lambda_name)), Timeout=yaep.env('LAMBDA_TIMEOUT', 3, convert_booleans=False, type_class=int), MemorySize=yaep.env('LAMBDA_MEMORY_SIZE', 128, convert_booleans=False, type_class=int), Publish=True) status_code = response.get('ResponseMetadata', {}).get('HTTPStatusCode') if status_code in [200, 201]: logger.info('Successfully deployed {} version {}'.format( self.lambda_name, response.get('Version', 'Unkown'))) else: logger.error('Error deploying {}: {}'.format( self.lambda_name, response))
def wsgi_handler(environ, start_response): # Alexa requests come as POST messages with a request body try: length = int(environ.get('CONTENT_LENGTH', '0')) except ValueError: length = 0 if length > 0: # Get the request body and parse out the Alexa JSON request body = environ['wsgi.input'].read(length) alexa_msg = json.loads(body) alexa_session = alexa_msg['session'] alexa_request = alexa_msg['request'] appid = alexa_msg['session']['application']['applicationId'] print("wsgi_handler: applicationId=" + appid) # Verify the request is coming from Amazon and includes a valid signature. try: if env('SKILL_VERIFY_CERT'): print "Verifying certificate is valid..." cert_url = environ['HTTP_SIGNATURECERTCHAINURL'] signature = environ['HTTP_SIGNATURE'] cert = verifier.load_certificate(cert_url) verifier.verify_signature(cert, signature, body) timestamp = aniso8601.parse_datetime( alexa_request['timestamp']) verifier.verify_timestamp(timestamp) except verifier.VerificationError as e: print e.args[0] raise # Verify the application ID is what the user expects verify_application_id(appid) if alexa_session['new']: on_session_started({'requestId': alexa_request['requestId']}, alexa_session) if alexa_request['type'] == 'LaunchRequest': # This is the type when you just say "Open <app>" response = prepare_help_message() elif alexa_request['type'] == 'IntentRequest': response = on_intent(alexa_request, alexa_session) else: response = build_alexa_response( "I received an unexpected request type.") start_response('200 OK', [('Content-Type', 'application/json'), ('Content-Length', str(len(json.dumps(response))))]) return [json.dumps(response)] else: # This should never happen with a real Echo request but could happen # if your URL is accessed by a browser or otherwise. start_response('502 No content', []) return ['']
def package(self, name): """Packages lambda data for deployment into a zip""" logger.info('Packaging lambda {}'.format(name)) src_dir = os.path.join(self.lambda_dir, name) zfh = io.BytesIO() with zipfile.ZipFile(zfh, 'w') as zf: self.add_directory_to_zip(src_dir, zf) # Construct a .env file in the archive with our # needed envrionment variables. envinfo = zipfile.ZipInfo('.env') envinfo.external_attr = 0644 << 16L zf.writestr( envinfo, '\n'.join( '{} = {}'.format(key, yaep.env(key)) for key in self.env_vars ) ) if 'requirements.txt' in os.listdir(src_dir): with TemporaryDirectory() as temp_dir: pip_args = [ 'install', '-r', os.path.join(src_dir, 'requirements.txt'), '-t', temp_dir ] # Do pip install to temporary dir if pip.main(pip_args) == 0: self.add_directory_to_zip(temp_dir, zf) else: if sys.platform == 'darwin': logger.error( 'A DistutilsOptionError about the prefix ' 'can occur when you are on OS X and ' 'installed Python via Homebrew.\nIf this ' 'is you, please look at https://github.com' '/Homebrew/brew/blob/master/share/doc/' 'homebrew/Homebrew-and-Python.md' '#note-on-pip-install---user\n' 'If this is not you, please contact us ' ' for support.' ) raise DependencyInstallationError( 'Failed to install dependencies of {}'.format( name ) ) zfh.seek(0) return zfh
def __init__(self, lambda_dir=None, env_file=None, env_vars=None, role=None, name=None): if not env_file or env_file == self.DEFAULT_ENV_FILE: env_file = os.path.realpath(os.getenv('LAMBDA_ENV_FILE', '.env')) else: # If they've specified a .env file, let's ensure it's there: env_file = os.path.realpath(env_file) if not os.path.exists(env_file): logger.error( 'Can\'t find Lambda env file at {}'.format(env_file) ) raise ArgumentsError('Cannot find Env file') # Now load the .env file if it exists. if os.path.exists(env_file): yaep.populate_env(env_file) if not lambda_dir or lambda_dir == self.lambda_dir: lambda_dir = yaep.env('LAMBDA_DIRECTORY', self.lambda_dir) if not env_vars: # If there were no env_vars passed, look for them # in the ENV_VARS environment variable, and return # an empty list if they aren't there. env_vars = map( lambda x: x.strip(), filter( None, yaep.env('LAMBDA_ENV_VARS', '').split(',') ) ) self.env_vars = env_vars self.lambda_dir = lambda_dir self.lambda_name = name if name else yaep.env( 'LAMBDA_NAME', os.path.basename(os.path.normpath(self.lambda_dir)) ) self.role = role if role else yaep.env('LAMBDA_ROLE') self.client = boto3.client('lambda')
def __init__(self, lambda_dir=None, env_file=None, env_vars=None, role=None, name=None): if not env_file or env_file == self.DEFAULT_ENV_FILE: env_file = os.path.realpath(os.getenv('LAMBDA_ENV_FILE', '.env')) else: # If they've specified a .env file, let's ensure it's there: env_file = os.path.realpath(env_file) if not os.path.exists(env_file): logger.error( 'Can\'t find Lambda env file at {}'.format(env_file)) raise ArgumentsError('Cannot find Env file') # Now load the .env file if it exists. if os.path.exists(env_file): yaep.populate_env(env_file) if not lambda_dir or lambda_dir == self.lambda_dir: lambda_dir = yaep.env('LAMBDA_DIRECTORY', self.lambda_dir) if not env_vars: # If there were no env_vars passed, look for them # in the ENV_VARS environment variable, and return # an empty list if they aren't there. env_vars = map( lambda x: x.strip(), filter(None, yaep.env('LAMBDA_ENV_VARS', '').split(','))) self.env_vars = env_vars self.lambda_dir = lambda_dir self.lambda_name = name if name else yaep.env( 'LAMBDA_NAME', os.path.basename(os.path.normpath(self.lambda_dir))) self.role = role if role else yaep.env('LAMBDA_ROLE') self.client = boto3.client('lambda')
def test_sticky(self): assert (os.getenv('FOOC') is None) yaep.env('FOOC', 'bar', sticky=True) assert (os.getenv('FOOC') == 'bar')
def test_not_in_env(self): assert (yaep.env('FOOA') is None)
def deploy(self, *lambdas): """Deploys lambdas to AWS""" if not self.role: logger.error('Missing AWS Role') raise ArgumentsError('Role required') logger.debug('Deploying lambda {}'.format(self.lambda_name)) zfh = self.package() if self.lambda_name in self.get_function_names(): logger.info('Updating {} lambda'.format(self.lambda_name)) response = self.client.update_function_code( FunctionName=self.lambda_name, ZipFile=zfh.getvalue(), Publish=True ) else: logger.info('Adding new {} lambda'.format(self.lambda_name)) response = self.client.create_function( FunctionName=self.lambda_name, Runtime=yaep.env( 'LAMBDA_RUNTIME', 'python2.7' ), Role=self.role, Handler=yaep.env( 'LAMBDA_HANDLER', 'lambda_function.lambda_handler' ), Code={ 'ZipFile': zfh.getvalue(), }, Description=yaep.env( 'LAMBDA_DESCRIPTION', 'Lambda code for {}'.format(self.lambda_name) ), Timeout=yaep.env( 'LAMBDA_TIMEOUT', 3, convert_booleans=False, type_class=int ), MemorySize=yaep.env( 'LAMBDA_MEMORY_SIZE', 128, convert_booleans=False, type_class=int ), Publish=True ) status_code = response.get( 'ResponseMetadata', {} ).get('HTTPStatusCode') if status_code in [200, 201]: logger.info('Successfully deployed {} version {}'.format( self.lambda_name, response.get('Version', 'Unkown') )) else: logger.error('Error deploying {}: {}'.format( self.lambda_name, response ))
def test_type_class(self): os.environ['FOOE'] = '5' assert (yaep.env('FOOE') == '5') assert (yaep.env('FOOE', type_class=int) == 5)
def test_raise_unset_exception(self): with self.assertRaises(yaep.exceptions.UnsetException): yaep.env('BEER', default=yaep.exceptions.UnsetException)
def package(self): """Packages lambda data for deployment into a zip""" logger.info('Packaging lambda {}'.format(self.lambda_name)) zfh = io.BytesIO() if os.path.exists(os.path.join(self.lambda_dir, '.env')): logger.warn( 'A .env file exists in your Lambda directory - be ' 'careful that it does not contain any secrets you ' 'don\'t want uploaded to AWS!' ) with zipfile.ZipFile(zfh, 'w') as zf: self.add_directory_to_zip(self.lambda_dir, zf) # Construct a .env file in the archive with our # needed envrionment variables. envinfo = zipfile.ZipInfo('.env') envinfo.external_attr = 0644 << 16L zf.writestr( envinfo, '\n'.join( '{} = {}'.format(key, yaep.env(key)) for key in self.env_vars ) ) if 'requirements.txt' in os.listdir(self.lambda_dir): with TemporaryDirectory() as temp_dir: pip_args = [ 'install', '-r', os.path.join(self.lambda_dir, 'requirements.txt'), '-t', temp_dir ] # Do pip install to temporary dir if pip.main(pip_args) == 0: self.add_directory_to_zip(temp_dir, zf) else: if sys.platform == 'darwin': logger.error( 'A DistutilsOptionError about the prefix ' 'can occur when you are on OS X and ' 'installed Python via Homebrew.\nIf this ' 'is you, please look at https://github.com' '/Homebrew/brew/blob/master/share/doc/' 'homebrew/Homebrew-and-Python.md' '#note-on-pip-install---user\n' 'If this is not you, please contact us ' ' for support.' ) raise DependencyInstallationError( 'Failed to install dependencies of {}'.format( self.lambda_name ) ) zfh.seek(0) return zfh
def test_default(self): assert (yaep.env('FOOB', 'bar') == 'bar')
def deploy(self, *lambdas): """Deploys lambdas to AWS""" if not self.role: raise ArgumentsError('Role required') lambda_dirs = filter( lambda dir: ( os.path.isdir(dir) and (not lambdas or dir in lambdas) and not dir.startswith('.') ), os.listdir(self.lambda_dir) ) for missing in [m for m in lambdas if m not in lambda_dirs]: logger.warn('Lambda {} not found, skipping.'.format(missing)) for lambda_name in lambda_dirs: logger.debug('Deploying lambda {}'.format(lambda_name)) zfh = self.package(lambda_name) if lambda_name in self.get_function_names(): logger.info('Updating {} lambda'.format(lambda_name)) response = self.client.update_function_code( FunctionName=lambda_name, ZipFile=zfh.getvalue(), Publish=True ) else: logger.info('Adding new {} lambda'.format(lambda_name)) response = self.client.create_function( FunctionName=lambda_name, Runtime=yaep.env( 'LAMBDA_RUNTIME', 'python2.7' ), Role=self.role, Handler=yaep.env( 'LAMBDA_HANDLER', 'lambda_function.lambda_handler' ), Code={ 'ZipFile': zfh.getvalue(), }, Description=yaep.env( 'LAMBDA_DESCRIPTION', 'Lambda code for {}'.format(lambda_name) ), Timeout=yaep.env( 'LAMBDA_TIMEOUT', 3, convert_booleans=False, type_class=int ), MemorySize=yaep.env( 'LAMBDA_MEMORY_SIZE', 128, convert_booleans=False, type_class=int ), Publish=True ) status_code = response.get( 'ResponseMetadata', {} ).get('HTTPStatusCode') if status_code in [200, 201]: logger.info('Successfully deployed {} version {}'.format( lambda_name, response.get('Version', 'Unkown') )) else: logger.error('Error deploying {}: {}'.format( lambda_name, response ))
def verify_appid(appid=None): if appid != env('SKILL_APPID'): raise ValueError("Invalid Application ID")
def test_convert_boolean(self): yaep.env('FOOD', 'True', sticky=True) assert (yaep.env('FOOD') is True) assert (yaep.env('FOOD', convert_booleans=False) == 'True')