Ejemplo n.º 1
0
 def testIsPanicModeNoPackages(self):
   """Test IsPanicModeNoPackages()."""
   self.mox.StubOutWithMock(common, 'IsPanicMode')
   common.IsPanicMode(common.PANIC_MODE_NO_PACKAGES).AndReturn(123)
   self.mox.ReplayAll()
   self.assertEqual(123, common.IsPanicModeNoPackages())
   self.mox.VerifyAll()
Ejemplo n.º 2
0
  def testGetComputerManifestWhenEmptyDynamic(self):
    """Test ComputerInstallsPending()."""
    uuid = 'uuid'
    last_notified_datetime = self.mox.CreateMockAnything()

    client_id = {
        'uuid': 'uuid',
        'owner': 'owner',
        'hostname': 'hostname',
        'serial': 'serial',
        'config_track': 'config_track',
        'track': 'track',
        'site': 'site',
        'office': 'office',
        'os_version': 'os_version',
        'client_version': 'client_version',
        'on_corp': True,
        'last_notified_datetime': last_notified_datetime,
        'uptime': None,
        'root_disk_free': None,
        'user_disk_free': None,
    }

    computer = test.GenericContainer(**client_id)
    computer.connections_on_corp = 2
    computer.connections_off_corp = 1
    computer.user_settings = None

    # PackageInfo entities
    package_infos = [
        test.GenericContainer(plist='plistOtherPackage', version='1.0'),
        test.GenericContainer(plist='plistPackageInstalled1', version='1.0'),
        test.GenericContainer(plist='plistPackageInstalled2', version='1.0'),
        test.GenericContainer(plist='plistPackageNotInstalled1', version='1.0'),
    ]

    packagemap = {}

    self.mox.StubOutWithMock(common.models, 'Computer')
    self.mox.StubOutWithMock(common, 'IsPanicModeNoPackages')
    self.mox.StubOutWithMock(common.models, 'Manifest')
    self.mox.StubOutWithMock(common, 'GenerateDynamicManifest')
    self.mox.StubOutWithMock(common.plist_module, 'MunkiManifestPlist')
    self.mox.StubOutWithMock(common.models, 'PackageInfo')
    self.mox.StubOutWithMock(common.plist_module, 'MunkiPackageInfoPlist')

    # mock manifest creation
    common.models.Computer.get_by_key_name(uuid).AndReturn(computer)
    common.IsPanicModeNoPackages().AndReturn(False)
    mock_plist = self.mox.CreateMockAnything()
    common.models.Manifest.MemcacheWrappedGet('track').AndReturn(
        test.GenericContainer(enabled=True, plist=mock_plist))
    common.GenerateDynamicManifest(
        mock_plist, client_id, user_settings=None).AndReturn(None)

    self.mox.ReplayAll()
    self.assertRaises(
        common.ManifestNotFoundError,
        common.GetComputerManifest, uuid=uuid)
    self.mox.VerifyAll()
Ejemplo n.º 3
0
    def GetReportFeedback(self, uuid, report_type, **kwargs):
        """Inspect a report and provide a feedback status/command.

    Args:
      uuid: str, computer uuid
      report_type: str, report type
      **kwargs: dict, additional report parameters, e.g:
          on_corp: str, optional, '1' or '0', on_corp status
          message: str, optional, message from client
          details: str, optional, details from client
          ip_address: str, optional, IP address of client
    Returns:
      common.ReportFeedback.* constant
    """
        feedback = {}
        if 'computer' in kwargs:
            c = kwargs['computer']
        else:
            c = models.Computer.get_by_key_name(uuid)
        ip_address = kwargs.get('ip_address', None)
        client_exit = kwargs.get('client_exit', None)

        if client_exit and report_type == 'preflight':
            # client has requested an exit, but let's ensure we should allow it.
            if c is None or c.postflight_datetime is None:
                # client has never fully executed Munki.
                feedback['force_continue'] = True
            else:
                # check if the postflight_datetime warrants a FORCE_CONTINUE
                now = datetime.datetime.utcnow()
                postflight_stale_datetime = now - datetime.timedelta(
                    days=FORCE_CONTINUE_POSTFLIGHT_DAYS)
                if c.postflight_datetime < postflight_stale_datetime:
                    # client hasn't executed Munki in FORCE_CONTINUE_POSTFLIGHT_DAYS.
                    feedback['force_continue'] = True
                else:
                    feedback['exit'] = True
        elif report_type == 'preflight':
            if IsExitFeedbackIpAddress(ip_address):
                feedback['exit'] = True
            elif common.IsPanicModeNoPackages():
                feedback['exit'] = True
            elif not c or c.preflight_datetime is None:
                # this is the first preflight post from this client.
                feedback['force_continue'] = True
            elif getattr(c, 'upload_logs_and_notify', None) is not None:
                feedback['logging_level'] = 3
                feedback['upload_logs'] = True
            else:
                # check if preflight_count_since_postflight warrants a repair.
                if (c.preflight_count_since_postflight >=
                        REPAIR_CLIENT_PREFLIGHT_COUNT_SINCE_POSTFLIGHT):
                    feedback['pkill_installd'] = True
                    feedback['pkill_softwareupdated'] = True
                    feedback['repair'] = True
                    feedback['logging_level'] = 3
                    feedback['upload_logs'] = True

        return feedback
