示例#1
0
 def NotifyAdminsOfPackageUnlock(self, pkginfo):
     """Notifies admins of package being unlocked."""
     subject_line = 'MSU Package Unlocked by %s - %s' % (
         users.get_current_user(), pkginfo.filename)
     main_body = 'That package has been removed from all catalogs and manifests.'
     if mail:
         mail.SendMail(settings.EMAIL_ADMIN_LIST, subject_line, main_body)
示例#2
0
def SendNotificationEmail(recipients, c, server_fqdn):
    """Sends a log upload notification email to passed recipients.

  Args:
    recipients: list, str email addresses to email.
    c: models.Computer entity.
    server_fqdn: str, fully qualified domain name of the server.
  """
    body = []
    body.append('https://%s/admin/host/%s\n' % (server_fqdn, c.uuid))
    body.append('Owner: %s' % c.owner)
    body.append('Hostname: %s' % c.hostname)
    body.append('Client Version: %s' % c.client_version)
    body.append('OS Version: %s' % c.os_version)
    body.append('Site: %s' % c.site)
    body.append('Track / Config Track: %s / %s' % (c.track, c.config_track))
    body.append('Serial Number: %s' % c.serial)
    body.append('Last preflight: %s' % c.preflight_datetime)
    body.append('Last postflight: %s' % c.postflight_datetime)
    body.append(('Preflight count since postflight: %s' %
                 c.preflight_count_since_postflight))
    body = '\n'.join(body)
    subject = 'Logs you requested have been uploaded for %s' % c.hostname

    mail.SendMail(recipients, subject, body)
示例#3
0
 def NotifyAdminsOfPackageDeletion(self, pkginfo):
     """Notifies admins of packages deletions."""
     subject_line = 'MSU Package Deleted by %s - %s' % (
         users.get_current_user(), pkginfo.filename)
     main_body = 'That package has been deleted, hope you didn\'t need it.'
     if mail:
         mail.SendMail(settings.EMAIL_ADMIN_LIST, subject_line, main_body)
示例#4
0
 def NotifyAdminsOfChange(self, setting, value):
     """Notify Admins of changes to Settings."""
     subject_line = 'Simian Settings Change by %s' % (
         users.get_current_user())
     main_body = '%s set to: %s' % (setting, value)
     mail.SendMail(settings_module.EMAIL_ADMIN_LIST, subject_line,
                   main_body)
示例#5
0
  def ProposalMailer(self, action):
    """Notifies admins of proposed changes and changed proposals.

    Args:
      action: string, defines what message will be sent.
    """
    current_user = users.get_current_user()
    current_user_nick = current_user.nickname()

    body = self._BuildProposalBody(os.environ.get('DEFAULT_VERSION_HOSTNAME'),
                                   self.filename)

    if action == 'proposal':
      subject = 'Proposal for %s by %s' % (self.filename, current_user_nick)
    elif action == 'approval':
      subject = 'Proposal Approved for %s by %s' % (
          self.filename, current_user_nick)
    elif action == 'rejection':
      subject = 'Proposal Rejected for %s by %s' % (
          self.filename, current_user_nick)
    else:
      logging.warning('Unknown action in ProposalMailer: %s', action)
      return

    recipient_list = [self.user]
    recipient, _ = settings.Settings.GetItem('email_admin_list')
    if recipient:
      recipient_list.append(recipient)
    mail_tool.SendMail(recipient_list, subject, body)
示例#6
0
文件: panic.py 项目: StrayDawg/simian
  def post(self):
    """POST handler."""
    if not self.IsAdminUser():
      return

    mode = self.request.get('mode')
    enabled = self.request.get('enabled')
    verify = self.request.get('verify')

    if not verify:
      self.Render(
          'panic_set_verify.html',
          {'mode': {'name': mode, 'enabled': enabled}, 'report_type': 'panic'})
    else:
      if enabled == 'disable':
        enabled = False
      elif enabled == 'enable':
        enabled = True
      else:
        enabled = None

      if enabled is None:
        self.error(400)
      else:
        try:
          common.SetPanicMode(mode, enabled)
          if mail:
            user = users.get_current_user()
            subject = 'Panic Mode Update by %s' % user
            body = '%s has set \'%s\' for Panic Mode.\n' % (user, enabled)
            mail.SendMail(settings.EMAIL_ADMIN_LIST, subject, body)

          self.redirect('/admin/panic')
        except ValueError:
          self.error(400)
