def _AnalyzeUserMissingInLDAP(self, args):
   """ For the syncOneUser command: if the admin has entered an
   expression which didn't map to any LDAP users, figure out what's
   what.  Is it a user who's in the UserDB but no longer in LDAP?
   If so, that's probably an exited.
   Args:
     args: stripped version of the expression the admin entered
   Returns:
     dn of user,  or None if a user in UserDB couldn't be found
   Side effects:
     displays message to the admin if more than one DN matches
       the expression, and waits for him to choose one.
   """
   # see if it's in UserDB, but deleted from LDAP:
   comps = self._SplitExpression(args)
   if not comps:
     return
   (attr, val) = comps
   if not attr:
     return
   dns = self.users.LookupAttrVal(attr, val)
   if not dns:
     return None
   print messages.msg(messages.MSG_FOUND_IN_USERDB, str(len(dns)))
   return self._ChooseFromList(dns)
  def do_syncAllUsers(self, rest):
    args = rest.strip().lower()
    if args:
      if args == 'added':
        actions = ['added']
      elif args == 'exited':
        actions = ['exited']
      elif args == 'updated':
        actions = ['updated']
      elif args == 'renamed':
        actions = ['renamed']
      elif args == 'all':
        actions = self.sync_google.google_operations
      else:
        logging.error(messages.msg(messages.ERR_SYNC_USERS_ACTION))
        return
    else:
      actions = self.sync_google.google_operations

    # be sure we can connect, before we spawn a bunch of threads that'll try:
    errs = self.sync_google.TestConnectivity()
    if errs:
      logging.error(messages.msg(messages.ERR_CONNECTING_GOOGLE, errs))
      return

    try:
      for action in actions:
        stats = self.sync_google.DoAction(action)
        if stats is not None:
          self._ShowSyncStats(stats)

    except utils.ConfigError, e:
      logging.error(str(e))
      return
  def do_showUsers(self, rest):
    args = rest.strip()
    start = 1
    user_count = self.users.UserCount()
    if not user_count:
      logging.info(messages.ERR_NO_USERS)
      return
    end = self.users.UserCount()
    if args:
      nums = self._GetNumArgs(rest, 2)
      if not nums:
        logging.error(messages.msg(messages.ERR_SHOW_USERS_ARGS))
        return
      start = nums[0]
      if len(nums) > 1:
        end = nums[1]
      else:
        end = start
      user_count = end - start + 1

    # don't just spew out 20,000 users without a warning:
    if user_count > 10:
      ans = raw_input(messages.msg(messages.ERR_TOO_MANY_USERS, 
                      str(user_count)))
      first = ans[:1].lower()
      if first != "y":
        return
    dns = self.users.UserDNs()
    print "Display new users %d to %d" % (start, end)
    for ix in xrange(start-1, end):
      print "%d: %s" % (ix + 1, dns[ix])
      pp.pprint(self.users.LookupDN(dns[ix]))
  def do_updateUsers(self, unused_rest):
    try:
      if not self.ldap_context.GetUserFilter():
        logging.error(messages.ERR_NO_USER_FILTER)
        return
      print messages.msg(messages.MSG_ADDING, self.ldap_context.GetUserFilter())
      self._ShowGoogleAttributes()
      last_update_time.beginNewRun()
      self.errors = False

      # add in the condition for "> lastUpdate"
      search_filter = self.ldap_context.ldap_user_filter
      self.last_update = None
      if last_update_time.get():
        self.last_update = self._TimeFromLDAPTime(last_update_time.get())

      logging.debug('last_update time=%s' % str(self.last_update))
      attrs = self.users.GetAttributes()
      directory_type = _GetDirectoryType(attrs)
      if self.last_update:
        search_filter = self._AndUpdateTime(search_filter,
                   self.users.GetTimestampAttributeName(), self.last_update,
                   directory_type)
      try:
        found_users = self.ldap_context.Search(filter_arg=search_filter,
                                attrlist=attrs)
      except RuntimeError,e:
        logging.exception(str(e))
        return

      if not found_users or found_users.UserCount() == 0:
        print messages.msg(messages.MSG_FIND_USERS_RETURNED, "0")

      if found_users:
        # we need to compute the Google attrs now, since
        # userdb.AnalyzeChangedUsers uses that:
        self.users.MapGoogleAttrs(found_users)
        (adds, mods, renames) = self.users.AnalyzeChangedUsers(found_users)

        # mark new uses as "to be added to Google"
        for dn in adds:
          found_users.SetGoogleAction(dn, 'added')
        for dn in mods:
          found_users.SetGoogleAction(dn, 'updated')
        for dn in renames:
          found_users.SetGoogleAction(dn, 'renamed')
        self.users.MergeUsers(found_users)
        if adds:
          print messages.msg(messages.MSG_NEW_USERS_ADDED, (str(len(adds)), 
            str(self.users.UserCount())))
        if mods:
          print messages.msg(messages.MSG_UPDATED_USERS_MARKED, 
              (str(len(mods))))
        if renames:
          print messages.msg(messages.MSG_RENAMED_USERS_MARKED,
                             (str(len(renames))))

      # find exited users & lock their accounts
      self._FindExitedUsers()
 def do_connect(self, unused_rest):
   try:
     if self.ldap_context.Connect():
       logging.error(messages.msg(messages.ERR_CONNECT_FAILED))
     else:
       logging.info(messages.msg(messages.MSG_CONNECTED, 
                    self.ldap_context.ldap_url))
   except utils.ConfigError, e:
     logging.error(str(e))
 def do_showLastUpdate(self, unused_rest):
   self.last_update = last_update_time.get()
   if not self.last_update:
     print messages.MSG_SHOW_NO_LAST_UPDATE
   else:
     try:
       self.last_update = float(self.last_update)
     except ValueError:
       logging.exception('bad update time: %s', str(self.last_update))
       self.last_update = 0
     tstr = time.asctime(time.localtime())
     print messages.msg(messages.MSG_SHOW_LAST_UPDATE, tstr)
 def _FetchOneUser(self, username):
   """ Fetch info on a single username from Google, with user feedback
   """
   print messages.msg(messages.MSG_LOOKING_UP, username)
   user_rec = self.sync_google.FetchOneUser(username)
   if not user_rec:
     print messages.msg(messages.ERR_USER_NOT_FOUND, username)
   else:
     print messages.MSG_GOOGLE_RETURNED
     #pp.pprint(user_rec)
     self._PrintGoogleUserRec(user_rec)
   return user_rec
 def do_writeUsers(self, rest):
   args = rest.strip()
   if not args:
     logging.error(messages.MSG_GIVE_A_FILE_NAME)
     return
   else:
     fname = rest.split(" ")[0]
   print messages.msg(messages.MSG_WRITE_USERS, fname)
   try:
     rejected_attrs = self.users.WriteDataFile(fname)
   except RuntimeError, e:
     logging.exception(str(e))
     return
 def SetConfigVar(self, attr, val):
   """ To be called AFTER initial config, e.g. when the user does
   something to change a variable.
   Args:
     attr: name of variable
     val: the value
   """
   if not attr in self._config_parms:
     return messages.msg(messages.ERR_NO_SUCH_ATTR, attr)
   try:
     setattr(self, attr, val)
   except ValueError:
       return messages.msg(messages.ERR_INVALID_VALUE, attr)
 def do_readUsers(self, rest):
   args = rest.strip()
   if not args:
     logging.error(messages.MSG_GIVE_A_FILE_NAME)
     return
   else:
     fname = rest.split(" ")[0]
   print messages.msg(messages.MSG_READ_USERS, fname)
   try:
     self.users.ReadDataFile(fname)
   except RuntimeError, e:
     logging.exception(str(e))
     return
 def do_batch(self, rest):
   args = rest.strip()
   if not args:
     logging.error(messages.msg(messages.ERR_BATCH_ARG_NEEDED))
     return
   fname = args.split(" ")[0]
   if not os.path.exists(fname):
     logging.error(messages.msg(messages.ERR_FILE_NOT_FOUND, fname))
     return
   f = open(fname, "r")
   for line in f.readlines():
     print line
     self.onecmd(line)
   f.close()
 def _ChooseFromList(self, dns):
   """ Utility to present the user with a list of DNs and ask them
   to choose one
   Args:
     dns: list of DNs
   Return:
     dn of the one chosen, or None if none chosen
   """
   count = len(dns)
   if count == 1:
     return dns[0]
   else:
     if count > MAX_USER_DISPLAY:
       logging.info(messages.msg(messages.MSG_HERE_ARE_FIRST_N, 
                    str(MAX_USER_DISPLAY)))
       limit = MAX_USER_DISPLAY
     for i in xrange(limit):
       print '%d: %s' % (i, dns[i])
     ans = raw_input(messages.MSG_WHICH_USER)
     try:
       num = int(ans)
       if num < 0 or num >= limit:
         return None
       return dns[num]
     except ValueError,e:
       logging.error(str(e))
       return None
  def __init__(self, ldap_context, users, google, config):
    """ Constructor.
    Args:
      ldap_context: LDAPCtxt object
      users: Users object
      google: sync_google object
      config: utils.Config object
    """
    cmd.Cmd.__init__(self)
    self.ldap_context = ldap_context
    self.users = users
    self.sync_google = google
    self._config = config

    self.new_users = None
    self.last_update = None

    # stuff needed by the Cmd superclass:
    self.completekey = None
    self.cmdqueue = []
    self.prompt = "Command: "
    self.prompt = messages.msg(messages.CMD_PROMPT)

    # code only for use of the unittest:
    self._testing_last_update = None
