def testGenerateDynamicManifest(self):
    """Tests GenerateDynamicManifest()."""
    plist_xml = (
        '<plist><dict><key>catalogs</key><array><string>hello</string></array>'
        '<key>managed_updates</key><array><string>hello</string></array>'
        '</dict></plist>')
    manifest = 'stable'
    site = 'foosite'
    os_version = '10.6.5'
    owner = 'foouser'
    uuid = '12345-abcdef'
    client_id = {
        'track': manifest, 'site': site, 'os_version': os_version,
        'owner': owner, 'uuid': uuid,
    }

    install_type_optional_installs = 'optional_installs'
    install_type_managed_updates = 'managed_updates'

    site_mod_one = self.mox.CreateMockAnything()
    site_mod_one.manifests = [manifest]
    site_mod_one.enabled = True
    site_mod_one.install_types = [install_type_optional_installs]
    site_mod_one.value = 'foo pkg 1'

    site_mod_two = self.mox.CreateMockAnything()
    site_mod_two.manifests = [manifest]
    site_mod_two.enabled = True
    site_mod_two.install_types = [install_type_managed_updates]
    site_mod_two.value = 'foo pkg 2'
    site_mod_disabled = self.mox.CreateMockAnything()
    site_mod_disabled.enabled = False
    site_mods = [site_mod_one, site_mod_two, site_mod_disabled]
    self.mox.StubOutWithMock(
        models.SiteManifestModification,
        'MemcacheWrappedGetAllFilter')
    models.SiteManifestModification.MemcacheWrappedGetAllFilter(
        (('site =', site),)).AndReturn(site_mods)

    os_version_mod_one = self.mox.CreateMockAnything()
    os_version_mod_one.manifests = [manifest]
    os_version_mod_one.enabled = True
    os_version_mod_one.install_types = [install_type_managed_updates]
    os_version_mod_one.value = 'foo os version pkg'
    os_version_mods = [os_version_mod_one]
    self.mox.StubOutWithMock(
        models.OSVersionManifestModification,
        'MemcacheWrappedGetAllFilter')
    models.OSVersionManifestModification.MemcacheWrappedGetAllFilter(
        (('os_version =', os_version),)).AndReturn(os_version_mods)

    owner_mod_one = self.mox.CreateMockAnything()
    owner_mod_one.manifests = [manifest]
    owner_mod_one.enabled = True
    owner_mod_one.install_types = [
        install_type_optional_installs, install_type_managed_updates]
    owner_mod_one.value = 'foo owner pkg'
    owner_mods = [owner_mod_one]
    self.mox.StubOutWithMock(
        models.OwnerManifestModification,
        'MemcacheWrappedGetAllFilter')
    models.OwnerManifestModification.MemcacheWrappedGetAllFilter(
        (('owner =', owner),)).AndReturn(owner_mods)

    uuid_mod_one = self.mox.CreateMockAnything()
    uuid_mod_one.manifests = [manifest]
    uuid_mod_one.enabled = True
    uuid_mod_one.install_types = [install_type_managed_updates]
    uuid_mod_one.value = 'foo uuid pkg'
    uuid_mods = [uuid_mod_one]
    self.mox.StubOutWithMock(
        models.UuidManifestModification,
        'MemcacheWrappedGetAllFilter')
    models.UuidManifestModification.MemcacheWrappedGetAllFilter(
        (('uuid =', uuid),)).AndReturn(uuid_mods)

    tag_mod_one = self.mox.CreateMockAnything()
    tag_mod_one.manifests = [manifest]
    tag_mod_one.enabled = True
    tag_mod_one.install_types = [install_type_managed_updates]
    tag_mod_one.value = 'foo tag pkg'
    tag_mods = [tag_mod_one]
    computer_tags = ['footag1', 'footag2']
    self.mox.StubOutWithMock(models.db.Key, 'from_path')
    self.mox.StubOutWithMock(models.Tag, 'GetAllTagNamesForKey')
    models.db.Key.from_path('Computer', uuid).AndReturn('k')
    models.Tag.GetAllTagNamesForKey('k').AndReturn(computer_tags)
    self.mox.StubOutWithMock(
        models.TagManifestModification,
        'MemcacheWrappedGetAllFilter')
    models.TagManifestModification.MemcacheWrappedGetAllFilter(
        (('tag_key_name =', 'footag1'),)).AndReturn([])
    models.TagManifestModification.MemcacheWrappedGetAllFilter(
        (('tag_key_name =', 'footag2'),)).AndReturn(tag_mods)

    # Setup dict of expected output xml.
    tmp_plist_exp = plist.MunkiManifestPlist(plist_xml)
    tmp_plist_exp.Parse()
    expected_out_dict = tmp_plist_exp.GetContents()
    expected_out_dict[install_type_optional_installs] = [site_mod_one.value]
    expected_out_dict[install_type_managed_updates].append(site_mod_two.value)
    expected_out_dict[install_type_managed_updates].append(
        os_version_mod_one.value)
    expected_out_dict[install_type_optional_installs].append(
        owner_mod_one.value)
    expected_out_dict[install_type_managed_updates].append(owner_mod_one.value)
    expected_out_dict[install_type_managed_updates].append(uuid_mod_one.value)
    expected_out_dict[install_type_managed_updates].append(tag_mod_one.value)

    self.mox.ReplayAll()
    # Generate the dynamic manifest, then get dict output to compare to the
    # expected output.
    out_xml = manifests.common.GenerateDynamicManifest(plist_xml, client_id)
    tmp_plist_out = plist.MunkiManifestPlist(out_xml)
    tmp_plist_out.Parse()
    out_dict = tmp_plist_out.GetContents()
    self.assertEqual(out_dict, expected_out_dict)
    self.mox.VerifyAll()
