Exemple #1
0
    def _DisplayHost(self, uuid=None, computer=None):
        """Displays the report for a single host.

    Args:
      uuid: str uuid for host to display.
      computer: models.Computer object to display.
    """
        if not computer:
            computer = models.Computer.get_by_key_name(uuid)
        else:
            uuid = computer.uuid
        client_log_files = models.ClientLogFile.all().filter(
            'uuid =', uuid).order('-mtime').fetch(100)
        msu_log = models.ComputerMSULog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(100)
        applesus_installs = models.InstallLog.all().filter(
            'uuid =', uuid).filter(
                'applesus =',
                True).order('-mtime').fetch(SINGLE_HOST_DATA_FETCH_LIMIT)
        installs = models.InstallLog.all().filter('uuid =', uuid).filter(
            'applesus =',
            False).order('-mtime').fetch(SINGLE_HOST_DATA_FETCH_LIMIT)
        exits = models.PreflightExitLog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(SINGLE_HOST_DATA_FETCH_LIMIT)
        install_problems = models.ClientLog.all().filter(
            'action =', 'install_problem').filter(
                'uuid =',
                uuid).order('-mtime').fetch(SINGLE_HOST_DATA_FETCH_LIMIT)
        uptime = None
        if computer:
            AddTimezoneToComputerDatetimes(computer)
            computer.connection_dates.reverse()
            computer.connection_datetimes.reverse()
            if computer.uptime:
                uptime_days = datetime.timedelta(seconds=computer.uptime).days
                uptime_hms = time.strftime('%H:%M:%S',
                                           time.gmtime(computer.uptime))
                uptime = '%d days, %s' % (uptime_days, uptime_hms)
            else:
                uptime = 'unknown'

        values = {
            'uuid_lookup_url': settings.UUID_LOOKUP_URL,
            'owner_lookup_url': settings.OWNER_LOOKUP_URL,
            'computer': computer,
            'applesus_installs': applesus_installs,
            'installs': installs,
            'client_log_files': client_log_files,
            'msu_log': msu_log,
            'install_problems': install_problems,
            'preflight_exits': exits,
            'uptime': uptime,
            'host_report': True,
            'limit': SINGLE_HOST_DATA_FETCH_LIMIT,
            'is_admin': auth.IsAdminUser(),
            'is_support_user': auth.IsSupportUser(),
            'is_security_user': auth.IsSecurityUser(),
        }
        self.response.out.write(
            RenderTemplate('templates/stats_host.html', values))
Exemple #2
0
 def get(self):
     """GET handler."""
     can_mod_tags = (self.IsAdminUser() or auth.IsSupportUser
                     or auth.IsSecurityUser())
     tags = models.Tag.all()
     tags = sorted(tags, key=lambda t: unicode.lower(t.key().name()))
     d = {'tags': tags, 'can_mod_tags': can_mod_tags, 'report_type': 'tags'}
     self.Render('tags.html', d)
Exemple #3
0
    def post(self):
        """POST handler."""
        can_mod_tags = (self.IsAdminUser() or auth.IsSupportUser
                        or auth.IsSecurityUser())
        if not can_mod_tags:
            return

        tag = self.request.get('tag').strip()
        tag = urllib.unquote(tag)
        action = self.request.get('action')
        if action == 'create':
            t = models.Tag(key_name=tag)
            uuid = self.request.get('uuid')
            if uuid:
                key = db.Key.from_path('Computer', uuid)
                t.keys.append(key)
            t.put()
            msg = 'Tag successfully saved.'
        elif action == 'delete':
            tag_manifest_mods = models.TagManifestModification.all().filter(
                'tag_key_name =', tag).get()
            if tag_manifest_mods:
                msg = 'Tag not deleted as it\'s being used for Manifest Modifications.'
            else:
                t = models.Tag.get_by_key_name(tag)
                if t:
                    t.delete()
                else:
                    self.error(404)
                    return
                msg = 'Tag successfully deleted.'
        elif action == 'change':
            uuid = self.request.get('uuid')
            add_tag = self.request.get('add') == '1'
            t = models.Tag.get_by_key_name(tag)
            if not t:
                self.error(404)
                return

            key = db.Key.from_path('Computer', uuid)
            if add_tag:
                t.keys.append(key)
            else:
                if key in t.keys:
                    t.keys.remove(key)
            t.put()
            msg = 'Tag successfully modified'

        self.redirect('/admin/tags?msg=%s' % msg)
