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()
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()
def setUp(self): mox.MoxTestBase.setUp(self) self.stubs = stubout.StubOutForTesting() self.munki = plist.MunkiManifestPlist()
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, }