Exemple #2
0
def GenerateDynamicManifest(plist, client_id, user_settings=None):
  """Generate a dynamic manifest based on a the various client_id fields.

  Args:
    plist: str XML or plist_module.ApplePlist object, manifest to start with.
    client_id: dict client_id parsed by common.ParseClientId.
    user_settings: dict UserSettings as defined in Simian client.
  Returns:
    str XML manifest with any custom modifications based on the client_id.
  """
  # TODO(user): This function is getting out of control and needs refactoring.
  manifest_changed = False
  manifest = client_id['track']

  site_mods = models.SiteManifestModification.MemcacheWrappedGetAllFilter(
      (('site =', client_id['site']),))

  os_version_mods = \
      models.OSVersionManifestModification.MemcacheWrappedGetAllFilter(
          (('os_version =', client_id['os_version']),))

  owner_mods = models.OwnerManifestModification.MemcacheWrappedGetAllFilter(
      (('owner =', client_id['owner']),))

  uuid_mods = models.UuidManifestModification.MemcacheWrappedGetAllFilter(
      (('uuid =', client_id['uuid']),))

  tag_mods = []
  if client_id['uuid']:  # not set if viewing a base manifest.
    computer_key = models.db.Key.from_path('Computer', client_id['uuid'])
    computer_tags = models.Tag.GetAllTagNamesForKey(computer_key)
    if computer_tags:
      # NOTE(user): if we feel most computers will have tags, it might make
      #             sense to regularly fetch and cache all mods.
      for tag in computer_tags:
        t = (('tag_key_name =', tag),)
        tag_mods.extend(
            models.TagManifestModification.MemcacheWrappedGetAllFilter(t))

  def __ApplyModifications(manifest, mod, plist):
    """Applies a manifest modification if the manifest matches mod manifest.

    NOTE(user): if mod.manifests is empty or None, mod is made to any manifest.
    """
    plist_xml = None
    if type(plist) is str:
      plist_xml = plist

    if not mod.enabled:
      return  # return it the mod is disabled
    elif mod.manifests and manifest not in mod.manifests:
      return  # return if the desired manifest is not in the mod manifests.

    #logging.debug(
    #    'Applying manifest mod: %s %s', mod.install_types, mod.value)
    for install_type in mod.install_types:
      plist_module.UpdateIterable(
          plist, install_type, mod.value, default=[], op=_ModifyList)

  if site_mods or owner_mods or os_version_mods or uuid_mods or tag_mods:
    manifest_changed = True
    if type(plist) is str:
      plist = plist_module.MunkiManifestPlist(plist)
      plist.Parse()
    for mod in site_mods:
      __ApplyModifications(manifest, mod, plist)
    for mod in os_version_mods:
      __ApplyModifications(manifest, mod, plist)
    for mod in owner_mods:
      __ApplyModifications(manifest, mod, plist)
    for mod in uuid_mods:
      __ApplyModifications(manifest, mod, plist)
    for mod in tag_mods:
      __ApplyModifications(manifest, mod, plist)

  if user_settings:
    flash_developer = user_settings.get('FlashDeveloper', False)
    block_packages = user_settings.get('BlockPackages', [])
    # If plist is not parsed yet and modifications are required, parse it.
    if (flash_developer or block_packages) and type(plist) is str:
      if type(plist) is str:
        plist = plist_module.MunkiManifestPlist(plist)
        plist.Parse()

    # If FlashDeveloper is True, replace the regular flash plugin with the
    # debug version in managed_updates.
    if flash_developer:
      manifest_changed = True
      plist[common.MANAGED_UPDATES].append(FLASH_PLUGIN_DEBUG_NAME)
      try:
        plist[common.MANAGED_UPDATES].remove(FLASH_PLUGIN_NAME)
      except ValueError:
        pass  # FLASH_PLUGIN_NAME was not in managed_updates to begin with.

    # Look for each block package in each install type, remove if found.
    for block_package in block_packages:
      for install_type in common.INSTALL_TYPES:
        if block_package in plist.get(install_type, []):
          manifest_changed = True
          plist[install_type].remove(block_package)
          #logging.debug(
          #    'Removed BlockPackage from %s: %s', block_package, install_type)

  if type(plist) is str:
    return plist
  else:
    return plist.GetXml()