Exemple #4
0
    def _DisplayMain(self):
        """Displays the main Manifest Modification report."""
        error = self.request.get('error')

        mod_type = self.request.get('mod_type') or 'owner'
        model = models.MANIFEST_MOD_MODELS.get(mod_type)
        if mod_type and not model:
            raise ValueError('Invalid mod_type: %s' % mod_type)
        elif mod_type:
            mods_query = model.all().order('-mtime')

        mods = self.Paginate(mods_query, DEFAULT_MANIFEST_MOD_FETCH_LIMIT)

        is_admin = self.IsAdminUser()
        is_support = False
        is_security = False
        if not is_admin:
            is_support = auth.IsSupportUser()
            if not is_support:
                is_security = auth.IsSecurityUser()
        if is_admin:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_ADMIN_GROUP)
            mod_types = MOD_TYPES
        elif is_support:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_SUPPORT_GROUP)
            mod_types = MOD_GROUP_TYPES[common.MANIFEST_MOD_SUPPORT_GROUP]
        elif is_security:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_SECURITY_GROUP)
            mod_types = MOD_GROUP_TYPES[common.MANIFEST_MOD_SECURITY_GROUP]
        else:
            munki_pkg_names = None
            mod_types = []

        data = {
            'mod_types': mod_types,
            'mod_type': mod_type,
            'mods': mods,
            'error': error,
            'can_add_manifest_mods': is_admin or is_support or is_security,
            'munki_pkg_names': munki_pkg_names,
            'install_types': common.INSTALL_TYPES,
            'manifests': common.TRACKS,
            'report_type': 'manifests_admin',
        }
        self.Render('manifest_modifications.html', data)
 def post(self):
     """POST handler."""
     if self.request.get('add_manifest_mod'):
         if (not self.IsAdminUser() and not auth.IsSupportUser()
                 and not auth.IsSecurityUser()):
             self.response.set_status(httplib.FORBIDDEN)
             return
         self._AddManifestModification()
     elif self.IsAdminUser() and self.request.get('delete'):
         self._DeleteManifestModification()
     elif self.IsAdminUser() and self.request.get('enabled'):
         self._ToggleManifestModification()
     else:
         if not self.IsAdminUser():
             self.response.set_status(httplib.FORBIDDEN)
             return
         self.response.set_status(httplib.NOT_FOUND)
Exemple #6
0
    def _DisplayBrokenClients(self):
        """Displays a report of broken clients."""
        # client with broken python
        py_computers = models.ComputerClientBroken.all().filter(
            'fixed =', False)
        py_computers = list(py_computers)
        for computer in py_computers:
            computer.details = computer.details.replace("'", "\\'")
            computer.details = computer.details.replace('"', "\\'")
            computer.details = re.sub('\n', '<br/>', computer.details)
            computer.broken_datetimes.reverse()

        # clients with zero connection
        zero_conn_computers = models.Computer.AllActive().filter(
            'connections_on_corp =', 0).filter('connections_off_corp =',
                                               0).fetch(COMPUTER_FETCH_LIMIT)
        zero_conn_computers = list(zero_conn_computers)
        zero_conn_computers.sort(key=lambda x: x.preflight_datetime,
                                 reverse=True)

        # clients with no recent postflight, but recent preflight
        # NOTE: this takes ~5s to complete in ~20k fleet where ~1400 clients have
        #       old postflight_datetime. if far more clients are in this state then
        #       then the query could cause DeadlineExceededError.
        pf_computers = []
        now = datetime.datetime.utcnow()
        not_recent = now - datetime.timedelta(days=15)
        q = models.Computer.AllActive().filter('postflight_datetime <',
                                               not_recent)
        for c in q:
            if not c.preflight_datetime or not c.postflight_datetime:
                continue  # already covered zero connection clients above.
            if (c.preflight_datetime - c.postflight_datetime).days > 7:
                pf_computers.append(c)
        pf_computers.sort(key=lambda x: x.preflight_datetime, reverse=True)

        self.response.out.write(
            RenderTemplate(
                'templates/stats_brokenclients.html', {
                    'py_computers': py_computers,
                    'zero_conn_computers': zero_conn_computers,
                    'pf_computers': pf_computers,
                    'is_admin': auth.IsAdminUser(),
                    'is_security_user': auth.IsSecurityUser(),
                }))