def DoMain(options):
  """ main module. A client of the optparse module for command-line
  parsing.
  Args:
    options: first return value from parser.parse_args(), where 'parser' is a
      optparse.OptionParser
  """
  (config, ldap_context, user_database, google_context, log_config) = \
    SetupMain(options)
  cmd = commands.Commands(ldap_context, user_database, google_context, config)
  cmd.cmdloop()

  # write out the config parms:
  save_config = False
  if not options.config_file:
    ans = raw_input(messages.msg(messages.MSG_Q_SAVE_CONFIG))
    first = ans[:1].lower()
    if first == messages.CHAR_YES:
      options.config_file = GetValidFileFromUser()
      save_config = True
  else:
    ans = raw_input(messages.msg(messages.MSG_Q_SAVE_CONFIG_2, 
                    options.config_file))
    first = ans[:1].lower()
    if first == messages.CHAR_YES:
      save_config = True

  # if the files can't be written (e.g. on Windows it's open in another window)
  # we want to allow user to rectify the situation.
  if save_config and options.config_file:
    logging.info(messages.msg(messages.MSG_WRITE_CONFIG_FILE, 
                              options.config_file))
    ldap_context.WriteConfig()
    user_database.WriteConfig()
    google_context.WriteConfig()
    log_config.WriteConfig()
    while True:
      try:
        config.WriteConfig(options.config_file)
        break
      except IOError, e:
        logging.error(str(e))
        ans = raw_input(messages.MSG_TRY_AGAIN)
        if ans[:1] != messages.CHAR_YES:
          break
    logging.info(messages.MSG_DONE)
  def do_attrList(self, rest):
    args = rest.strip()
    if args:
      toks = args.split(" ")
      if toks[0].lower() == "show":
        attrs = self.users.GetAttributes()
        print messages.msg(messages.MSG_MAPPINGS)
        pp.pprint(attrs)
        self._ShowGoogleAttributes()
        return

    # if here, we require a second argument
    if len(toks) < 2:
      logging.error(messages.msg(messages.MSG_USAGE_ATTR_LIST))
      return
    attr = toks[1]

    if toks[0].lower() == "add":
      self.users.AddAttribute(attr)
    elif toks[0].lower() == "remove":
      if not attr in self.users.GetAttributes():
        logging.error(messages.msg(messages.ERR_NO_SUCH_ATTR, attr))
        return
      count = self.users.RemoveAttribute(attr)
      print messages.msg(messages.MSG_ATTR_REMOVED, (attr, str(count)))
    else:
      logging.error(messages.msg(messages.MSG_USAGE_ATTR_LIST))
  def do_mapGoogleAttribute(self, rest):
    line = rest.strip()
    if not line:
      print messages.msg(messages.ERR_MAP_ATTR)
      return

    toks = line.split(" ")
    attr = toks[0]
    if not attr in self.users.GetGoogleMappings():
      print messages.msg(messages.ERR_NO_SUCH_ATTR, attr)
      return

    if len(toks) > 1:
      mapping = rest.replace(attr, "", 1)
    else:
      mapping = raw_input(messages.MSG_ENTER_EXPRESSION)

    # test the expression
    print messages.msg(messages.MSG_TESTING_MAPPING)
    err = self.users.TestMapping(mapping.strip())
    if err:
      logging.error(messages.msg(messages.ERR_MAPPING_FAILED))
      logging.error(err)
      return
    self.users.MapAttr(attr, mapping)
    print messages.MSG_DONE
 def SetConfigVar(self, attr, val):
     """ Overrides: Configurable.SetConfigVar
 Imposes some rules on which config vars can be set via the 'set'
 command, mainly for the multi-valued ones, whose syntax would be
 very difficult for users to get right (so there are special routines
 provided)
 """
     if not attr in self.config_parms:
         return messages.msg(messages.ERR_NO_SUCH_ATTR, attr)
     if attr == "mapping":
         return messages.ERR_NO_SET_MAPPING
     elif attr == "attrs":
         return messages.ERR_NO_SET_ATTRS
     else:
         try:
             setattr(self, attr, val)
         except ValueError:
             return messages.msg(messages.ERR_INVALID_VALUE, attr)
  def do_markUsers(self, rest):
    args = rest.strip()
    if not args:
      logging.error(messages.msg(messages.ERR_MARK_USERS))
      logging.error(messages.msg(messages.HELP_MARK_USERS))
      return
    toks = args.split(' ')
    if len(toks) < 2 or len(toks) > 3:
      logging.error(messages.msg(messages.ERR_MARK_USERS))
      logging.error(messages.msg(messages.HELP_MARK_USERS))
      return
    first_str = toks[0]
    second_str = None
    second = None
    if len(toks) == 3:
      second_str = toks[1]
      action = toks[2]
    else:
      action = toks[1]
    try:
      s = first_str
      first = int(first_str)
      second = first
      if second_str:
        s = second_str
        second = int(second_str)
    except ValueError:
      logging.exception('%s\n' % messages.msg(messages.ERR_ENTER_NUMBER, s))
      return

    # parse the action
    if action != 'added' and action != 'exited' and action != 'update':
      logging.error(messages.msg(messages.ERR_MARK_USERS_ACTION))
      logging.error(messages.msg(messages.HELP_MARK_USERS))
      return
    else:
      dns = self.users.UserDNs()
      if first < 0 or first > len(dns):
        logging.error(messages.msg(messages.ERR_NUMBER_OUT_OF_RANGE, first_str))
        return
      if second:
        if second < 0 or second > len(dns) or second < first:
          logging.error(messages.msg(messages.ERR_NUMBER_OUT_OF_RANGE, 
                        second_str))
          return
      for ix in xrange(first, second + 1):
        self.users.SetGoogleAction(dns[ix], action)