示例#7
0
 def NotifyAdminsOfPackageChange(self, pkginfo, **kwargs):
   """Notifies admins of changes to packages."""
   subject_line = 'MSU Package Update by %s - %s' % (users.get_current_user(),
                                                     pkginfo.filename)
   main_body = ['New configuration:\n']
   for key, value in kwargs.iteritems():
     if key == 'manifests':
       if pkginfo.manifests != value:
         main_body.append('Manifests: %s --> %s' % (
             ', '.join(pkginfo.manifests), ', '.join(value)))
     elif key == 'catalogs':
       if pkginfo.catalogs != value:
         main_body.append('Catalogs: %s --> %s' % (
             ', '.join(pkginfo.catalogs), ', '.join(value)))
     elif key == 'install_types':
       if pkginfo.install_types != value:
         main_body.append('Install Types: %s --> %s' % (
             ', '.join(pkginfo.install_types), ', '.join(value)))
     elif key == 'munki_name':
       if pkginfo.munki_name != value:
         main_body.append('Munki Name: %s --> %s' % (
             pkginfo.munki_name, value))
     elif (key == 'force_install_after_date'
           and pkginfo.plist.get(key, '') != value):
       main_body.append('%s: %s' % (key, value))
     elif type(value) is list:
       if pkginfo.plist.get(key, []) != value:
         main_body.append('%s: %s --> %s' % (
             key, ', '.join(pkginfo.plist.get(key, [])), ', '.join(value)))
     else:
       if pkginfo.plist.get(key, '') != value:
         main_body.append(
             '%s: %s --> %s' % (key, pkginfo.plist.get(key, ''), value))
   mail.SendMail(settings.EMAIL_ADMIN_LIST, subject_line, '\n'.join(main_body))
示例#8
0
  def NotifyAdminsOfPackageChangeFromPlist(self, log, defer=True):
    """Notifies admins of changes to packages."""
    subject_line = 'MSU Package Update by %s - %s' % (
        users.get_current_user(), log.filename)

    plist_diff = log.plist_diff
    main_body = 'Diff:\n' + '\n'.join([x['line'] for x in plist_diff])
    if mail:
      mail.SendMail(
          settings.EMAIL_ADMIN_LIST, subject_line, main_body, defer=defer)
示例#9
0
 def _NotifyAboutPkgInfosWithoutFile(self):
   """Verify that entities older than a week have a file in Blobstore."""
   for p in models.PackageInfo.all():
     if p.blobstore_key and blobstore.BlobInfo.get(p.blobstore_key):
       continue
     elif p.mtime < (datetime.datetime.utcnow() - datetime.timedelta(days=7)):
       subject = 'Package is lacking a file: %s' % p.filename
       body = (
           'The following package is lacking a DMG file: \n'
           'https://%s/admin/package/%s' % (
               settings.SERVER_HOSTNAME, p.filename))
       mail.SendMail(settings.EMAIL_ADMIN_LIST, subject, body, defer=False)
示例#10
0
 def NotifyAdminsOfChange(self, setting, value):
     """Notify Admins of changes to Settings."""
     try:
         recipients = settings_module.EMAIL_ADMIN_LIST
     except AttributeError:
         logging.info(
             'email_admin_list unset, skipping change notification: %s',
             setting)
         return
     subject_line = 'Simian Settings Change by %s' % (
         users.get_current_user())
     main_body = '%s set to: %s' % (setting, value)
     mail.SendMail(recipients, subject_line, main_body)
示例#11
0
    def get(self):
        """Handle GET."""
        # Verify that all PackageInfo entities older than a week have a file in
        # Blobstore.
        for p in models.PackageInfo.all():
            if p.blobstore_key and blobstore.BlobInfo.get(p.blobstore_key):
                continue
            elif p.mtime < (datetime.datetime.utcnow() -
                            datetime.timedelta(days=7)):

                subject = 'Package is lacking a file: %s' % p.filename
                body = ('The following package is lacking a DMG file: \n'
                        'https://%s/admin/package/%s' %
                        (settings.SERVER_HOSTNAME, p.filename))
                mail.SendMail([settings.EMAIL_ADMIN_LIST], subject, body)

        # Verify all Blobstore Blobs have associated PackageInfo entities.
        for b in blobstore.BlobInfo.all():
            # Filter by blobstore_key as duplicate filenames are allowed in Blobstore.
            key = b.key()
            max_attempts = 5
            for i in xrange(1, max_attempts + 1):
                p = models.PackageInfo.all().filter('blobstore_key =',
                                                    key).get()
                if p:
                    break
                elif i == max_attempts:
                    if not b.filename and not b.size:
                        b.delete()
                        break
                    subject = 'Orphaned Blob in Blobstore: %s' % b.filename
                    body = (
                        'An orphaned Blob exists in Blobstore. Use App Engine Admin '
                        'Console\'s "Blob Viewer" to locate and delete this Blob.\n\n'
                        'Filename: %s\nBlobstore Key: %s' % (b.filename, key))
                    mail.SendMail([settings.EMAIL_ADMIN_LIST], subject, body)
                    break
                time.sleep(1)