Exemple #7
0
  def testDoUserAuthWithAllDomainUsersOff(self):
    self.stubs.Set(auth.settings, 'ALLOW_ALL_DOMAIN_USERS_READ_ACCESS', False)
    self.stubs.Set(auth, 'users', self.mox.CreateMock(auth.users))
    self.mox.StubOutWithMock(auth, 'IsAdminUser')
    self.mox.StubOutWithMock(auth, 'IsSupportUser')
    self.mox.StubOutWithMock(auth, 'IsSecurityUser')
    self.mox.StubOutWithMock(auth, 'IsPhysicalSecurityUser')

    mock_user = self.mox.CreateMockAnything()
    email = '*****@*****.**'
    auth.users.get_current_user().AndReturn(mock_user)
    mock_user.email().AndReturn(email)

    auth.IsAdminUser(email).AndReturn(False)
    auth.IsSupportUser(email).AndReturn(False)
    auth.IsSecurityUser(email).AndReturn(False)
    auth.IsPhysicalSecurityUser(email).AndReturn(True)

    self.mox.ReplayAll()
    self.assertEqual(mock_user, auth.DoUserAuth())
    self.mox.VerifyAll()
    def _AddManifestModification(self):
        """Adds a new manifest modification to Datastore."""
        mod_type = self.request.get('mod_type')
        targets = [
            x.strip() for x in self.request.get('target').split(',')
            if x.strip()
        ]
        munki_pkg_name = self.request.get('munki_pkg_name').strip()
        manifests = self.request.get_all('manifests')
        install_types = self.request.get_all('install_types')
        remove_from_manifest = bool(self.request.get('remove-from-manifest'))

        # Security users are only able to inject specific packages.
        if not self.IsAdminUser():
            grp = None
            if auth.IsSupportUser():
                grp = common.MANIFEST_MOD_SUPPORT_GROUP
                # Support users can only inject items into optional_installs.
                install_types = ['optional_installs']
            elif auth.IsSecurityUser():
                grp = common.MANIFEST_MOD_SECURITY_GROUP
                # Security users can only inject items into managed_installs.
                install_types = ['managed_installs']

            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                grp, only_names=True)
            if munki_pkg_name not in munki_pkg_names:
                self.response.out.write('You are not allowed to inject: %s' %
                                        munki_pkg_name)
                self.response.set_status(httplib.FORBIDDEN)
                return
            elif mod_type not in [k for k, _ in MOD_GROUP_TYPES.get(grp, [])]:
                self.response.out.write(
                    'You are not allowed to inject to: %s' % mod_type)
                self.response.set_status(httplib.FORBIDDEN)
                return

        # Validation.
        error_msg = None
        if not targets or not munki_pkg_name or not install_types:
            error_msg = (
                'target, munki_pkg_name, and install_types are all required')
        if not error_msg:
            for manifest in manifests:
                if manifest not in common.TRACKS:
                    error_msg = 'manifest %s is not in %s' % (manifest,
                                                              common.TRACKS)
        if not error_msg:
            for install_type in install_types:
                if install_type not in common.INSTALL_TYPES:
                    error_msg = 'install_type %s is not in %s' % (
                        install_type, common.INSTALL_TYPES)
        if not error_msg:
            if not models.PackageInfo.all().filter('name =',
                                                   munki_pkg_name).get():
                error_msg = 'No package found with Munki name: %s' % munki_pkg_name
        if not error_msg and len(targets) > MAX_TARGETS_PER_POST:
            error_msg = 'too many targets'
        if error_msg:
            self.redirect('/admin/manifest_modifications?msg=%s' % error_msg)
            return

        to_put = []
        for target in targets:
            mod = models.BaseManifestModification.GenerateInstance(
                mod_type,
                target,
                munki_pkg_name,
                manifests=manifests,
                install_types=install_types,
                user=users.get_current_user(),
                remove=remove_from_manifest)
            to_put.append(mod)

        gae_util.BatchDatastoreOp(db.put, to_put)
        for target in targets:
            models.BaseManifestModification.ResetModMemcache(mod_type, target)

        msg = 'Manifest Modification successfully saved.'
        self.redirect('/admin/manifest_modifications?mod_type=%s&msg=%s' %
                      (mod_type, msg))
    def _DisplayMain(self):
        """Displays the main Manifest Modification report."""
        error_msg = self.request.get('error')

        mod_type = self.request.get('mod_type') or 'owner'
        model = models.MANIFEST_MOD_MODELS.get(mod_type)
        if mod_type and not model:
            error_msg = 'Unknown mod_type provided; defaulting to owner'
            mod_type = 'owner'
            model = models.MANIFEST_MOD_MODELS.get(mod_type)

        mods_query = model.all().order('-mtime')

        filter_value = self.request.get('filter_value')
        filter_field = self.request.get('filter_field')
        if filter_value:
            if filter_field == 'target':
                mods_query.filter(model.TARGET_PROPERTY_NAME, filter_value)
            elif filter_field == 'package':
                mods_query.filter('value', filter_value)
            elif filter_field == 'admin':
                if '@' not in filter_value:
                    filter_value += '@' + settings.AUTH_DOMAIN
                mods_query.filter('user', users.User(email=filter_value))

        mods = self.Paginate(mods_query, DEFAULT_MANIFEST_MOD_FETCH_LIMIT)

        is_admin = self.IsAdminUser()
        is_support = False
        is_security = False
        if not is_admin:
            is_support = auth.IsSupportUser()
            if not is_support:
                is_security = auth.IsSecurityUser()
        if is_admin:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_ADMIN_GROUP)
            mod_types = MOD_TYPES
        elif is_support:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_SUPPORT_GROUP)
            mod_types = MOD_GROUP_TYPES[common.MANIFEST_MOD_SUPPORT_GROUP]
        elif is_security:
            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                common.MANIFEST_MOD_SECURITY_GROUP)
            mod_types = MOD_GROUP_TYPES[common.MANIFEST_MOD_SECURITY_GROUP]
        else:
            munki_pkg_names = None
            mod_types = []

        data = {
            'mod_types': mod_types,
            'mod_type': mod_type,
            'mods': mods,
            'error': error_msg,
            'can_add_manifest_mods': is_admin or is_support or is_security,
            'munki_pkg_names': munki_pkg_names,
            'install_types': common.INSTALL_TYPES,
            'manifests': common.TRACKS,
            'report_type': 'manifests_admin',
            'mods_filter': filter_field,
            'mods_filter_value': filter_value,
        }
        self.Render('manifest_modifications.html', data)
