Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Teardowndebug #26

Merged
merged 38 commits into from
May 5, 2017
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e4af557
import fix
jimbr70 Apr 24, 2017
a8bfa49
refactor fix
jimbr70 Apr 25, 2017
1a9829c
refactor fix
jimbr70 Apr 25, 2017
3b8733a
try/import correction to set var
jimbr70 Apr 25, 2017
6498acc
try/import correction to set var
jimbr70 Apr 25, 2017
35c71e5
refactor fix
jimbr70 Apr 25, 2017
487a17b
refactor fix
jimbr70 Apr 25, 2017
97fba27
removed a print
jimbr70 Apr 25, 2017
11585ba
sorted issue why this had to set env name previously. Now removed.
jimbr70 Apr 25, 2017
a002f36
Added test if blueprint name is empty - force error
jimbr70 Apr 25, 2017
1e63cec
message consistency and now uses self.sandbox.Blueprint_name to set n…
jimbr70 Apr 25, 2017
a4b0728
added test if pool = 0 then do not attempt to prpocess VMs
jimbr70 Apr 26, 2017
c0413a4
added test if pool = 0 then do not attempt to process network devices
jimbr70 Apr 26, 2017
e178657
just to help run debugging
jimbr70 Apr 26, 2017
30650ad
updated clear all resoruce live status to set the status to Info and …
jimbr70 Apr 26, 2017
43585fb
Added feature to email report_error conditions, using attributes in t…
jimbr70 Apr 26, 2017
56f6a10
created function to get the value of the attribute ending in ".Model"…
jimbr70 Apr 27, 2017
9e0d91c
edits, fixes to image_key and dict stuff relating to concrete name ve…
jimbr70 Apr 28, 2017
5a12d61
created function to get the value of the attribute ending in ".Model"…
jimbr70 Apr 28, 2017
62b03b7
fixes, updates for handling model attrib
jimbr70 Apr 28, 2017
3c3a210
change to
jimbr70 May 4, 2017
fa997dc
changes to fix isues with test config, adding environmentPath,
jimbr70 May 4, 2017
0312028
changes to fix isues with test config, adding environmentPath,
jimbr70 May 4, 2017
1c36302
cleaned appearance, added reporting info
jimbr70 May 4, 2017
c81fda8
added freeze_gun
jimbr70 May 4, 2017
50eeb9f
changes to init per yaniv
jimbr70 May 5, 2017
d1a20f2
Merged two ifs to one, per Yaniv
jimbr70 May 5, 2017
3bd9812
rename emailalert to _emailalert
jimbr70 May 5, 2017
fb30370
removed function for handling attribute or attribute ending in Model …
jimbr70 May 5, 2017
90860eb
Update .travis.yml
kalsky May 5, 2017
25ade05
Update Sandbox.py
kalsky May 5, 2017
1000180
Update Sandbox.py
kalsky May 5, 2017
3818b05
Update .travis.yml
kalsky May 5, 2017
3194c5a
Update test_requirements.txt
kalsky May 5, 2017
6eabbf1
Update Sandbox.py
kalsky May 5, 2017
32b9e6d
Revert "Update Sandbox.py"
kalsky May 5, 2017
4232efb
Reverted and removed the environment_path variable
kalsky May 5, 2017
b471401
Fixed code alignment
kalsky May 5, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import pip

try:
import gitlab
imported_gitlab = True
import gitlab
except:
try:
pip.main(["install","pyapi-gitlab"])
Expand Down Expand Up @@ -58,7 +58,6 @@ def download(self, source, destination):
try:
with open(destination,'w') as dest:
dest.write(filetext)
print "Downloaded: " + source
return 0, "Successfully retrieved file from repository and saved to destination"
except Exception as ex:
raise QualiError("GitLabClient","ERROR: Retrieved file from repository - failed to save to destination : " + str(ex.message))
29 changes: 19 additions & 10 deletions sandbox_scripts/QualiEnvironmentUtils/Resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ def __init__(self, resource_name, resource_alias=''):

self.attributes = self.details.ResourceAttributes
# If there is an attribute named 'model' take its value (exist in shells), otherwise take the family's model
if self.attribute_exist('Model'):
self.model = self.get_attribute('Model')
else:
self.model = self.details.ResourceModelName

self.model = self.get_attrib_value_ending_in_model()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use the previous logic now that you fixed the attribute_exist function

self.alias = resource_alias

# -----------------------------------------
Expand All @@ -45,17 +41,24 @@ def has_command(self, command_name):
def attribute_exist(self, attribute_name):
attribute_name = attribute_name.lower()
for attribute in self.attributes:
if attribute.Name.lower() == attribute_name:
if attribute.Name.lower() == attribute_name or attribute.Name.lower().endswith('.' + attribute_name):
return True
return False