示例#12
0
 def NotifyAdminsOfPackageChangeFromPlist(self, plist_xml):
   """Notifies admins of changes to packages."""
   plist = plist_lib.MunkiPackageInfoPlist(plist_xml)
   plist.EncodeXml()
   try:
     plist.Parse()
   except plist_lib.PlistError as e:
     raise models.PackageInfoUpdateError(
         'plist_lib.PlistError parsing plist XML: %s', str(e))
   subject_line = 'MSU Package Update by %s - %s' % (
       users.get_current_user(), plist['installer_item_location'])
   main_body = str(plist.GetXml(indent_num=2))
   if mail:
     mail.SendMail(settings.EMAIL_ADMIN_LIST, subject_line, main_body)
示例#13
0
    def _NotifyAdminsOfAutoPromotions(self, promotions):
        """Notifies Simian admins that a new Apple Updates were auto-promoted.

    Args:
      promotions: a dict of track keys with lists of update product entities.
    """
        msg = []
        restart_required = False
        for track, updates in promotions.iteritems():
            msg.append('\n%s:' % track)
            for u in updates:
                msg.append('\t%s: %s %s %s' %
                           (u.product_id, u.name, u.version,
                            '*' if u.restart_required else ''))
                if u.restart_required:
                    restart_required = True
        if restart_required:
            msg.append('\n\n%s' % RESTART_REQUIRED_FOOTER)
        msg = '\n'.join(msg)
        body = 'The following Apple Updates were promoted:\n%s' % msg
        subject = 'Apple Updates Auto-Promotion'

        mail.SendMail([settings.EMAIL_ADMIN_LIST], subject, body)
示例#14
0
    def _NotifyAdminsOfCatalogSync(cls, catalog, new_products,
                                   deprecated_products):
        """Notifies Simian admins that a new Apple Updates catalog was synced.

    Args:
      catalog: models.AppleSUSCatalog entity.
      new_products: a list of models.AppleSUSProduct objects.
      deprecated_products: a list of models.AppleSUSProduct objects.
    """
        if not new_products and not deprecated_products:
            return  # don't notify if the new catalog has no product changes.
        new_products_strs = [
            '%s: %s %s %s' % (p.product_id, p.name, p.version,
                              '*' if p.restart_required else '')
            for p in new_products
        ]
        deprecated_products_strs = [
            '%s: %s %s' % (p.product_id, p.name, p.version)
            for p in deprecated_products
        ]
        catalog_name = catalog.key().name()

        new_msg = '\n\nNew Products:\n%s' % '\n'.join(new_products_strs)
        if deprecated_products_strs:
            dep_msg = '\n\nDeprecated Products:\n%s' % '\n'.join(
                deprecated_products_strs)
        else:
            dep_msg = ''
        if any(p.restart_required for p in new_products):
            restart_note = '\n\n%s' % RESTART_REQUIRED_FOOTER
        else:
            restart_note = ''
        body = '%s Apple Updates catalog synced to Simian on %s UTC.%s%s%s' % (
            catalog_name, catalog.mtime, new_msg, dep_msg, restart_note)
        subject = '%s Apple Updates catalog synced to Simian.' % catalog_name

        mail.SendMail([settings.EMAIL_ADMIN_LIST], subject, body)
