Beispiel #1
0
    def testEqualWithIgnoreKeysReturningFalse(self):
        """Tests Equal() false."""
        pl = plist.ApplePlist()
        pl._plist = {'foo': 1, 'bar': True}

        other = plist.ApplePlist()
        other._plist = {'foo': 2, 'bar': True}

        self.assertFalse(pl.Equal(other, ignore_keys=['bar']))
Beispiel #2
0
    def testEqual(self):
        """Tests Equal()."""
        pl = plist.ApplePlist()
        pl._plist = {'foo': 1, 'bar': True}

        other = plist.ApplePlist()
        other._plist = {'foo': 1, 'bar': True}

        self.assertTrue(pl.Equal(other))
Beispiel #3
0
 def _GetSystemProfile(self):
     sp_xml = self._GetSystemProfilerOutput()
     p = plist.ApplePlist(sp_xml)
     try:
         p.Parse()
     except plist.Error, e:
         raise SystemProfilerError('plist Parse() error: %s' % str(e))
Beispiel #4
0
    def _ProcessCatalogAndNotifyAdmins(cls, catalog, os_version):
        """Wrapper method to process a catalog and notify admin of changes.

    Args:
      catalog: models.AppleSUSCatalog object to process.
      os_version: str OS version like 10.5, 10.6, 10.7, etc.
    """
        catalog_plist = plist.ApplePlist(catalog.plist)
        try:
            catalog_plist.Parse()
        except plist.Error:
            logging.exception('Error parsing Apple Updates catalog: %s',
                              catalog.key().name())
            return

        new_products = cls._UpdateProductDataFromCatalog(catalog_plist)
        deprecated_products = cls._DeprecateOrphanedProducts()

        cls._NotifyAdminsOfCatalogSync(catalog, new_products,
                                       deprecated_products)

        # Regenerate the unstable catalog, including new updates but excluding
        # any that were previously manually disabled.
        applesus.GenerateAppleSUSCatalog(os_version, common.UNSTABLE)

        models.AdminAppleSUSProductLog.Log(new_products,
                                           'new for %s' % os_version)
        models.AdminAppleSUSProductLog.Log(deprecated_products,
                                           'deprecated for %s' % os_version)
Beispiel #5
0
    def _DeprecateOrphanedProducts(self):
        """Deprecates products in Datastore that no longer exist in any catalogs.

    Returns:
      List of AppleSUSProduct objects that were marked deprecated.
    """
        # Loop over all catalogs, generating a dict of all unique product ids.
        catalog_products = set()
        for os_version in applesus.OS_VERSIONS:
            for track in common.TRACKS + ['untouched']:
                key = '%s_%s' % (os_version, track)
                catalog_obj = models.AppleSUSCatalog.get_by_key_name(key)
                if not catalog_obj:
                    logging.error('Catalog does not exist: %s', key)
                    continue
                catalog_plist = plist.ApplePlist(catalog_obj.plist)
                try:
                    catalog_plist.Parse()
                except plist.Error:
                    logging.exception(
                        'Error parsing Apple Updates catalog: %s', key)
                    continue
                for product in catalog_plist.get('Products', []):
                    catalog_products.add(product)

        deprecated = []
        # Loop over Datastore products, deprecating all that aren't in any catalogs.
        for p in models.AppleSUSProduct.all().filter('deprecated =', False):
            if p.product_id not in catalog_products:
                p.deprecated = True
                p.put()
                deprecated.append(p)
        return deprecated
Beispiel #6
0
    def PackageInfoTemplateHook(self, input_pkginfo, open_=open):
        """Allow a template to supply values into the pkginfo.

    The template is loaded. Its values are overlaid onto a new pkginfo
    instance with values copied from the one that is supplied as
    input_pkginfo. Note this means callers to this method will not have
    their input_pkginfo modified, rather a new pkginfo is received as output
    if any values changed.

    Args:
      input_pkginfo: plist.MunkiPackageInfoPlist, input pkginfo to use as base
        values
    Returns:
      a different plist.MunkiPackageInfoPlist instance with potentially new
      values populated
    Raises:
      CliError: an error occurs reading the template
    """
        pkginfo = input_pkginfo.copy()
        try:
            plist_xml = open_(self.config['template_pkginfo'], 'r').read()
            template = plist.ApplePlist(plist_xml)
            template.Parse()
        except IOError:
            raise CliError('I/O error %s' % self.config['template_pkginfo'])
        except plist.Error, e:
            raise CliError('Error parsing %s: %s' %
                           (self.config['template_pkginfo'], str(e)))