Exemple #10
0
    def _AddManifestModification(self):
        """Adds a new manifest modification to Datastore."""
        mod_type = self.request.get('mod_type')
        target = self.request.get('target').strip()
        munki_pkg_name = self.request.get('munki_pkg_name').strip()
        manifests = self.request.get_all('manifests')
        install_types = self.request.get_all('install_types')

        # Security users are only able to inject specific packages.
        if not self.IsAdminUser():
            grp = None
            if auth.IsSupportUser():
                grp = common.MANIFEST_MOD_SUPPORT_GROUP
                # Support users can only inject items into optional_installs.
                install_types = ['optional_installs']
            elif auth.IsSecurityUser():
                grp = common.MANIFEST_MOD_SECURITY_GROUP
                # Security users can only inject items into managed_installs.
                install_types = ['managed_installs']

            munki_pkg_names = models.PackageInfo.GetManifestModPkgNames(
                grp, only_names=True)
            if munki_pkg_name not in munki_pkg_names:
                self.response.out.write('You are not allowed to inject: %s' %
                                        munki_pkg_name)
                self.response.set_status(403)
                return
            elif mod_type not in [k for k, v in MOD_GROUP_TYPES.get(grp, [])]:
                self.response.out.write(
                    'You are not allowed to inject to: %s' % mod_type)
                self.response.set_status(403)
                return

        # Validation.
        error_msg = None
        if not target or not munki_pkg_name or not install_types:
            error_msg = (
                'target, munki_pkg_name, and install_types are all required')
        if not error_msg:
            for manifest in manifests:
                if manifest not in common.TRACKS:
                    error_msg = 'manifest %s is not in %s' % (manifest,
                                                              common.TRACKS)
        if not error_msg:
            for install_type in install_types:
                if install_type not in common.INSTALL_TYPES:
                    error_msg = 'install_type %s is not in %s' % (
                        install_type, common.INSTALL_TYPES)
        if not error_msg:
            if not models.PackageInfo.all().filter('name =',
                                                   munki_pkg_name).get():
                error_msg = 'No package found with Munki name: %s' % munki_pkg_name
        if error_msg:
            self.redirect('/admin/manifest_modifications?msg=%s' % error_msg)
            return

        mod = models.BaseManifestModification.GenerateInstance(
            mod_type,
            target,
            munki_pkg_name,
            manifests=manifests,
            install_types=install_types,
            user=users.get_current_user())
        mod.put()
        models.BaseManifestModification.ResetModMemcache(mod_type, target)
        msg = 'Manifest Modification successfully saved.'
        self.redirect('/admin/manifest_modifications?mod_type=%s&msg=%s' %
                      (mod_type, msg))
