Esempio n. 1
0
def GetSshKeyFilenames(key_type, suffix=""):
  """Get filenames of the SSH key pair of the given type.

  @type key_type: string
  @param key_type: type of SSH key, must be element of C{constants.SSHK_ALL}
  @type suffix: string
  @param suffix: optional suffix for the key filenames
  @rtype: tuple of (string, string)
  @returns: a tuple containing the name of the private key file and the
       public key file.

  """
  if key_type not in constants.SSHK_ALL:
    raise errors.SshUpdateError("Unsupported key type '%s'. Supported key types"
                                " are: %s." % (key_type, constants.SSHK_ALL))
  (_, root_keyfiles) = \
      GetAllUserFiles(constants.SSH_LOGIN_USER, mkdir=False, dircheck=False)
  if not key_type in root_keyfiles.keys():
    raise errors.SshUpdateError("No keyfile for key type '%s' available."
                                % key_type)

  key_filenames = root_keyfiles[key_type]
  if suffix:
    key_filenames = [_ComputeKeyFilePathWithSuffix(key_filename, suffix)
                     for key_filename in key_filenames]

  return key_filenames
Esempio n. 2
0
def ReadLocalSshPubKeys(key_types, suffix=""):
  """Reads the local root user SSH key.

  @type key_types: list of string
  @param key_types: types of SSH keys. Must be subset of constants.SSHK_ALL. If
      'None' or [], all available keys are returned.
  @type suffix: string
  @param suffix: optional suffix to be attached to key names when reading
      them. Used for temporary key files.
  @rtype: list of string
  @return: list of public keys

  """
  fetch_key_types = []
  if key_types:
    fetch_key_types += key_types
  else:
    fetch_key_types = constants.SSHK_ALL

  (_, root_keyfiles) = \
      GetAllUserFiles(constants.SSH_LOGIN_USER, mkdir=False, dircheck=False)

  result_keys = []
  for (public_key_type, (_, public_key_file)) in root_keyfiles.items():

    if public_key_type not in fetch_key_types:
      continue

    public_key_dir = os.path.dirname(public_key_file)
    public_key_filename = ""
    if suffix:
      public_key_filename = \
          os.path.splitext(os.path.basename(public_key_file))[0] \
          + suffix + ".pub"
    else:
      public_key_filename = public_key_file
    public_key_path = os.path.join(public_key_dir,
                                   public_key_filename)

    if not os.path.exists(public_key_path):
      raise errors.SshUpdateError("Cannot find SSH public key of type '%s'."
                                  % public_key_type)
    else:
      key = utils.ReadFile(public_key_path)
      result_keys.append(key)

  return result_keys
Esempio n. 3
0
def ReplaceSshKeys(src_key_type,
                   dest_key_type,
                   src_key_suffix="",
                   dest_key_suffix=""):
    """Replaces an SSH key pair by another SSH key pair.

  Note that both parts, the private and the public key, are replaced.

  @type src_key_type: string
  @param src_key_type: key type of key pair that is replacing the other
      key pair
  @type dest_key_type: string
  @param dest_key_type: key type of the key pair that is being replaced
      by the source key pair
  @type src_key_suffix: string
  @param src_key_suffix: optional suffix of the key files of the source
      key pair
  @type dest_key_suffix: string
  @param dest_key_suffix: optional suffix of the keey files of the
      destination key pair

  """
    (src_priv_filename,
     src_pub_filename) = GetSshKeyFilenames(src_key_type,
                                            suffix=src_key_suffix)
    (dest_priv_filename,
     dest_pub_filename) = GetSshKeyFilenames(dest_key_type,
                                             suffix=dest_key_suffix)

    if not (os.path.exists(src_priv_filename)
            and os.path.exists(src_pub_filename)):
        raise errors.SshUpdateError(
            "At least one of the source key files is missing: %s",
            ", ".join([src_priv_filename, src_pub_filename]))

    for dest_file in [dest_priv_filename, dest_pub_filename]:
        if os.path.exists(dest_file):
            utils.CreateBackup(dest_file)
            utils.RemoveFile(dest_file)

    shutil.move(src_priv_filename, dest_priv_filename)
    shutil.move(src_pub_filename, dest_pub_filename)
Esempio n. 4
0
def _ManipulatePubKeyFile(target_identifier,
                          target_key,
                          key_file=pathutils.SSH_PUB_KEYS,
                          error_fn=errors.ProgrammerError,
                          process_line_fn=None,
                          process_else_fn=None):
    """Manipulates the list of public SSH keys of the cluster.

  This is a general function to manipulate the public key file. It needs
  two auxiliary functions C{process_line_fn} and C{process_else_fn} to
  work. Generally, the public key file is processed as follows:
  1) The function processes each line of the original ganeti public key file,
  applies the C{process_line_fn} function on it, which returns a possibly
  manipulated line and an indicator whether the line in question was found.
  If a line is returned, it is added to a list of lines for later writing
  to the file.
  2) If all lines are processed and the 'found' variable is False, the
  seconds auxiliary function C{process_else_fn} is called to possibly
  add more lines to the list of lines.
  3) Finally, the list of lines is assembled to a string and written
  atomically to the public key file, thereby overriding it.

  If the public key file does not exist, we create it. This is necessary for
  a smooth transition after an upgrade.

  @type target_identifier: str
  @param target_identifier: identifier of the node whose key is added; in most
    cases this is the node's UUID, but in some it is the node's host name
  @type target_key: str
  @param target_key: string containing a public SSH key (a complete line
    possibly including more parameters than just the key)
  @type key_file: str
  @param key_file: filename of the file of public node keys (optional
    parameter for testing)
  @type error_fn: function
  @param error_fn: Function that returns an exception, used to customize
    exception types depending on the calling context
  @type process_line_fn: function
  @param process_line_fn: function to process one line of the public key file
  @type process_else_fn: function
  @param process_else_fn: function to be called if no line of the key file
    matches the target uuid

  """
    assert process_else_fn is not None
    assert process_line_fn is not None

    old_lines = []
    f_orig = None
    if os.path.exists(key_file):
        try:
            f_orig = open(key_file, "r")
            old_lines = f_orig.readlines()
        finally:
            f_orig.close()
    else:
        try:
            f_orig = open(key_file, "w")
            f_orig.close()
        except IOError as e:
            raise errors.SshUpdateError("Cannot create public key file: %s" %
                                        e)

    found = False
    new_lines = []
    for line in old_lines:
        (uuid, key) = _ParseKeyLine(line, error_fn)
        if not uuid:
            continue
        (new_found, new_line) = process_line_fn(target_identifier, target_key,
                                                uuid, key, found)
        if new_found:
            found = True
        if new_line is not None:
            new_lines.append(new_line)
    if not found:
        new_line = process_else_fn(target_identifier, target_key)
        if new_line is not None:
            new_lines.append(new_line)
    new_file_content = "".join(new_lines)
    utils.WriteFile(key_file, data=new_file_content)