Ejemplo n.º 4
0
  def testGetComputerManifestIsPanicMode(self):
    """Test ComputerInstallsPending()."""
    uuid = 'uuid'
    last_notified_datetime = self.mox.CreateMockAnything()

    client_id = {
        'uuid': 'uuid',
        'owner': 'owner',
        'hostname': 'hostname',
        'serial': 'serial',
        'config_track': 'config_track',
        'track': 'track',
        'site': 'site',
        'office': 'office',
        'os_version': 'os_version',
        'client_version': 'client_version',
        'on_corp': True,
        'last_notified_datetime': last_notified_datetime,
        'uptime': None,
        'root_disk_free': None,
        'user_disk_free': None,
    }

    computer = test.GenericContainer(**client_id)
    computer.connections_on_corp = 2
    computer.connections_off_corp = 1
    computer.user_settings = None

    # PackageInfo entities
    package_infos = [
        test.GenericContainer(plist='plistOtherPackage', version='1.0'),
        test.GenericContainer(plist='plistPackageInstalled1', version='1.0'),
        test.GenericContainer(plist='plistPackageInstalled2', version='1.0'),
        test.GenericContainer(plist='plistPackageNotInstalled1', version='1.0'),
    ]

    packagemap = {}

    self.mox.StubOutWithMock(common.models, 'Computer')
    self.mox.StubOutWithMock(common, 'IsPanicModeNoPackages')

    common.models.Computer.get_by_key_name(uuid).AndReturn(computer)
    common.IsPanicModeNoPackages().AndReturn(True)

    manifest_expected = '%s%s' % (
        common.plist_module.PLIST_HEAD,
        common.plist_module.PLIST_FOOT)

    self.mox.ReplayAll()
    manifest = common.GetComputerManifest(uuid=uuid)
    self.assertEqual(manifest, manifest_expected)
    self.mox.VerifyAll()
Ejemplo n.º 5
0
  def testGetComputerManifestWhenManifestNotFound(self):
    """Test ComputerInstallsPending()."""
    uuid = 'uuid'
    last_notified_datetime = self.mox.CreateMockAnything()

    client_id = {
        'uuid': 'uuid',
        'owner': 'owner',
        'hostname': 'hostname',
        'serial': 'serial',
        'config_track': 'config_track',
        'track': 'track',
        'site': 'site',
        'office': 'office',
        'os_version': 'os_version',
        'client_version': 'client_version',
        'on_corp': True,
        'last_notified_datetime': last_notified_datetime,
        'uptime': None,
        'root_disk_free': None,
        'user_disk_free': None,
    }

    computer = test.GenericContainer(**client_id)
    computer.connections_on_corp = 2
    computer.connections_off_corp = 1
    computer.user_settings = None

    packagemap = {}

    self.mox.StubOutWithMock(common.models, 'Computer')
    self.mox.StubOutWithMock(common, 'IsPanicModeNoPackages')
    self.mox.StubOutWithMock(common.models, 'Manifest')

    # mock manifest creation
    common.models.Computer.get_by_key_name(uuid).AndReturn(computer)
    common.IsPanicModeNoPackages().AndReturn(False)
    common.models.Manifest.MemcacheWrappedGet('track').AndReturn(None)

    self.mox.ReplayAll()
    self.assertRaises(
        common.ManifestNotFoundError,
        common.GetComputerManifest, uuid=uuid)
    self.mox.VerifyAll()
