def test_no_new_version(self): """We don't autoupgrade if a new version isn't available.""" self.config_db['autoupgrade.channel'] = 'beta' self.config_db['autoupgrade.latest_beta_version'] = '1.2.3' with mock.patch(self.upgrade_method) as mock_upgrade: system_utilities.try_to_autoupgrade() self.assertEqual(False, mock_upgrade.called)
def test_just_after_window(self): """Don't upgrade if the window has just passed.""" self.config_db['autoupgrade.in_window'] = True # Set the window to have started duration + a second before now. the_past = datetime.datetime.utcnow() - datetime.timedelta(seconds=601) self.config_db['autoupgrade.window_start'] = ( the_past.strftime('%H:%M:%S')) with mock.patch(self.upgrade_method) as mock_upgrade: system_utilities.try_to_autoupgrade() self.assertEqual(False, mock_upgrade.called)
def test_just_before_window(self): """Don't upgrade if the window hasn't quite started.""" self.config_db['autoupgrade.in_window'] = True # Set the window to start a second from now. the_future = datetime.datetime.utcnow() + datetime.timedelta(seconds=1) self.config_db['autoupgrade.window_start'] = ( the_future.strftime('%H:%M:%S')) with mock.patch(self.upgrade_method) as mock_upgrade: system_utilities.try_to_autoupgrade() self.assertEqual(False, mock_upgrade.called)
def test_not_in_window(self): """Don't upgrade if we're not in the window.""" self.config_db['autoupgrade.in_window'] = True # Set the window to a few hours from now. the_future = datetime.datetime.utcnow() + datetime.timedelta(hours=2) self.config_db['autoupgrade.window_start'] = ( the_future.strftime('%H:%M:%S')) with mock.patch(self.upgrade_method) as mock_upgrade: system_utilities.try_to_autoupgrade() self.assertEqual(False, mock_upgrade.called)
def test_immediate(self): """We can upgrade as soon as a new package is available.""" self.config_db['autoupgrade.channel'] = 'beta' self.config_db['autoupgrade.latest_beta_version'] = '3.2.1' with mock.patch(self.upgrade_method) as mock_upgrade: system_utilities.try_to_autoupgrade() self.assertEqual(True, mock_upgrade.called) # A new version is suddenly available, and we can upgrade again. self.config_db['autoupgrade.latest_beta_version'] = '3.2.2' with mock.patch(self.upgrade_method) as second_mock_upgrade: system_utilities.try_to_autoupgrade() self.assertEqual(True, second_mock_upgrade.called)
def test_correct_window(self): """Upgrade if we're in the correct window.""" self.config_db['autoupgrade.in_window'] = True # Set the upgrade window to have started a second before now. the_past = datetime.datetime.utcnow() - datetime.timedelta(seconds=1) self.config_db['autoupgrade.window_start'] = ( the_past.strftime('%H:%M:%S')) # Setup a specific upgrade channel. self.config_db['autoupgrade.channel'] = 'beta' self.config_db['autoupgrade.latest_beta_version'] = '3.4.5' with mock.patch(self.upgrade_method) as mock_upgrade: system_utilities.try_to_autoupgrade() # The upgrade command should be called with a specific channel. self.assertEqual(True, mock_upgrade.called) args, _ = mock_upgrade.call_args self.assertEqual('beta', args[0])
def test_back_to_back(self): """We won't upgrade twice in a short period of time.""" self.config_db['autoupgrade.in_window'] = True self.config_db['autoupgrade.channel'] = 'beta' self.config_db['autoupgrade.latest_beta_version'] = '3.4.5' # Set the upgrade window to have started a second before now. the_past = datetime.datetime.utcnow() - datetime.timedelta(seconds=1) self.config_db['autoupgrade.window_start'] = ( the_past.strftime('%H:%M:%S')) with mock.patch(self.upgrade_method) as mock_upgrade: system_utilities.try_to_autoupgrade() # The upgrade command should be called. self.assertEqual(True, mock_upgrade.called) # But another attempt to ugprade will be blocked. with mock.patch(self.upgrade_method) as second_mock_upgrade: system_utilities.try_to_autoupgrade() self.assertEqual(False, second_mock_upgrade.called)
def run(self): """ Main loop for endagad. This moves the system through the various states of operation -- it should be a state machine really! General flow is: 1) Tries to get configuration from server to produce VPN keys 2) Generates keys locally. 3) Sends CSR for signing, returns that. 4) Starts system services (FS, BTS, etc) and configures them appropriately. Note configuration can change depending on registration and VPN state of the system. 5) Runs checkin periodically. """ eapi = interconnect.endaga_ic(self._conf) if 'registration_interval' not in self._conf: self._conf['registration_interval'] = 60 UNHEALTHY_THRESH = self._conf.get('bts.unhealthy_threshold', 3) unhealthy_count = UNHEALTHY_THRESH # fail quickly on first pass while True: # Retrieve keys/tokens, or do nothing if we have them. logger.notice("Performing gen_keys") registration.generate_keys() # generate_keys() loads auth token on success. Need to update the # interconnect client's token if so. if eapi.token is None: eapi.token = self._conf['endaga_token'] # Try to register/get VPN credentials. Tries forever if fails. logger.notice("Performing register") registration.register(eapi) # Registered, start services and tries to start VPN. Stop # everything otherwise. logger.notice("Performing clear_pid") registration.clear_old_pid() logger.notice("Performing update_vpn") registration.update_vpn() # At this point, all services should be up, so we can perform # additional configuration. self._reset_bts_config() # Update the inbound_url if the VPN is up. if system_utilities.get_vpn_ip() is not None: logger.notice("Performing register_update") registration.register_update(eapi) logger.notice("Performing ensure_fs_external_bound") registration.ensure_fs_external_bound_to_vpn() # Send checkin to cloud try: # Sends events, tries to get config info. Can proceed w/o VPN. logger.notice("Performing checkin.") checkin_data = eapi.checkin(timeout=30) logger.notice("Performing system health check.") if not registration.system_healthcheck(checkin_data): unhealthy_count += 1 logger.notice("System unhealthy: %d" % unhealthy_count) else: unhealthy_count = 0 except (ConnectionError, Timeout): logger.error( "checkin failed due to connection error or timeout.") except BSSError as e: logger.error("bts exception: %s" % e) if unhealthy_count > UNHEALTHY_THRESH: logger.notice("BTS seems unhealthy, restarting BTS services.") bts.restart() Service.SystemService("freeswitch").restart() # Upgrade the endaga metapackage, when appropriate and only if that # feature is enabled. logger.notice("Performing autoupgrade") system_utilities.try_to_autoupgrade() # Sleep for some amount of time before retrying logger.notice("Performing sleep") time.sleep(self._conf['registration_interval'])
def test_disabled(self): """If autoupgrade is disabled, we should not try to upgrade.""" self.config_db['autoupgrade.enabled'] = False with mock.patch(self.upgrade_method) as mock_upgrade: system_utilities.try_to_autoupgrade() self.assertEqual(False, mock_upgrade.called)