def GetValidFileFromUser():

  """ Prompt the user for a writeable file name, until he/she either
  does, or gives up
  Return:
    fname: name of the file
  """
  fname = None
  while not fname:
    fname = raw_input(messages.msg(messages.MSG_GIVE_A_FILE_NAME))
    if not fname:
      return None
    try:
      f = open(fname, 'w')
      f.close()
      return fname
    except IOError:
      sys.stderr.write('%s\n' % 
                       messages.msg(messages.ERR_NOT_VALID_FILE_NAME, fname))
      fname = None
 def do_summarizeUsers(self, unused_rest):
   total = 0
   added = 0
   exited = 0
   updated = 0
   renamed = 0
   for (dn, attrs) in self.users.db.iteritems():
     total += 1
     if 'meta-Google-action' in attrs:
       action = attrs['meta-Google-action']
       if action == 'added':
         added += 1
       elif action == 'exited':
         exited += 1
       elif action == 'renamed':
         renamed += 1
       elif action == 'updated':
         updated += 1
   print messages.msg(messages.MSG_USER_SUMMARY,
       (str(total), str(added), str(exited), str(renamed), 
         str(updated)))
 def SetConfigVar(self, attr, val):
   """ Overrides: the superclass method, in order to provide more
   validation
   Args
     attr: name of config variable
     val: value
   Raises:
     ValueError: if the value is not valid, e.g. not a number
       when a number is required.
   """
   if not attr in self.config_parms:
     return messages.msg(messages.ERR_NO_SUCH_ATTR, attr)
   try:
     if attr == 'ldap_timeout':
        try:
          self.ldap_timeout = float(val)
        except ValueError:
          return messages.msg(messages.ERR_ENTER_NUMBER, val)
     else:
       setattr(self, attr, val)
   except ValueError:
       return messages.msg(messages.ERR_INVALID_VALUE, attr)