Ejemplo n.º 6
0
Archivo: pkgs.py Proyecto: smusa/simian
    def get(self, filename):
        """GET

    Args:
      filename: str, package filename like 'foo.dmg'
    Returns:
      None if a blob is being returned,
      or a response object
    """
        auth_return = auth.DoAnyAuth()
        if hasattr(auth_return, 'email'):
            email = auth_return.email()
            if not auth.IsAdminUser(email) and not auth.IsSupportUser(email):
                raise auth.IsAdminMismatch

        filename = urllib.unquote(filename)
        pkg = models.PackageInfo.MemcacheWrappedGet(filename)

        if pkg is None or not pkg.blobstore_key:
            self.error(404)
            return

        if common.IsPanicModeNoPackages():
            self.error(503)
            return

        # Get the Blobstore BlobInfo for this package; memcache wrapped.
        memcache_key = 'blobinfo_%s' % filename
        blob_info = memcache.get(memcache_key)
        if not blob_info:
            blob_info = blobstore.BlobInfo.get(pkg.blobstore_key)
            if blob_info:
                memcache.set(memcache_key, blob_info,
                             300)  # cache for 5 minutes.
            else:
                logging.critical(
                    'Failure fetching BlobInfo for %s. Verify the blob exists: %s',
                    pkg.filename, pkg.blobstore_key)
                self.error(404)
                return

        header_date_str = self.request.headers.get('If-Modified-Since', '')
        etag_nomatch_str = self.request.headers.get('If-None-Match', 0)
        etag_match_str = self.request.headers.get('If-Match', 0)
        pkg_date = blob_info.creation
        pkg_size_bytes = blob_info.size

        # TODO(user): The below can be simplified once all of our clients
        # have ETag values set on the filesystem for these files.  The
        # parsing of If-Modified-Since could be removed.  Removing it prematurely
        # will cause a re-download of all packages on all clients for 1 iteration
        # until they all have ETag values.

        # Reduce complexity of elif conditional below.
        # If an If-None-Match: ETag is supplied, don't worry about a
        # missing file modification date -- the ETag supplies everything needed.
        if etag_nomatch_str and not header_date_str:
            resource_expired = False
        else:
            resource_expired = handlers.IsClientResourceExpired(
                pkg_date, header_date_str)

        # Client supplied If-Match: etag, but that etag does not match current
        # etag.  return 412.
        if (etag_match_str and pkg.pkgdata_sha256
                and etag_match_str != pkg.pkgdata_sha256):
            self.response.set_status(412)

        # Client supplied no etag or If-No-Match: etag, and the etag did not
        # match, or the client's file is older than the mod time of this package.
        elif ((etag_nomatch_str and pkg.pkgdata_sha256
               and etag_nomatch_str != pkg.pkgdata_sha256)
              or resource_expired):
            self.response.headers['Content-Disposition'] = str(
                'attachment; filename=%s' % filename)
            # header date empty or package has changed, send blob with last-mod date.
            if pkg.pkgdata_sha256:
                self.response.headers['ETag'] = str(pkg.pkgdata_sha256)
            self.response.headers['Last-Modified'] = pkg_date.strftime(
                handlers.HEADER_DATE_FORMAT)
            self.response.headers['X-Download-Size'] = str(pkg_size_bytes)
            self.send_blob(pkg.blobstore_key)
        else:
            # Client doesn't need to do anything, current version is OK based on
            # ETag and/or last modified date.
            if pkg.pkgdata_sha256:
                self.response.headers['ETag'] = str(pkg.pkgdata_sha256)
            self.response.set_status(304)