示例#15
0
文件: applesus.py 项目: runt18/simian
    def _ChangeProduct(self, product_id):
        """Method to change properties of a given Apple SUS product."""
        user = users.get_current_user()

        track = self.request.get('track')
        enabled = self.request.get('enabled', None)
        manual_override = self.request.get('manual_override', None)
        unattended = self.request.get('unattended', None)
        force_install_after_date = self.request.get('force_install_after_date',
                                                    None)

        product = models.AppleSUSProduct.get_by_key_name(product_id)
        if not product:
            self.response.set_status(httplib.NOT_FOUND)
            return

        data = {
            'product_id': product_id,
        }

        changed_tracks = set()

        # set/unset manual_override property
        if manual_override is not None:
            manual_override = bool(int(manual_override))
            product.manual_override = manual_override
            product.put()
            log_action = 'manual_override=%s' % manual_override
            for track in common.TRACKS:
                if track not in product.tracks:
                    prom_date = applesus.GetAutoPromoteDate(track, product)
                    if prom_date:
                        data['%s_promote_date' %
                             track] = prom_date.strftime('%b. %d, %Y')
            data['manual_override'] = manual_override
        # set/unset force_install_after_date property
        elif force_install_after_date is not None:
            if force_install_after_date:
                try:
                    tomorrow = datetime.datetime.utcnow() + datetime.timedelta(
                        hours=12)
                    if datetime.datetime.strptime(  # only allow future force install date
                            force_install_after_date,
                            '%Y-%m-%d %H:%M') > tomorrow:
                        product.force_install_after_date_str = force_install_after_date
                    else:
                        self.error(httplib.BAD_REQUEST)
                        return
                except ValueError:
                    self.error(httplib.BAD_REQUEST)
                    return
            else:
                product.force_install_after_date = None
            product.put()
            data['force_install_after_date'] = force_install_after_date
            log_action = 'force_install_after_date=%s' % force_install_after_date
            changed_tracks.update(product.tracks)
        # set/unset unattended property
        elif unattended is not None:
            unattended = bool(int(unattended))
            product.unattended = unattended
            product.put()
            data['unattended'] = unattended
            log_action = 'unattended=%s' % unattended
            changed_tracks.update(product.tracks)
        # add/remove track to product
        elif enabled is not None:
            enabled = bool(int(enabled))
            if enabled:
                if track not in product.tracks:
                    product.tracks.append(track)
                    product.put()
            else:
                if track in product.tracks:
                    product.tracks.remove(track)
                    product.put()
            log_action = '%s=%s' % (track, enabled)
            data.update({'track': track, 'enabled': enabled})
            changed_tracks.add(track)

        log = models.AdminAppleSUSProductLog(product_id=product_id,
                                             action=log_action,
                                             tracks=product.tracks,
                                             user=user.email())
        log.put()

        # Send email notification to admins
        if mail and settings.EMAIL_ON_EVERY_CHANGE:
            display_name = '%s - %s' % (product.name, product.version)

            subject = 'Apple SUS Update by %s - %s (%s)' % (user, display_name,
                                                            product_id)
            body = '%s has set \'%s\' on %s.\n' % (user, log_action,
                                                   display_name)
            body += '%s is now in %s track(s).\n' % (product_id, ', '.join(
                map(str, product.tracks)))
            mail.SendMail(settings.EMAIL_ADMIN_LIST, subject, body)

        # Regenerate catalogs for any changed tracks, if a task isn't already
        # queued to do so.
        for track in changed_tracks:
            if gae_util.ObtainLock(applesus.CATALOG_REGENERATION_LOCK_NAME %
                                   track):
                deferred.defer(applesus.GenerateAppleSUSCatalogs,
                               track=track,
                               delay=180)
        # TODO(user): add a visual cue to UI so admins know a generation is pending.

        self.response.headers['Content-Type'] = 'application/json'
        self.response.out.write(json.dumps(data))
