def testLogClientConnectionWithInvalidUuid(self): """Tests LogClientConnection() function with an invalid uuid.""" client_id = {'uuid': ''} event = 'custom' self.mox.StubOutWithMock(common.logging, 'warning') common.logging.warning( 'LogClientConnection: uuid is unknown, skipping log') self.mox.ReplayAll() common.LogClientConnection(event, client_id) self.mox.VerifyAll()
def testLogClientConnectionAsync(self): """Tests calling LogClientConnection(delay=2).""" event = 'eventname' client_id = {'uuid': 'fooo'} ip_address = 'fooip' utcnow = datetime.datetime(2010, 9, 2, 19, 30, 21, 377827) self.mox.StubOutWithMock(datetime, 'datetime') self.stubs.Set(common.deferred, 'defer', self.mox.CreateMockAnything()) deferred_name = 'log-client-conn-%s-%s' % ( client_id['uuid'], '2010-09-02-19-30-21') common.datetime.datetime.utcnow().AndReturn(utcnow) common.deferred.defer( common.LogClientConnection, event, client_id, user_settings=None, pkgs_to_install=None, apple_updates_to_install=None, ip_address=ip_address, report_feedback=None, _name=deferred_name, _countdown=2) self.mox.ReplayAll() common.LogClientConnection(event, client_id, delay=2, ip_address=ip_address) self.mox.VerifyAll()
def testLogClientConnectionPreflightAndNew(self): """Tests LogClientConnection() function.""" event = 'preflight' uuid = 'foo-uuid' ip_address = 'fooip' hostname = 'foohostname' serial = 'fooserial' owner = 'foouser' track = 'footrack' config_track = 'footrack' site = 'NYC' office = 'US-NYC-FOO' os_version = '10.6.3' client_version = '0.6.0.759.0' on_corp = True last_notified_datetime_str = '2010-11-03 15:15:10' last_notified_datetime = datetime.datetime( 2010, 11, 03, 15, 15, 10) uptime = 123 root_disk_free = 456 user_disk_free = 789 runtype = 'auto' client_id = { 'uuid': uuid, 'hostname': hostname, 'serial': serial, 'owner': owner, 'track': track, 'config_track': config_track, 'os_version': os_version, 'client_version': client_version, 'on_corp': on_corp, 'last_notified_datetime': last_notified_datetime_str, 'site': site, 'office': office, 'uptime': uptime, 'root_disk_free': root_disk_free, 'user_disk_free': user_disk_free, 'runtype': runtype, } # bypass the db.run_in_transaction step self.stubs.Set( common.models.db, 'run_in_transaction', lambda fn, *args, **kwargs: fn(*args, **kwargs)) self.MockModelStaticNone('Computer', 'get_by_key_name', uuid) mock_computer = self.MockModel('Computer', key_name=uuid) self.mox.StubOutWithMock(common.deferred, 'defer') mock_computer.connection_datetimes = [] mock_computer.connection_dates = [] mock_computer.connections_on_corp = None mock_computer.connections_off_corp = None mock_computer.preflight_count_since_postflight = None mock_computer.put().AndReturn(None) common.deferred.defer( common._SaveFirstConnection, client_id=client_id, computer=mock_computer, _countdown=300, _queue='first') self.mox.ReplayAll() common.LogClientConnection(event, client_id, ip_address=ip_address) self.assertEquals(uuid, mock_computer.uuid) self.assertEquals(ip_address, mock_computer.ip_address) self.assertEquals(runtype, mock_computer.runtype) self.assertEquals(hostname, mock_computer.hostname) self.assertEquals(serial, mock_computer.serial) self.assertEquals(owner, mock_computer.owner) self.assertEquals(track, mock_computer.track) self.assertEquals(config_track, mock_computer.config_track) self.assertEquals(site, mock_computer.site) self.assertEquals(office, mock_computer.office) self.assertEquals(os_version, mock_computer.os_version) self.assertEquals(client_version, mock_computer.client_version) self.assertEquals( last_notified_datetime, mock_computer.last_notified_datetime) # New client, so zero connection date/datetimes until after postflight. self.assertEquals([], mock_computer.connection_datetimes) self.assertEquals([], mock_computer.connection_dates) # Verify on_corp/off_corp counts. self.assertEquals(None, mock_computer.connections_on_corp) self.assertEquals(None, mock_computer.connections_off_corp) self.assertEquals(1, mock_computer.preflight_count_since_postflight) self.mox.VerifyAll()
def testLogClientConnectionPostflight(self): """Tests LogClientConnection() function.""" event = 'postflight' uuid = 'foo-uuid' ip_address = 'fooip' hostname = 'foohostname' serial = 'serial' owner = 'foouser' track = 'footrack' config_track = 'footrack' site = 'NYC' office = 'US-NYC-FOO' os_version = '10.6.3' client_version = '0.6.0.759.0' on_corp = True last_notified_datetime_str = '2010-11-03 15:15:10' last_notified_datetime = datetime.datetime(2010, 11, 03, 15, 15, 10) uptime = 123 root_disk_free = 456 user_disk_free = 789 runtype = 'custom' client_id = { 'uuid': uuid, 'hostname': hostname, 'serial': serial, 'owner': owner, 'track': track, 'config_track': config_track, 'os_version': os_version, 'client_version': client_version, 'on_corp': on_corp, 'last_notified_datetime': last_notified_datetime_str, 'site': site, 'office': office, 'uptime': uptime, 'root_disk_free': root_disk_free, 'user_disk_free': user_disk_free, 'runtype': runtype, } pkgs_to_install = ['FooApp1', 'FooApp2'] apple_updates_to_install = ['FooUpdate1', 'FooUpdate2'] all_pkgs_to_install = pkgs_to_install + [ common.APPLESUS_PKGS_TO_INSTALL_FORMAT % update for update in apple_updates_to_install] connection_datetimes = range(1, common.CONNECTION_DATETIMES_LIMIT + 1) connection_dates = range(1, common.CONNECTION_DATES_LIMIT + 1) # bypass the db.run_in_transaction step self.stubs.Set( common.models.db, 'run_in_transaction', lambda fn, *args, **kwargs: fn(*args, **kwargs)) mock_computer = self.mox.CreateMockAnything() mock_computer.connection_datetimes = connection_datetimes mock_computer.connection_dates = connection_dates mock_computer.connections_on_corp = None # test (None or 0) + 1 mock_computer.connections_off_corp = 0 mock_computer.put().AndReturn(None) self.mox.ReplayAll() common.LogClientConnection( event, client_id, pkgs_to_install=pkgs_to_install, apple_updates_to_install=apple_updates_to_install, computer=mock_computer, ip_address=ip_address) self.assertEquals(uuid, mock_computer.uuid) self.assertEquals(ip_address, mock_computer.ip_address) self.assertEquals(runtype, mock_computer.runtype) self.assertEquals(hostname, mock_computer.hostname) self.assertEquals(serial, mock_computer.serial) self.assertEquals(owner, mock_computer.owner) self.assertEquals(track, mock_computer.track) self.assertEquals(config_track, mock_computer.config_track) self.assertEquals(site, mock_computer.site) self.assertEquals(office, mock_computer.office) self.assertEquals(os_version, mock_computer.os_version) self.assertEquals(client_version, mock_computer.client_version) self.assertEquals( last_notified_datetime, mock_computer.last_notified_datetime) # Verify that the first "datetime" was popped off. self.assertEquals(connection_datetimes[0], 2) # Verify that the last datetime is the new datetime. new_datetime = connection_datetimes[common.CONNECTION_DATETIMES_LIMIT - 1] self.assertEquals(type(new_datetime), datetime.datetime) # Verify that the first "date" was popped off. self.assertEquals(connection_dates[0], 2) # Verify that the last date is the new date. new_date = connection_dates[common.CONNECTION_DATES_LIMIT - 1] self.assertEquals(type(new_date), datetime.datetime) # Verify on_corp/off_corp counts. self.assertEquals(1, mock_computer.connections_on_corp) self.assertEquals(0, mock_computer.connections_off_corp) self.assertEquals(all_pkgs_to_install, mock_computer.pkgs_to_install) self.assertEquals(False, mock_computer.all_pkgs_installed) self.assertEquals(0, mock_computer.preflight_count_since_postflight) self.mox.VerifyAll()
def testLogClientConnectionPreflight(self): """Tests LogClientConnection() function.""" user_settings = {'foo': True} event = 'preflight' uuid = 'foo-uuid' hostname = 'foohostname' serial = 'serial' owner = 'foouser' track = 'footrack' config_track = 'footrack' site = 'NYC' office = 'US-NYC-FOO' os_version = '10.6.3' client_version = '0.6.0.759.0' on_corp = True last_notified_datetime_str = '2010-11-03 15:15:10' last_notified_datetime = datetime.datetime(2010, 11, 03, 15, 15, 10) uptime = 123 root_disk_free = 456 user_disk_free = 789 ip_address = 'fooip' runtype = 'auto' report_feedback = {'force_continue': True} client_id = { 'uuid': uuid, 'hostname': hostname, 'serial': serial, 'owner': owner, 'track': track, 'config_track': config_track, 'os_version': os_version, 'client_version': client_version, 'on_corp': on_corp, 'last_notified_datetime': last_notified_datetime_str, 'site': site, 'office': office, 'uptime': uptime, 'root_disk_free': root_disk_free, 'user_disk_free': user_disk_free, 'runtype': runtype, } connection_datetimes = range(1, common.CONNECTION_DATETIMES_LIMIT + 1) connection_dates = range(1, common.CONNECTION_DATES_LIMIT + 1) # bypass the db.run_in_transaction step self.stubs.Set( common.models.db, 'run_in_transaction', lambda fn, *args, **kwargs: fn(*args, **kwargs)) mock_computer = self.MockModelStatic('Computer', 'get_by_key_name', uuid) mock_computer.connection_datetimes = connection_datetimes mock_computer.connection_dates = connection_dates mock_computer.connections_on_corp = 2 mock_computer.connections_off_corp = 2 mock_computer.preflight_count_since_postflight = 3 mock_computer.put().AndReturn(None) self.mox.ReplayAll() common.LogClientConnection( event, client_id, user_settings=user_settings, ip_address=ip_address, report_feedback=report_feedback) self.assertEquals(uuid, mock_computer.uuid) self.assertEquals(ip_address, mock_computer.ip_address) self.assertEquals(runtype, mock_computer.runtype) self.assertEquals(hostname, mock_computer.hostname) self.assertEquals(serial, mock_computer.serial) self.assertEquals(owner, mock_computer.owner) self.assertEquals(track, mock_computer.track) self.assertEquals(config_track, mock_computer.config_track) self.assertEquals(site, mock_computer.site) self.assertEquals(office, mock_computer.office) self.assertEquals(os_version, mock_computer.os_version) self.assertEquals(client_version, mock_computer.client_version) self.assertEquals( last_notified_datetime, mock_computer.last_notified_datetime) # Verify on_corp/off_corp counts. self.assertEquals(2, mock_computer.connections_on_corp) self.assertEquals(2, mock_computer.connections_off_corp) self.assertEquals( datetime.datetime, type(mock_computer.last_on_corp_preflight_datetime)) self.assertEquals(4, mock_computer.preflight_count_since_postflight) self.mox.VerifyAll()
def post(self): """Reports get handler. Returns: A webapp.Response() response. """ session = gaeserver.DoMunkiAuth() uuid = main_common.SanitizeUUID(session.uuid) report_type = self.request.get('_report_type') feedback_requested = self.request.get('_feedback') message = None details = None client_id = None computer = None if report_type == 'preflight' or report_type == 'postflight': client_id_str = urllib.unquote(self.request.get('client_id')) client_id = common.ParseClientId(client_id_str, uuid=uuid) user_settings_str = self.request.get('user_settings') user_settings = None try: if user_settings_str: user_settings = util.Deserialize( urllib.unquote(str(user_settings_str))) except util.DeserializeError: logging.warning('Client %s sent broken user_settings: %s', client_id_str, user_settings_str) pkgs_to_install = self.request.get_all('pkgs_to_install') apple_updates_to_install = self.request.get_all( 'apple_updates_to_install') computer = models.Computer.get_by_key_name(uuid) ip_address = os.environ.get('REMOTE_ADDR', '') report_feedback = None if report_type == 'preflight': # if the UUID is known to be lost/stolen, log this connection. if models.ComputerLostStolen.IsLostStolen(uuid): logging.warning('Connection from lost/stolen machine: %s', uuid) models.ComputerLostStolen.LogLostStolenConnection( computer=computer, ip_address=ip_address) # we want to get feedback now, before preflight_datetime changes. if feedback_requested: client_exit = self.request.get('client_exit', None) report_feedback = self.GetReportFeedback( uuid, report_type, computer=computer, ip_address=ip_address, client_exit=client_exit) self.response.out.write(report_feedback) # if report feedback calls for a client exit, log it. if report_feedback == common.ReportFeedback.EXIT: if not client_exit: # client didn't ask for an exit, which means server decided. client_exit = 'Connection from defined exit IP address' common.WriteClientLog(models.PreflightExitLog, uuid, computer=computer, exit_reason=client_exit) common.LogClientConnection(report_type, client_id, user_settings, pkgs_to_install, apple_updates_to_install, computer=computer, ip_address=ip_address, report_feedback=report_feedback) elif report_type == 'install_report': computer = models.Computer.get_by_key_name(uuid) self._LogInstalls(self.request.get_all('installs'), computer) for removal in self.request.get_all('removals'): common.WriteClientLog(models.ClientLog, uuid, computer=computer, action='removal', details=removal) for problem in self.request.get_all('problem_installs'): common.WriteClientLog(models.ClientLog, uuid, computer=computer, action='install_problem', details=problem) elif report_type == 'preflight_exit': # NOTE(user): only remains for older clients. message = self.request.get('message') computer = common.WriteClientLog(models.PreflightExitLog, uuid, exit_reason=message) elif report_type == 'broken_client': # Default reason of "objc" to support legacy clients, existing when objc # was the only broken state ever reported. reason = self.request.get('reason', 'objc') details = self.request.get('details') logging.warning('Broken Munki client (%s): %s', reason, details) common.WriteBrokenClient(uuid, reason, details) elif report_type == 'msu_log': details = {} for k in ['time', 'user', 'source', 'event', 'desc']: details[k] = self.request.get(k, None) common.WriteComputerMSULog(uuid, details) else: # unknown report type; log all post params. params = [] for param in self.request.arguments(): params.append('%s=%s' % (param, self.request.get_all(param))) common.WriteClientLog(models.ClientLog, uuid, action='unknown', details=str(params)) # If the client asked for feedback, get feedback and respond. # Skip this if the report_type is preflight, as report feedback was # retrieved before LogComputerConnection changed preflight_datetime. if feedback_requested and report_type != 'preflight': self.response.out.write( self.GetReportFeedback( uuid, report_type, message=message, details=details, computer=computer, ))
def post(self): """Reports get handler. Returns: A webapp.Response() response. """ session = gaeserver.DoMunkiAuth() uuid = main_common.SanitizeUUID(session.uuid) report_type = self.request.get('_report_type') report_feedback = {} message = None details = None client_id = None computer = None if report_type == 'preflight' or report_type == 'postflight': client_id_str = urllib.unquote(self.request.get('client_id')) client_id = common.ParseClientId(client_id_str, uuid=uuid) user_settings_str = self.request.get('user_settings') user_settings = None try: if user_settings_str: user_settings = util.Deserialize( urllib.unquote(str(user_settings_str))) except util.DeserializeError: logging.warning('Client %s sent broken user_settings: %s', client_id_str, user_settings_str) pkgs_to_install = self.request.get_all('pkgs_to_install') apple_updates_to_install = self.request.get_all( 'apple_updates_to_install') computer = models.Computer.get_by_key_name(uuid) ip_address = os.environ.get('REMOTE_ADDR', '') if report_type == 'preflight': # we want to get feedback now, before preflight_datetime changes. client_exit = self.request.get('client_exit', None) report_feedback = self.GetReportFeedback( uuid, report_type, computer=computer, ip_address=ip_address, client_exit=client_exit) if self.request.get('json') == '1': self.response.out.write(JSON_PREFIX + json.dumps(report_feedback)) else: # For legacy clients that accept a single string, not JSON. feedback_to_send = 'OK' for feedback in LEGACY_FEEDBACK_LIST: if report_feedback.get(feedback.lower()): feedback_to_send = feedback self.response.out.write(feedback_to_send) # if report feedback calls for a client exit, log it. if report_feedback.get('exit'): if not client_exit: # client didn't ask for an exit, which means server decided. client_exit = 'Connection from defined exit IP address' common.WriteClientLog(models.PreflightExitLog, uuid, computer=computer, exit_reason=client_exit) common.LogClientConnection(report_type, client_id, user_settings, pkgs_to_install, apple_updates_to_install, computer=computer, ip_address=ip_address, report_feedback=report_feedback) elif report_type == 'install_report': computer = models.Computer.get_by_key_name(uuid) self._LogInstalls(self.request.get_all('installs'), computer) for removal in self.request.get_all('removals'): common.WriteClientLog(models.ClientLog, uuid, computer=computer, action='removal', details=removal) for problem in self.request.get_all('problem_installs'): common.WriteClientLog(models.ClientLog, uuid, computer=computer, action='install_problem', details=problem) elif report_type == 'broken_client': # Default reason of "objc" to support legacy clients, existing when objc # was the only broken state ever reported. reason = self.request.get('reason', 'objc') details = self.request.get('details') logging.warning('Broken Munki client (%s): %s', reason, details) common.WriteBrokenClient(uuid, reason, details) elif report_type == 'msu_log': details = {} for k in ['time', 'user', 'source', 'event', 'desc']: details[k] = self.request.get(k, None) common.WriteComputerMSULog(uuid, details) else: # unknown report type; log all post params. params = [] for param in self.request.arguments(): params.append('%s=%s' % (param, self.request.get_all(param))) common.WriteClientLog(models.ClientLog, uuid, action='unknown', details=str(params))