How to clean up the leftovers using pytest fixtures yield? - python

Currently if test will fail from any reason the objects which were created in AWS service catalog(SC) can stay there after test is finished due all failed asserts stop script, so clean few lines after cant be invoked.
Example of code:
product_name, result = launch_product(role, product, storagerole)
logger.info("Creating pod with storagerole: {}".format(storagerole))
assert result, 'Product ' + product + ' could not be launched by role ' + role + ' assuming role ' + storagerole
# Get part of pod unique name
for key in client.get_provisioned_product_outputs(ProvisionedProductName=product_name)["Outputs"]:
if key["OutputKey"] == 'SSH':
pod_unique_id = key["OutputValue"].split('-')[1]
# Pick up pod with selected unique name
querypod = "kubectl get po -n rstudio | grep " + pod_unique_id + " | awk 'END {print $1}'| tr -d '\n'"
launched_pod = subprocess.check_output(querypod, shell=True).decode()
logger.info("Checking pod: {}".format(launched_pod))
cmd = "kubectl -n rstudio exec " + launched_pod + " -- aws sts get-caller-identity"
try:
output = subprocess.check_output(cmd, shell=True).decode()
except subprocess.CalledProcessError as error:
logger.error("error: {}".format(error))
assert delete_product(role, product_name), 'Product ' + product_name + ' could not be deleted by role ' + role
assert False, error
try:
assert "assumed-role/" + storagerole + "/kiam-kiam" in output, 'Expected role ' + storagerole + ' was not assumed within container'
except AssertionError as error:
logger.error("error: {}".format(error))
assert delete_product(role, product_name), 'Product ' + product_name + ' could not be deleted by role ' + role
assert False, error
logger.info("All steps passed, deleting pod: {}".format(launched_pod))
assert delete_product(role, product_name), 'Product ' + product_name + ' could not be deleted by role ' + role
how can we make a solution to clean remains even if any assertion is failed using pytest fixtures?

Related

How to use session-manager-plugin command

I want to use session-manager-plugin in python code.
The code is written as follows
import boto3
from boto3.session import Session
import subprocess
AWS_REGION = "ap-northeast-1"
AWS_PROFILE = "default"
INSTANCE_ID = "i-XXXXX"
ssm = boto3.client('ssm')
response = ssm.start_session(
Target=INSTANCE_ID,
DocumentName='AWS-StartPortForwardingSession',
Parameters={
'portNumber': ['3389'],
'localPortNumber': ['13389'],
}
)
parameters = "{'DocumentName': 'AWS-StartPortForwardingSession', 'Target': "+INSTANCE_ID+", 'Parameters': {'portNumber': ['3389'], 'localPortNumber': ['13389']}}"
def start_aws_ssm_plugin(create_session_response, parameters, profile, region):
arg0 = '"' + 'session-manager-plugin' + '"'
arg1 = '"' + str(create_session_response).replace('\'', '\\"') + '"'
arg2 = region
arg3 = 'StartSession'
arg4 = profile
arg5 = '"' + str(parameters).replace('\'', '\\"') + '"'
arg6 = 'https://ssm.{region}.amazonaws.com'.format(region=region)
command = arg0 + ' ' + arg1 + ' ' + arg2 + ' ' + arg3 + ' ' + arg4 + ' ' + arg5 + ' ' + arg6
pid = subprocess.Popen(command).pid
return pid
start_aws_ssm_plugin(response, parameters, AWS_PROFILE, AWS_REGION)
But, the code gets an error.
panic: interface conversion: interface {} is nil, not string
goroutine 1 [running]:
github.com/aws/SSMCLI/src/sessionmanagerplugin/session.ValidateInputAndStartSession(0xc00010c000, 0x7, 0x8, 0x14c2380, 0xc000006018)
I wrote the code with reference to "https://stackoverflow.com/questions/65963897/how-do-i-use-the-results-of-an-ssm-port-forwarding-session-started-with-ruby/66043222#66043222"
If you have any information, please let me know.
Thank you
You seem to mess up quoting the two json arg strings. This works on Windows10:
import boto3
ssm = boto3.client('ssm')
instance_id = "i-XXXXX"
ssm_response = ssm.start_session(
Target=instance_id,
DocumentName='AWS-StartPortForwardingSession',
Parameters={"portNumber": ["8080"], "localPortNumber": ["9999"]}
)
cmd = [
'C:/Program Files/Amazon/SessionManagerPlugin/bin/session-manager-plugin.exe',
json.dumps(ssm_response),
'eu-central-1', # client region
'StartSession',
'default', # profile name from aws credentials/config files
json.dumps(dict(Target=instance_id)),
'https://ssm.eu-central-1.amazonaws.com' # endpoint for ssm service
]
subprocess.run(cmd)
The source https://github.com/aws/session-manager-plugin/blob/mainline/src/sessionmanagerplugin/session/session.go was helpful.
As I know you need call the start-session endpoint to get the streamurl, sessionid and token. Then call session-manager-plugin to forward tty.
https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_StartSession.html

