def test_exception_temp_backup_action_files(self): CLONE_ACTION_6 = clone_action_db( SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, TEST_DEST_PACK, "clone_action_6") clone_action_files(SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, CLONE_ACTION_6, TEST_DEST_PACK_PATH) dest_action_metadata_file = CLONE_ACTION_6["metadata_file"] dest_action_entry_point_file = CLONE_ACTION_6["entry_point"] temp_sub_dir = str(uuid.uuid4()) temp_dir_path = "/tmp/%s" % temp_sub_dir tmp_action_metadata_file_path = os.path.join( temp_dir_path, dest_action_metadata_file) expected_msg = ( 'Unable to copy file to "%s". Please check the logs or ask your ' "administrator to clone the files manually." % tmp_action_metadata_file_path) with mock.patch("shutil.copy") as mock_copy: mock_copy.side_effect = Exception with self.assertRaisesRegexp(Exception, expected_msg): temp_backup_action_files( TEST_DEST_PACK_PATH, dest_action_metadata_file, dest_action_entry_point_file, temp_sub_dir, ) remove_temp_action_files(temp_sub_dir)
def test_permission_error_restore_temp_action_files(self): CLONE_ACTION_9 = clone_action_db( SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, TEST_DEST_PACK, "clone_action_9") clone_action_files(SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, CLONE_ACTION_9, TEST_DEST_PACK_PATH) dest_action_metadata_file = CLONE_ACTION_9["metadata_file"] dest_action_entry_point_file = CLONE_ACTION_9["entry_point"] dest_action_files_path = os.path.join(TEST_DEST_PACK_PATH, "actions") for file in os.listdir(dest_action_files_path): if os.path.isfile(os.path.join(dest_action_files_path, file)): os.remove(os.path.join(dest_action_files_path, file)) temp_sub_dir = str(uuid.uuid4()) dest_action_metadata_file_path = os.path.join( TEST_DEST_PACK_PATH, dest_action_metadata_file) expected_msg = 'Unable to copy file to "%s".' % dest_action_metadata_file_path with mock.patch("shutil.copy") as mock_copy: mock_copy.side_effect = PermissionError with self.assertRaisesRegexp(PermissionError, expected_msg): restore_temp_action_files( TEST_DEST_PACK_PATH, dest_action_metadata_file, dest_action_entry_point_file, temp_sub_dir, ) remove_temp_action_files(temp_sub_dir)
def test_exception_restore_temp_action_files(self): CLONE_ACTION_8 = clone_action_db( SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, TEST_DEST_PACK, "clone_action_8") clone_action_files(SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, CLONE_ACTION_8, TEST_DEST_PACK_PATH) dest_action_metadata_file = CLONE_ACTION_8["metadata_file"] dest_action_entry_point_file = CLONE_ACTION_8["entry_point"] dest_action_files_path = os.path.join(TEST_DEST_PACK_PATH, "actions") for file in os.listdir(dest_action_files_path): if os.path.isfile(os.path.join(dest_action_files_path, file)): os.remove(os.path.join(dest_action_files_path, file)) temp_sub_dir = str(uuid.uuid4()) dest_action_metadata_file_path = os.path.join( TEST_DEST_PACK_PATH, dest_action_metadata_file) expected_msg = ( 'Unable to copy file to "%s". Please check the logs or ask your ' "administrator to clone the files manually." % dest_action_metadata_file_path) with mock.patch("shutil.copy") as mock_copy: mock_copy.side_effect = Exception with self.assertRaisesRegexp(Exception, expected_msg): restore_temp_action_files( TEST_DEST_PACK_PATH, dest_action_metadata_file, dest_action_entry_point_file, temp_sub_dir, ) remove_temp_action_files(temp_sub_dir)
def test_exception_remove_temp_action_files(self): CLONE_ACTION_4 = clone_action_db( SOURCE_ACTION_WITH_PYTHON_SCRIPT_RUNNER, TEST_DEST_PACK, "clone_action_4") clone_action_files(SOURCE_ACTION_WITH_PYTHON_SCRIPT_RUNNER, CLONE_ACTION_4, TEST_DEST_PACK_PATH) dest_action_metadata_file = CLONE_ACTION_4["metadata_file"] dest_action_entry_point_file = CLONE_ACTION_4["entry_point"] temp_sub_dir = str(uuid.uuid4()) temp_backup_action_files( TEST_DEST_PACK_PATH, dest_action_metadata_file, dest_action_entry_point_file, temp_sub_dir, ) temp_dir_path = "/tmp/%s" % temp_sub_dir self.assertTrue(os.path.isdir(temp_dir_path)) expected_msg = ( 'The temporary directory "%s" could not be removed from disk, please check the logs ' "or ask your StackStorm administrator to check and delete the temporary directory " "manually" % temp_dir_path) with mock.patch("shutil.rmtree") as mock_rmdir: mock_rmdir.side_effect = Exception with self.assertRaisesRegexp(Exception, expected_msg): remove_temp_action_files(temp_sub_dir) remove_temp_action_files(temp_sub_dir)
def test_clone_files_for_workflow_action(self): CLONE_WORKFLOW = clone_action_db(SOURCE_WORKFLOW, TEST_DEST_PACK, "clone_workflow") clone_action_files(SOURCE_WORKFLOW, CLONE_WORKFLOW, TEST_DEST_PACK_PATH) cloned_workflow_metadata_file_path = os.path.join( TEST_DEST_PACK_PATH, "actions", "clone_workflow.yaml") cloned_workflow_entry_point_file_path = os.path.join( TEST_DEST_PACK_PATH, "actions", "workflows", "clone_workflow.yaml") self.assertTrue(os.path.exists(cloned_workflow_metadata_file_path)) self.assertTrue(os.path.exists(cloned_workflow_entry_point_file_path))
def test_clone_files_for_python_script_runner_action(self): CLONE_ACTION_1 = clone_action_db( SOURCE_ACTION_WITH_PYTHON_SCRIPT_RUNNER, TEST_DEST_PACK, "clone_action_1") clone_action_files(SOURCE_ACTION_WITH_PYTHON_SCRIPT_RUNNER, CLONE_ACTION_1, TEST_DEST_PACK_PATH) cloned_action_metadata_file_path = os.path.join( TEST_DEST_PACK_PATH, "actions", "clone_action_1.yaml") cloned_action_entry_point_file_path = os.path.join( TEST_DEST_PACK_PATH, "actions", "clone_action_1.py") self.assertTrue(os.path.exists(cloned_action_metadata_file_path)) self.assertTrue(os.path.exists(cloned_action_entry_point_file_path))
def test_clone_files_for_local_shell_cmd_runner_action(self): CLONE_ACTION_3 = clone_action_db( SOURCE_ACTION_WITH_LOCAL_SHELL_CMD_RUNNER, TEST_DEST_PACK, "clone_action_3") clone_action_files( SOURCE_ACTION_WITH_LOCAL_SHELL_CMD_RUNNER, CLONE_ACTION_3, TEST_DEST_PACK_PATH, ) cloned_action_metadata_file_path = os.path.join( TEST_DEST_PACK_PATH, "actions", "clone_action_3.yaml") self.assertTrue(os.path.exists(cloned_action_metadata_file_path))
def test_clone_files_for_shell_script_runner_action(self): CLONE_ACTION_2 = clone_action_db( SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, TEST_DEST_PACK, "clone_action_2") clone_action_files(SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, CLONE_ACTION_2, TEST_DEST_PACK_PATH) cloned_action_metadata_file_path = os.path.join( TEST_DEST_PACK_PATH, "actions", "clone_action_2.yaml") cloned_action_entry_point_file_path = os.path.join( TEST_DEST_PACK_PATH, "actions", "clone_action_2") self.assertTrue(os.path.exists(cloned_action_metadata_file_path)) self.assertTrue(os.path.exists(cloned_action_entry_point_file_path))
def test_clone_action_db(self): CLONE_ACTION_1 = clone_action_db( SOURCE_ACTION_WITH_PYTHON_SCRIPT_RUNNER, TEST_DEST_PACK, "clone_action_1") exptected_uid = UIDFieldMixin.UID_SEPARATOR.join( ["action", TEST_DEST_PACK, "clone_action_1"]) actual_uid = CLONE_ACTION_1["uid"] self.assertEqual(actual_uid, exptected_uid) exptected_parameters = SOURCE_ACTION_WITH_PYTHON_SCRIPT_RUNNER[ "parameters"] actual_parameters = CLONE_ACTION_1["parameters"] self.assertDictEqual(actual_parameters, exptected_parameters)
def test_workflows_directory_created_if_does_not_exist(self): action_dir_path = os.path.join(TEST_DEST_PACK_PATH, "actions") workflows_dir_path = os.path.join(TEST_DEST_PACK_PATH, "actions", "workflows") # removing workflows directory and asserting it doesn't exist shutil.rmtree(workflows_dir_path) self.assertFalse(os.path.exists(workflows_dir_path)) self.assertTrue(os.path.exists(action_dir_path)) CLONE_WORKFLOW = clone_action_db(SOURCE_WORKFLOW, TEST_DEST_PACK, "clone_workflow") clone_action_files(SOURCE_WORKFLOW, CLONE_WORKFLOW, TEST_DEST_PACK_PATH) # workflows directory created and asserting it exists self.assertTrue(os.path.exists(workflows_dir_path))
def test_permission_error_to_write_in_destination_file(self, mock_copy): mock_copy.side_effect = PermissionError( "No permission to write in file") cloned_action_metadata_file_path = os.path.join( TEST_DEST_PACK_PATH, "actions", "clone_action_4.yaml") expected_msg = 'Unable to copy file to "%s".' % ( cloned_action_metadata_file_path) CLONE_ACTION_4 = clone_action_db( SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, TEST_DEST_PACK, "clone_action_4") with self.assertRaisesRegexp(PermissionError, expected_msg): clone_action_files( SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, CLONE_ACTION_4, TEST_DEST_PACK_PATH, )
def test_exceptions_to_write_in_destination_file(self, mock_copy): mock_copy.side_effect = Exception( "Exception encoutntered during writing in destination action file") CLONE_ACTION_5 = clone_action_db( SOURCE_ACTION_WITH_LOCAL_SHELL_CMD_RUNNER, TEST_DEST_PACK, "clone_action_5") cloned_action_metadata_file_path = os.path.join( TEST_DEST_PACK_PATH, "actions", "clone_action_5.yaml") expected_msg = ( 'Unable to copy file to "%s". Please check the logs or ask your ' "administrator to clone the files manually." % cloned_action_metadata_file_path) with self.assertRaisesRegexp(Exception, expected_msg): clone_action_files( SOURCE_ACTION_WITH_LOCAL_SHELL_CMD_RUNNER, CLONE_ACTION_5, TEST_DEST_PACK_PATH, )
def test_actions_directory_created_if_does_not_exist(self): action_dir_path = os.path.join(TEST_DEST_PACK_PATH, "actions") # removing actions directory and asserting it doesn't exist shutil.rmtree(action_dir_path) self.assertFalse(os.path.exists(action_dir_path)) CLONE_ACTION_6 = clone_action_db( SOURCE_ACTION_WITH_LOCAL_SHELL_CMD_RUNNER, TEST_DEST_PACK, "clone_action_6") clone_action_files( SOURCE_ACTION_WITH_LOCAL_SHELL_CMD_RUNNER, CLONE_ACTION_6, TEST_DEST_PACK_PATH, ) # workflows directory created and asserting it exists self.assertTrue(os.path.exists(action_dir_path)) wf_dir_path = os.path.join(action_dir_path, "workflows") if not os.path.isdir(wf_dir_path): os.mkdir(wf_dir_path)
def test_permission_error_temp_backup_action_files(self): CLONE_ACTION_7 = clone_action_db( SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, TEST_DEST_PACK, "clone_action_7") clone_action_files(SOURCE_ACTION_WITH_SHELL_SCRIPT_RUNNER, CLONE_ACTION_7, TEST_DEST_PACK_PATH) dest_action_metadata_file = CLONE_ACTION_7["metadata_file"] dest_action_entry_point_file = CLONE_ACTION_7["entry_point"] temp_sub_dir = str(uuid.uuid4()) temp_dir_path = "/tmp/%s" % temp_sub_dir tmp_action_metadata_file_path = os.path.join( temp_dir_path, dest_action_metadata_file) expected_msg = 'Unable to copy file to "%s".' % tmp_action_metadata_file_path with mock.patch("shutil.copy") as mock_copy: mock_copy.side_effect = PermissionError with self.assertRaisesRegexp(PermissionError, expected_msg): temp_backup_action_files( TEST_DEST_PACK_PATH, dest_action_metadata_file, dest_action_entry_point_file, temp_sub_dir, ) remove_temp_action_files(temp_sub_dir)
def test_permission_error_remove_temp_action_files(self): CLONE_ACTION_5 = clone_action_db( SOURCE_ACTION_WITH_PYTHON_SCRIPT_RUNNER, TEST_DEST_PACK, "clone_action_5") clone_action_files(SOURCE_ACTION_WITH_PYTHON_SCRIPT_RUNNER, CLONE_ACTION_5, TEST_DEST_PACK_PATH) dest_action_metadata_file = CLONE_ACTION_5["metadata_file"] dest_action_entry_point_file = CLONE_ACTION_5["entry_point"] temp_sub_dir = str(uuid.uuid4()) temp_backup_action_files( TEST_DEST_PACK_PATH, dest_action_metadata_file, dest_action_entry_point_file, temp_sub_dir, ) temp_dir_path = "/tmp/%s" % temp_sub_dir self.assertTrue(os.path.isdir(temp_dir_path)) expected_msg = 'No permission to delete the "%s" directory' % temp_dir_path with mock.patch("shutil.rmtree") as mock_rmdir: mock_rmdir.side_effect = PermissionError with self.assertRaisesRegexp(PermissionError, expected_msg): remove_temp_action_files(temp_sub_dir) remove_temp_action_files(temp_sub_dir)
def clone(self, dest_data, ref_or_id, requester_user): """ Clone an action from source pack to destination pack. Handles requests: POST /actions/{ref_or_id}/clone """ source_action_db = self._get_by_ref_or_id(ref_or_id=ref_or_id) if not source_action_db: msg = "The requested source for cloning operation doesn't exists" abort(http_client.BAD_REQUEST, six.text_type(msg)) extra = {"action_db": source_action_db} LOG.audit("Source action found. Action.id=%s" % (source_action_db.id), extra=extra) try: permission_type = PermissionType.ACTION_VIEW rbac_utils = get_rbac_backend().get_utils_class() rbac_utils.assert_user_has_resource_db_permission( user_db=requester_user, resource_db=source_action_db, permission_type=permission_type, ) except ResourceAccessDeniedError as e: abort(http_client.UNAUTHORIZED, six.text_type(e)) cloned_dest_action_db = clone_action_db( source_action_db=source_action_db, dest_pack=dest_data.dest_pack, dest_action=dest_data.dest_action, ) cloned_action_api = ActionAPI.from_model(cloned_dest_action_db) try: permission_type = PermissionType.ACTION_CREATE rbac_utils.assert_user_has_resource_api_permission( user_db=requester_user, resource_api=cloned_action_api, permission_type=permission_type, ) except ResourceAccessDeniedError as e: abort(http_client.UNAUTHORIZED, six.text_type(e)) dest_pack_base_path = get_pack_base_path(pack_name=dest_data.dest_pack) if not os.path.isdir(dest_pack_base_path): msg = "Destination pack '%s' doesn't exist" % (dest_data.dest_pack) abort(http_client.BAD_REQUEST, six.text_type(msg)) dest_pack_base_path = get_pack_base_path(pack_name=dest_data.dest_pack) dest_ref = ".".join([dest_data.dest_pack, dest_data.dest_action]) dest_action_db = self._get_by_ref(resource_ref=dest_ref) try: validate_not_part_of_system_pack_by_name(dest_data.dest_pack) except ValueValidationException as e: abort(http_client.BAD_REQUEST, six.text_type(e)) if dest_action_db: if not dest_data.overwrite: msg = "The requested destination action already exists" abort(http_client.BAD_REQUEST, six.text_type(msg)) try: permission_type = PermissionType.ACTION_DELETE rbac_utils.assert_user_has_resource_db_permission( user_db=requester_user, resource_db=dest_action_db, permission_type=permission_type, ) options = GenericRequestParam(remove_files=True) dest_metadata_file = dest_action_db["metadata_file"] dest_entry_point = dest_action_db["entry_point"] temp_sub_dir = str(uuid.uuid4()) temp_backup_action_files( dest_pack_base_path, dest_metadata_file, dest_entry_point, temp_sub_dir, ) self.delete(options, dest_ref, requester_user) except ResourceAccessDeniedError as e: abort(http_client.UNAUTHORIZED, six.text_type(e)) except Exception as e: LOG.debug( "Exception encountered during deleting existing destination action. " "Exception was: %s", e, ) abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e)) try: post_response = self.post(cloned_action_api, requester_user) if post_response.status_code != http_client.CREATED: raise Exception("Could not add cloned action to database.") cloned_dest_action_db["id"] = post_response.json["id"] clone_action_files( source_action_db=source_action_db, dest_action_db=cloned_dest_action_db, dest_pack_base_path=dest_pack_base_path, ) extra = {"cloned_acion_db": cloned_dest_action_db} LOG.audit("Action cloned. Action.id=%s" % (cloned_dest_action_db.id), extra=extra) if dest_action_db: remove_temp_action_files(temp_sub_dir) return post_response except PermissionError as e: LOG.error("No permission to clone the action. Exception was %s", e) delete_action_files_from_pack( pack_name=cloned_dest_action_db["pack"], entry_point=cloned_dest_action_db["entry_point"], metadata_file=cloned_dest_action_db["metadata_file"], ) if post_response.status_code == http_client.CREATED: Action.delete(cloned_dest_action_db) if dest_action_db: self._restore_action(dest_action_db, dest_pack_base_path, temp_sub_dir) abort(http_client.FORBIDDEN, six.text_type(e)) except Exception as e: LOG.error( "Exception encountered during cloning action. Exception was %s", e, ) delete_action_files_from_pack( pack_name=cloned_dest_action_db["pack"], entry_point=cloned_dest_action_db["entry_point"], metadata_file=cloned_dest_action_db["metadata_file"], ) if post_response.status_code == http_client.CREATED: Action.delete(cloned_dest_action_db) if dest_action_db: self._restore_action(dest_action_db, dest_pack_base_path, temp_sub_dir) abort(http_client.INTERNAL_SERVER_ERROR, six.text_type(e))
def test_temp_backup_restore_remove_action_files(self): CLONE_ACTION_1 = clone_action_db( SOURCE_ACTION_WITH_PYTHON_SCRIPT_RUNNER, TEST_DEST_PACK, "clone_action_1") clone_action_files(SOURCE_ACTION_WITH_PYTHON_SCRIPT_RUNNER, CLONE_ACTION_1, TEST_DEST_PACK_PATH) dest_action_metadata_file = CLONE_ACTION_1["metadata_file"] dest_action_entry_point_file = CLONE_ACTION_1["entry_point"] temp_sub_dir = str(uuid.uuid4()) # creating backup of dest action files at /tmp/<uuid> temp_backup_action_files( TEST_DEST_PACK_PATH, dest_action_metadata_file, dest_action_entry_point_file, temp_sub_dir, ) temp_dir_path = "/tmp/%s" % temp_sub_dir self.assertTrue(os.path.isdir(temp_dir_path)) temp_metadata_file_path = os.path.join(temp_dir_path, dest_action_metadata_file) temp_entry_point_file_path = os.path.join( temp_dir_path, "actions", dest_action_entry_point_file) # asserting backup files exists self.assertTrue(os.path.exists(temp_metadata_file_path)) self.assertTrue(os.path.exists(temp_entry_point_file_path)) # removing destination action files dest_action_files_path = os.path.join(TEST_DEST_PACK_PATH, "actions") for file in os.listdir(dest_action_files_path): if os.path.isfile(os.path.join(dest_action_files_path, file)): os.remove(os.path.join(dest_action_files_path, file)) dest_action_metadata_file_path = os.path.join( TEST_DEST_PACK_PATH, dest_action_metadata_file) dest_action_entry_point_file_path = os.path.join( TEST_DEST_PACK_PATH, "actions", dest_action_entry_point_file) # asserting destination action files doesn't exist self.assertFalse(os.path.isfile(dest_action_metadata_file_path)) self.assertFalse(os.path.isfile(dest_action_entry_point_file_path)) # restoring temp backed action files to destination restore_temp_action_files( TEST_DEST_PACK_PATH, dest_action_metadata_file, dest_action_entry_point_file, temp_sub_dir, ) # asserting action files restored at destination self.assertTrue(os.path.isfile(dest_action_metadata_file_path)) self.assertTrue(os.path.isfile(dest_action_entry_point_file_path)) # asserting temp_dir and backed action files exits self.assertTrue(os.path.isdir(temp_dir_path)) self.assertTrue(os.path.exists(temp_metadata_file_path)) self.assertTrue(os.path.exists(temp_entry_point_file_path)) # removing temp_dir and backed action files remove_temp_action_files(temp_sub_dir) # asserting temp_dir and backed action files doesn't exit self.assertFalse(os.path.isdir(temp_dir_path)) self.assertFalse(os.path.exists(temp_metadata_file_path)) self.assertFalse(os.path.exists(temp_entry_point_file_path))