Ejemplo n.º 7
0
  def testGetComputerManifest(self):
    """Test ComputerInstallsPending()."""
    uuid = 'uuid'
    last_notified_datetime = self.mox.CreateMockAnything()

    client_id = {
        'uuid': 'uuid',
        'owner': 'owner',
        'hostname': 'hostname',
        'serial': 'serial',
        'config_track': 'config_track',
        'track': 'track',
        'site': 'site',
        'office': 'office',
        'os_version': 'os_version',
        'client_version': 'client_version',
        'on_corp': True,
        'last_notified_datetime': last_notified_datetime,
        'uptime': None,
        'root_disk_free': None,
        'user_disk_free': None,
    }

    computer = test.GenericContainer(**client_id)
    computer.connections_on_corp = 2
    computer.connections_off_corp = 1
    computer.user_settings = None

    # PackageInfo entities
    mock_pl1 = self.mox.CreateMockAnything()
    mock_pl2 = self.mox.CreateMockAnything()
    mock_pl3 = self.mox.CreateMockAnything()
    mock_pl4 = self.mox.CreateMockAnything()
    package_infos = [
        test.GenericContainer(plist=mock_pl1, version='1.0', name='fooname1'),
        test.GenericContainer(plist=mock_pl2, version='1.0', name='fooname2'),
        test.GenericContainer(plist=mock_pl3, version='1.0', name='fooname3'),
        test.GenericContainer(plist=mock_pl4, version='1.0', name='fooname4'),
    ]

    packagemap = {}

    self.mox.StubOutWithMock(common.models, 'Computer')
    self.mox.StubOutWithMock(common, 'IsPanicModeNoPackages')
    self.mox.StubOutWithMock(common.models, 'Manifest')
    self.mox.StubOutWithMock(common, 'GenerateDynamicManifest')
    self.mox.StubOutWithMock(common.plist_module, 'MunkiManifestPlist')
    self.mox.StubOutWithMock(common.models, 'PackageInfo')
    self.mox.StubOutWithMock(common.plist_module, 'MunkiPackageInfoPlist')

    # mock manifest creation
    common.models.Computer.get_by_key_name(uuid).AndReturn(computer)
    common.IsPanicModeNoPackages().AndReturn(False)
    mock_plist = self.mox.CreateMockAnything()
    common.models.Manifest.MemcacheWrappedGet('track').AndReturn(
        test.GenericContainer(enabled=True, plist=mock_plist))
    common.GenerateDynamicManifest(
        mock_plist, client_id, user_settings=None).AndReturn(
        'manifest_plist')

    # mock manifest parsing
    mock_manifest_plist = self.mox.CreateMockAnything()
    common.plist_module.MunkiManifestPlist('manifest_plist').AndReturn(
        mock_manifest_plist)
    mock_manifest_plist.Parse().AndReturn(None)

    # mock manifest reading and package map creation
    mock_package_info = self.mox.CreateMockAnything()
    common.models.PackageInfo.all().AndReturn(mock_package_info)
    iter_return = []

    for package_info in package_infos:
      iter_return.append(test.GenericContainer(
          plist=package_info.plist,
          name=package_info.name))
      package_info.plist.get('display_name', None).AndReturn(None)
      package_info.plist.get('name').AndReturn(package_info.name)
      package_info.plist.get('version', '').AndReturn(package_info.version)
      packagemap[package_info.name] = '%s-%s' % (
          package_info.name, package_info.version)

    def __iter_func():
      for i in iter_return:
        yield i

    mock_package_info.__iter__().AndReturn(__iter_func())

    manifest_expected = {
        'plist': mock_manifest_plist,
        'packagemap': packagemap,
    }

    self.mox.ReplayAll()
    manifest = common.GetComputerManifest(uuid=uuid, packagemap=True)
    self.assertEqual(manifest, manifest_expected)
    self.mox.VerifyAll()
Ejemplo n.º 8
0
    def GetReportFeedback(self, uuid, report_type, **kwargs):
        """Inspect a report and provide a feedback status/command.

    Args:
      uuid: str, computer uuid
      report_type: str, report type
      kwargs: dict, additional report parameters, e.g:

      on_corp: str, optional, '1' or '0', on_corp status
      message: str, optional, message from client
      details: str, optional, details from client
      ip_address: str, optional, IP address of client
    Returns:
      common.ReportFeedback.* constant
    """
        report = common.ReportFeedback.OK
        if 'computer' in kwargs:
            c = kwargs['computer']
        else:
            c = models.Computer.get_by_key_name(uuid)
        ip_address = kwargs.get('ip_address', None)
        client_exit = kwargs.get('client_exit', None)

        # TODO(user): if common.BusinessLogicMethod ...
        if client_exit and report_type == 'preflight':
            report = common.ReportFeedback.EXIT
            # client has requested an exit, but let's ensure we should allow it.
            if c is None or c.postflight_datetime is None:
                # client has never fully executed Munki.
                report = common.ReportFeedback.FORCE_CONTINUE
            else:
                # check if the postflight_datetime warrants a FORCE_CONTINUE
                now = datetime.datetime.utcnow()
                postflight_stale_datetime = now - datetime.timedelta(
                    days=FORCE_CONTINUE_POSTFLIGHT_DAYS)
                if c.postflight_datetime < postflight_stale_datetime:
                    # client hasn't executed Munki in FORCE_CONTINUE_POSTFLIGHT_DAYS.
                    report = common.ReportFeedback.FORCE_CONTINUE
        elif report_type == 'preflight':
            if IsExitFeedbackIpAddress(ip_address):
                report = common.ReportFeedback.EXIT
            elif common.IsPanicModeNoPackages():
                report = common.ReportFeedback.EXIT
            elif not c or c.preflight_datetime is None:
                # this is the first preflight post from this client.
                report = common.ReportFeedback.FORCE_CONTINUE
            elif getattr(c, 'upload_logs_and_notify', None) is not None:
                report = common.ReportFeedback.UPLOAD_LOGS
            elif c.postflight_datetime is None:
                # client has posted preflight before, but not postflight
                report = common.ReportFeedback.REPAIR
            else:
                # check if postflight_datetime warrants a repair.
                pre_post_timedelta = c.preflight_datetime - c.postflight_datetime
                if pre_post_timedelta > datetime.timedelta(
                        days=REPAIR_CLIENT_PRE_POST_DIFF_DAYS):
                    report = common.ReportFeedback.REPAIR

        if report not in [
                common.ReportFeedback.OK, common.ReportFeedback.FORCE_CONTINUE
        ]:
            logging.info('Feedback to %s: %s', uuid, report)

        return report