# -----------------------------------------
# -----------------------------------------
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function is not needed anymore

def get_attrib_value_ending_in_model(self):
for attribute in self.attributes:
if attribute.Name.endswith('.Model'):
return str(attribute.Value)
return str(self.details.ResourceModelName)

# -----------------------------------------
# -----------------------------------------
def get_attribute(self, attribute_name):
attribute_name = attribute_name.lower()
for attribute in self.attributes:
if attribute.Name.lower() == attribute_name:
if attribute.Name.lower() == attribute_name or attribute.Name.lower().endswith('.' + attribute_name):
if attribute.Type == 'Password':
decrypted = self.api_session.DecryptPassword(attribute.Value)
return decrypted.Value
Expand All @@ -66,11 +69,17 @@ def get_attribute(self, attribute_name):
# -----------------------------------------
# -----------------------------------------
def set_attribute_value(self, attribute_name, attribute_value):
# if caller passes ending string of name, need to handle not knowing prefix
try:
self.api_session.SetAttributeValue(resourceFullPath=self.name, attributeName=attribute_name,
attributeValue=attribute_value)
attribute_name = attribute_name.lower()
for attribute in self.attributes:
if attribute.Name.lower() == attribute_name or attribute.Name.lower().endswith('.' + attribute_name):
self.api_session.SetAttributeValue(resourceFullPath=self.name,
attributeName=attribute.Name,
attributeValue=attribute_value)
return
except CloudShellAPIError as error:
raise QualiError(self.name, "Attribute: " + attribute_name + " not found. " + error.message)
raise QualiError(self.name, "Attribute named or ending-with: " + attribute_name + " not found. " + error.message)

# -----------------------------------------
# implement the command to get the neighbors and their ports
Expand Down
85 changes: 79 additions & 6 deletions sandbox_scripts/QualiEnvironmentUtils/Sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from cloudshell.core.logger.qs_logger import *
from cloudshell.helpers.scripts import cloudshell_scripts_helpers as helpers
from os.path import *
from time import gmtime, strftime
import smtplib
import socket
from email.mime.text import MIMEText


SEVERITY_INFO = 20
Expand All @@ -20,9 +24,10 @@ def __init__(self, reservation_id, logger):
""":type : logging.Logger"""
self.api_session = helpers.get_api_session()
self.id = reservation_id

self.owner = helpers.get_reservation_context_details().owner_user
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the get_reservation_context_details result should be saved into a variable and then from there, you can take the owner and environment instead of calling this function twice.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, now that we have the environmentPath, i would save it as well (self.environmentPath =..)

self.Blueprint_name = helpers.get_reservation_context_details().environment_name

if self.Blueprint_name == '':
raise QualiError("Blueprint name empty (from env name)")

full_path = None
tp = self.api_session.GetActiveTopologyNames()
Expand Down Expand Up @@ -53,19 +58,41 @@ def _write_message_to_output(self, message, severity_level=SEVERITY_INFO):
self.api_session.WriteMessageToReservationOutput(self.id, '<font color="red">' + message + '</font>')

# ----------------------------------
def report_error(self, error_message, log_message=None, raise_error=True, write_to_output_window=False):
def report_error(self, error_message, log_message=None, raise_error=True, write_to_output_window=False,
send_email=False):
"""
Report on an error to the log file, output window is optional.There is also an option to raise the error up
:param str error_message: The error message you would like to present
:param str log_message: The error message you would like to write to the log. Keep None to use the message param
:param bool raise_error: Do you want to throw an exception
:param bool write_to_output_window: Would you like to write the message to the output window
"""

emailresult = ''
if raise_error:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these 2 ifs can be one

if send_email:
emailOwner = False
try:
emailSubject = str(self.Blueprint_name) + ' / ' + str(self.owner)
emailBody = "Sandbox: " + str(self.Blueprint_name) + "\n" + \
"Owner: " + str(self.owner) + "\n\n"
sb_owner = str(self.owner)
except:
emailSubject = "Catastrophic ERROR in sandbox."
emailBody = str(os.environ) + "\n\n"
sb_owner = "Owner Unknown"

if log_message:
emailBody += "LogMsg: " + log_message + "\n\n"
if error_message:
emailBody += "ErrMsg: " + error_message + "\n\n"
emailresult = self.emailalert(emailSubject, emailBody, owner=sb_owner, ishtml=False, emailOwner=emailOwner) + "\n"

if self._logger:
if log_message:
self._logger.error(log_message)
self._logger.error(emailresult + log_message)
else:
self._logger.error(error_message)
self._logger.error(emailresult + error_message)
if write_to_output_window:
self._write_message_to_output(error_message, SEVERITY_ERROR)
if raise_error:
Expand All @@ -87,6 +114,51 @@ def report_info(self, message, log_message=None, write_to_output_window=False):
if write_to_output_window:
self._write_message_to_output(message, SEVERITY_INFO)