Beispiel #7
0
def GenerateAppleSUSCatalog(
    os_version, track, datetime_=datetime.datetime, catalog_lock=None):
  """Generates an Apple SUS catalog for a given os_version and track.

  This function loads the untouched/raw Apple SUS catalog, removes any
  products/updates that are not approved for the given track, then saves
  a new catalog (plist/xml) to Datastore for client consumption.

  Args:
    os_version: str OS version to generate the catalog for.
    track: str track name to generate the catalog for.
    datetime_: datetime module; only used for stub during testing.
    catalog_lock: datastore_lock.DatastoreLock; If provided, the lock to release
                  upon completion of the operation.
  Returns:
    tuple, new models.AppleSUSCatalog object and plist.ApplePlist object. Or,
    if there is no "untouched" catalog for the os_version, then (None, None) is
    returned.
  """
  logging.info('Generating catalog: %s_%s', os_version, track)

  catalog_key = '%s_untouched' % os_version
  untouched_catalog_obj = models.AppleSUSCatalog.get_by_key_name(catalog_key)
  if not untouched_catalog_obj:
    logging.warning('Apple Update catalog does not exist: %s', catalog_key)
    if catalog_lock:
      catalog_lock.Release()
    return None, None
  untouched_catalog_plist = plist.ApplePlist(untouched_catalog_obj.plist)
  untouched_catalog_plist.Parse()

  approved_product_ids = set()
  products_query = models.AppleSUSProduct.AllActive().filter('tracks =', track)
  for product in products_query:
    approved_product_ids.add(product.product_id)

  product_ids = untouched_catalog_plist.get('Products', {}).keys()
  new_plist = untouched_catalog_plist
  for product_id in product_ids:
    if product_id not in approved_product_ids:
      del new_plist['Products'][product_id]

  catalog_plist_xml = new_plist.GetXml()

  # Save the catalog using a time-specific key for rollback purposes.
  now = datetime_.utcnow()
  now_str = now.strftime('%Y-%m-%d-%H-%M-%S')
  backup = models.AppleSUSCatalog(
      key_name='backup_%s_%s_%s' % (os_version, track, now_str))
  backup.plist = catalog_plist_xml
  backup.put()
  # Overwrite the catalog being served for this os_version/track pair.
  c = models.AppleSUSCatalog(key_name='%s_%s' % (os_version, track))
  c.plist = catalog_plist_xml
  c.put()

  if catalog_lock:
    catalog_lock.Release()

  return c, new_plist
Beispiel #8
0
    def _GetPkginfoPlist(self):
        """Returns a pkginfo plist for an Apple Update Product."""
        d = {
            'installer_type': 'apple_update_metadata',
            'name': self.product_id,
        }
        if self.unattended:
            d['unattended_install'] = self.unattended
        if self.force_install_after_date:
            d['force_install_after_date'] = self.force_install_after_date
        d['version'] = '1.0'  # TODO(user): find out if this is needed.

        plist = plist_lib.ApplePlist()
        plist.SetContents(d)
        return plist
Beispiel #9
0
 def testBasicNested(self):
     xml = ('%s  <dict>\n    <key>foo</key>\n    <string>bar</string>\n  '
            '</dict>%s' % (plist.PLIST_HEAD, plist.PLIST_FOOT))
     xml2 = (
         '%s  <dict>\n    <key>subway</key>\n    <string>BDFM</string>\n  '
         '</dict>%s' % (plist.PLIST_HEAD, plist.PLIST_FOOT))
     nested_xml = ('%s  <dict>\n    <key>foo</key>\n    <dict>\n'
                   '      <key>subway</key>\n'
                   '      <string>BDFM</string>\n'
                   '    </dict>\n'
                   '  </dict>%s' % (plist.PLIST_HEAD, plist.PLIST_FOOT))
     plist2 = plist.ApplePlist(xml2)
     plist2.Parse()
     self.PlistTest(xml, {'foo': 'bar'})
     self.apl.GetContents()['foo'] = plist2
     self.assertEqual(nested_xml, self.apl.GetXml())
Beispiel #10
0
def GenerateAppleSUSCatalog(os_version, track, _datetime=datetime.datetime):
    """Generates an Apple SUS catalog for a given os_version and track.

  This function loads the untouched/raw Apple SUS catalog, removes any
  products/updates that are not approved for the given track, then saves
  a new catalog (plist/xml) to Datastore for client consumption.

  Args:
    os_version: str OS version to generate the catalog for.
    track: str track name to generate the catalog for.
    _datetime: datetime module; only used for stub during testing.
  Returns:
    tuple, new models.AppleSUSCatalog object and plist.ApplePlist object.
  """
    logging.info('Generating catalog: %s_%s', os_version, track)
    approved_product_ids = {}
    products_query = models.AppleSUSProduct.all().filter('tracks =', track)
    for product in products_query:
        approved_product_ids[product.product_id] = True

    untouched_catalog_obj = models.AppleSUSCatalog.get_by_key_name(
        '%s_untouched' % os_version)
    untouched_catalog_plist = plist.ApplePlist(untouched_catalog_obj.plist)
    untouched_catalog_plist.Parse()

    product_ids = untouched_catalog_plist.get('Products', {}).keys()
    new_plist = untouched_catalog_plist
    for product_id in product_ids:
        if product_id not in approved_product_ids:
            del new_plist['Products'][product_id]

    catalog_plist_xml = new_plist.GetXml()

    # Save the catalog using a time-specific key for rollback purposes.
    now = _datetime.utcnow()
    now_str = now.strftime('%Y-%m-%d-%H-%M-%S')
    backup = models.AppleSUSCatalog(key_name='backup_%s_%s_%s' %
                                    (os_version, track, now_str))
    backup.plist = catalog_plist_xml
    backup.put()
    # Overwrite the catalog being served for this os_version/track pair.
    c = models.AppleSUSCatalog(key_name='%s_%s' % (os_version, track))
    c.plist = catalog_plist_xml
    c.put()
    return c, new_plist
Beispiel #11
0
 def setUp(self):
     mox.MoxTestBase.setUp(self)
     self.stubs = stubout.StubOutForTesting()
     self.apl = plist.ApplePlist()
Beispiel #12
0
 def testBasicEmptyString(self):
     xml = '%s<dict><key>foo</key><string></string><key>bar</key><string/></dict>%s' % (
         plist.PLIST_HEAD, plist.PLIST_FOOT)
     plist2 = plist.ApplePlist(xml)
     plist2.Parse()
     self.PlistTest(xml, {'foo': '', 'bar': ''})