Python custom exception not giving message in proper syntax

In the following code snippet, I get the response as -
__main__.CheckSumNotMatched: ('Kirti matches with - ', 'Kirti', ' . They are same.')
class CheckSumNotMatched(Exception):
"""Raised when the remote file's checksum doesn't match with local file checksum"""
pass
def test(name):
try:
if name=="Kirti":
error_msg = 'Kirti matches with - ', name, '. They are same. '
raise CheckSumNotMatched(error_msg)
except CheckSumNotMatched as csnm:
logger.error(csnm)
if __name__ == "__main__":
test("Kirti")
I want the response as -
__main__.CheckSumNotMatched: Kirti matches with - Kirti. They are same.
I don't want ( and ' in the response.
What should be the right way to do that?
you can replace
error_msg = 'Kirti matches with - ', name, '. They are same. '
with
error_msg = 'Kirti matches with - ' + name + '. They are same. '

How to get API call function that has multiple print statements to display in Flask?

I've got a Python script that checks an API for train data using requests and prints out relevant information based on information stored in dictionaries. This works fine in the console, but I'd like for it to be accessible online, for this I've been recommend to use Flask.
However, I can't get around using the Flask's function/returns in the routes to get the same output as I get in the console. I've gotten as far as getting the the requests module imported, but this throws up a HTTPError 400 when I use my actual code.
How would I go about getting the console output printed out into a page? Here is my current code:
import requests
import re
from darwin_token import DARWIN_KEY
jsonToken = DARWIN_KEY
train_station = {'work_station': 'whs', 'home_station': 'tth', 'connect_station': 'ecr'}
user_time = {'morning_time': ['0821', '0853'], 'evening_time': ['1733'], 'connect_time': ['0834', '0843']}
def darwinChecker(departure_station, arrival_station, user_time):
response = requests.get("https://huxley.apphb.com/all/" + str(departure_station) + "/to/" + str(arrival_station) + "/" + str(user_time), params={"accessToken": jsonToken})
response.raise_for_status() # this makes an error if something failed
data1 = response.json()
train_service = data1["trainServices"]
print('Departure Station: ' + str(data1['crs']))
print('Arrival Station: ' + str(data1['filtercrs']))
print('-' * 40)
try:
found_service = 0 # keeps track of services so note is generated if service not in user_time
for index, service in enumerate(train_service): # enumerate adds index value to train_service list
if service['sta'].replace(':', '') in user_time: # replaces sta time with values in user_time
found_service += 1 # increments for each service in user_time
print('Service RSID: ' + str(train_service[index]['rsid']))
print('Scheduled arrival time: ' + str(train_service[index]['sta']))
print('Scheduled departure time: ' + str(train_service[index]['std']))
print('Status: ' + str(train_service[index]['eta']))
print('-' * 40)
if service['eta'] == 'Cancelled':
print('The ' + str(train_service[index]['sta']) + ' service is cancelled.')
print('Previous train departure time: ' + str(train_service[index - 1]['sta']))
print('Previous train status: ' + str(train_service[index - 1]['eta']))
if found_service == 0: # if no service is found
print('The services currently available are not specified in user_time.')
except TypeError:
print('There is no train service data')
try:
NRCCRegex = re.compile('^(.*?)[\.!\?](?:\s|$)') # regex pulls all characters until hitting a . or ! or ?
myline = NRCCRegex.search(data1['nrccMessages'][0]['value']) # regex searches through nrccMessages
print('\nNRCC Messages: ' + myline.group(1) + '\n') # prints parsed NRCC message
except (TypeError, AttributeError) as error: # tuple catches multiple errors, AttributeError for None value
print('\nThere is no NRCC data currently available\n')
print('Morning Journey'.center(50, '='))
darwinChecker(train_station['home_station'], train_station['connect_station'], user_time['morning_time'])
The only thing I can think of is that I'd have to split each print statement in a function and a corresponding return?
Any help/clarification would be much appreciated!