# ----------------------------------
def emailalert(self, subject, body, owner, ishtml=False, emailOwner=False):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change it to private (_email_alert)

try:
globalsresource = self.get_config_set_pool_resource()
host = str(globalsresource.get_attribute("ConfigPool_SMTP_Server"))
port = str(globalsresource.get_attribute("ConfigPool_SMTP_port"))
emailfrom = str(globalsresource.get_attribute("ConfigPool_SMTP_from"))
emailto = emailfrom
emailcc = ''
emailbcc = ''

if emailOwner:
try:
emailto = str(self.api_session.GetUserDetails(owner).Email)
emailbcc = emailfrom
body += "----\n A copy of this email was also sent to our support staff."
except:
emailbcc = ''
emailto = emailfrom

try:
if ishtml:
emsg = MIMEText(body + '\n\n', 'html')
else:
emsg = MIMEText(body + '\n\n', 'plain')

emsg['Subject'] = subject
emsg['From'] = emailfrom
emsg['To'] = ",".join([emailto])
emsg['CC'] = ""
emsg.preamble = subject
tolist = emailto.split(",") + emailcc.split(",") + emailbcc.split(",")
mailer = smtplib.SMTP(host=host, port=port)
mailer.sendmail(emailfrom, tolist, emsg.as_string())
return "Emailed OK"

except smtplib.SMTPException as e:
# cannot post again as error or we could be in a loop!
return ("ERROR Failed to send email, %s" % str(e))
except:
# cannot post again as error or we could be in a loop!
return "ERROR Failed to send email(1)"
except:
return "ERROR Failed to send email(2)"

# ----------------------------------
def get_root_resources(self):
"""
Expand Down Expand Up @@ -173,7 +245,8 @@ def clear_all_resources_live_status(self):
"""
root_resources = self.get_root_resources()
for resource in root_resources:
self.api_session.SetResourceLiveStatus(resource.name, '')
self.api_session.SetResourceLiveStatus(resource.name, liveStatusName="Info",
additionalInfo='status cleared ' + strftime("%H:%M:%S", gmtime()))

# ----------------------------------
# ----------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import tempfile
import pip


try:
import tftpy
imported_tftpy = True
import tftpy
except:
try:
pip.main(["install","tftpy"])
Expand Down
6 changes: 6 additions & 0 deletions sandbox_scripts/QualiEnvironmentUtils/StorageManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ def __init__(self, sandbox ):

# ----------------------------------
# ----------------------------------
#def _get_storage_client(self, storage_resource):
# if storage_resource.model.lower() == 'generic tftp server':
# return TFTPClient(self.sandbox,storage_resource)
# elif storage_resource.model.lower() == 'generic ftp server':
# return FTPClient(self.sandbox,storage_resource)

def _get_storage_client(self, storage_resource):
if storage_resource.model.lower() == 'generic tftp server':
return TFTPClient(self.sandbox,storage_resource)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import cloudshell.helpers.scripts.cloudshell_dev_helpers as dev_helpers
from sandbox_scripts.environment.setup.setup_resources import *

