From e4af557cef773166b0a919d9de4bc8ff54c763cb Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Mon, 24 Apr 2017 11:00:46 -0700 Subject: [PATCH 01/38] import fix --- sandbox_scripts/environment/teardown/teardown_resources.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sandbox_scripts/environment/teardown/teardown_resources.py b/sandbox_scripts/environment/teardown/teardown_resources.py index 45d5416..555be79 100644 --- a/sandbox_scripts/environment/teardown/teardown_resources.py +++ b/sandbox_scripts/environment/teardown/teardown_resources.py @@ -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: From a8bfa4936187846077d1fc5594fcbbf6923214cf Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Tue, 25 Apr 2017 09:52:56 -0700 Subject: [PATCH 02/38] refactor fix --- sandbox_scripts/helpers/Networking/save_restore_mgr.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sandbox_scripts/helpers/Networking/save_restore_mgr.py b/sandbox_scripts/helpers/Networking/save_restore_mgr.py index 84fc425..dc219b5 100644 --- a/sandbox_scripts/helpers/Networking/save_restore_mgr.py +++ b/sandbox_scripts/helpers/Networking/save_restore_mgr.py @@ -45,4 +45,9 @@ def get_storage_manager(self): # Is this Sandbox originates from a snapshot Blueprint? # ---------------------------------- def is_snapshot(self,fileName = " "): - return self.vm_save_restore.is_snapshot(fileName) \ No newline at end of file + return self.vm_save_restore.is_snapshot(fileName) + + # ---------------------------------- + # ---------------------------------- + def delete_src_file(self, fileName): + self.vm_save_restore.delete_src_file(fileName) \ No newline at end of file From 1a9829c3a89d13b9e397508000706c7f1f788dd8 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Tue, 25 Apr 2017 09:53:09 -0700 Subject: [PATCH 03/38] refactor fix --- .../helpers/Networking/vm_save_restore.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sandbox_scripts/helpers/Networking/vm_save_restore.py b/sandbox_scripts/helpers/Networking/vm_save_restore.py index c4056e3..ac6f62a 100644 --- a/sandbox_scripts/helpers/Networking/vm_save_restore.py +++ b/sandbox_scripts/helpers/Networking/vm_save_restore.py @@ -283,4 +283,15 @@ def _get_concrete_config_file_path(self, root_path, resource, config_stage, writ # Set the path to the new concrete file config_path = concrete_file_path - return config_path \ No newline at end of file + return config_path + + + # ---------------------------------- + # delete file name on storage + # ---------------------------------- + def delete_src_file(self,fileName): + + env_dir = self.config_files_root + '/Snapshots/' + fileName + env_dir = env_dir.replace(' ', '_') + self.storage_mgr.delete(env_dir) + From 3b8733aa2212d5bcf5960610aea2c26ad0afefc6 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Tue, 25 Apr 2017 11:08:28 -0700 Subject: [PATCH 04/38] try/import correction to set var --- .../QualiEnvironmentUtils/RepositoryClients/GitLabClient.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/RepositoryClients/GitLabClient.py b/sandbox_scripts/QualiEnvironmentUtils/RepositoryClients/GitLabClient.py index c1aaf14..7b66955 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/RepositoryClients/GitLabClient.py +++ b/sandbox_scripts/QualiEnvironmentUtils/RepositoryClients/GitLabClient.py @@ -4,8 +4,8 @@ import pip try: - import gitlab imported_gitlab = True + import gitlab except: try: pip.main(["install","pyapi-gitlab"]) From 6498acc6945d0d59d1c9fce819b9e43e7837dc0b Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Tue, 25 Apr 2017 11:08:40 -0700 Subject: [PATCH 05/38] try/import correction to set var --- .../QualiEnvironmentUtils/StorageClients/TFTPClient.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/StorageClients/TFTPClient.py b/sandbox_scripts/QualiEnvironmentUtils/StorageClients/TFTPClient.py index c9fabbe..12de9e1 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/StorageClients/TFTPClient.py +++ b/sandbox_scripts/QualiEnvironmentUtils/StorageClients/TFTPClient.py @@ -5,9 +5,10 @@ import tempfile import pip + try: - import tftpy imported_tftpy = True + import tftpy except: try: pip.main(["install","tftpy"]) From 35c71e5add5bf4e0ac8db44cca203ac370ca8dff Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Tue, 25 Apr 2017 11:10:50 -0700 Subject: [PATCH 06/38] refactor fix --- sandbox_scripts/environment/setup/setup_VM.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sandbox_scripts/environment/setup/setup_VM.py b/sandbox_scripts/environment/setup/setup_VM.py index 5daa1cc..887d22b 100644 --- a/sandbox_scripts/environment/setup/setup_VM.py +++ b/sandbox_scripts/environment/setup/setup_VM.py @@ -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): @@ -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 From 487a17b55aa25225cd942bdb2f8f7adc840d0a5e Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Tue, 25 Apr 2017 11:11:29 -0700 Subject: [PATCH 07/38] refactor fix --- sandbox_scripts/environment/teardown/teardown_VM.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sandbox_scripts/environment/teardown/teardown_VM.py b/sandbox_scripts/environment/teardown/teardown_VM.py index 6b2651f..0fe67a3 100644 --- a/sandbox_scripts/environment/teardown/teardown_VM.py +++ b/sandbox_scripts/environment/teardown/teardown_VM.py @@ -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: @@ -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" From 97fba27fbf4f63c0b2f30261ca2d10a6baf9e01b Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Tue, 25 Apr 2017 15:12:09 -0700 Subject: [PATCH 08/38] removed a print --- .../QualiEnvironmentUtils/RepositoryClients/GitLabClient.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/RepositoryClients/GitLabClient.py b/sandbox_scripts/QualiEnvironmentUtils/RepositoryClients/GitLabClient.py index 7b66955..3cc4490 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/RepositoryClients/GitLabClient.py +++ b/sandbox_scripts/QualiEnvironmentUtils/RepositoryClients/GitLabClient.py @@ -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)) From 11585ba6f7ee5ed61bfd1972dc757532aaab8299 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Tue, 25 Apr 2017 15:13:07 -0700 Subject: [PATCH 09/38] sorted issue why this had to set env name previously. Now removed. --- .../tests/DebugInteractive_setup_resources.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/tests/DebugInteractive_setup_resources.py b/sandbox_scripts/QualiEnvironmentUtils/tests/DebugInteractive_setup_resources.py index aeb2201..80bb02d 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/tests/DebugInteractive_setup_resources.py +++ b/sandbox_scripts/QualiEnvironmentUtils/tests/DebugInteractive_setup_resources.py @@ -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() \ No newline at end of file +x.execute() From a002f3664531c4bd817e54896e8874777f7fa705 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Tue, 25 Apr 2017 15:13:43 -0700 Subject: [PATCH 10/38] Added test if blueprint name is empty - force error --- sandbox_scripts/QualiEnvironmentUtils/Sandbox.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index efe0eb5..79877aa 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -20,9 +20,9 @@ def __init__(self, reservation_id, logger): """:type : logging.Logger""" self.api_session = helpers.get_api_session() self.id = reservation_id - 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() From 1e63cec9c7c101311526b58f782d8b340ec79308 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Tue, 25 Apr 2017 15:15:28 -0700 Subject: [PATCH 11/38] message consistency and now uses self.sandbox.Blueprint_name to set name vs os.environ var --- .../Networking/NetworkingSaveNRestore.py | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py b/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py index 37d6d8a..181aabf 100644 --- a/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py +++ b/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py @@ -57,9 +57,10 @@ def load_config(self, config_stage, config_type, restore_method="Override", conf :param list[str] ignore_models: Optional. Models that should be ignored and not load config on the device :param bool write_to_output: Optional. should messages be sent to the command output. """ + #self.sandbox.report_info(str(os.environ),write_to_output_window=False) root_path = '' if config_stage.lower() == 'gold' or config_stage.lower() == 'snapshots': - root_path = self.config_files_root + '/' + config_stage + '/' + os.environ["environment_name"].strip() + '/' + root_path = self.config_files_root + '/' + config_stage + '/' + self.sandbox.Blueprint_name + '/' elif config_stage.lower() == 'base': root_path = self.config_files_root + '/' + config_stage + '/' if config_set_name != '': @@ -123,6 +124,7 @@ def _run_asynch_load(self, resource, images_path_dict, root_path, ignore_models, load_config_to_device = self._is_load_config_to_device(resource, ignore_models=ignore_models) if load_config_to_device: + self.sandbox.report_info(resource.name + " starting health check", write_to_output_window=True) health_check_result = resource.health_check(self.sandbox.id) if health_check_result == "": self.sandbox.report_info(resource.name + " -- Initial Health Check Passed.") @@ -155,30 +157,30 @@ def _run_asynch_load(self, resource, images_path_dict, root_path, ignore_models, image_key = resource.model.replace(' ', '_') dict_img_version = images_path_dict[image_key].version # same image version - Only load config (running override) - message += "\nLoading configuration for device: " + resource.name + " from:" + config_path + message += "\n" + resource.name + ": loading configuration from: " + config_path if dict_img_version.lower() == version.lower(): resource.load_network_config(self.sandbox.id, config_path=config_path, config_type='Running', restore_method='Override') # Different image - Load config to the RUNNING ALSO and load the image else: - message += "\nLoading configuration for device: " + resource.name + " from:" + config_path + message += "\n" + resource.name + ": loading configuration from:" + config_path resource.load_network_config(self.sandbox.id, config_path, config_type='Running', restore_method='Override') resource_image_path = images_path_dict[image_key].path if resource_image_path != '': - message += "\nChanging " + resource.name + " firmware from: " + version + \ + message += "\n" + resource.name + ": changing firmware from: " + version + \ " to: " + dict_img_version + " at \n " + resource_image_path additionalinfo = " (firmware) " - self.sandbox.report_info("Config uploaded; Changing " + resource.name + - " firmware from: " + version + " to: " + dict_img_version + - " at \n " + resource_image_path, + self.sandbox.report_info(resource.name + " changing firmware from: " + version + + " to: " + dict_img_version + " at \n " + + resource_image_path, write_to_output_window=True) resource.load_firmware(self.sandbox.id, resource_image_path) else: - message += "\nLoading configuration for device: " + resource.name + " from:" + config_path + message += "\n" + resource.name + ": loading config from:" + config_path resource.load_network_config(self.sandbox.id, config_path, 'Running', 'Override') health_check_result = resource.health_check(self.sandbox.id) @@ -198,6 +200,7 @@ def _run_asynch_load(self, resource, images_path_dict, root_path, ignore_models, ". Unexpected error: " + str(ex) message += err else: + self.sandbox.report_info(resource.name + " health check failed.", write_to_output_window=True) load_result.run_result = False err = resource.name + " did not pass health check. Configuration will not be loaded to the device.\n" + \ "Health check error is: " + health_check_result @@ -382,7 +385,7 @@ def _run_asynch_save(self, resource, snapshot_dir, config_type, lock, ignore_mod save_result.message = message return save_result - + ''' # ---------------------------------- # delete file name on storage # ---------------------------------- @@ -391,7 +394,7 @@ def delete_src_file(self,fileName): env_dir = self.config_files_root + '/Snapshots/' + fileName env_dir = env_dir.replace(' ', '_') self.storage_mgr.delete(env_dir) - + ''' # ---------------------------------- # Check if need to load configuration to the given device # A device should not be in the ignored models list, From a4b0728b17bcd1f010e586c9a82c2e2c830c2209 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Wed, 26 Apr 2017 09:46:56 -0700 Subject: [PATCH 12/38] added test if pool = 0 then do not attempt to prpocess VMs --- .../helpers/Networking/vm_save_restore.py | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/sandbox_scripts/helpers/Networking/vm_save_restore.py b/sandbox_scripts/helpers/Networking/vm_save_restore.py index ac6f62a..8b6ccf2 100644 --- a/sandbox_scripts/helpers/Networking/vm_save_restore.py +++ b/sandbox_scripts/helpers/Networking/vm_save_restore.py @@ -37,23 +37,26 @@ def load_config(self, config_stage, config_set_name='', ignore_models=None, "Loading image on the devices. This action may take some time",write_to_output_window=True) root_resources = self.sandbox.get_root_vm_resources() """:type : list[ResourceBase]""" - pool = ThreadPool(len(root_resources)) - async_results = [pool.apply_async(self._run_asynch_load, - (resource, root_path, ignore_models, in_teardown_mode)) - for resource in root_resources] - - pool.close() - pool.join() - for async_result in async_results: - res = async_result.get() - """:type : load_result_struct""" - if not res.run_result: - err = "Failed to load configuration on device " + res.resource_name - self.sandbox.report_error(err, write_to_output_window=write_to_output, raise_error=False) - self.sandbox.report_error(res.message, raise_error=False) - self.sandbox.api_session.SetResourceLiveStatus(res.resource_name, 'Error') - elif res.message != '': - self.sandbox.report_info(res.resource_name + "\n" + res.message) + if len(root_resources) > 0: + pool = ThreadPool(len(root_resources)) + async_results = [pool.apply_async(self._run_asynch_load, + (resource, root_path, ignore_models, in_teardown_mode)) + for resource in root_resources] + + pool.close() + pool.join() + for async_result in async_results: + res = async_result.get() + """:type : load_result_struct""" + if not res.run_result: + err = "Failed to load configuration on device " + res.resource_name + self.sandbox.report_error(err, write_to_output_window=write_to_output, raise_error=False) + self.sandbox.report_error(res.message, raise_error=False) + self.sandbox.api_session.SetResourceLiveStatus(res.resource_name, 'Error') + elif res.message != '': + self.sandbox.report_info(res.resource_name + "\n" + res.message) + else: + self.sandbox.report_info("No VM resources found to process") # ---------------------------------- # ---------------------------------- From c0413a44dc312c7baf7fc1b4ed6a0784bf541793 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Wed, 26 Apr 2017 09:47:53 -0700 Subject: [PATCH 13/38] added test if pool = 0 then do not attempt to process network devices --- .../Networking/NetworkingSaveNRestore.py | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py b/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py index 181aabf..6f326d7 100644 --- a/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py +++ b/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py @@ -73,27 +73,30 @@ def load_config(self, config_stage, config_type, restore_method="Override", conf write_to_output_window=True) root_resources = self.sandbox.get_root_networking_resources() """:type : list[ResourceBase]""" - pool = ThreadPool(len(root_resources)) - lock = Lock() - async_results = [pool.apply_async(self._run_asynch_load, - (resource, images_path_dict, root_path, ignore_models,config_stage, lock, - use_Config_file_path_attr)) - for resource in root_resources] - - pool.close() - pool.join() - for async_result in async_results: - res = async_result.get() - """:type : load_result_struct""" - if not res.run_result: - err = "Failed to load configuration on device " + res.resource_name - self.sandbox.report_error(err, write_to_output_window=write_to_output, raise_error=False) - self.sandbox.report_error(res.message, raise_error=False) - self.sandbox.api_session.SetResourceLiveStatus(res.resource_name, 'Error') - elif res.message != '': - self.sandbox.report_info(res.resource_name + "\n" + res.message,write_to_output_window=True) - if remove_temp_files: - self._remove_temp_config_files() + if len(root_resources) > 0: + pool = ThreadPool(len(root_resources)) + lock = Lock() + async_results = [pool.apply_async(self._run_asynch_load, + (resource, images_path_dict, root_path, ignore_models,config_stage, lock, + use_Config_file_path_attr)) + for resource in root_resources] + + pool.close() + pool.join() + for async_result in async_results: + res = async_result.get() + """:type : load_result_struct""" + if not res.run_result: + err = "Failed to load configuration on device " + res.resource_name + self.sandbox.report_error(err, write_to_output_window=write_to_output, raise_error=False) + self.sandbox.report_error(res.message, raise_error=False) + self.sandbox.api_session.SetResourceLiveStatus(res.resource_name, 'Error') + elif res.message != '': + self.sandbox.report_info(res.resource_name + "\n" + res.message,write_to_output_window=True) + if remove_temp_files: + self._remove_temp_config_files() + else: + self.sandbox.report_info("No networking resources found to process.") # ---------------------------------- From e1786577e7c9f106cd3186ab27fd1db9b2d7eebc Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Wed, 26 Apr 2017 09:53:45 -0700 Subject: [PATCH 14/38] just to help run debugging --- .../tests/DebugInteractive_teardown_resources.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 sandbox_scripts/QualiEnvironmentUtils/tests/DebugInteractive_teardown_resources.py diff --git a/sandbox_scripts/QualiEnvironmentUtils/tests/DebugInteractive_teardown_resources.py b/sandbox_scripts/QualiEnvironmentUtils/tests/DebugInteractive_teardown_resources.py new file mode 100644 index 0000000..ef0874a --- /dev/null +++ b/sandbox_scripts/QualiEnvironmentUtils/tests/DebugInteractive_teardown_resources.py @@ -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() From 30650adc044850eaa60ad7dc8f19719a0667b87c Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Wed, 26 Apr 2017 10:27:09 -0700 Subject: [PATCH 15/38] updated clear all resoruce live status to set the status to Info and the message to "status cleared HH:MM:SS" --- sandbox_scripts/QualiEnvironmentUtils/Sandbox.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index 79877aa..d53c2a6 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -3,7 +3,7 @@ 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 SEVERITY_INFO = 20 SEVERITY_ERROR = 40 @@ -173,7 +173,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())) # ---------------------------------- # ---------------------------------- From 43585fb7f9515b3f2229b9d3ba953402ab9b99a5 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Wed, 26 Apr 2017 15:51:41 -0700 Subject: [PATCH 16/38] Added feature to email report_error conditions, using attributes in the Globals resource. --- .../QualiEnvironmentUtils/Sandbox.py | 64 ++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index d53c2a6..1203c41 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -4,6 +4,10 @@ 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 SEVERITY_ERROR = 40 @@ -20,6 +24,7 @@ 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 self.Blueprint_name = helpers.get_reservation_context_details().environment_name if self.Blueprint_name == '': raise QualiError("Blueprint name empty (from env name)") @@ -61,11 +66,24 @@ def report_error(self, error_message, log_message=None, raise_error=True, write_ :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: + emailOwner = False + emailSubject = str(self.Blueprint_name) + ' / ' + str(self.owner) + emailBody = "Sandbox: " + str(self.Blueprint_name) + "\n" + \ + "Owner: " + str(self.owner) + "\n\n" + if log_message: + emailBody += "LogMsg: " + log_message + "\n\n" + if error_message: + emailBody += "ErrMsg: " + error_message + "\n\n" + emailresult = self.emailalert(emailSubject, emailBody, owner=self.owner, ishtml=False, emailOwner=emailOwner) + if self._logger: if log_message: - self._logger.error(log_message) + self._logger.error(emailresult + "\n" + log_message) else: - self._logger.error(error_message) + self._logger.error(emailresult + "\n" + error_message) if write_to_output_window: self._write_message_to_output(error_message, SEVERITY_ERROR) if raise_error: @@ -87,6 +105,48 @@ 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): + 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" + # ---------------------------------- def get_root_resources(self): """ From 56f6a10a874f397559ad5fb2281f66c8bf4280ce Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Thu, 27 Apr 2017 16:08:48 -0700 Subject: [PATCH 17/38] created function to get the value of the attribute ending in ".Model" as the model and if none found, uses the self.details.ResourceModelName. --- sandbox_scripts/QualiEnvironmentUtils/Resource.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Resource.py b/sandbox_scripts/QualiEnvironmentUtils/Resource.py index c33c55f..e9acc5c 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Resource.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Resource.py @@ -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 self.alias = resource_alias # ----------------------------------------- @@ -49,6 +45,13 @@ def attribute_exist(self, attribute_name): return True return False + # ----------------------------------------- + # ----------------------------------------- + def get_attrib_value_ending_in_Model(self): + for attribute in self.attributes: + if attribute.Name.endswith('.Model'): + return attribute.Value + return self.details.ResourceModelName # ----------------------------------------- # ----------------------------------------- From 9e0d91cd196a19f7b31187a752dd5302adba3d80 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Fri, 28 Apr 2017 09:49:21 -0700 Subject: [PATCH 18/38] edits, fixes to image_key and dict stuff relating to concrete name ve alias-model vs model --- .../Networking/NetworkingSaveNRestore.py | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py b/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py index 6f326d7..788a475 100644 --- a/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py +++ b/sandbox_scripts/helpers/Networking/NetworkingSaveNRestore.py @@ -148,17 +148,31 @@ def _run_asynch_load(self, resource, images_path_dict, root_path, ignore_models, resource.load_network_config(self.sandbox.id, config_path, 'Running', 'Override') else: if len(images_path_dict) > 0: - # check what the device FW version - image_key = (resource.alias + '_' + resource.model).replace(' ', '_') + # check what the device FW version is currently. version = resource.get_version(self.sandbox.id) self.sandbox.report_info(resource.name + ": current version: " + version, write_to_output_window=False) + # First try with an firmware image key of concrete resource name!! + dict_img_version = '' + image_key = '' try: + # Try using concrete resource name to find entry + image_key = resource.name dict_img_version = images_path_dict[image_key].version - self.sandbox.report_info(resource.name + ": FirmwareData specifies version " + dict_img_version) except: - image_key = resource.model.replace(' ', '_') - dict_img_version = images_path_dict[image_key].version + try: + # Try using alias_model + image_key = (resource.alias + '_' + resource.model).replace(' ', '_') + dict_img_version = images_path_dict[image_key].version + except: + try: + # Try using just model, hopefully from attribute xxxxxx.Model + image_key = resource.model.replace(' ', '_') + dict_img_version = images_path_dict[image_key].version + except: + # Getting here means no firmware specified in FirmwareData.csv + message += "\n" + resource.name + ": NO firmware version specified in Base FirmwareData.csv" + # same image version - Only load config (running override) message += "\n" + resource.name + ": loading configuration from: " + config_path if dict_img_version.lower() == version.lower(): @@ -172,8 +186,8 @@ def _run_asynch_load(self, resource, images_path_dict, root_path, ignore_models, config_type='Running', restore_method='Override') - resource_image_path = images_path_dict[image_key].path - if resource_image_path != '': + if dict_img_version != '': + resource_image_path = images_path_dict[image_key].path message += "\n" + resource.name + ": changing firmware from: " + version + \ " to: " + dict_img_version + " at \n " + resource_image_path additionalinfo = " (firmware) " @@ -203,7 +217,7 @@ def _run_asynch_load(self, resource, images_path_dict, root_path, ignore_models, ". Unexpected error: " + str(ex) message += err else: - self.sandbox.report_info(resource.name + " health check failed.", write_to_output_window=True) + self.sandbox.report_error(resource.name + " health check failed.", write_to_output_window=True) load_result.run_result = False err = resource.name + " did not pass health check. Configuration will not be loaded to the device.\n" + \ "Health check error is: " + health_check_result @@ -304,7 +318,6 @@ def _get_concrete_config_file_path(self, root_path, resource, config_stage, writ os.unlink(tmp_concrete_config_file.name) # Set the path to the new concrete file config_path = concrete_file_path - #print tmp_template_config_file.name return config_path @@ -413,7 +426,7 @@ def _is_load_config_to_device(self, resource, ignore_models=None): if ignore_models: for ignore_model in ignore_models: - if resource.model.lower() == ignore_model.lower(): + if resource.details.ResourceModelName.lower() == ignore_model.lower(): return False apps = self.sandbox.get_Apps_resources() From 5a12d61780838b3d4dcb989d9e40e29f5087017b Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Fri, 28 Apr 2017 09:49:53 -0700 Subject: [PATCH 19/38] created function to get the value of the attribute ending in ".Model" as the model and if none found, uses the self.details.ResourceModelName. fixes --- sandbox_scripts/QualiEnvironmentUtils/Resource.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Resource.py b/sandbox_scripts/QualiEnvironmentUtils/Resource.py index e9acc5c..8889c47 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Resource.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Resource.py @@ -22,7 +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 - self.model = self.get_attrib_value_ending_in_Model + self.model = self.get_attrib_value_ending_in_model() self.alias = resource_alias # ----------------------------------------- @@ -47,11 +47,11 @@ def attribute_exist(self, attribute_name): # ----------------------------------------- # ----------------------------------------- - def get_attrib_value_ending_in_Model(self): + def get_attrib_value_ending_in_model(self): for attribute in self.attributes: if attribute.Name.endswith('.Model'): - return attribute.Value - return self.details.ResourceModelName + return str(attribute.Value) + return str(self.details.ResourceModelName) # ----------------------------------------- # ----------------------------------------- From 62b03b78fe8a0c41bcb5b8ace89d0bbefe3851ab Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Fri, 28 Apr 2017 09:50:21 -0700 Subject: [PATCH 20/38] fixes, updates for handling model attrib --- sandbox_scripts/QualiEnvironmentUtils/StorageManager.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sandbox_scripts/QualiEnvironmentUtils/StorageManager.py b/sandbox_scripts/QualiEnvironmentUtils/StorageManager.py index 45505fb..b2e4374 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/StorageManager.py +++ b/sandbox_scripts/QualiEnvironmentUtils/StorageManager.py @@ -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) From 3c3a21013dd50985ca95a007c22b7f317ccb2b81 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Thu, 4 May 2017 12:48:41 -0700 Subject: [PATCH 21/38] =?UTF-8?q?change=20to=20=E2=80=A2=09attribute=5Fexi?= =?UTF-8?q?st=20=E2=80=A2=09get=5Fattribute=20=E2=80=A2=09set=5Fattribute?= =?UTF-8?q?=5Fvalue=20to=20handle=20being=20passed=20in=20an=20attribute?= =?UTF-8?q?=20name=20or=20the=20ending=20string=20of=20an=20attribute=20na?= =?UTF-8?q?me=20which=20is=20preceeded=20by=20a=20period=20and=20a=20model?= =?UTF-8?q?=20in=20the=20case=20of=20a=202nd=20gen=20shell.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../QualiEnvironmentUtils/Resource.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Resource.py b/sandbox_scripts/QualiEnvironmentUtils/Resource.py index 8889c47..d22c8ec 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Resource.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Resource.py @@ -41,7 +41,7 @@ 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 @@ -58,7 +58,7 @@ def get_attrib_value_ending_in_model(self): 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 @@ -69,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 From fa997dc2463d63c412788135bf812b7e30b387d0 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Thu, 4 May 2017 14:55:40 -0700 Subject: [PATCH 22/38] changes to fix isues with test config, adding environmentPath, --- .../QualiEnvironmentUtils/tests/test_Sandbox.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/tests/test_Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/tests/test_Sandbox.py index 7771194..e31febf 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/tests/test_Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/tests/test_Sandbox.py @@ -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": [], @@ -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) #================================================================ From 03120287cfa44d9292d59422e342ea1f1da08622 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Thu, 4 May 2017 14:55:49 -0700 Subject: [PATCH 23/38] changes to fix isues with test config, adding environmentPath, --- .../QualiEnvironmentUtils/Sandbox.py | 108 ++++++++++-------- 1 file changed, 60 insertions(+), 48 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index 1203c41..3bafd4d 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -58,7 +58,8 @@ def _write_message_to_output(self, message, severity_level=SEVERITY_INFO): self.api_session.WriteMessageToReservationOutput(self.id, '' + message + '') # ---------------------------------- - 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 @@ -69,21 +70,29 @@ def report_error(self, error_message, log_message=None, raise_error=True, write_ emailresult = '' if raise_error: - emailOwner = False - emailSubject = str(self.Blueprint_name) + ' / ' + str(self.owner) - emailBody = "Sandbox: " + str(self.Blueprint_name) + "\n" + \ - "Owner: " + str(self.owner) + "\n\n" - if log_message: - emailBody += "LogMsg: " + log_message + "\n\n" - if error_message: - emailBody += "ErrMsg: " + error_message + "\n\n" - emailresult = self.emailalert(emailSubject, emailBody, owner=self.owner, ishtml=False, emailOwner=emailOwner) + 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(emailresult + "\n" + log_message) + self._logger.error(emailresult + log_message) else: - self._logger.error(emailresult + "\n" + 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: @@ -107,45 +116,48 @@ def report_info(self, message, log_message=None, write_to_output_window=False): # ---------------------------------- def emailalert(self, subject, body, owner, ishtml=False, emailOwner=False): - 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: + 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: - emailto = str(self.api_session.GetUserDetails(owner).Email) - emailbcc = emailfrom - body += "----\n A copy of this email was also sent to our support staff." + 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: - 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)) + # cannot post again as error or we could be in a loop! + return "ERROR Failed to send email(1)" except: - # cannot post again as error or we could be in a loop! - return "ERROR Failed to send email" + return "ERROR Failed to send email(2)" # ---------------------------------- def get_root_resources(self): From 1c363022fa7c4937d494016215b2cfebe9529c8c Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Thu, 4 May 2017 14:56:26 -0700 Subject: [PATCH 24/38] cleaned appearance, added reporting info --- .../environment/teardown/teardown_resources.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sandbox_scripts/environment/teardown/teardown_resources.py b/sandbox_scripts/environment/teardown/teardown_resources.py index 555be79..21a0c92 100644 --- a/sandbox_scripts/environment/teardown/teardown_resources.py +++ b/sandbox_scripts/environment/teardown/teardown_resources.py @@ -19,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) From c81fda8cdacc49895c2a84c8d5bc0858359ea03f Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Thu, 4 May 2017 14:56:52 -0700 Subject: [PATCH 25/38] added freeze_gun --- test_requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test_requirements.txt b/test_requirements.txt index 4a6670f..812d4b1 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -6,3 +6,4 @@ jsonpickle nose-exclude coveralls pyapi-gitlab +freezegun \ No newline at end of file From 50eeb9f46b74b623737c1321d20a78d594280e39 Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Fri, 5 May 2017 08:39:12 -0700 Subject: [PATCH 26/38] changes to init per yaniv - call context once - add environment_path --- sandbox_scripts/QualiEnvironmentUtils/Sandbox.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index 3bafd4d..6eae4e1 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -24,8 +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 - self.Blueprint_name = helpers.get_reservation_context_details().environment_name + self.context = helpers.get_reservation_context_details() + self.owner = self.context.owner_user + self.environment_path = self.context.environment_path + self.Blueprint_name = self.context.environment_name if self.Blueprint_name == '': raise QualiError("Blueprint name empty (from env name)") From d1a20f28c242154deb0c689370bc5d1b93e2ed4d Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Fri, 5 May 2017 08:41:30 -0700 Subject: [PATCH 27/38] Merged two ifs to one, per Yaniv --- .../QualiEnvironmentUtils/Sandbox.py | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index 6eae4e1..b4ded58 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -71,24 +71,23 @@ def report_error(self, error_message, log_message=None, raise_error=True, write_ """ emailresult = '' - if raise_error: - if send_email: - emailOwner = False - try: - emailSubject = str(self.Blueprint_name) + ' / ' + str(self.owner) - emailBody = "Sandbox: " + str(self.Blueprint_name) + "\n" + \ + if raise_error and 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" + 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: From 3bd98121d0c515c4c2b33df73872adfce1606fed Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Fri, 5 May 2017 08:53:55 -0700 Subject: [PATCH 28/38] rename emailalert to _emailalert --- sandbox_scripts/QualiEnvironmentUtils/Sandbox.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index b4ded58..3b7a2ef 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -87,7 +87,7 @@ def report_error(self, error_message, log_message=None, raise_error=True, write_ 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" + emailresult = self._emailalert(emailSubject, emailBody, owner=sb_owner, ishtml=False, emailOwner=emailOwner) + "\n" if self._logger: if log_message: @@ -116,7 +116,7 @@ def report_info(self, message, log_message=None, write_to_output_window=False): self._write_message_to_output(message, SEVERITY_INFO) # ---------------------------------- - def emailalert(self, subject, body, owner, ishtml=False, emailOwner=False): + def _emailalert(self, subject, body, owner, ishtml=False, emailOwner=False): try: globalsresource = self.get_config_set_pool_resource() host = str(globalsresource.get_attribute("ConfigPool_SMTP_Server")) From fb303709551c8390d10a68240984fe63d7378f7e Mon Sep 17 00:00:00 2001 From: jimbr70 Date: Fri, 5 May 2017 10:01:17 -0700 Subject: [PATCH 29/38] removed function for handling attribute or attribute ending in Model - init updated to handle. --- sandbox_scripts/QualiEnvironmentUtils/Resource.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Resource.py b/sandbox_scripts/QualiEnvironmentUtils/Resource.py index d22c8ec..6194f47 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Resource.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Resource.py @@ -21,8 +21,11 @@ def __init__(self, resource_name, resource_alias=''): self.connected_commands = self.api_session.GetResourceConnectedCommands(resource_name).Commands self.attributes = self.details.ResourceAttributes - # If there is an attribute named 'model' take its value (exist in shells), otherwise take the family's model - self.model = self.get_attrib_value_ending_in_model() + # If there is an attribute 'named' 'model' use its value, otherwise take the family's model + if self.attribute_exist('Model'): + self.model = self.get_attribute('Model') + else: + self.model = str(self.details.ResourceModelName) self.alias = resource_alias # ----------------------------------------- @@ -45,14 +48,6 @@ def attribute_exist(self, attribute_name): return True return False - # ----------------------------------------- - # ----------------------------------------- - 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): From 90860ebf747e77fb776327e1292f049cc51c5dc3 Mon Sep 17 00:00:00 2001 From: kalsky Date: Fri, 5 May 2017 10:41:07 -0700 Subject: [PATCH 30/38] Update .travis.yml --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index aade0aa..2d20713 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ after_success: coveralls install: - pip install -r ./test_requirements.txt - - pip install "cloudshell-core>=2.0.0,<2.1.0" - - pip install "cloudshell-automation-api>=7.1,<7.3" - - pip install "cloudshell-shell-core>=2.3.0,<2.4.0" + - pip install "cloudshell-core>=2.0.0,<2.3.0" + - pip install "cloudshell-automation-api>=7.1,<8.1" + - pip install "cloudshell-shell-core>=3.1.0,<3.2" - pip install pytest-cov language: python notifications: From 25ade05eec6b22bd2c2a3aea00dd0535c4299784 Mon Sep 17 00:00:00 2001 From: kalsky Date: Fri, 5 May 2017 10:57:13 -0700 Subject: [PATCH 31/38] Update Sandbox.py trying to get the attribute error --- sandbox_scripts/QualiEnvironmentUtils/Sandbox.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index 3b7a2ef..e677c1b 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -1,4 +1,5 @@ # coding=utf-8 +import traceback from Resource import * from cloudshell.core.logger.qs_logger import * from cloudshell.helpers.scripts import cloudshell_scripts_helpers as helpers @@ -42,8 +43,8 @@ def __init__(self, reservation_id, logger): if full_path: self.blueprint_details = self.api_session.GetTopologyDetails(full_path) - except: + traceback.print_exc() err = "Failed to initialize the Sandbox. Unexpected error:" + \ str(sys.exc_info()[0]) self.report_error(error_message=err) From 1000180bd44e29722ba1c8b586d77dc992a086c1 Mon Sep 17 00:00:00 2001 From: kalsky Date: Fri, 5 May 2017 11:43:55 -0700 Subject: [PATCH 32/38] Update Sandbox.py trying again to print the exception details --- sandbox_scripts/QualiEnvironmentUtils/Sandbox.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index e677c1b..581b1c1 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -1,5 +1,4 @@ # coding=utf-8 -import traceback from Resource import * from cloudshell.core.logger.qs_logger import * from cloudshell.helpers.scripts import cloudshell_scripts_helpers as helpers @@ -26,8 +25,9 @@ def __init__(self, reservation_id, logger): self.api_session = helpers.get_api_session() self.id = reservation_id self.context = helpers.get_reservation_context_details() + print vars(self.context) self.owner = self.context.owner_user - self.environment_path = self.context.environment_path + self.environment_path = self.context.environment_path self.Blueprint_name = self.context.environment_name if self.Blueprint_name == '': raise QualiError("Blueprint name empty (from env name)") @@ -43,9 +43,10 @@ def __init__(self, reservation_id, logger): if full_path: self.blueprint_details = self.api_session.GetTopologyDetails(full_path) + except AttributeError, e: + print e except: - traceback.print_exc() - err = "Failed to initialize the Sandbox. Unexpected error:" + \ + err = "Failed to initialize the Sandbox. Unexpected error:" + \ str(sys.exc_info()[0]) self.report_error(error_message=err) From 3818b053fc86dc23f9de9af6f3f089230887422d Mon Sep 17 00:00:00 2001 From: kalsky Date: Fri, 5 May 2017 11:50:45 -0700 Subject: [PATCH 33/38] Update .travis.yml move cloudshell required packages to the test_requirements --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2d20713..5de6ad3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,6 @@ after_success: coveralls install: - pip install -r ./test_requirements.txt - - pip install "cloudshell-core>=2.0.0,<2.3.0" - - pip install "cloudshell-automation-api>=7.1,<8.1" - - pip install "cloudshell-shell-core>=3.1.0,<3.2" - pip install pytest-cov language: python notifications: From 3194c5a6f5b0c30b6771a33620f2c9283e72dd35 Mon Sep 17 00:00:00 2001 From: kalsky Date: Fri, 5 May 2017 11:52:15 -0700 Subject: [PATCH 34/38] Update test_requirements.txt move the cloudshell packages requirements to test_requirements --- test_requirements.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test_requirements.txt b/test_requirements.txt index 812d4b1..06b2e13 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -6,4 +6,8 @@ jsonpickle nose-exclude coveralls pyapi-gitlab -freezegun \ No newline at end of file +freezegun + +cloudshell-shell-core>=3.1.0,<3.2 +cloudshell-core>=2.0.0,<2.3.0 +cloudshell-automation-api>=8.0,<8.1 From 6eabbf1e3aa921eaf9ed6f3294c58ea4689e3fe0 Mon Sep 17 00:00:00 2001 From: kalsky Date: Fri, 5 May 2017 12:02:12 -0700 Subject: [PATCH 35/38] Update Sandbox.py removed try/catch to debug exception --- .../QualiEnvironmentUtils/Sandbox.py | 49 +++++++------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index 581b1c1..955b7ec 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -19,36 +19,25 @@ def __init__(self, reservation_id, logger): Load the configuration from config files on the Blueprint's devices :param str reservation_id: reservation id """ - try: - self._logger = logger - """:type : logging.Logger""" - self.api_session = helpers.get_api_session() - self.id = reservation_id - self.context = helpers.get_reservation_context_details() - print vars(self.context) - self.owner = self.context.owner_user - self.environment_path = self.context.environment_path - self.Blueprint_name = self.context.environment_name - if self.Blueprint_name == '': - raise QualiError("Blueprint name empty (from env name)") - - full_path = None - tp = self.api_session.GetActiveTopologyNames() - - for value in tp.Topologies: - filename = basename(value) - if filename == self.Blueprint_name: - full_path = value - break - - if full_path: - self.blueprint_details = self.api_session.GetTopologyDetails(full_path) - except AttributeError, e: - print e - except: - err = "Failed to initialize the Sandbox. Unexpected error:" + \ - str(sys.exc_info()[0]) - self.report_error(error_message=err) + #try: + self._logger = logger + """:type : logging.Logger""" + self.api_session = helpers.get_api_session() + self.id = reservation_id + self.context = helpers.get_reservation_context_details() + print vars(self.context) + self.owner = self.context.owner_user + self.environment_path = self.context.environment_path + self.Blueprint_name = self.context.environment_name + if self.Blueprint_name == '': + raise QualiError("Blueprint name empty (from env name)") + + if self.environment_path: + self.blueprint_details = self.api_session.GetTopologyDetails(self.environment_path) + #except: + # err = "Failed to initialize the Sandbox. Unexpected error:" + \ + # str(sys.exc_info()[0]) + # self.report_error(error_message=err) # ---------------------------------- # ---------------------------------- From 32b9e6dc96439b816e2664adad4b22c631e0241f Mon Sep 17 00:00:00 2001 From: Yaniv Kalsky Date: Fri, 5 May 2017 12:06:25 -0700 Subject: [PATCH 36/38] Revert "Update Sandbox.py" This reverts commit 6eabbf1e3aa921eaf9ed6f3294c58ea4689e3fe0. --- .../QualiEnvironmentUtils/Sandbox.py | 49 ++++++++++++------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index 955b7ec..581b1c1 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -19,25 +19,36 @@ def __init__(self, reservation_id, logger): Load the configuration from config files on the Blueprint's devices :param str reservation_id: reservation id """ - #try: - self._logger = logger - """:type : logging.Logger""" - self.api_session = helpers.get_api_session() - self.id = reservation_id - self.context = helpers.get_reservation_context_details() - print vars(self.context) - self.owner = self.context.owner_user - self.environment_path = self.context.environment_path - self.Blueprint_name = self.context.environment_name - if self.Blueprint_name == '': - raise QualiError("Blueprint name empty (from env name)") - - if self.environment_path: - self.blueprint_details = self.api_session.GetTopologyDetails(self.environment_path) - #except: - # err = "Failed to initialize the Sandbox. Unexpected error:" + \ - # str(sys.exc_info()[0]) - # self.report_error(error_message=err) + try: + self._logger = logger + """:type : logging.Logger""" + self.api_session = helpers.get_api_session() + self.id = reservation_id + self.context = helpers.get_reservation_context_details() + print vars(self.context) + self.owner = self.context.owner_user + self.environment_path = self.context.environment_path + self.Blueprint_name = self.context.environment_name + if self.Blueprint_name == '': + raise QualiError("Blueprint name empty (from env name)") + + full_path = None + tp = self.api_session.GetActiveTopologyNames() + + for value in tp.Topologies: + filename = basename(value) + if filename == self.Blueprint_name: + full_path = value + break + + if full_path: + self.blueprint_details = self.api_session.GetTopologyDetails(full_path) + except AttributeError, e: + print e + except: + err = "Failed to initialize the Sandbox. Unexpected error:" + \ + str(sys.exc_info()[0]) + self.report_error(error_message=err) # ---------------------------------- # ---------------------------------- From 4232efb13081fb6ae12844595b46524b52786fb7 Mon Sep 17 00:00:00 2001 From: Yaniv Kalsky Date: Fri, 5 May 2017 12:15:43 -0700 Subject: [PATCH 37/38] Reverted and removed the environment_path variable --- .../QualiEnvironmentUtils/Sandbox.py | 878 +++++++++--------- 1 file changed, 447 insertions(+), 431 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index 581b1c1..49f051c 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -5,10 +5,8 @@ from os.path import * from time import gmtime, strftime import smtplib -import socket from email.mime.text import MIMEText - SEVERITY_INFO = 20 SEVERITY_ERROR = 40 @@ -24,10 +22,8 @@ def __init__(self, reservation_id, logger): """:type : logging.Logger""" self.api_session = helpers.get_api_session() self.id = reservation_id - self.context = helpers.get_reservation_context_details() - print vars(self.context) + context = helpers.get_reservation_context_details() self.owner = self.context.owner_user - self.environment_path = self.context.environment_path self.Blueprint_name = self.context.environment_name if self.Blueprint_name == '': raise QualiError("Blueprint name empty (from env name)") @@ -43,451 +39,471 @@ def __init__(self, reservation_id, logger): if full_path: self.blueprint_details = self.api_session.GetTopologyDetails(full_path) - except AttributeError, e: - print e + except: - err = "Failed to initialize the Sandbox. Unexpected error:" + \ - str(sys.exc_info()[0]) + err = "Failed to initialize the Sandbox. Unexpected error:" + \ + str(sys.exc_info()[0]) self.report_error(error_message=err) - # ---------------------------------- - # ---------------------------------- - def _write_message_to_output(self, message, severity_level=SEVERITY_INFO): - """ - Write a message to the output window - """ - if severity_level == SEVERITY_INFO: - self.api_session.WriteMessageToReservationOutput(self.id, message) - elif severity_level == SEVERITY_ERROR: - self.api_session.WriteMessageToReservationOutput(self.id, '' + message + '') - - # ---------------------------------- - 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 and send_email: - emailOwner = False +# ---------------------------------- +# ---------------------------------- +def _write_message_to_output(self, message, severity_level=SEVERITY_INFO): + """ + Write a message to the output window + """ + if severity_level == SEVERITY_INFO: + self.api_session.WriteMessageToReservationOutput(self.id, message) + elif severity_level == SEVERITY_ERROR: + self.api_session.WriteMessageToReservationOutput(self.id, '' + message + '') + + +# ---------------------------------- +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 and 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(emailresult + log_message) + else: + self._logger.error(emailresult + error_message) + if write_to_output_window: + self._write_message_to_output(error_message, SEVERITY_ERROR) + if raise_error: + raise QualiError(self.id, error_message) + + +# ---------------------------------- +def report_info(self, message, log_message=None, write_to_output_window=False): + """ + Report information to the log file, output window is optional. + :param str message: The 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 write_to_output_window: Would you like to write the message to the output window? + """ + if self._logger: + if log_message: + self._logger.info(log_message) + else: + self._logger.info(message) + if write_to_output_window: + self._write_message_to_output(message, SEVERITY_INFO) + + +# ---------------------------------- +def _emailalert(self, subject, body, owner, ishtml=False, emailOwner=False): + 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: - 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) + 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: - 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(emailresult + log_message) - else: - self._logger.error(emailresult + error_message) - if write_to_output_window: - self._write_message_to_output(error_message, SEVERITY_ERROR) - if raise_error: - raise QualiError(self.id, error_message) - - # ---------------------------------- - def report_info(self, message, log_message=None, write_to_output_window=False): - """ - Report information to the log file, output window is optional. - :param str message: The 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 write_to_output_window: Would you like to write the message to the output window? - """ - if self._logger: - if log_message: - self._logger.info(log_message) - else: - self._logger.info(message) - if write_to_output_window: - self._write_message_to_output(message, SEVERITY_INFO) + emailbcc = '' + emailto = emailfrom - # ---------------------------------- - def _emailalert(self, subject, body, owner, ishtml=False, emailOwner=False): 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)" + 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: - return "ERROR Failed to send email(2)" - - # ---------------------------------- - def get_root_resources(self): - """ - Get the root resources - :rtype: list[ResourceBase] - """ - root_resources = [] - root_resources_names_dict = {} - details = self.get_details() - resources = details.ReservationDescription.Resources - topo_resources = details.ReservationDescription.TopologiesReservedResources - # Loop over all devices in the sandbox and add to a dictionary all root devices: - for resource in resources: + # 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): + """ + Get the root resources + :rtype: list[ResourceBase] + """ + root_resources = [] + root_resources_names_dict = {} + details = self.get_details() + resources = details.ReservationDescription.Resources + topo_resources = details.ReservationDescription.TopologiesReservedResources + # Loop over all devices in the sandbox and add to a dictionary all root devices: + for resource in resources: + split_name = resource.Name.split('/') + root_resources_names_dict[split_name[0]] = 1 + + # instantiate a resource object for each root device + for root_resource_name in root_resources_names_dict.keys(): + root_resource_alias = '' + for topo_resource in topo_resources: + if topo_resource.Name == root_resource_name: + root_resource_alias = topo_resource.Alias + break + root_resources.append(ResourceBase(root_resource_name, root_resource_alias)) + + return root_resources + + +# ---------------------------------- +# ---------------------------------- +def get_root_vm_resources(self): + """ + Get the root resources of vm type + :rtype: list[ResourceBase] + """ + root_resources = [] + root_resources_names_dict = {} + details = self.get_details() + resources = details.ReservationDescription.Resources + # Loop over all devices in the sandbox and add to a dictionary all root devices of VM type: + for resource in resources: + # resource_details = self.api_session.GetResourceDetails(resource.Name) + if resource.VmDetails and hasattr(resource.VmDetails, 'UID') and resource.VmDetails.UID: + split_name = resource.Name.split('/') + root_resources_names_dict[split_name[0]] = 1 + root_resources.append(ResourceBase(resource.Name, '')) + + return root_resources + + +# ---------------------------------- +# ---------------------------------- +def get_root_networking_resources(self): + """ + Get the root resources of networking type + :rtype: list[ResourceBase] + """ + root_resources = [] + root_resources_names_dict = {} + details = self.get_details() + resources = details.ReservationDescription.Resources + topo_resources = details.ReservationDescription.TopologiesReservedResources + # Loop over all devices in the sandbox and add to a dictionary all root devices of type networking devices: + for resource in resources: + if not (resource.VmDetails and hasattr(resource.VmDetails, 'UID') and resource.VmDetails.UID): split_name = resource.Name.split('/') root_resources_names_dict[split_name[0]] = 1 - # instantiate a resource object for each root device - for root_resource_name in root_resources_names_dict.keys(): - root_resource_alias = '' - for topo_resource in topo_resources: - if topo_resource.Name == root_resource_name: - root_resource_alias = topo_resource.Alias - break - root_resources.append(ResourceBase(root_resource_name, root_resource_alias)) - - return root_resources - - - # ---------------------------------- - # ---------------------------------- - def get_root_vm_resources(self): - """ - Get the root resources of vm type - :rtype: list[ResourceBase] - """ - root_resources = [] - root_resources_names_dict = {} + # instantiate a resource object for each root device + for root_resource_name in root_resources_names_dict.keys(): + root_resource_alias = '' + for topo_resource in topo_resources: + if topo_resource.Name == root_resource_name: + root_resource_alias = topo_resource.Alias + break + root_resources.append(ResourceBase(root_resource_name, root_resource_alias)) + + return root_resources + + +# ---------------------------------- +# ---------------------------------- +def clear_all_resources_live_status(self): + """ + Clear the live status from all the devices + """ + root_resources = self.get_root_resources() + for resource in root_resources: + self.api_session.SetResourceLiveStatus(resource.name, liveStatusName="Info", + additionalInfo='status cleared ' + strftime("%H:%M:%S", gmtime())) + + +# ---------------------------------- +# ---------------------------------- +def get_details(self): + """ + Retrieves all details and parameters for a specified Sandbox, including its resources, routes and route + segments, topologies, and Sandbox conflicts. + """ + try: + return self.api_session.GetReservationDetails(self.id) + except: + err = "Failed to get the Sandbox's details. Unexpected error: " + str(sys.exc_info()[0]) + self.report_error(error_message=err) + + +# ---------------------------------- +# ---------------------------------- +def activate_all_routes_and_connectors(self, write_to_output=True): + """ + Activate the routes in the topology + """ + try: + self.report_info(message="Connecting the connectors and routes", write_to_output_window=write_to_output) + self.activate_connectors(write_to_output=False) + + self.activate_routes(write_to_output=False) + self.report_info(message="Connectors and routes are connected", write_to_output_window=write_to_output) + except CloudShellAPIError as error: + err = "Failed to activate connectors and routes. " + error.message + self.report_error(error_message=err, write_to_output_window=write_to_output) + except: + err = "Failed to activate connectors and routes. Unexpected error: " + str(sys.exc_info()[0]) + self.report_error(error_message=err, write_to_output_window=write_to_output) + + +# ---------------------------------- +# ---------------------------------- +def activate_connectors(self, write_to_output=True): + """ + Activate the connectors in the topology + """ + try: + self.report_info(message="Connecting the connectors", write_to_output_window=write_to_output) details = self.get_details() - resources = details.ReservationDescription.Resources - # Loop over all devices in the sandbox and add to a dictionary all root devices of VM type: - for resource in resources: - #resource_details = self.api_session.GetResourceDetails(resource.Name) - if resource.VmDetails and hasattr(resource.VmDetails,'UID') and resource.VmDetails.UID: - split_name = resource.Name.split('/') - root_resources_names_dict[split_name[0]] = 1 - root_resources.append(ResourceBase(resource.Name, '')) - - return root_resources - - # ---------------------------------- - # ---------------------------------- - def get_root_networking_resources(self): - """ - Get the root resources of networking type - :rtype: list[ResourceBase] - """ - root_resources = [] - root_resources_names_dict = {} + connectors = details.ReservationDescription.Connectors + bi_endpoints = [] + for endpoint in connectors: + if endpoint.State in ['Disconnected', 'PartiallyConnected', 'ConnectionFailed'] \ + and endpoint.Target and endpoint.Source: + bi_endpoints.append(endpoint.Target) + bi_endpoints.append(endpoint.Source) + if not bi_endpoints: + self.report_info(message="No connectors to connect for reservation {0}".format(self.id), + write_to_output_window=write_to_output) + return + self.api_session.ConnectRoutesInReservation(self.id, bi_endpoints, 'bi') + self.report_info(message="Connectors connected", write_to_output_window=write_to_output) + except CloudShellAPIError as error: + err = "Failed to activate the connectors. " + error.message + self.report_error(error_message=err, write_to_output_window=write_to_output) + except: + err = "Failed to activate the connectors. Unexpected error: " + str(sys.exc_info()[0]) + self.report_error(error_message=err, write_to_output_window=write_to_output) + + +# ---------------------------------- +# ---------------------------------- +def activate_routes(self, write_to_output=True): + """ + Activate the routes in the topology + """ + try: + self.report_info(message="Connecting routes", write_to_output_window=write_to_output) details = self.get_details() - resources = details.ReservationDescription.Resources - topo_resources = details.ReservationDescription.TopologiesReservedResources - # Loop over all devices in the sandbox and add to a dictionary all root devices of type networking devices: - for resource in resources: - if not(resource.VmDetails and hasattr(resource.VmDetails,'UID') and resource.VmDetails.UID): - split_name = resource.Name.split('/') - root_resources_names_dict[split_name[0]] = 1 - - # instantiate a resource object for each root device - for root_resource_name in root_resources_names_dict.keys(): - root_resource_alias = '' - for topo_resource in topo_resources: - if topo_resource.Name == root_resource_name: - root_resource_alias = topo_resource.Alias - break - root_resources.append(ResourceBase(root_resource_name, root_resource_alias)) - - return root_resources - - # ---------------------------------- - # ---------------------------------- - def clear_all_resources_live_status(self): - """ - Clear the live status from all the devices - """ - root_resources = self.get_root_resources() - for resource in root_resources: - self.api_session.SetResourceLiveStatus(resource.name, liveStatusName="Info", - additionalInfo='status cleared ' + strftime("%H:%M:%S", gmtime())) - - # ---------------------------------- - # ---------------------------------- - def get_details(self): - """ - Retrieves all details and parameters for a specified Sandbox, including its resources, routes and route - segments, topologies, and Sandbox conflicts. - """ - try: - return self.api_session.GetReservationDetails(self.id) - except: - err = "Failed to get the Sandbox's details. Unexpected error: " + str(sys.exc_info()[0]) - self.report_error(error_message=err) - - # ---------------------------------- - # ---------------------------------- - def activate_all_routes_and_connectors(self, write_to_output=True): - """ - Activate the routes in the topology - """ - try: - self.report_info(message="Connecting the connectors and routes", write_to_output_window=write_to_output) - self.activate_connectors(write_to_output=False) - - self.activate_routes(write_to_output=False) - self.report_info(message="Connectors and routes are connected", write_to_output_window=write_to_output) - except CloudShellAPIError as error: - err = "Failed to activate connectors and routes. " + error.message - self.report_error(error_message=err, write_to_output_window=write_to_output) - except: - err = "Failed to activate connectors and routes. Unexpected error: " + str(sys.exc_info()[0]) - self.report_error(error_message=err, write_to_output_window=write_to_output) - - # ---------------------------------- - # ---------------------------------- - def activate_connectors(self, write_to_output=True): - """ - Activate the connectors in the topology - """ - try: - self.report_info(message="Connecting the connectors", write_to_output_window=write_to_output) - details = self.get_details() - connectors = details.ReservationDescription.Connectors - bi_endpoints = [] - for endpoint in connectors: - if endpoint.State in ['Disconnected', 'PartiallyConnected', 'ConnectionFailed'] \ - and endpoint.Target and endpoint.Source: - bi_endpoints.append(endpoint.Target) - bi_endpoints.append(endpoint.Source) - if not bi_endpoints: - self.report_info(message="No connectors to connect for reservation {0}".format(self.id), - write_to_output_window=write_to_output) - return + routes = details.ReservationDescription.RequestedRoutesInfo + bi_endpoints = [] + uni_endpoints = [] + for route_endpoint in routes: + if route_endpoint.Target and route_endpoint.Source: + if route_endpoint.RouteType == 'bi': + bi_endpoints.append(route_endpoint.Target) + bi_endpoints.append(route_endpoint.Source) + elif route_endpoint.RouteType == 'uni': + uni_endpoints.append(route_endpoint.Source) + uni_endpoints.append(route_endpoint.Target) + + if not bi_endpoints and not uni_endpoints: + self.report_info(message="No routes to connect for reservation {0}".format(self.id), + write_to_output_window=write_to_output) + return + if bi_endpoints: self.api_session.ConnectRoutesInReservation(self.id, bi_endpoints, 'bi') - self.report_info(message="Connectors connected", write_to_output_window=write_to_output) - except CloudShellAPIError as error: - err = "Failed to activate the connectors. " + error.message - self.report_error(error_message=err, write_to_output_window=write_to_output) - except: - err = "Failed to activate the connectors. Unexpected error: " + str(sys.exc_info()[0]) - self.report_error(error_message=err, write_to_output_window=write_to_output) - - # ---------------------------------- - # ---------------------------------- - def activate_routes(self, write_to_output=True): - """ - Activate the routes in the topology - """ - try: - self.report_info(message="Connecting routes", write_to_output_window=write_to_output) - details = self.get_details() - routes = details.ReservationDescription.RequestedRoutesInfo - bi_endpoints = [] - uni_endpoints = [] - for route_endpoint in routes: - if route_endpoint.Target and route_endpoint.Source: - if route_endpoint.RouteType == 'bi': - bi_endpoints.append(route_endpoint.Target) - bi_endpoints.append(route_endpoint.Source) - elif route_endpoint.RouteType == 'uni': - uni_endpoints.append(route_endpoint.Source) - uni_endpoints.append(route_endpoint.Target) - - if not bi_endpoints and not uni_endpoints: - self.report_info(message="No routes to connect for reservation {0}".format(self.id), - write_to_output_window=write_to_output) - return - if bi_endpoints: - self.api_session.ConnectRoutesInReservation(self.id, bi_endpoints, 'bi') - if uni_endpoints: - self.api_session.ConnectRoutesInReservation(self.id, uni_endpoints, 'uni') - self.report_info(message="Routes connected", write_to_output_window=write_to_output) - except CloudShellAPIError as error: - err = "Failed to activate routes. " + error.message - self.report_error(error_message=err, write_to_output_window=write_to_output) - except: - err = "Failed to activate routes. Unexpected error: " + str(sys.exc_info()[0]) - self.report_error(error_message=err, write_to_output_window=write_to_output) - - # ----------------------------------------- - # ----------------------------------------- - def execute_command(self, commandName, commandInputs=[], printOutput=False): - """ - Executes a command - :param str commandName: Command Name - Specify the name of the command. - :param list[InputNameValue] commandInputs: Command Inputs - Specify a matrix of input names and values - required for executing the command. - :param bool printOutput: Print Output - Defines whether to print the command output - in the Sandbox command output window. - :rtype: CommandExecutionCompletedResultInfo - """ - try: - return self.api_session.ExecuteEnvironmentCommand(self.id, commandName, commandInputs, printOutput) - - except CloudShellAPIError as error: - raise QualiError(self.id, error.message) - - # ----------------------------------------- - # ----------------------------------------- - def enqueue_command(self, commandName, commandInputs=[], printOutput=False): - """ - Enqueue a command - :param str commandName: Command Name - Specify the name of the command. - :param list[InputNameValue] commandInputs: Command Inputs - Specify a matrix of input names and values - required for executing the command. - :param bool printOutput: Print Output - Defines whether to print the command output - in the Sandbox command output window. - :rtype: CommandExecutionCompletedResultInfo - """ - try: - return self.api_session.EnqueueEnvironmentCommand(self.id, commandName, commandInputs, printOutput) - - except CloudShellAPIError as error: - raise QualiError(self.id, error.message) - - # ----------------------------------------- - # ----------------------------------------- - def save_sandbox_as_blueprint(self, blueprint_name, write_to_output=True): - try: - #TODO - fullpath should be passed as a param to the function and not hard coded - # save the current Sandbox as a new Blueprint with the given snapshot name - fullpath = 'Snapshots' - self.api_session.SaveReservationAsTopology(self.id, topologyName=blueprint_name,folderFullPath=fullpath, includeInactiveRoutes=True) - - except CloudShellAPIError as error: - err = "Failed to save sandbox as blueprint. " + error.message - self.report_error(error_message=err, raise_error=True, write_to_output_window=write_to_output) - # if snapshot_exist: - # err = "Blueprint " + blueprint_name + " already exist. Please select a different name." - # self.report_error(error_message=err, write_to_output_window=write_to_output) - # raise Exception('Blueprint name already exist. Please select a different name.') - - #update the new snapshot with the user as owner - username = helpers.get_reservation_context_details().owner_user - fullTopologyName = 'Snapshots/'+blueprint_name - self.api_session.UpdateTopologyOwner(topologyName=fullTopologyName,ownerName=username) - - # ----------------------------------------- - # check if this resource originated from an abstract resource - # ----------------------------------------- - def is_abstract(self, resource_alias): - for abstract_resource in self.blueprint_details.AbstractResources: - if resource_alias == abstract_resource.Alias: - return True + if uni_endpoints: + self.api_session.ConnectRoutesInReservation(self.id, uni_endpoints, 'uni') + self.report_info(message="Routes connected", write_to_output_window=write_to_output) + except CloudShellAPIError as error: + err = "Failed to activate routes. " + error.message + self.report_error(error_message=err, write_to_output_window=write_to_output) + except: + err = "Failed to activate routes. Unexpected error: " + str(sys.exc_info()[0]) + self.report_error(error_message=err, write_to_output_window=write_to_output) + + +# ----------------------------------------- +# ----------------------------------------- +def execute_command(self, commandName, commandInputs=[], printOutput=False): + """ + Executes a command + :param str commandName: Command Name - Specify the name of the command. + :param list[InputNameValue] commandInputs: Command Inputs - Specify a matrix of input names and values + required for executing the command. + :param bool printOutput: Print Output - Defines whether to print the command output + in the Sandbox command output window. + :rtype: CommandExecutionCompletedResultInfo + """ + try: + return self.api_session.ExecuteEnvironmentCommand(self.id, commandName, commandInputs, printOutput) + + except CloudShellAPIError as error: + raise QualiError(self.id, error.message) + + +# ----------------------------------------- +# ----------------------------------------- +def enqueue_command(self, commandName, commandInputs=[], printOutput=False): + """ + Enqueue a command + :param str commandName: Command Name - Specify the name of the command. + :param list[InputNameValue] commandInputs: Command Inputs - Specify a matrix of input names and values + required for executing the command. + :param bool printOutput: Print Output - Defines whether to print the command output + in the Sandbox command output window. + :rtype: CommandExecutionCompletedResultInfo + """ + try: + return self.api_session.EnqueueEnvironmentCommand(self.id, commandName, commandInputs, printOutput) + + except CloudShellAPIError as error: + raise QualiError(self.id, error.message) + + +# ----------------------------------------- +# ----------------------------------------- +def save_sandbox_as_blueprint(self, blueprint_name, write_to_output=True): + try: + # TODO - fullpath should be passed as a param to the function and not hard coded + # save the current Sandbox as a new Blueprint with the given snapshot name + fullpath = 'Snapshots' + self.api_session.SaveReservationAsTopology(self.id, topologyName=blueprint_name, folderFullPath=fullpath, + includeInactiveRoutes=True) + + except CloudShellAPIError as error: + err = "Failed to save sandbox as blueprint. " + error.message + self.report_error(error_message=err, raise_error=True, write_to_output_window=write_to_output) + # if snapshot_exist: + # err = "Blueprint " + blueprint_name + " already exist. Please select a different name." + # self.report_error(error_message=err, write_to_output_window=write_to_output) + # raise Exception('Blueprint name already exist. Please select a different name.') + + # update the new snapshot with the user as owner + username = helpers.get_reservation_context_details().owner_user + fullTopologyName = 'Snapshots/' + blueprint_name + self.api_session.UpdateTopologyOwner(topologyName=fullTopologyName, ownerName=username) + + +# ----------------------------------------- +# check if this resource originated from an abstract resource +# ----------------------------------------- +def is_abstract(self, resource_alias): + for abstract_resource in self.blueprint_details.AbstractResources: + if resource_alias == abstract_resource.Alias: + return True + return False + + +# ----------------------------------------- +# Return the storage resource of the sandbox (e.g. tftp, ftp), if found +# ----------------------------------------- +def get_storage_server_resource(self): + root_resources = self.get_root_resources() + for resource in root_resources: + if resource.details.ResourceFamilyName.lower() == 'storage server': + return resource + return None + + +# ----------------------------------------- +# Return the repositroy resource of the sandbox (e.g. gitlab), if found +# ----------------------------------------- +def get_repository_server_resource(self): + root_resources = self.get_root_resources() + for resource in root_resources: + if resource.details.ResourceFamilyName.lower() == 'repository': + return resource + return None + + +# ----------------------------------------- +# Return the pool resource of the sandbox, if found +# ----------------------------------------- +def get_config_set_pool_resource(self): + root_resources = self.get_root_resources() + for resource in root_resources: + if resource.model.lower() == 'config set pool': + return resource + return None + + +# ----------------------------------------- +# Return the pool Apps of the sandbox, if found +# ----------------------------------------- +def get_Apps_resources(self): + """ + Get the Apps resources + :rtype: list[ReservationAppResource] + """ + details = self.get_details() + apps_resources = details.ReservationDescription.Apps + + return apps_resources + + +# ----------------------------------------- +# Return if there are apps in the sandbox +# ----------------------------------------- +def is_apps_in_reservation(self): + """Check if there are apps in reservation""" + details = self.get_details() + apps = details.ReservationDescription.App + + if not apps or (len(apps) == 1 and not apps[0].Name): + self.report_info("No apps found in reservation {0}".format(self.reservation_id)) + self.api_session.WriteMessageToReservationOutput(reservationId=self.reservation_id, + message='No apps in reservation') return False - # ----------------------------------------- - # Return the storage resource of the sandbox (e.g. tftp, ftp), if found - # ----------------------------------------- - def get_storage_server_resource(self): - root_resources = self.get_root_resources() - for resource in root_resources: - if resource.details.ResourceFamilyName.lower() == 'storage server': - return resource - return None - - # ----------------------------------------- - # Return the repositroy resource of the sandbox (e.g. gitlab), if found - # ----------------------------------------- - def get_repository_server_resource(self): - root_resources = self.get_root_resources() - for resource in root_resources: - if resource.details.ResourceFamilyName.lower() == 'repository': - return resource - return None - - # ----------------------------------------- - # Return the pool resource of the sandbox, if found - # ----------------------------------------- - def get_config_set_pool_resource(self): - root_resources = self.get_root_resources() - for resource in root_resources: - if resource.model.lower() == 'config set pool': - return resource - return None - - - # ----------------------------------------- - # Return the pool Apps of the sandbox, if found - # ----------------------------------------- - def get_Apps_resources(self): - """ - Get the Apps resources - :rtype: list[ReservationAppResource] - """ - details = self.get_details() - apps_resources = details.ReservationDescription.Apps - - return apps_resources - - # ----------------------------------------- - # Return if there are apps in the sandbox - # ----------------------------------------- - def is_apps_in_reservation(self): - """Check if there are apps in reservation""" - details = self.get_details() - apps = details.ReservationDescription.App - - if not apps or (len(apps) == 1 and not apps[0].Name): - self.report_info("No apps found in reservation {0}".format(self.reservation_id)) - self.api_session.WriteMessageToReservationOutput(reservationId=self.reservation_id, - message='No apps in reservation') - return False - - return True + return True - # ---------------------------------- - # Power on VMs - # ---------------------------------- - def power_on_vms(self, write_to_output=True): - root_resources = self.get_root_resources() +# ---------------------------------- +# Power on VMs +# ---------------------------------- +def power_on_vms(self, write_to_output=True): + root_resources = self.get_root_resources() - for resource in root_resources: - if resource.is_app(): - deployed_app_name = resource.name - self.api_session.WriteMessageToReservationOutput(reservationId=self.id, - message='Power on Apps again') - self.api_session.ExecuteResourceConnectedCommand(self.id, deployed_app_name, "PowerOn", "power") + for resource in root_resources: + if resource.is_app(): + deployed_app_name = resource.name + self.api_session.WriteMessageToReservationOutput(reservationId=self.id, + message='Power on Apps again') + self.api_session.ExecuteResourceConnectedCommand(self.id, deployed_app_name, "PowerOn", "power") From b4714016c8ee2a5e24dc25eb969d8e4e87895537 Mon Sep 17 00:00:00 2001 From: Yaniv Kalsky Date: Fri, 5 May 2017 12:20:48 -0700 Subject: [PATCH 38/38] Fixed code alignment --- .../QualiEnvironmentUtils/Sandbox.py | 890 +++++++++--------- 1 file changed, 445 insertions(+), 445 deletions(-) diff --git a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py index 49f051c..10a61cf 100644 --- a/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py +++ b/sandbox_scripts/QualiEnvironmentUtils/Sandbox.py @@ -23,8 +23,8 @@ def __init__(self, reservation_id, logger): self.api_session = helpers.get_api_session() self.id = reservation_id context = helpers.get_reservation_context_details() - self.owner = self.context.owner_user - self.Blueprint_name = self.context.environment_name + self.owner = context.owner_user + self.Blueprint_name = context.environment_name if self.Blueprint_name == '': raise QualiError("Blueprint name empty (from env name)") @@ -46,464 +46,464 @@ def __init__(self, reservation_id, logger): self.report_error(error_message=err) -# ---------------------------------- -# ---------------------------------- -def _write_message_to_output(self, message, severity_level=SEVERITY_INFO): - """ - Write a message to the output window - """ - if severity_level == SEVERITY_INFO: - self.api_session.WriteMessageToReservationOutput(self.id, message) - elif severity_level == SEVERITY_ERROR: - self.api_session.WriteMessageToReservationOutput(self.id, '' + message + '') - - -# ---------------------------------- -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 and 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(emailresult + log_message) - else: - self._logger.error(emailresult + error_message) - if write_to_output_window: - self._write_message_to_output(error_message, SEVERITY_ERROR) - if raise_error: - raise QualiError(self.id, error_message) - - -# ---------------------------------- -def report_info(self, message, log_message=None, write_to_output_window=False): - """ - Report information to the log file, output window is optional. - :param str message: The 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 write_to_output_window: Would you like to write the message to the output window? - """ - if self._logger: - if log_message: - self._logger.info(log_message) - else: - self._logger.info(message) - if write_to_output_window: - self._write_message_to_output(message, SEVERITY_INFO) - - -# ---------------------------------- -def _emailalert(self, subject, body, owner, ishtml=False, emailOwner=False): - 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: + # ---------------------------------- + # ---------------------------------- + def _write_message_to_output(self, message, severity_level=SEVERITY_INFO): + """ + Write a message to the output window + """ + if severity_level == SEVERITY_INFO: + self.api_session.WriteMessageToReservationOutput(self.id, message) + elif severity_level == SEVERITY_ERROR: + self.api_session.WriteMessageToReservationOutput(self.id, '' + message + '') + + + # ---------------------------------- + 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 and send_email: + emailOwner = False 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." + 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: - emailbcc = '' - emailto = emailfrom + 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(emailresult + log_message) + else: + self._logger.error(emailresult + error_message) + if write_to_output_window: + self._write_message_to_output(error_message, SEVERITY_ERROR) + if raise_error: + raise QualiError(self.id, error_message) - try: - if ishtml: - emsg = MIMEText(body + '\n\n', 'html') + + # ---------------------------------- + def report_info(self, message, log_message=None, write_to_output_window=False): + """ + Report information to the log file, output window is optional. + :param str message: The 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 write_to_output_window: Would you like to write the message to the output window? + """ + if self._logger: + if log_message: + self._logger.info(log_message) 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)) + self._logger.info(message) + if write_to_output_window: + self._write_message_to_output(message, SEVERITY_INFO) + + + # ---------------------------------- + def _emailalert(self, subject, body, owner, ishtml=False, emailOwner=False): + 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: - # 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): - """ - Get the root resources - :rtype: list[ResourceBase] - """ - root_resources = [] - root_resources_names_dict = {} - details = self.get_details() - resources = details.ReservationDescription.Resources - topo_resources = details.ReservationDescription.TopologiesReservedResources - # Loop over all devices in the sandbox and add to a dictionary all root devices: - for resource in resources: - split_name = resource.Name.split('/') - root_resources_names_dict[split_name[0]] = 1 - - # instantiate a resource object for each root device - for root_resource_name in root_resources_names_dict.keys(): - root_resource_alias = '' - for topo_resource in topo_resources: - if topo_resource.Name == root_resource_name: - root_resource_alias = topo_resource.Alias - break - root_resources.append(ResourceBase(root_resource_name, root_resource_alias)) - - return root_resources - - -# ---------------------------------- -# ---------------------------------- -def get_root_vm_resources(self): - """ - Get the root resources of vm type - :rtype: list[ResourceBase] - """ - root_resources = [] - root_resources_names_dict = {} - details = self.get_details() - resources = details.ReservationDescription.Resources - # Loop over all devices in the sandbox and add to a dictionary all root devices of VM type: - for resource in resources: - # resource_details = self.api_session.GetResourceDetails(resource.Name) - if resource.VmDetails and hasattr(resource.VmDetails, 'UID') and resource.VmDetails.UID: - split_name = resource.Name.split('/') - root_resources_names_dict[split_name[0]] = 1 - root_resources.append(ResourceBase(resource.Name, '')) - - return root_resources - - -# ---------------------------------- -# ---------------------------------- -def get_root_networking_resources(self): - """ - Get the root resources of networking type - :rtype: list[ResourceBase] - """ - root_resources = [] - root_resources_names_dict = {} - details = self.get_details() - resources = details.ReservationDescription.Resources - topo_resources = details.ReservationDescription.TopologiesReservedResources - # Loop over all devices in the sandbox and add to a dictionary all root devices of type networking devices: - for resource in resources: - if not (resource.VmDetails and hasattr(resource.VmDetails, 'UID') and resource.VmDetails.UID): + return "ERROR Failed to send email(2)" + + + # ---------------------------------- + def get_root_resources(self): + """ + Get the root resources + :rtype: list[ResourceBase] + """ + root_resources = [] + root_resources_names_dict = {} + details = self.get_details() + resources = details.ReservationDescription.Resources + topo_resources = details.ReservationDescription.TopologiesReservedResources + # Loop over all devices in the sandbox and add to a dictionary all root devices: + for resource in resources: split_name = resource.Name.split('/') root_resources_names_dict[split_name[0]] = 1 - # instantiate a resource object for each root device - for root_resource_name in root_resources_names_dict.keys(): - root_resource_alias = '' - for topo_resource in topo_resources: - if topo_resource.Name == root_resource_name: - root_resource_alias = topo_resource.Alias - break - root_resources.append(ResourceBase(root_resource_name, root_resource_alias)) - - return root_resources - - -# ---------------------------------- -# ---------------------------------- -def clear_all_resources_live_status(self): - """ - Clear the live status from all the devices - """ - root_resources = self.get_root_resources() - for resource in root_resources: - self.api_session.SetResourceLiveStatus(resource.name, liveStatusName="Info", - additionalInfo='status cleared ' + strftime("%H:%M:%S", gmtime())) - - -# ---------------------------------- -# ---------------------------------- -def get_details(self): - """ - Retrieves all details and parameters for a specified Sandbox, including its resources, routes and route - segments, topologies, and Sandbox conflicts. - """ - try: - return self.api_session.GetReservationDetails(self.id) - except: - err = "Failed to get the Sandbox's details. Unexpected error: " + str(sys.exc_info()[0]) - self.report_error(error_message=err) - - -# ---------------------------------- -# ---------------------------------- -def activate_all_routes_and_connectors(self, write_to_output=True): - """ - Activate the routes in the topology - """ - try: - self.report_info(message="Connecting the connectors and routes", write_to_output_window=write_to_output) - self.activate_connectors(write_to_output=False) - - self.activate_routes(write_to_output=False) - self.report_info(message="Connectors and routes are connected", write_to_output_window=write_to_output) - except CloudShellAPIError as error: - err = "Failed to activate connectors and routes. " + error.message - self.report_error(error_message=err, write_to_output_window=write_to_output) - except: - err = "Failed to activate connectors and routes. Unexpected error: " + str(sys.exc_info()[0]) - self.report_error(error_message=err, write_to_output_window=write_to_output) - - -# ---------------------------------- -# ---------------------------------- -def activate_connectors(self, write_to_output=True): - """ - Activate the connectors in the topology - """ - try: - self.report_info(message="Connecting the connectors", write_to_output_window=write_to_output) + # instantiate a resource object for each root device + for root_resource_name in root_resources_names_dict.keys(): + root_resource_alias = '' + for topo_resource in topo_resources: + if topo_resource.Name == root_resource_name: + root_resource_alias = topo_resource.Alias + break + root_resources.append(ResourceBase(root_resource_name, root_resource_alias)) + + return root_resources + + + # ---------------------------------- + # ---------------------------------- + def get_root_vm_resources(self): + """ + Get the root resources of vm type + :rtype: list[ResourceBase] + """ + root_resources = [] + root_resources_names_dict = {} details = self.get_details() - connectors = details.ReservationDescription.Connectors - bi_endpoints = [] - for endpoint in connectors: - if endpoint.State in ['Disconnected', 'PartiallyConnected', 'ConnectionFailed'] \ - and endpoint.Target and endpoint.Source: - bi_endpoints.append(endpoint.Target) - bi_endpoints.append(endpoint.Source) - if not bi_endpoints: - self.report_info(message="No connectors to connect for reservation {0}".format(self.id), - write_to_output_window=write_to_output) - return - self.api_session.ConnectRoutesInReservation(self.id, bi_endpoints, 'bi') - self.report_info(message="Connectors connected", write_to_output_window=write_to_output) - except CloudShellAPIError as error: - err = "Failed to activate the connectors. " + error.message - self.report_error(error_message=err, write_to_output_window=write_to_output) - except: - err = "Failed to activate the connectors. Unexpected error: " + str(sys.exc_info()[0]) - self.report_error(error_message=err, write_to_output_window=write_to_output) - - -# ---------------------------------- -# ---------------------------------- -def activate_routes(self, write_to_output=True): - """ - Activate the routes in the topology - """ - try: - self.report_info(message="Connecting routes", write_to_output_window=write_to_output) + resources = details.ReservationDescription.Resources + # Loop over all devices in the sandbox and add to a dictionary all root devices of VM type: + for resource in resources: + # resource_details = self.api_session.GetResourceDetails(resource.Name) + if resource.VmDetails and hasattr(resource.VmDetails, 'UID') and resource.VmDetails.UID: + split_name = resource.Name.split('/') + root_resources_names_dict[split_name[0]] = 1 + root_resources.append(ResourceBase(resource.Name, '')) + + return root_resources + + + # ---------------------------------- + # ---------------------------------- + def get_root_networking_resources(self): + """ + Get the root resources of networking type + :rtype: list[ResourceBase] + """ + root_resources = [] + root_resources_names_dict = {} details = self.get_details() - routes = details.ReservationDescription.RequestedRoutesInfo - bi_endpoints = [] - uni_endpoints = [] - for route_endpoint in routes: - if route_endpoint.Target and route_endpoint.Source: - if route_endpoint.RouteType == 'bi': - bi_endpoints.append(route_endpoint.Target) - bi_endpoints.append(route_endpoint.Source) - elif route_endpoint.RouteType == 'uni': - uni_endpoints.append(route_endpoint.Source) - uni_endpoints.append(route_endpoint.Target) - - if not bi_endpoints and not uni_endpoints: - self.report_info(message="No routes to connect for reservation {0}".format(self.id), - write_to_output_window=write_to_output) - return - if bi_endpoints: + resources = details.ReservationDescription.Resources + topo_resources = details.ReservationDescription.TopologiesReservedResources + # Loop over all devices in the sandbox and add to a dictionary all root devices of type networking devices: + for resource in resources: + if not (resource.VmDetails and hasattr(resource.VmDetails, 'UID') and resource.VmDetails.UID): + split_name = resource.Name.split('/') + root_resources_names_dict[split_name[0]] = 1 + + # instantiate a resource object for each root device + for root_resource_name in root_resources_names_dict.keys(): + root_resource_alias = '' + for topo_resource in topo_resources: + if topo_resource.Name == root_resource_name: + root_resource_alias = topo_resource.Alias + break + root_resources.append(ResourceBase(root_resource_name, root_resource_alias)) + + return root_resources + + + # ---------------------------------- + # ---------------------------------- + def clear_all_resources_live_status(self): + """ + Clear the live status from all the devices + """ + root_resources = self.get_root_resources() + for resource in root_resources: + self.api_session.SetResourceLiveStatus(resource.name, liveStatusName="Info", + additionalInfo='status cleared ' + strftime("%H:%M:%S", gmtime())) + + + # ---------------------------------- + # ---------------------------------- + def get_details(self): + """ + Retrieves all details and parameters for a specified Sandbox, including its resources, routes and route + segments, topologies, and Sandbox conflicts. + """ + try: + return self.api_session.GetReservationDetails(self.id) + except: + err = "Failed to get the Sandbox's details. Unexpected error: " + str(sys.exc_info()[0]) + self.report_error(error_message=err) + + + # ---------------------------------- + # ---------------------------------- + def activate_all_routes_and_connectors(self, write_to_output=True): + """ + Activate the routes in the topology + """ + try: + self.report_info(message="Connecting the connectors and routes", write_to_output_window=write_to_output) + self.activate_connectors(write_to_output=False) + + self.activate_routes(write_to_output=False) + self.report_info(message="Connectors and routes are connected", write_to_output_window=write_to_output) + except CloudShellAPIError as error: + err = "Failed to activate connectors and routes. " + error.message + self.report_error(error_message=err, write_to_output_window=write_to_output) + except: + err = "Failed to activate connectors and routes. Unexpected error: " + str(sys.exc_info()[0]) + self.report_error(error_message=err, write_to_output_window=write_to_output) + + + # ---------------------------------- + # ---------------------------------- + def activate_connectors(self, write_to_output=True): + """ + Activate the connectors in the topology + """ + try: + self.report_info(message="Connecting the connectors", write_to_output_window=write_to_output) + details = self.get_details() + connectors = details.ReservationDescription.Connectors + bi_endpoints = [] + for endpoint in connectors: + if endpoint.State in ['Disconnected', 'PartiallyConnected', 'ConnectionFailed'] \ + and endpoint.Target and endpoint.Source: + bi_endpoints.append(endpoint.Target) + bi_endpoints.append(endpoint.Source) + if not bi_endpoints: + self.report_info(message="No connectors to connect for reservation {0}".format(self.id), + write_to_output_window=write_to_output) + return self.api_session.ConnectRoutesInReservation(self.id, bi_endpoints, 'bi') - if uni_endpoints: - self.api_session.ConnectRoutesInReservation(self.id, uni_endpoints, 'uni') - self.report_info(message="Routes connected", write_to_output_window=write_to_output) - except CloudShellAPIError as error: - err = "Failed to activate routes. " + error.message - self.report_error(error_message=err, write_to_output_window=write_to_output) - except: - err = "Failed to activate routes. Unexpected error: " + str(sys.exc_info()[0]) - self.report_error(error_message=err, write_to_output_window=write_to_output) - - -# ----------------------------------------- -# ----------------------------------------- -def execute_command(self, commandName, commandInputs=[], printOutput=False): - """ - Executes a command - :param str commandName: Command Name - Specify the name of the command. - :param list[InputNameValue] commandInputs: Command Inputs - Specify a matrix of input names and values - required for executing the command. - :param bool printOutput: Print Output - Defines whether to print the command output - in the Sandbox command output window. - :rtype: CommandExecutionCompletedResultInfo - """ - try: - return self.api_session.ExecuteEnvironmentCommand(self.id, commandName, commandInputs, printOutput) - - except CloudShellAPIError as error: - raise QualiError(self.id, error.message) - - -# ----------------------------------------- -# ----------------------------------------- -def enqueue_command(self, commandName, commandInputs=[], printOutput=False): - """ - Enqueue a command - :param str commandName: Command Name - Specify the name of the command. - :param list[InputNameValue] commandInputs: Command Inputs - Specify a matrix of input names and values - required for executing the command. - :param bool printOutput: Print Output - Defines whether to print the command output - in the Sandbox command output window. - :rtype: CommandExecutionCompletedResultInfo - """ - try: - return self.api_session.EnqueueEnvironmentCommand(self.id, commandName, commandInputs, printOutput) - - except CloudShellAPIError as error: - raise QualiError(self.id, error.message) - - -# ----------------------------------------- -# ----------------------------------------- -def save_sandbox_as_blueprint(self, blueprint_name, write_to_output=True): - try: - # TODO - fullpath should be passed as a param to the function and not hard coded - # save the current Sandbox as a new Blueprint with the given snapshot name - fullpath = 'Snapshots' - self.api_session.SaveReservationAsTopology(self.id, topologyName=blueprint_name, folderFullPath=fullpath, - includeInactiveRoutes=True) - - except CloudShellAPIError as error: - err = "Failed to save sandbox as blueprint. " + error.message - self.report_error(error_message=err, raise_error=True, write_to_output_window=write_to_output) - # if snapshot_exist: - # err = "Blueprint " + blueprint_name + " already exist. Please select a different name." - # self.report_error(error_message=err, write_to_output_window=write_to_output) - # raise Exception('Blueprint name already exist. Please select a different name.') - - # update the new snapshot with the user as owner - username = helpers.get_reservation_context_details().owner_user - fullTopologyName = 'Snapshots/' + blueprint_name - self.api_session.UpdateTopologyOwner(topologyName=fullTopologyName, ownerName=username) - - -# ----------------------------------------- -# check if this resource originated from an abstract resource -# ----------------------------------------- -def is_abstract(self, resource_alias): - for abstract_resource in self.blueprint_details.AbstractResources: - if resource_alias == abstract_resource.Alias: - return True - return False - - -# ----------------------------------------- -# Return the storage resource of the sandbox (e.g. tftp, ftp), if found -# ----------------------------------------- -def get_storage_server_resource(self): - root_resources = self.get_root_resources() - for resource in root_resources: - if resource.details.ResourceFamilyName.lower() == 'storage server': - return resource - return None - - -# ----------------------------------------- -# Return the repositroy resource of the sandbox (e.g. gitlab), if found -# ----------------------------------------- -def get_repository_server_resource(self): - root_resources = self.get_root_resources() - for resource in root_resources: - if resource.details.ResourceFamilyName.lower() == 'repository': - return resource - return None - - -# ----------------------------------------- -# Return the pool resource of the sandbox, if found -# ----------------------------------------- -def get_config_set_pool_resource(self): - root_resources = self.get_root_resources() - for resource in root_resources: - if resource.model.lower() == 'config set pool': - return resource - return None - - -# ----------------------------------------- -# Return the pool Apps of the sandbox, if found -# ----------------------------------------- -def get_Apps_resources(self): - """ - Get the Apps resources - :rtype: list[ReservationAppResource] - """ - details = self.get_details() - apps_resources = details.ReservationDescription.Apps - - return apps_resources - - -# ----------------------------------------- -# Return if there are apps in the sandbox -# ----------------------------------------- -def is_apps_in_reservation(self): - """Check if there are apps in reservation""" - details = self.get_details() - apps = details.ReservationDescription.App - - if not apps or (len(apps) == 1 and not apps[0].Name): - self.report_info("No apps found in reservation {0}".format(self.reservation_id)) - self.api_session.WriteMessageToReservationOutput(reservationId=self.reservation_id, - message='No apps in reservation') + self.report_info(message="Connectors connected", write_to_output_window=write_to_output) + except CloudShellAPIError as error: + err = "Failed to activate the connectors. " + error.message + self.report_error(error_message=err, write_to_output_window=write_to_output) + except: + err = "Failed to activate the connectors. Unexpected error: " + str(sys.exc_info()[0]) + self.report_error(error_message=err, write_to_output_window=write_to_output) + + + # ---------------------------------- + # ---------------------------------- + def activate_routes(self, write_to_output=True): + """ + Activate the routes in the topology + """ + try: + self.report_info(message="Connecting routes", write_to_output_window=write_to_output) + details = self.get_details() + routes = details.ReservationDescription.RequestedRoutesInfo + bi_endpoints = [] + uni_endpoints = [] + for route_endpoint in routes: + if route_endpoint.Target and route_endpoint.Source: + if route_endpoint.RouteType == 'bi': + bi_endpoints.append(route_endpoint.Target) + bi_endpoints.append(route_endpoint.Source) + elif route_endpoint.RouteType == 'uni': + uni_endpoints.append(route_endpoint.Source) + uni_endpoints.append(route_endpoint.Target) + + if not bi_endpoints and not uni_endpoints: + self.report_info(message="No routes to connect for reservation {0}".format(self.id), + write_to_output_window=write_to_output) + return + if bi_endpoints: + self.api_session.ConnectRoutesInReservation(self.id, bi_endpoints, 'bi') + if uni_endpoints: + self.api_session.ConnectRoutesInReservation(self.id, uni_endpoints, 'uni') + self.report_info(message="Routes connected", write_to_output_window=write_to_output) + except CloudShellAPIError as error: + err = "Failed to activate routes. " + error.message + self.report_error(error_message=err, write_to_output_window=write_to_output) + except: + err = "Failed to activate routes. Unexpected error: " + str(sys.exc_info()[0]) + self.report_error(error_message=err, write_to_output_window=write_to_output) + + + # ----------------------------------------- + # ----------------------------------------- + def execute_command(self, commandName, commandInputs=[], printOutput=False): + """ + Executes a command + :param str commandName: Command Name - Specify the name of the command. + :param list[InputNameValue] commandInputs: Command Inputs - Specify a matrix of input names and values + required for executing the command. + :param bool printOutput: Print Output - Defines whether to print the command output + in the Sandbox command output window. + :rtype: CommandExecutionCompletedResultInfo + """ + try: + return self.api_session.ExecuteEnvironmentCommand(self.id, commandName, commandInputs, printOutput) + + except CloudShellAPIError as error: + raise QualiError(self.id, error.message) + + + # ----------------------------------------- + # ----------------------------------------- + def enqueue_command(self, commandName, commandInputs=[], printOutput=False): + """ + Enqueue a command + :param str commandName: Command Name - Specify the name of the command. + :param list[InputNameValue] commandInputs: Command Inputs - Specify a matrix of input names and values + required for executing the command. + :param bool printOutput: Print Output - Defines whether to print the command output + in the Sandbox command output window. + :rtype: CommandExecutionCompletedResultInfo + """ + try: + return self.api_session.EnqueueEnvironmentCommand(self.id, commandName, commandInputs, printOutput) + + except CloudShellAPIError as error: + raise QualiError(self.id, error.message) + + + # ----------------------------------------- + # ----------------------------------------- + def save_sandbox_as_blueprint(self, blueprint_name, write_to_output=True): + try: + # TODO - fullpath should be passed as a param to the function and not hard coded + # save the current Sandbox as a new Blueprint with the given snapshot name + fullpath = 'Snapshots' + self.api_session.SaveReservationAsTopology(self.id, topologyName=blueprint_name, folderFullPath=fullpath, + includeInactiveRoutes=True) + + except CloudShellAPIError as error: + err = "Failed to save sandbox as blueprint. " + error.message + self.report_error(error_message=err, raise_error=True, write_to_output_window=write_to_output) + # if snapshot_exist: + # err = "Blueprint " + blueprint_name + " already exist. Please select a different name." + # self.report_error(error_message=err, write_to_output_window=write_to_output) + # raise Exception('Blueprint name already exist. Please select a different name.') + + # update the new snapshot with the user as owner + username = helpers.get_reservation_context_details().owner_user + fullTopologyName = 'Snapshots/' + blueprint_name + self.api_session.UpdateTopologyOwner(topologyName=fullTopologyName, ownerName=username) + + + # ----------------------------------------- + # check if this resource originated from an abstract resource + # ----------------------------------------- + def is_abstract(self, resource_alias): + for abstract_resource in self.blueprint_details.AbstractResources: + if resource_alias == abstract_resource.Alias: + return True return False - return True + + # ----------------------------------------- + # Return the storage resource of the sandbox (e.g. tftp, ftp), if found + # ----------------------------------------- + def get_storage_server_resource(self): + root_resources = self.get_root_resources() + for resource in root_resources: + if resource.details.ResourceFamilyName.lower() == 'storage server': + return resource + return None + + + # ----------------------------------------- + # Return the repositroy resource of the sandbox (e.g. gitlab), if found + # ----------------------------------------- + def get_repository_server_resource(self): + root_resources = self.get_root_resources() + for resource in root_resources: + if resource.details.ResourceFamilyName.lower() == 'repository': + return resource + return None + + + # ----------------------------------------- + # Return the pool resource of the sandbox, if found + # ----------------------------------------- + def get_config_set_pool_resource(self): + root_resources = self.get_root_resources() + for resource in root_resources: + if resource.model.lower() == 'config set pool': + return resource + return None + + + # ----------------------------------------- + # Return the pool Apps of the sandbox, if found + # ----------------------------------------- + def get_Apps_resources(self): + """ + Get the Apps resources + :rtype: list[ReservationAppResource] + """ + details = self.get_details() + apps_resources = details.ReservationDescription.Apps + + return apps_resources + + + # ----------------------------------------- + # Return if there are apps in the sandbox + # ----------------------------------------- + def is_apps_in_reservation(self): + """Check if there are apps in reservation""" + details = self.get_details() + apps = details.ReservationDescription.App + + if not apps or (len(apps) == 1 and not apps[0].Name): + self.report_info("No apps found in reservation {0}".format(self.reservation_id)) + self.api_session.WriteMessageToReservationOutput(reservationId=self.reservation_id, + message='No apps in reservation') + return False + + return True -# ---------------------------------- -# Power on VMs -# ---------------------------------- -def power_on_vms(self, write_to_output=True): - root_resources = self.get_root_resources() + # ---------------------------------- + # Power on VMs + # ---------------------------------- + def power_on_vms(self, write_to_output=True): + root_resources = self.get_root_resources() - for resource in root_resources: - if resource.is_app(): - deployed_app_name = resource.name - self.api_session.WriteMessageToReservationOutput(reservationId=self.id, - message='Power on Apps again') - self.api_session.ExecuteResourceConnectedCommand(self.id, deployed_app_name, "PowerOn", "power") + for resource in root_resources: + if resource.is_app(): + deployed_app_name = resource.name + self.api_session.WriteMessageToReservationOutput(reservationId=self.id, + message='Power on Apps again') + self.api_session.ExecuteResourceConnectedCommand(self.id, deployed_app_name, "PowerOn", "power")