Example #22
0
def convert_wac(filein, fileout, codec='utf8', line_funcs=[]):
    """Remove xml tags and extra newlines.
    The resulting file will have sentences separated with a newline.
    Args:
        filein (str): the path to the input file
        fileout (str): the path to the output file
        codec (str, optional): the codecs used to decode the file.
            Default 'utf8'
    """
    XML_TAG = re.compile(r'<[^<]+>')

    filein = codecs.open(filein, 'r', codec)
    fileout = codecs.open(fileout, 'w', codec)
    messages.msg("Converting file...")
    try:
        last_is_newline = True
        for line in messages.pbar(filein):
            line = XML_TAG.sub('', line)
            if line == '\n':
                if last_is_newline:
                    pass
                else:
                    fileout.write(line)
                    last_is_newline = True
            else:
                for func in line_funcs:
                    line = func(line)
                if line:
                    fileout.write(line)
                last_is_newline = False
    except Exception as e:
        filein.close()
        fileout.close()
        raise e
    filein.close()
    fileout.close()
    messages.done()
  def do_set(self, rest):
    args = rest.strip()
    if not len(args):
      self.help_set()
      return
    toks = rest.split(' ')

    # see if it's a real variable
    owner = self._config.FindOwner(toks[0])
    if owner == None:
      logging.error(messages.msg(messages.ERR_NO_SUCH_ATTR, toks[0]))
      return
    value = ' '.join(toks[1:])
    msg = owner.SetConfigVar(toks[0], value)
    if msg:
      logging.error(msg)
 def _SplitExpression(self, expr):
   """ For an admin-typed expression, e.g. givenName=joe, split it
   into two components around the equals sign.
   Args:
     expr: as entered by the admin
   Returns: (None, None) if the expression couldn't be split, or
     attr: name of the attribute
     value: value
   """
   ix = expr.find('=')
   if ix <= 0:
     logging.error(messages.msg(messages.ERR_CANT_USE_EXPR, expr))
     return (None, None)
   attr = expr[:ix].strip()
   val = expr[ix + 1:].strip()
   return (attr, val)
 def _ShowSyncStats(self, stats):
   """ Display the results of a "sync to Google" operation. The
   assumption is that 'stats' will contain all members of
   ThreadStats.stat_names but that some will be zero. If either
   <op>s or <op>_fails is non-zero, then a line concerning <op>
   will be displayed, op in {'add', 'exit', 'rename', 'update'}
   Args:
     stats: return value of all sync_google.Do_<operation>. An
     instance of sync_google.ThreadStats.
   """
   if stats['adds'] > 0 or stats['add_fails'] > 0:
     print messages.msg(messages.MSG_ADD_RESULTS, (stats['adds'],
                        stats['add_fails']))
   if stats['exits'] > 0 or stats['exit_fails'] > 0:
     print messages.msg(messages.MSG_EXITED_RESULTS, (stats['exits'],
                        stats['exit_fails']))
   if stats['renames'] > 0 or stats['rename_fails'] > 0:
     print messages.msg(messages.MSG_RENAME_RESULTS, (stats['renames'],
                        stats['rename_fails']))
   if stats['updates'] > 0 or stats['update_fails'] > 0:
     print messages.msg(messages.MSG_UPDATE_RESULTS, (stats['updates'],
                        stats['update_fails']))
  def _FindExitedUsers(self):
    """
    Finding "exited" users: if we have a special filter for that, use it.
    Else do the search without the "> lastUpdate" filter, to find
    users no longer in the DB.
    Even if we DO have a ldap_disabled_filter, still check for deleted
    entries, since you never know what might have happened.

    """
    total_exits = 0
    if (self.ldap_context.ldap_disabled_filter and 
        self.users.GetTimestampAttributeName()):
      attrs = self.users.GetAttributes()
      directory_type = _GetDirectoryType(attrs)
      search_filter = self._AndUpdateTime(
          self.ldap_context.ldap_disabled_filter, 
          self.users.GetTimestampAttributeName(), self.last_update,
          directory_type)
      try:
        logging.debug(messages.msg(messages.MSG_FIND_EXITS,
                                   self.ldap_context.ldap_disabled_filter))
        userdb_exits = self.ldap_context.Search(filter_arg=search_filter,
                                                attrlist=attrs)
        if not userdb_exits:
          return
        logging.debug('userdb_exits=%s' % userdb_exits.UserDNs())
        exited_users = userdb_exits.UserDNs()
        for dn in exited_users:
          # Note: users previously marked added can be reset to exited
          # if they match the exit filter.  This ensures 
          # added_user_google_action is never called on a locked user that 
          # exists in Google Apps 
          self.users.SetGoogleAction(dn, 'exited')
          total_exits += 1
      except RuntimeError,e:
        logging.exception(str(e))
        return
 def help_stop(self):
   print messages.msg(messages.HELP_STOP)
 def help_readUsers(self):
   print messages.msg(messages.HELP_READ_USERS)
 def help_writeUsers(self):
   print messages.msg(messages.HELP_WRITE_USERS)
 def help_batch(self):
   print messages.msg(messages.HELP_BATCH)
  def do_stop(self, unused_rest):
    print messages.msg(messages.MSG_STOPPING)

    # don't know where this is documented, but returning something
    # other than None stops the cmdloop()
    return -1