Exemple #11
0
    def _DisplayHost(self, uuid=None, computer=None):
        """Displays the report for a single host.

    Args:
      uuid: str uuid for host to display.
      computer: models.Computer object to display.
    """
        if not uuid and not computer:
            self.response.set_status(404)
            return
        elif not computer:
            computer = models.Computer.get_by_key_name(uuid)
        else:
            uuid = computer.uuid

        popup = self.request.get('format', None) == 'popup'
        if popup:
            limit = 1
        else:
            limit = SINGLE_HOST_DATA_FETCH_LIMIT
        client_log_files = models.ClientLogFile.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        msu_log = models.ComputerMSULog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        applesus_installs = models.InstallLog.all().filter(
            'uuid =', uuid).filter('applesus =',
                                   True).order('-mtime').fetch(limit)
        installs = models.InstallLog.all().filter('uuid =', uuid).filter(
            'applesus =', False).order('-mtime').fetch(limit)
        exits = models.PreflightExitLog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        install_problems = models.ClientLog.all().filter(
            'action =',
            'install_problem').filter('uuid =',
                                      uuid).order('-mtime').fetch(limit)

        tags = {}
        tags_list = []
        if computer:
            # Generate tags data.
            tags_list = models.Tag.GetAllTagNamesForEntity(computer)
            for tag in tags_list:
                tags[tag] = True
            for tag in models.Tag.GetAllTagNames():
                if tag not in tags:
                    tags[tag] = False
            tags = json.dumps(tags, sort_keys=True)

            admin.AddTimezoneToComputerDatetimes(computer)
            computer.connection_dates.reverse()
            computer.connection_datetimes.reverse()

        try:
            uuid_lookup_url = settings.UUID_LOOKUP_URL
        except AttributeError:
            uuid_lookup_url = None

        try:
            owner_lookup_url = settings.OWNER_LOOKUP_URL
        except AttributeError:
            owner_lookup_url = None

        values = {
            'uuid_lookup_url': uuid_lookup_url,
            'owner_lookup_url': owner_lookup_url,
            'computer': computer,
            'applesus_installs': applesus_installs,
            'installs': installs,
            'client_log_files': client_log_files,
            'msu_log': msu_log,
            'install_problems': install_problems,
            'preflight_exits': exits,
            'tags': tags,
            'tags_list': tags_list,
            'host_report': True,
            'limit': SINGLE_HOST_DATA_FETCH_LIMIT,
            'is_support_user': auth.IsSupportUser(),
            'is_security_user': auth.IsSecurityUser(),
            'is_physical_security_user': auth.IsPhysicalSecurityUser(),
        }

        if popup:
            self.Render('host_popup.html', values)
        else:
            self.Render('host.html', values)
Exemple #12
0
    def _DisplayBrokenClients(self):
        """Displays a report of broken clients."""
        # client with broken python
        py_computers = models.ComputerClientBroken.all().filter(
            'fixed =', False)
        py_computers = list(py_computers)
        for computer in py_computers:
            computer.details = computer.details.replace("'", "\\'")
            computer.details = computer.details.replace('"', "\\'")
            computer.details = re.sub('\n', '<br/>', computer.details)
            computer.broken_datetimes.reverse()
            computer.likely_fixed = False
            # if a UUID is set, attempt to figure out when it last connected.
            if computer.uuid:
                try:
                    c_obj = models.Computer.get_by_key_name(computer.uuid)
                    if c_obj.preflight_datetime > computer.broken_datetimes[0]:
                        computer.likely_fixed = True
                except (IndexError, TypeError, models.db.Error):
                    pass

        # clients with zero connection
        q = models.Computer.AllActive().filter(
            'connections_on_corp =',
            0).filter('connections_off_corp =',
                      0).fetch(admin.DEFAULT_COMPUTER_FETCH_LIMIT)
        zero_conn_computers = []
        for c in q:
            if c.preflight_count_since_postflight > PREFLIGHT_COUNT_BROKEN_THRESHOLD:
                zero_conn_computers.append(c)
        zero_conn_computers.sort(key=lambda x: x.preflight_datetime,
                                 reverse=True)

        # clients with no recent postflight, but recent preflight
        fetch_limit = 1000
        pf_computers = []
        q = models.Computer.AllActive().filter(
            'preflight_count_since_postflight >',
            PREFLIGHT_COUNT_BROKEN_THRESHOLD)
        i = 0
        for c in q:
            i += 1
            if i >= fetch_limit:  # avoid DeadlineExceededError.
                break
            if not c.preflight_datetime or not c.postflight_datetime:
                continue  # already covered zero connection clients above.
            pf_computers.append(c)
        pf_computers.sort(key=lambda x: x.preflight_datetime, reverse=True)

        self.Render(
            'broken_clients.html', {
                'py_computers':
                py_computers,
                'zero_conn_computers':
                zero_conn_computers,
                'pf_computers':
                pf_computers,
                'is_security_user':
                auth.IsSecurityUser(),
                'report_type':
                'broken_clients',
                'truncated':
                i >= fetch_limit,
                'preflight_count_broken_threshold':
                PREFLIGHT_COUNT_BROKEN_THRESHOLD,
            })