示例#16
0
文件: package.py 项目: smusa/simian
class Package(admin.AdminHandler):
    """Handler for /admin/package."""

    XSRF_PROTECT = True

    def get(self, filename=None):
        """GET handler."""
        if not self.IsAdminUser() or not filename:
            self.error(404)
            return

        filename = urllib.unquote(filename)
        p = models.PackageInfo.get_by_key_name(filename)
        if not p:
            self.error(404)
            self.response.out.write('PackageInfo not found: %s' % filename)
            return

        p.name = p.plist['name']
        p.display_name = p.plist.get('display_name', '')
        p.unattended = p.plist.get('unattended_install')
        p.version = p.plist['version']
        force_install_after_date = p.plist.get('force_install_after_date',
                                               None)
        if force_install_after_date:
            p.force_install_after_date = datetime.datetime.strftime(
                force_install_after_date, '%Y-%m-%d')
            p.force_install_after_date_time = datetime.datetime.strftime(
                force_install_after_date, '%H:%M')

        if self.request.get('plist_xml'):
            self.Render(
                'plist.html', {
                    'report_type': 'packages',
                    'plist_type': 'package_plist',
                    'xml': admin.XmlToHtml(p.plist.GetXml()),
                    'title': 'Plist for %s' % p.name,
                    'raw_xml_link': '/pkgsinfo/%s' % filename,
                })
        else:
            manifests_and_catalogs_unlocked = (
                p.blob_info or p.plist.get('PackageCompleteURL'))
            data = {
                'pkg': p,
                'report_type': 'package',
                'tracks': common.TRACKS,
                'install_types': common.INSTALL_TYPES,
                'manifest_mod_groups': common.MANIFEST_MOD_GROUPS,
                'pkg_safe_to_modify': p.IsSafeToModify(),
                'editxml': self.request.get('editxml'),
                'manifests_and_catalogs_unlocked':
                manifests_and_catalogs_unlocked
            }

            self.Render('package.html', data)

    def post(self, filename=None):
        """POST handler."""
        if not self.IsAdminUser():
            self.error(403)
            self.response.out.write('Access Denied for current user')
            return

        xsrf_token = self.request.get('xsrf_token', None)
        report_type = filename and 'package' or 'packages'
        if not xsrf.XsrfTokenValidate(xsrf_token, report_type):
            self.error(400)
            self.response.out.write(
                'Invalid XSRF token. Please refresh and retry.')
            return

        if filename:
            filename = urllib.unquote(filename)

            # If we're updating from new plist xml, perform the update and return.
            if self.request.get('new_pkginfo_plist'):
                self.UpdatePackageInfoFromPlist()
                return

            # All non-plist updates require an existing PackageInfo entity.
            p = models.PackageInfo.get_by_key_name(filename)
            if not p:
                self.error(404)
                self.response.out.write('Filename not found: %s' % filename)
                return

            if self.request.get('delete') == '1':
                if settings.EMAIL_ON_EVERY_CHANGE:
                    self.NotifyAdminsOfPackageDeletion(p)
                p.delete()
                self.redirect('/admin/packages?msg=%s successfully deleted' %
                              filename)
                return
            elif self.request.get('submit', None) == 'save':
                self.UpdatePackageInfo(p)
            elif self.request.get('unlock') == '1':
                if settings.EMAIL_ON_EVERY_CHANGE:
                    self.NotifyAdminsOfPackageUnlock(p)
                p.MakeSafeToModify()
                self.redirect('/admin/package/%s?msg=%s is safe to modify' %
                              (filename, filename))
            else:
                self.error(400)
                self.response.out.write(
                    'No action specified or unknown action.')

        elif self.request.get('new_pkginfo_plist'):
            # No filename was specified, so we're creating a new PackageInfo.
            self.UpdatePackageInfoFromPlist(create_new=True)
        else:
            self.error(404)

    def NotifyAdminsOfPackageChange(self, pkginfo, **kwargs):
        """Notifies admins of changes to packages."""
        subject_line = 'MSU Package Update by %s - %s' % (
            users.get_current_user(), pkginfo.filename)
        main_body = ['New configuration:\n']
        for key, value in kwargs.iteritems():
            # TODO(user) : This should do better checking of value.
            if value:
                if key == 'manifests':
                    if pkginfo.manifests != value:
                        main_body.append(
                            'Manifests: %s --> %s' %
                            (', '.join(pkginfo.manifests), ', '.join(value)))
                elif key == 'catalogs':
                    if pkginfo.catalogs != value:
                        main_body.append(
                            'Catalogs: %s --> %s' %
                            (', '.join(pkginfo.catalogs), ', '.join(value)))
                elif key == 'install_types':
                    if pkginfo.install_types != value:
                        main_body.append(
                            'Install Types: %s --> %s' % (', '.join(
                                pkginfo.install_types), ', '.join(value)))
                elif key == 'munki_name':
                    if pkginfo.munki_name != value:
                        main_body.append('Munki Name: %s --> %s' %
                                         (pkginfo.munki_name, value))
                elif (key == 'force_install_after_date'
                      and pkginfo.plist[key] != value):
                    main_body.append('%s: %s' % (key, value))
                elif type(value) is list:
                    if pkginfo.plist[key] != value:
                        main_body.append('%s: %s --> %s' % (key, ', '.join(
                            pkginfo.plist[key]), ', '.join(value)))
                else:
                    if pkginfo.plist[key] != value:
                        main_body.append('%s: %s --> %s' %
                                         (key, pkginfo.plist[key], value))
        mail.SendMail(settings.EMAIL_ADMIN_LIST, subject_line,
                      '\n'.join(main_body))

    def NotifyAdminsOfPackageChangeFromPlist(self, plist_xml):
        """Notifies admins of changes to packages."""
        plist = plist_lib.MunkiPackageInfoPlist(plist_xml)
        plist.EncodeXml()
        try:
            plist.Parse()
        except plist_lib.PlistError, e:
            raise models.PackageInfoUpdateError(
                'plist_lib.PlistError parsing plist XML: %s', str(e))
        subject_line = 'MSU Package Update by %s - %s' % (
            users.get_current_user(), plist['installer_item_location'])
        main_body = str(plist.GetXml(2))
        mail.SendMail(settings.EMAIL_ADMIN_LIST, subject_line, main_body)