dev_helpers.attach_to_cloudshell_as(user="admin", password="dev", domain="Global",
reservation_id="d7be79c2-57d0-4063-9ada-e27cd3c608a7",
dev_helpers.attach_to_cloudshell_as(user="admin", password="xxx", domain="Global",
reservation_id="3a8cad5c-f197-4b1e-8739-70829957562f",
server_address="svl-dev-quali")
os.environ["environment_name"] = "Abstract-ALL"

x = EnvironmentSetupResources()
x.execute()
x.execute()
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import cloudshell.helpers.scripts.cloudshell_dev_helpers as dev_helpers
from sandbox_scripts.environment.teardown.teardown_resources import *

dev_helpers.attach_to_cloudshell_as(user="admin", password="xx", domain="Global",
reservation_id="bc0517e5-7240-4184-b04d-19e755f9c9a7",
server_address="svl-dev-quali")

x = EnvironmentTeardownResources()
x.execute()
9 changes: 6 additions & 3 deletions sandbox_scripts/QualiEnvironmentUtils/tests/test_Sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
import json
import os
from cloudshell.api.common_cloudshell_api import CloudShellAPIError
from freezegun import freeze_time

resContext = '''{"id":"5487c6ce-d0b3-43e9-8ee7-e27af8406905",
"ownerUser":"bob",
"ownerPass":"nIqm+BG6ZGJjby5hUittVFFJASc=",
"domain":"Global",
"environmentName":"My environment",
"environmentPath":"My environment",
"description":"New demo environment",
"parameters":
{ "globalInputs": [],
Expand Down Expand Up @@ -202,9 +204,10 @@ def test_clear_all_resources_live_status_two_devices(self,mock_resourcebase):
rr = [resource1, resource2]
self.sandbox.get_root_resources = Mock(return_value=rr)

self.sandbox.clear_all_resources_live_status()
calls = [call('r1', ''),
call('r2', '')]
with freeze_time("2017-01-17 12:00:01"):
self.sandbox.clear_all_resources_live_status()
calls = [call('r1', additionalInfo='status cleared 12:00:01', liveStatusName='Info'),
call('r2', additionalInfo='status cleared 12:00:01', liveStatusName='Info')]
self.mock_api_session.return_value.SetResourceLiveStatus.assert_has_calls(calls)

#================================================================
Expand Down
9 changes: 7 additions & 2 deletions sandbox_scripts/environment/setup/setup_VM.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from sandbox_scripts.helpers.Networking.NetworkingSaveNRestore import *
from cloudshell.helpers.scripts import cloudshell_scripts_helpers as helpers
from sandbox_scripts.helpers.Networking.save_restore_mgr import SaveRestoreManager
from sandbox_scripts.QualiEnvironmentUtils.Sandbox import SandboxBase
from cloudshell.core.logger.qs_logger import get_qs_logger
from multiprocessing.pool import ThreadPool
from threading import Lock


class EnvironmentSetupVM(object):
Expand All @@ -19,7 +24,7 @@ def execute(self):
reservation_details = self.sandbox.api_session.GetReservationDetails(self.reservation_id)

#TODO: don't use networking save and restore to figure if it's a snapshot setup
saveNRestoreTool = NetworkingSaveRestore(self.sandbox)
saveNRestoreTool = SaveRestoreManager(self.sandbox)
if saveNRestoreTool.get_storage_manager():
if saveNRestoreTool.is_snapshot():
self.is_snapshot = True
Expand Down
10 changes: 6 additions & 4 deletions sandbox_scripts/environment/teardown/teardown_VM.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from cloudshell.helpers.scripts import cloudshell_scripts_helpers as helpers
from cloudshell.core.logger import qs_logger
from sandbox_scripts.helpers.Networking.save_restore_mgr import SaveRestoreManager
from sandbox_scripts.QualiEnvironmentUtils.Sandbox import SandboxBase
from multiprocessing.pool import ThreadPool
from threading import Lock
from cloudshell.api.common_cloudshell_api import CloudShellAPIError

from cloudshell.core.logger import qs_logger

from sandbox_scripts.helpers.Networking.NetworkingSaveNRestore import *


class EnvironmentTeardownVM:
Expand All @@ -25,7 +27,7 @@ def execute(self):
reservation_details = self.sandbox.api_session.GetReservationDetails(self.reservation_id)


saveNRestoreTool = NetworkingSaveRestore(self.sandbox)
saveNRestoreTool = SaveRestoreManager(self.sandbox)

filename = "Snapshot_"+self.reservation_id+".txt"

Expand Down
12 changes: 8 additions & 4 deletions sandbox_scripts/environment/teardown/teardown_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from cloudshell.helpers.scripts import cloudshell_scripts_helpers as helpers
from sandbox_scripts.QualiEnvironmentUtils.Sandbox import SandboxBase
from sandbox_scripts.helpers.Networking.save_restore_mgr import SaveRestoreManager
from QualiUtils import QualiError
from sandbox_scripts.QualiEnvironmentUtils.QualiUtils import QualiError
import sys


class EnvironmentTeardownResources:
Expand All @@ -18,14 +19,17 @@ def execute(self):
sandbox = SandboxBase(self.reservation_id, self.logger)
saveNRestoreTool = SaveRestoreManager(sandbox)

sandbox.report_info("Beginning load configuration for resources")
sandbox.report_info("Beginning load baseline configuration for resources", write_to_output_window=True)
sandbox.clear_all_resources_live_status()
try:
if saveNRestoreTool.get_storage_manager():
ignore_models = ['Generic TFTP server', 'Config Set Pool', 'Generic FTP server', 'netscout switch 3912',
'OnPATH Switch 3903', 'Ixia Traffic generator', "SubNet-28", "SubNet-30", "GitLab"]
saveNRestoreTool.load_config(config_stage='Base', config_type='Running',
ignore_models=ignore_models, remove_temp_files=True, in_teardown_mode=True)
saveNRestoreTool.load_config(config_stage='Base',
config_type='Running',
ignore_models=ignore_models,
remove_temp_files=True,
in_teardown_mode=True)
else:
sandbox.report_info("Skipping load configuration. No storage resource associated with the blueprint ",
write_to_output_window=True)
Expand Down
Loading