Exemple #13
0
    def _DisplayHost(self, computer, self_report):
        """Displays the report for a single host.

    Args:
      computer: models.Computer object to display.
      self_report: if True, display as self report.
    """

        uuid = computer.uuid

        popup = self.request.get('format', None) == 'popup'
        if popup:
            limit = 1
        else:
            limit = SINGLE_HOST_DATA_FETCH_LIMIT
        client_log_files = models.ClientLogFile.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        msu_log = models.ComputerMSULog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        applesus_installs = models.InstallLog.all().filter(
            'uuid =', uuid).filter('applesus =',
                                   True).order('-mtime').fetch(limit)
        installs = models.InstallLog.all().filter('uuid =', uuid).filter(
            'applesus =', False).order('-mtime').fetch(limit)
        exits = models.PreflightExitLog.all().filter(
            'uuid =', uuid).order('-mtime').fetch(limit)
        install_problems = models.ClientLog.all().filter(
            'action =',
            'install_problem').filter('uuid =',
                                      uuid).order('-mtime').fetch(limit)

        tags = {}
        tags_list = []
        groups = {}
        groups_list = []
        duplicates = []
        if computer:
            # Generate tags data.
            tags_list = models.Tag.GetAllTagNamesForEntity(computer)
            for tag in tags_list:
                tags[tag] = True
            for tag in models.Tag.GetAllTagNames():
                if tag not in tags:
                    tags[tag] = False
            tags = json.dumps(tags, sort_keys=True)

            # Generate groups data.
            groups_list = models.Group.GetAllGroupNamesForUser(computer.owner)
            for group in groups_list:
                groups[group] = True
            for group in models.Group.GetAllGroupNames():
                if group not in groups:
                    groups[group] = False
            groups = json.dumps(groups, sort_keys=True)

            admin.AddTimezoneToComputerDatetimes(computer)
            computer.connection_dates.reverse()
            computer.connection_datetimes.reverse()
            duplicates = models.Computer.all().filter(
                'serial =', computer.serial).fetch(20)
            duplicates = [e for e in duplicates if e.uuid != computer.uuid]

        try:
            uuid_lookup_url = settings.UUID_LOOKUP_URL
        except AttributeError:
            uuid_lookup_url = None

        try:
            owner_lookup_url = settings.OWNER_LOOKUP_URL
        except AttributeError:
            owner_lookup_url = None

        values = {
            'report_type': 'host',
            'uuid_lookup_url': uuid_lookup_url,
            'owner_lookup_url': owner_lookup_url,
            'client_site_enabled': settings.CLIENT_SITE_ENABLED,
            'computer': computer,
            'applesus_installs': applesus_installs,
            'installs': installs,
            'client_log_files': client_log_files,
            'msu_log': msu_log,
            'install_problems': install_problems,
            'preflight_exits': exits,
            'tags': tags,
            'tags_list': tags_list,
            'groups': groups,
            'groups_list': groups_list,
            'host_report': True,
            'limit': SINGLE_HOST_DATA_FETCH_LIMIT,
            'is_support_user': auth.IsSupportUser(),
            'is_security_user': auth.IsSecurityUser(),
            'is_physical_security_user': auth.IsPhysicalSecurityUser(),
            'self_report': self_report,
            'duplicates': duplicates,
            'tags_xsrf_token': xsrf.XsrfTokenGenerate('tags'),
            'groups_xsrf_token': xsrf.XsrfTokenGenerate('groups'),
        }

        if popup:
            self.Render('host_popup.html', values)
        else:
            self.Render('host.html', values)