Exemple #3
0
 def setUp(self):
     mox.MoxTestBase.setUp(self)
     self.stubs = stubout.StubOutForTesting()
     self.munki = plist.MunkiManifestPlist()
Exemple #4
0
def GetComputerManifest(uuid=None, client_id=None, packagemap=False):
  """For a computer uuid or client_id, return the current manifest.

  Args:
    uuid: str, computer uuid    OR
    client_id: dict, client_id
    packagemap: bool, default False, whether to return packagemap or not
  Returns:
    if packagemap, dict = {
        'plist': plist.MunkiManifestPlist instance,
        'packagemap': {   # if packagemap == True
            'Firefox': 'Firefox-3.x.x.x.dmg',
        },
    }

    if not packagemap, str, manifest plist
  Raises:
    ValueError: error in type of arguments supplied to this method
    ComputerNotFoundError: computer cannot be found for uuid
    ManifestNotFoundError: manifest requested is invalid (not found)
    ManifestDisabledError: manifest requested is disabled
  """
  if client_id is None and uuid is None:
    raise ValueError('uuid or client_id must be supplied')

  if client_id is not None:
    if type(client_id) is not dict:
      raise ValueError('client_id must be dict')
    uuid = client_id.get('uuid')

  user_settings = None
  if uuid is not None:
    c = models.Computer.get_by_key_name(uuid)
    if not c:
      raise ComputerNotFoundError

    user_settings = c.user_settings
    client_id = {
        'uuid': uuid,
        'owner': c.owner,
        'hostname': c.hostname,
        'serial': c.serial,
        'config_track': c.config_track,
        'track': c.track,
        'site': c.site,
        'office': c.office,
        'os_version': c.os_version,
        'client_version': c.client_version,
        # TODO(user): Fix this; it may not be accurate.
        'on_corp': c.connections_on_corp > c.connections_off_corp,
        'last_notified_datetime': c.last_notified_datetime,
        'uptime': None,
        'root_disk_free': None,
        'user_disk_free': None,
    }

  # Step 1: Obtain a manifest for this uuid.
  manifest_plist_xml = None

  if IsPanicModeNoPackages():
    manifest_plist_xml = '%s%s' % (
        plist_module.PLIST_HEAD, plist_module.PLIST_FOOT)
  else:
    manifest_name = client_id['track']
    m = models.Manifest.MemcacheWrappedGet(manifest_name)
    if not m:
      raise ManifestNotFoundError(manifest_name)
    elif not m.enabled:
      raise ManifestDisabledError(manifest_name)

    manifest_plist_xml = GenerateDynamicManifest(
        m.plist, client_id, user_settings=user_settings)

  if not manifest_plist_xml:
    raise ManifestNotFoundError(manifest_name)

  # Step 1: Return now with xml if packagemap not requested.
  if not packagemap:
    return manifest_plist_xml

  # Step 2: Build lookup table from PackageName to PackageName-VersionNumber
  # for packages found in catalogs used by the client.

  manifest_plist = plist_module.MunkiManifestPlist(manifest_plist_xml)
  manifest_plist.Parse()

  catalogs = manifest_plist['catalogs']
  packages = {}

  query = models.PackageInfo.all()
  for p in query:
    display_name = p.plist.get('display_name', None) or p.plist.get('name')
    display_name = display_name.strip()
    version = p.plist.get('version', '')
    packages[p.name] = '%s-%s' % (display_name, version)

  return {
      'plist': manifest_plist,
      'packagemap': packages,
  }