Parsing JSON in Python

I have below query stored in a variable I got and I need to fetch value of 'resource_status'.
I need 'UPDATE_IN_PROGRESS'
As requested, putting the code here. The variable evntsdata is storing the events list.
try:
evntsdata = str(hc.events.list(stack_name)[0]).split(" ") # this is the variable that is getting the JSON response (or so)
#print(evntsdata[715:733])
#event_handle = evntsdata[715:733]
if event_handle == 'UPDATE_IN_PROGRESS':
loopcontinue = True
while loopcontinue:
evntsdata = str(hc.events.list(stack_name)[0]).split(" ")
#event_handle = evntsdata[715:733]
if (event_handle == 'UPDATE_COMPLETE'):
loopcontinue = False
print(str(timestamp()) + " " + "Stack Update is Completed!" + ' - ' + evntsdata[-3] + ' = ' + evntsdata[-1])
else:
print(str(timestamp()) + " " + "Stack Update in Progress!" + ' - ' + evntsdata[-3] + ' = ' + evntsdata[-1])
time.sleep(10)
else:
print("No updates to perform")
exit(0)
except AttributeError as e:
print(str(timestamp()) + " " + "ERROR: Stack Update Failure")
raise
print(evntsdata) has below result
['<Event', "{'resource_name':", "'Stackstack1',", "'event_time':", "'2017-05-26T12:10:43',", "'links':", "[{'href':", "'x',", "'rel':", "'self'},", "{'href':", "'x',", "'rel':", "'resource'},", "{'href':", "'x',", "'rel':", "'stack'}],", "'logical_resource_id':", "'Stackstack1',", "'resource_status':", "'UPDATE_IN_PROGRESS',", "'resource_status_reason':", "'Stack", 'UPDATE', "started',", "'physical_resource_id':", "'xxx',", "'id':", "'xxx'}>"]
Do not serialize and parse objects when the data is in front of you. This is inefficient and hard to understand and maintain. The solution is quite trivial:
data = hc.events.list(stack_name)[0].to_dict()
event_handle = data['resource_status']
It's not JSON, it's a class that you've printed
class Event(base.Resource):
def __repr__(self):
return "<Event %s>" % self._info
Try poking around the source code to get access to the dictionary self._info, then access your fields according
For example,
event_info = hc.events.list(stack_name)[0]._info
event_handle = event_info['resource_status']
Though, there may be another way like calling to_dict() instead, since the underscore indicates a private variable

Django logging with dynamic name

I'm trying to create logs in my django project, but i want a log with a different filename for each execution. What i did so far is set it up like it's written here, but this creates one log and puts everything in it. I want a log per execution with a dynamic name, like instance name + date or something. Can this be done?
Edit: Code example of creating a scheduled task. (I think you will get what it does from this)
def create_schedule (inst):
path_task=os.path.join(os.path.join(os.path.dirname(__file__),os.pardir),os.pardir)
path_task=path_task[:len(path_task)-2]+'executeInstance.py'
tr='"py '+path_task + ' ' + str(inst.id)+'"'
tn='Inst ' + str(inst.id)
time=inst.schedule.time
if inst.schedule.scheduleType=='Weekly':
w_days=''
for day in inst.schedule.weekDays.all():
if w_days!='':
w_days=w_days+','
w_days=w_days+day.weekDay[:3].upper()
tn='"'+tn+'"'
cmd_sch='schtasks /create /tn ' + tn + ' /tr ' + tr + ' /sc weekly /d '+ w_days + ' /st ' + time + ' /RU SYSTEM'
result = subprocess.check_output(cmd_sch, shell=True)
And then catching an exception in executeInstance.py
except smtplib.SMTPDataError as e:
status_log='Error'
error_desc='Message size too big for your email server'
inst=Instance.objects.get(id=instance_id)
log=Log(instance=inst,status=status_log,errorDesc=error_desc,executionDate=datetime.now())
log.save()
logger.error(log)
Maybe try to play with time rotated log files? https://docs.python.org/2.7/library/logging.handlers.html#rotatingfilehandler

Categories

Resources