def test_ca_cert_files_checks_are_skipped_under_dev_and_msi_install(self): # Skip those checks under dev and msi install because those final generated certs files # are not present under dev install from scalyr_agent.agent_main import ScalyrAgent from scalyr_agent.platform_controller import PlatformController # 1. Dev install (boths checks should be skipped) with mock.patch("scalyr_agent.__scalyr__.INSTALL_TYPE", __scalyr__.DEV_INSTALL): # ca_cert_path file doesn't exist config = mock.Mock() config.scalyr_server = "foo.bar.com" config.compression_level = 1 config.verify_server_certificate = True config.ca_cert_path = "/tmp/doesnt.exist" config.use_new_ingestion = False agent = ScalyrAgent(PlatformController()) agent._ScalyrAgent__config = config self.assertTrue(create_client(config=config)) # intermediate_certs_path file doesn't exist config.verify_server_certificate = True config.ca_cert_path = __file__ config.intermediate_certs_path = "/tmp/doesnt.exist" self.assertTrue(create_client(config=config)) # 2. MSI install (only intermediate_certs_path check should be skipped) with mock.patch("scalyr_agent.__scalyr__.INSTALL_TYPE", __scalyr__.MSI_INSTALL): config = mock.Mock() config.scalyr_server = "foo.bar.com" config.compression_level = 1 config.verify_server_certificate = True config.ca_cert_path = "/tmp/doesnt.exist" config.use_new_ingestion = False agent = ScalyrAgent(PlatformController()) agent._ScalyrAgent__config = config expected_msg = ( r'Invalid path "/tmp/doesnt.exist" specified for the "ca_cert_path" config ' "option: file does not exist") self.assertRaisesRegexp(ValueError, expected_msg, functools.partial(create_client, config)) # intermediate_certs_path file doesn't exist config.verify_server_certificate = True config.ca_cert_path = __file__ config.intermediate_certs_path = "/tmp/doesnt.exist" self.assertTrue(create_client(config=config))
def __init__(self, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): """Initializes the POSIX platform instance. """ self.__stdin = stdin self.__stdout = stdout self.__stderr = stderr # The file name storing the pid. self.__pidfile = None # The pidfile specified on the commandline using the flags, if any. This gives the user a chance to # specify the pidfile if the configuration cannot be read. self.__pidfile_from_options = None # The method to invoke when termination is requested. self.__termination_handler = None # The method to invoke when status is requested by another process. self.__status_handler = None self.__no_change_user = False # A list of log lines collected for debugging the initialization sequence. The entries # are tuples of the line and a boolean indicating whether or not it is a debug entry. self.__init_log_lines = [] self.__is_initializing = True # Whether or not to use the commandline in the pidfile to help protect against pid re-use. self.__verify_command_in_pidfile = False PlatformController.__init__(self)
def test_ca_cert_files_checks_are_skipped_under_dev_and_msi_install(self): # Skip those checks under dev and msi install because those final generated certs files # are not present under dev install import scalyr_agent.agent_main from scalyr_agent.agent_main import ScalyrAgent from scalyr_agent.platform_controller import PlatformController # 1. Dev install (boths checks should be skipped) scalyr_agent.agent_main.INSTALL_TYPE = DEV_INSTALL # ca_cert_path file doesn't exist config = mock.Mock() config.scalyr_server = "foo.bar.com" config.verify_server_certificate = True config.ca_cert_path = "/tmp/doesnt.exist" agent = ScalyrAgent(PlatformController()) agent._ScalyrAgent__config = config self.assertTrue(agent._ScalyrAgent__create_client()) # intermediate_certs_path file doesn't exist config.verify_server_certificate = True config.ca_cert_path = __file__ config.intermediate_certs_path = "/tmp/doesnt.exist" self.assertTrue(agent._ScalyrAgent__create_client()) # 2. MSI install (only intermediate_certs_path check should be skipped) scalyr_agent.agent_main.INSTALL_TYPE = MSI_INSTALL config = mock.Mock() config.scalyr_server = "foo.bar.com" config.verify_server_certificate = True config.ca_cert_path = "/tmp/doesnt.exist" agent = ScalyrAgent(PlatformController()) agent._ScalyrAgent__config = config expected_msg = ( r'Invalid path "/tmp/doesnt.exist" specified for the "ca_cert_path" config ' "option: file does not exist" ) self.assertRaisesRegexp( ValueError, expected_msg, agent._ScalyrAgent__create_client ) # intermediate_certs_path file doesn't exist config.verify_server_certificate = True config.ca_cert_path = __file__ config.intermediate_certs_path = "/tmp/doesnt.exist" self.assertTrue(agent._ScalyrAgent__create_client())
def test_create_client_ca_file_and_intermediate_certs_file_doesnt_exist(self): from scalyr_agent.agent_main import ScalyrAgent from scalyr_agent.platform_controller import PlatformController # 1. file doesn't exist but cert verification is disabled config = mock.Mock() config.scalyr_server = "foo.bar.com" config.verify_server_certificate = False config.ca_cert_path = "/tmp/doesnt.exist" agent = ScalyrAgent(PlatformController()) agent._ScalyrAgent__config = config self.assertTrue(agent._ScalyrAgent__create_client()) # ca_cert_path file doesn't exist config.verify_server_certificate = True config.ca_cert_path = "/tmp/doesnt.exist" agent = ScalyrAgent(PlatformController()) agent._ScalyrAgent__config = config expected_msg = ( r'Invalid path "/tmp/doesnt.exist" specified for the "ca_cert_path" config ' "option: file does not exist" ) self.assertRaisesRegexp( ValueError, expected_msg, agent._ScalyrAgent__create_client ) # intermediate_certs_path file doesn't exist config.verify_server_certificate = True config.ca_cert_path = __file__ config.intermediate_certs_path = "/tmp/doesnt.exist" agent = ScalyrAgent(PlatformController()) agent._ScalyrAgent__config = config expected_msg = ( r'Invalid path "/tmp/doesnt.exist" specified for the ' '"intermediate_certs_path" config option: file does not exist' ) self.assertRaisesRegexp( ValueError, expected_msg, agent._ScalyrAgent__create_client )
def __init__(self): """Initializes the Windows platform instance.""" # The method to invoke when termination is requested. self.__termination_handler = None # The method to invoke when status is requested by another process. self.__status_handler = None # The file path to the configuration. We need to stash this so it is available when start is invoked. self.__config_file_path = None # The local domain Administrators name. self.__local_administrators = "%s\\Administrators" % win32api.GetComputerName( ) self.__no_change_user = False # Controls whether or not we warn the user via stdout that we are about to escalate to Administrator privileges. self.__no_escalation_warning = False PlatformController.__init__(self)
def __init__(self, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): """Initializes the POSIX platform instance. """ self.__stdin = stdin self.__stdout = stdout self.__stderr = stderr # The file name storing the pid. self.__pidfile = None # The pidfile specified on the commandline using the flags, if any. This gives the user a chance to # specify the pidfile if the configuration cannot be read. self.__pidfile_from_options = None # The method to invoke when termination is requested. self.__termination_handler = None # The method to invoke when status is requested by another process. self.__status_handler = None self.__no_change_user = False PlatformController.__init__(self)
def config_object(self): # type: () -> Configuration """ Get config object from the config file. """ platform = PlatformController.new_platform() platform._install_type = self._installation_type default_types = platform.default_paths config = Configuration(six.text_type(self._agent_config_path), default_types, None) config.parse() return config
def __init__(self, install_type, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): """Initializes the POSIX platform instance. @param install_type: One of the constants describing the install type, such as PACKAGE_INSTALL, TARBALL_INSTALL, or DEV_INSTALL. @type install_type: int """ self.__stdin = stdin self.__stdout = stdout self.__stderr = stderr # The file name storing the pid. self.__pidfile = None # The pidfile specified on the commandline using the flags, if any. This gives the user a chance to # specify the pidfile if the configuration cannot be read. self.__pidfile_from_options = None # The method to invoke when termination is requested. self.__termination_handler = None # The method to invoke when status is requested by another process. self.__status_handler = None PlatformController.__init__(self, install_type)
def setUp(self): super(AgentMainStatusHandlerTestCase, self).setUp() self.data_path = tempfile.mkdtemp(suffix="agent-data-path") self.status_format_file = os.path.join(self.data_path, STATUS_FORMAT_FILE) default_paths = mock.Mock() default_paths.agent_data_path = self.data_path default_paths.agent_log_path = "agent.log" config_file = os.path.join(BASE_DIR, "fixtures/configs/agent1.json") config = Configuration(config_file, default_paths, None) config.parse() self.agent = ScalyrAgent(PlatformController()) self.agent._ScalyrAgent__config = config
def _get_default_paths(self): # type: () -> Dict[six.text_type, Path] """ Get default path for essential directories and files of the agent. Those paths are fetched from 'PlatformController'. """ # create new 'PlatformController' instance. Since this code is executed on the same machine with agent, # platform setting and paths should match. platform = PlatformController.new_platform() # change install type of the controller to needed one. platform._install_type = self._installation_type default_types = platform.default_paths result = dict() for k, v in default_types.__dict__.items(): result[k] = Path(v) return result
def run_standalone_monitor( monitor_module, monitor_python_path, monitor_config, monitor_sample_interval, monitor_debug_level, global_config_path, ): """Runs a single plugin monitor instance. @param monitor_module: The name of the python module implementing the monitor. @param monitor_python_path: The python path to search to find the module. @param monitor_config: The monitor configuration object. @param monitor_sample_interval: The default to use for the sample interval. @param monitor_debug_level: The debug level to use for logging. @param global_config_path: The path to the agent.json global configuration file to use, or None if none was supplied. """ scalyr_logging.set_log_destination(use_stdout=True) scalyr_logging.set_log_level(monitor_debug_level) log.log(scalyr_logging.DEBUG_LEVEL_1, "Attempting to run module %s", monitor_module) try: # Needs to be json_lib.parse because it is parsing configuration parsed_config = scalyr_util.json_scalyr_config_decode(monitor_config) log.log(scalyr_logging.DEBUG_LEVEL_1, "Parsed configuration successfully") except JsonParseException as e: print( "Failed to parse the monitor configuration as valid JSON: %s", six.text_type(e), file=sys.stderr, ) return 1 parsed_config["module"] = monitor_module if "id" not in parsed_config: parsed_config["id"] = "" # noinspection PyUnusedLocal def handle_shutdown_signal(signum, frame): print("Signal received, stopping monitor...", file=sys.stdout) monitor.stop() for sig in (signal.SIGTERM, signal.SIGINT): signal.signal(sig, handle_shutdown_signal) try: if global_config_path is not None: controller = PlatformController.new_platform() paths = controller.default_paths global_config = Configuration(global_config_path, paths, log) global_config.parse() else: global_config = None monitor = MonitorsManager.build_monitor( parsed_config, monitor_python_path, float(monitor_sample_interval), global_config, ) log.log(scalyr_logging.DEBUG_LEVEL_1, "Constructed monitor") monitor.open_metric_log() log.log(scalyr_logging.DEBUG_LEVEL_1, "Starting monitor") monitor.start() while monitor.isAlive(): time.sleep(0.1) except BadMonitorConfiguration as e: print("Invalid monitor configuration: %s" % six.text_type(e), file=sys.stderr) return 0
def upgrade_windows_install(config, release_track="stable", preserve_msi=False, use_ui=True): """Performs an upgrade for an existing Scalyr Agent 2 that was previously installed using a Windows MSI install file. This will contact the Scalyr servers to see what the most up-to-date version of the agent is and, if necessary, download an MSI file. @param config: The configuration for this agent. @param release_track: The release track to use when checking which version is the latest. @param preserve_msi: Whether or not to delete the MSI file once the upgrade is finished. Note, this argument is essentially ignored for now and we always leave the file because we cannot delete it with the current way we exec the msiexec process. @param use_ui: Whether or not the msiexec upgrade command should be run with the UI. @rtype config: Configuration @rtype release_track: str @rtype preserve_msi: bool @rtype use_ui: bool @return: The exit status code. """ # The URL path of the agent to upgrade to. url_path = None try: platform_controller = PlatformController.new_platform() my_default_paths = platform_controller.default_paths # Ensure agent was installed via MSI if MSI_INSTALL != platform_controller.install_type: raise UpgradeFailure( 'The current agent was not installed via MSI, so you may not use the upgrade windows ' 'command.') # Ensure that the user has not changed the defaults for the config, data, and log directory. if my_default_paths.config_file_path != config.file_path: raise UpgradeFailure( 'The agent is not using the default configuration file so you may not use the ' 'upgrade windows command.') if my_default_paths.agent_data_path != config.agent_data_path: raise UpgradeFailure( 'The agent is not using the default data directory so you may not use the upgrade ' 'windows command.') if my_default_paths.agent_log_path != config.agent_log_path: raise UpgradeFailure( 'The agent is not using the default log directory so you may not use the upgrade ' 'windows command.') # Determine if a newer version is available client = ScalyrClientSession(config.scalyr_server, config.api_key, SCALYR_VERSION, quiet=True, ca_file=config.ca_cert_path) status, size, response = client.perform_agent_version_check( release_track) if status.lower() != 'success': raise UpgradeFailure( 'Failed to contact the Scalyr servers to check for latest update. Error code ' 'was "%s"' % status) # TODO: We shouldn't have to reparse response on JSON, but for now that, that's what the client library # does. data_payload = json_lib.parse(response)['data'] if not data_payload['update_required']: print 'The latest version is already installed.' return 0 print 'Attempting to upgrade agent from version %s to version %s.' % ( SCALYR_VERSION, data_payload['current_version']) url_path = data_payload['urls']['win32'] file_portion = url_path[url_path.rfind('/') + 1:] download_location = os.path.join(tempfile.gettempdir(), file_portion) try: try: print 'Downloading agent from %s.' % url_path urllib.urlretrieve(url_path, download_location) if not os.path.isfile(download_location): raise UpgradeFailure( 'Failed to download installation package') if use_ui: print( 'Executing upgrade. Please follow the instructions in the subsequent dialog boxes to ' 'complete the upgrade process.') else: print( 'Executing upgrade. It will finish in the background.' ) # Because this file, config_main.py, is part of the currently installed Scalyr Agent package, we have # to finish our use of it before the upgrade can proceed. So, we just fork off the msiexec process # in detached mode and terminate this program. This means we cannot report any errors that happen # here, but I don't see a way around this for now. # noinspection PyUnresolvedReferences from win32process import DETACHED_PROCESS upgrade_command = [ 'msiexec.exe', '/i', "{}".format(download_location) ] if not use_ui: upgrade_command.append('/qn') subprocess.Popen(upgrade_command, shell=False, stdin=None, stdout=None, stderr=None, close_fds=True, creationflags=DETACHED_PROCESS) return 0 except IOError, error: raise UpgradeFailure( 'Could not download the installer, returned error %s' % str(error)) finally: # TODO: Actually delete the temporary file. We cannot right now since our execution finishes # before the msiexec process runs, but maybe we can do something like have a small shell script # that runs the upgrader and then deletes the file. Something to consider post-alpha release. if preserve_msi: print 'Downloaded installer file has been left at %s' % download_location except UpgradeFailure, error: print >> sys.stderr print >> sys.stderr, 'The upgrade failed due to the following reason: %s' % error.message if url_path is not None: print >> sys.stderr, 'You may try downloading and running the installer file yourself.' print >> sys.stderr, 'The installer can be downloaded from %s' % url_path print >> sys.stderr, 'Please e-mail [email protected] for help resolving this issue.' return 1
def upgrade_tarball_install(config, new_tarball, preserve_old_install): """Performs an upgrade for an existing Scalyr Agent 2 that was previously installed using the tarball method. @param config: The configuration for this agent. @param new_tarball: The path to file containing the new tarball to install. @param preserve_old_install: If True, will move the old install directory to a new location rather than deleting it. @return: The exit status code. """ # Create a temporary directory hold the new install as we untar it and copy files into it. tmp_install_dir = tempfile.mkdtemp() # Some variables that capture some important state that we may need to unwind if we execute # out the installation along the way. # # If not None, then the directory we are currently holding the old installation directory in. preserve_dir = None # True if the agent was running when the install started. was_running = False # True if the agent was successfully restarted. was_restarted = False try: try: platform_controller = PlatformController.new_platform() my_default_paths = platform_controller.default_paths # Ensure that this is a tarball install if platform_controller.install_type != TARBALL_INSTALL: raise UpgradeFailure( 'The current agent was not installed using a tarball, so you may not use the ' 'upgrade tarball command.') # Ensure that the user has not changed the defaults for the config, data, and log directory. if my_default_paths.config_file_path != config.file_path: raise UpgradeFailure( 'The agent is not using the default configuration file so you may not use the ' 'upgrade tarball command.') if my_default_paths.agent_data_path != config.agent_data_path: raise UpgradeFailure( 'The agent is not using the default data directory so you may not use the upgrade ' 'tarball command.') if my_default_paths.agent_log_path != config.agent_log_path: raise UpgradeFailure( 'The agent is not using the default log directory so you may not use the upgrade ' 'tarball command.') # We rely on the current installation being included in the PATH variable. if spawn.find_executable('scalyr-agent-2-config') is None: raise UpgradeFailure( 'Could not locate the scalyr-agent-2-config command from the current ' 'installation. Please ensure that the agent\'s bin directory is in the system\'s ' 'PATH variable.') if not os.path.isfile(new_tarball): raise UpgradeFailure('The tarball file %s does not exist.' % new_tarball) file_name = os.path.basename(new_tarball) if re.match('^scalyr-agent-2\..*\.tar\.gz$', file_name) is None: raise UpgradeFailure( 'The supplied tarball file name does not match the expected format.' ) tarball_directory = file_name[0:-7] # We will be installing in the same directory where scalyr-agent-2 is currently installed. install_directory = os.path.dirname(get_install_root()) if not os.path.isdir( os.path.join(install_directory, 'scalyr-agent-2')): raise UpgradeFailure( 'Could not determine the install directory. Either the main directory is no ' 'longer called scalyr-agent-2, or the directory structure has changed.' ) # Compute the full paths to the scalyr-agent-2 directories for both the new install and old install. tmp_new_install_location = os.path.join(tmp_install_dir, tarball_directory) old_install_location = os.path.join(install_directory, 'scalyr-agent-2') # Untar the new package into the temp location. tar = tarfile.open(new_tarball, 'r:gz') for member in tar.getmembers(): tar.extract(member, path=tmp_install_dir) # Check to see if the agent is running. If so, stop it. was_running = run_command( 'scalyr-agent-2 stop', grep_for='Agent has stopped', command_name='scalyr-agent-2 stop')[0] == 0 # Copy the config, data, and log directories. for dir_name in ['config', 'log', 'data']: copy_dir_to_new_agent(old_install_location, tmp_new_install_location, dir_name) # Allow the new agent code to perform any actions it deems necessary. We do the special commandline # here where to pass in both directories to the --upgrade-tarball-command result = subprocess.call([ os.path.join(tmp_new_install_location, 'bin', 'scalyr-agent-2-config'), '--upgrade-tarball', '%s%s%s' % (old_install_location, os.pathsep, tmp_new_install_location) ]) if result != 0: raise UpgradeFailure( 'New package failed to finish the upgrade process.') # Move the old install directory to a temporary location, so we can undo the next move if we need to. preserve_dir = tempfile.mkdtemp() shutil.move(old_install_location, preserve_dir) # Move the new install into place. success = False try: shutil.move(tmp_new_install_location, old_install_location) success = True finally: if not success: # Move the old install back in place just to be safe. shutil.move(os.path.join(preserve_dir, 'scalyr-agent-2'), old_install_location) if success and not preserve_old_install: shutil.rmtree(preserve_dir) preserve_dir = None print 'New agent installed.' # Start the agent if it was previously running. if was_running: if run_command('scalyr-agent-2 start', exit_on_fail=False, command_name='scalyr-agent-2 start')[0] == 0: print 'Agent has successfully restarted.' print ' You may execute the following command for status details: scalyr-agent-2 status -v' was_restarted = True else: raise UpgradeFailure( 'Could not start the agent. Execute the following command for more details: ' 'scalyr-agent-2 start') else: print 'Execute the following command to start the agent: scalyr-agent-2 start' return 0 except UpgradeFailure, error: print >> sys.stderr print >> sys.stderr, 'The upgrade failed due to the following reason: %s' % error.message return 1 finally: # Delete the temporary directory. shutil.rmtree(tmp_install_dir) # Warn if we should have restarted the agent but did not. if was_running and not was_restarted: print '' print( 'WARNING, due to failure, the agent may no longer be running. Restart it with: scalyr-agent-2 ' 'start') # If there is still a preserve_directory, there must be a reason for it, so tell the user where it is. if preserve_dir is not None: print '' print 'The previous agent installation was left in \'%s\'' % preserve_dir print 'You should be sure to delete this directory once you no longer need it.'
def upgrade_windows_install(config, release_track="stable", preserve_msi=False, use_ui=True): """Performs an upgrade for an existing Scalyr Agent 2 that was previously installed using a Windows MSI install file. This will contact the Scalyr servers to see what the most up-to-date version of the agent is and, if necessary, download an MSI file. @param config: The configuration for this agent. @param release_track: The release track to use when checking which version is the latest. @param preserve_msi: Whether or not to delete the MSI file once the upgrade is finished. Note, this argument is essentially ignored for now and we always leave the file because we cannot delete it with the current way we exec the msiexec process. @param use_ui: Whether or not the msiexec upgrade command should be run with the UI. @rtype config: Configuration @rtype release_track: str @rtype preserve_msi: bool @rtype use_ui: bool @return: The exit status code. """ # The URL path of the agent to upgrade to. url_path = None try: platform_controller = PlatformController.new_platform() my_default_paths = platform_controller.default_paths # Ensure agent was installed via MSI if MSI_INSTALL != platform_controller.install_type: raise UpgradeFailure('The current agent was not installed via MSI, so you may not use the upgrade windows ' 'command.') # Ensure that the user has not changed the defaults for the config, data, and log directory. if my_default_paths.config_file_path != config.file_path: raise UpgradeFailure('The agent is not using the default configuration file so you may not use the ' 'upgrade windows command.') if my_default_paths.agent_data_path != config.agent_data_path: raise UpgradeFailure('The agent is not using the default data directory so you may not use the upgrade ' 'windows command.') if my_default_paths.agent_log_path != config.agent_log_path: raise UpgradeFailure('The agent is not using the default log directory so you may not use the upgrade ' 'windows command.') # Determine if a newer version is available client = ScalyrClientSession(config.scalyr_server, config.api_key, SCALYR_VERSION, quiet=True, ca_file=config.ca_cert_path) status, size, response = client.perform_agent_version_check(release_track) if status.lower() != 'success': raise UpgradeFailure('Failed to contact the Scalyr servers to check for latest update. Error code ' 'was "%s"' % status) # TODO: We shouldn't have to reparse response on JSON, but for now that, that's what the client library # does. data_payload = json_lib.parse(response)['data'] if not data_payload['update_required']: print 'The latest version is already installed.' return 0 print 'Attempting to upgrade agent from version %s to version %s.' % (SCALYR_VERSION, data_payload['current_version']) url_path = data_payload['urls']['win32'] file_portion = url_path[url_path.rfind('/')+1:] download_location = os.path.join(tempfile.gettempdir(), file_portion) try: try: print 'Downloading agent from %s.' % url_path urllib.urlretrieve(url_path, download_location) if not os.path.isfile(download_location): raise UpgradeFailure('Failed to download installation package') if use_ui: print ('Executing upgrade. Please follow the instructions in the subsequent dialog boxes to ' 'complete the upgrade process.') else: print ('Executing upgrade. It will finish in the background.') # Because this file, config_main.py, is part of the currently installed Scalyr Agent package, we have # to finish our use of it before the upgrade can proceed. So, we just fork off the msiexec process # in detached mode and terminate this program. This means we cannot report any errors that happen # here, but I don't see a way around this for now. # noinspection PyUnresolvedReferences from win32process import DETACHED_PROCESS upgrade_command = ['msiexec.exe', '/i', "{}".format(download_location)] if not use_ui: upgrade_command.append('/qn') subprocess.Popen(upgrade_command, shell=False, stdin=None, stdout=None, stderr=None, close_fds=True, creationflags=DETACHED_PROCESS) return 0 except IOError, error: raise UpgradeFailure('Could not download the installer, returned error %s' % str(error)) finally: # TODO: Actually delete the temporary file. We cannot right now since our execution finishes # before the msiexec process runs, but maybe we can do something like have a small shell script # that runs the upgrader and then deletes the file. Something to consider post-alpha release. if preserve_msi: print 'Downloaded installer file has been left at %s' % download_location except UpgradeFailure, error: print >>sys.stderr print >>sys.stderr, 'The upgrade failed due to the following reason: %s' % error.message if url_path is not None: print >>sys.stderr, 'You may try downloading and running the installer file yourself.' print >>sys.stderr, 'The installer can be downloaded from %s' % url_path print >>sys.stderr, 'Please e-mail [email protected] for help resolving this issue.' return 1
def test_skipped_bytes_warnings(self): from scalyr_agent.agent_main import ScalyrAgent from scalyr_agent.platform_controller import PlatformController with mock.patch("scalyr_agent.__scalyr__.INSTALL_TYPE", __scalyr__.DEV_INSTALL): config = mock.Mock() config.scalyr_server = "foo.bar.com" config.server_attributes = {"serverHost": "test"} config.additional_file_paths = [] config.compression_level = 1 config.copying_manager_stats_log_interval = 60 config.parsed_max_send_rate_enforcement = 12345 config.verify_server_certificate = True config.ca_cert_path = "/tmp/doesnt.exist" platform_controller = PlatformController() platform_controller.get_usage_info = AgentMainTestCase.fake_get_useage_info agent = ScalyrAgent(platform_controller) agent._ScalyrAgent__config = config client = create_client(config) def get_worker_session_statuses_mock(*args, **kwargs): return [client] with mock.patch.object(agent, "_ScalyrAgent__copying_manager") as m: m.generate_status = mock.MagicMock(return_value=None) m.get_worker_session_statuses = get_worker_session_statuses_mock base_stats = agent_status.OverallStats() base_stats.total_bytes_skipped = 500 test = agent._ScalyrAgent__calculate_overall_stats( base_stats, copy_manager_warnings=True) self.assertIsNotNone(test) self.assertLogFileContainsLineRegex(".*" + re.escape( "Warning, skipping copying log lines. Only copied 0.0 MB/s log bytes when 0.0 MB/s were generated over the last 1.0 minutes. This may be due to max_send_rate_enforcement. Log upload has been delayed 0.0 seconds in the last 1.0 minutes This may be desired (due to excessive bytes from a problematic log file). Please contact [email protected] for additional help." )) config = mock.Mock() config.scalyr_server = "foo.bar.com" config.server_attributes = {"serverHost": "test"} config.additional_file_paths = [] config.compression_level = 1 config.copying_manager_stats_log_interval = 60 config.parsed_max_send_rate_enforcement = None config.verify_server_certificate = True config.ca_cert_path = "/tmp/doesnt.exist" platform_controller = PlatformController() platform_controller.get_usage_info = AgentMainTestCase.fake_get_useage_info agent = ScalyrAgent(platform_controller) agent._ScalyrAgent__config = config client = create_client(config) with mock.patch.object(agent, "_ScalyrAgent__copying_manager") as m: m.generate_status = mock.MagicMock(return_value=None) m.get_worker_session_statuses = get_worker_session_statuses_mock base_stats.total_bytes_skipped = 1000 test = agent._ScalyrAgent__calculate_overall_stats( base_stats, copy_manager_warnings=True) self.assertIsNotNone(test) with open(self.agent_log_path, "r") as f: print((f.read())) self.assertLogFileContainsLineRegex(".*" + re.escape( "Warning, skipping copying log lines. Only copied 0.0 MB/s log bytes when 0.0 MB/s were generated over the last 1.0 minutes. This may be desired (due to excessive bytes from a problematic log file). Please contact [email protected] for additional help." ))
parsed_config['module'] = monitor_module if 'id' not in parsed_config: parsed_config['id'] = '' # noinspection PyUnusedLocal def handle_shutdown_signal(signum, frame): print >>sys.stdout, 'Signal received, stopping monitor...' monitor.stop() for sig in (signal.SIGTERM, signal.SIGINT): signal.signal(sig, handle_shutdown_signal) try: if global_config_path is not None: controller = PlatformController.new_platform() paths = controller.default_paths global_config = Configuration( global_config_path, paths ) global_config.parse(logger=log) else: global_config = None monitor = MonitorsManager.build_monitor(parsed_config, monitor_python_path, float(monitor_sample_interval), global_config ) log.log(scalyr_logging.DEBUG_LEVEL_1, 'Constructed monitor') monitor.open_metric_log() log.log(scalyr_logging.DEBUG_LEVEL_1, 'Starting monitor') monitor.start() while monitor.isAlive(): time.sleep(0.1) except BadMonitorConfiguration, e:
def upgrade_tarball_install(config, new_tarball, preserve_old_install): """Performs an upgrade for an existing Scalyr Agent 2 that was previously installed using the tarball method. @param config: The configuration for this agent. @param new_tarball: The path to file containing the new tarball to install. @param preserve_old_install: If True, will move the old install directory to a new location rather than deleting it. @return: The exit status code. """ # Create a temporary directory hold the new install as we untar it and copy files into it. tmp_install_dir = tempfile.mkdtemp() # Some variables that capture some important state that we may need to unwind if we execute # out the installation along the way. # # If not None, then the directory we are currently holding the old installation directory in. preserve_dir = None # True if the agent was running when the install started. was_running = False # True if the agent was successfully restarted. was_restarted = False try: try: platform_controller = PlatformController.new_platform() my_default_paths = platform_controller.default_paths # Ensure that this is a tarball install if platform_controller.install_type != TARBALL_INSTALL: raise UpgradeFailure('The current agent was not installed using a tarball, so you may not use the ' 'upgrade tarball command.') # Ensure that the user has not changed the defaults for the config, data, and log directory. if my_default_paths.config_file_path != config.file_path: raise UpgradeFailure('The agent is not using the default configuration file so you may not use the ' 'upgrade tarball command.') if my_default_paths.agent_data_path != config.agent_data_path: raise UpgradeFailure('The agent is not using the default data directory so you may not use the upgrade ' 'tarball command.') if my_default_paths.agent_log_path != config.agent_log_path: raise UpgradeFailure('The agent is not using the default log directory so you may not use the upgrade ' 'tarball command.') # We rely on the current installation being included in the PATH variable. if spawn.find_executable('scalyr-agent-2-config') is None: raise UpgradeFailure('Could not locate the scalyr-agent-2-config command from the current ' 'installation. Please ensure that the agent\'s bin directory is in the system\'s ' 'PATH variable.') if not os.path.isfile(new_tarball): raise UpgradeFailure('The tarball file %s does not exist.' % new_tarball) file_name = os.path.basename(new_tarball) if re.match('^scalyr-agent-2\..*\.tar\.gz$', file_name) is None: raise UpgradeFailure('The supplied tarball file name does not match the expected format.') tarball_directory = file_name[0:-7] # We will be installing in the same directory where scalyr-agent-2 is currently installed. install_directory = os.path.dirname(get_install_root()) if not os.path.isdir(os.path.join(install_directory, 'scalyr-agent-2')): raise UpgradeFailure('Could not determine the install directory. Either the main directory is no ' 'longer called scalyr-agent-2, or the directory structure has changed.') # Compute the full paths to the scalyr-agent-2 directories for both the new install and old install. tmp_new_install_location = os.path.join(tmp_install_dir, tarball_directory) old_install_location = os.path.join(install_directory, 'scalyr-agent-2') # Untar the new package into the temp location. tar = tarfile.open(new_tarball, 'r:gz') for member in tar.getmembers(): tar.extract(member, path=tmp_install_dir) # Check to see if the agent is running. If so, stop it. was_running = run_command('scalyr-agent-2 stop', grep_for='Agent has stopped', command_name='scalyr-agent-2 stop')[0] == 0 # Copy the config, data, and log directories. for dir_name in ['config', 'log', 'data']: copy_dir_to_new_agent(old_install_location, tmp_new_install_location, dir_name) # Allow the new agent code to perform any actions it deems necessary. We do the special commandline # here where to pass in both directories to the --upgrade-tarball-command result = subprocess.call([os.path.join(tmp_new_install_location, 'bin', 'scalyr-agent-2-config'), '--upgrade-tarball', '%s%s%s' % (old_install_location, os.pathsep, tmp_new_install_location)]) if result != 0: raise UpgradeFailure('New package failed to finish the upgrade process.') # Move the old install directory to a temporary location, so we can undo the next move if we need to. preserve_dir = tempfile.mkdtemp() shutil.move(old_install_location, preserve_dir) # Move the new install into place. success = False try: shutil.move(tmp_new_install_location, old_install_location) success = True finally: if not success: # Move the old install back in place just to be safe. shutil.move(os.path.join(preserve_dir, 'scalyr-agent-2'), old_install_location) if success and not preserve_old_install: shutil.rmtree(preserve_dir) preserve_dir = None print 'New agent installed.' # Start the agent if it was previously running. if was_running: if run_command('scalyr-agent-2 start', exit_on_fail=False, command_name='scalyr-agent-2 start')[0] == 0: print 'Agent has successfully restarted.' print ' You may execute the following command for status details: scalyr-agent-2 status -v' was_restarted = True else: raise UpgradeFailure('Could not start the agent. Execute the following command for more details: ' 'scalyr-agent-2 start') else: print 'Execute the following command to start the agent: scalyr-agent-2 start' return 0 except UpgradeFailure, error: print >>sys.stderr print >>sys.stderr, 'The upgrade failed due to the following reason: %s' % error.message return 1 finally: # Delete the temporary directory. shutil.rmtree(tmp_install_dir) # Warn if we should have restarted the agent but did not. if was_running and not was_restarted: print '' print ('WARNING, due to failure, the agent may no longer be running. Restart it with: scalyr-agent-2 ' 'start') # If there is still a preserve_directory, there must be a reason for it, so tell the user where it is. if preserve_dir is not None: print '' print 'The previous agent installation was left in \'%s\'' % preserve_dir print 'You should be sure to delete this directory once you no longer need it.'