Example #1
0
    def __getitem__(self, k):
        """Retrieve a piece of information.

        :param k: Name
        """
        try:
            modname, funcname = k.rsplit('.', 1)
        except ValueError:
            raise ConfigurationError(
                'Not a valid info entry (must be `module.name`): {}'.format(k))
        funcname = 'info_{}'.format(funcname)
        modname = 'remand.lib.{}'.format(modname)

        # ensure module is imported
        try:
            mod = import_module(modname)
        except ImportError:
            raise ConfigurationError(
                'Python module not found: {}'.format(modname))

        func = getattr(mod, funcname, None)

        if func is None:
            raise ConfigurationError('Missing callable {} in {}'.format(
                funcname, modname))

        return func()
Example #2
0
    def install_git(self,
                    host,
                    repo,
                    user='******',
                    branch='master',
                    egg=None,
                    upgrade=True,
                    editable=False,
                    protocol='git'):
        # FIXME: with newer git versions, we'd find a way here to pass in
        #        the deployment key, which would allow not having to store
        #        the key on the server
        if protocol in ('http', 'https'):
            url = 'git+{}://{}/{}@{}'.format(protocol, host, repo, branch)
        elif protocol == 'git':
            url = 'git+ssh://{}@{}/{}@{}'.format(user, host, repo, branch)
        else:
            raise ConfigurationError('Unknown protocol: {}'.format(protocol))

        if egg is not None:
            url += '#egg=' + egg

        # FIXME: determine changes?
        self.install([url], upgrade=upgrade, editable=editable)

        return Changed(msg='Installed {}'.format(url))
Example #3
0
File: util.py Project: mbr/remand
    def _by_short_name(cls, short_name):
        v = cls.registry.get(short_name, None)
        if v is None:
            raise ConfigurationError(
                'Unknown {}: {!r}. Check your configuration setting.'
                .format(cls.__name__, short_name))

        subclass = cls.registry[short_name]
        log.debug('{} {!r} -> {}'.format(cls.__name__, short_name,
                                         subclass.__name__))
        return subclass
Example #4
0
File: verify.py Project: mbr/remand
 def verify_buffer(self, st, buf, remote_path):
     raise ConfigurationError(
         '{} does not verify buffers.'.format(self.__class__.__name__))
Example #5
0
File: verify.py Project: mbr/remand
 def verify_file(self, st, local_path, remote_path):
     raise ConfigurationError(
         '{} does not verify files.'.format(self.__class__.__name__))
Example #6
0
def upload_file(local_path,
                remote_path=None,
                follow_symlink=True,
                create_parent=False):
    """Uploads a local file to a remote and if does not exist or differs
    from the local version, uploads it.

    To avoid having to transfer the file one or more times if unchanged,
    different methods for verification are available. These can be configured
    using the ``fs_remote_file_verify`` configuration variable.

    :param local_path: Local file to upload. If it is a symbolic link, it will
                       be resolved first.
    :param remote_path: Remote name for the file. If ``None``, same as
                        ``local_path``. If it points to a directory, the file
                        will be uploaded to the directory. Symbolic links not
                        pointing to a directory are an error.

    :param return: ``False`` if no upload was necessary, ``True`` otherwise.
    """
    st, remote_path = _expand_remote_dest(local_path, remote_path)
    lst = os.stat(local_path) if follow_symlink else os.lstat(local_path)

    verifier = Verifier._by_short_name(config['fs_remote_file_verify'])()
    uploader = Uploader._by_short_name(config['fs_remote_file_upload'])()

    if lst is None:
        raise ConfigurationError(
            'Local file {!r} does not exist'.format(local_path))

    if S_ISLNK(lst.st_mode):
        # local file is a link
        rst = remote.lstat(remote_path)

        if rst:
            if not S_ISLNK(rst.st_mode):
                # remote file is not a link, unlink it
                remote.unlink(remote_path)
            elif remote.readlink(remote_path) != os.readlink(local_path):
                # non matching links
                remote.unlink(remote_path)
            else:
                # links pointing to the same target
                return Unchanged(
                    msg='Symbolink link up-to-date: {}'.format(remote_path))

        remote.symlink(os.readlink(local_path), remote_path)
        return Changed(msg='Created remote link: {}'.format(remote_path))

    if not st or not verifier.verify_file(st, local_path, remote_path):
        if create_parent:
            create_dir(remote.path.dirname(remote_path))

        uploader.upload_file(local_path, remote_path)

        if config.get_bool('fs_update_mtime'):
            times = (lst.st_mtime, lst.st_mtime)
            remote.utime(remote_path, times)
            log.debug('Updated atime/mtime: {}'.format(times))
        return Changed(msg='Upload {} -> {}'.format(local_path, remote_path))

    return Unchanged(msg='File up-to-date: {}'.format(remote_path))
Example #7
0
File: ssl.py Project: mbr/remand
def install_cert(cert, key, cert_name=None, key_name=None):
    """Installs an SSL certificate with including key on the remote

    Certificate filenames are unchanged, per default they will be installed in
    `/etc/ssl`, with the corresponding keys at `/etc/ssl/private`."""
    cert_name = cert_name or os.path.basename(cert)
    key_name = key_name or os.path.basename(key)

    # small sanity check
    with open(cert) as f:
        if 'PRIVATE' in f.read():
            raise ValueError(
                'You seem to have passed a private key as a cert!')

    with open(key) as f:
        if 'PRIVATE' not in f.read():
            raise ValueError(
                '{} does not seem to be a valid private key'.format(key))

    # check if remote is reasonably secure
    cert_dir = config['sslcert_cert_dir']
    cert_dir_st = remote.lstat(cert_dir)

    if not cert_dir_st:
        raise ConfigurationError(
            'Remote SSL dir {} does not exist'.format(cert_dir))

    key_dir = config['sslcert_key_dir']
    key_dir_st = remote.lstat(key_dir)

    if not key_dir_st:
        raise ConfigurationError(
            'Remote key dir {} does not exist'.format(key_dir))

    SECURE_MODES = (0o700, 0o710)
    actual_mode = key_dir_st.st_mode & 0o777
    if actual_mode not in SECURE_MODES:
        raise ConfigurationError(
            'Mode of remote key dir {} is {:o}, should be one of {:o}'.format(
                key_dir, actual_mode, SECURE_MODES))

    if key_dir_st.st_uid != 0:
        raise ConfigurationError(
            'Remove key dir {} is not owned by root'.format(key_dir))

    # we can safely upload the key and cert
    cert_rpath = remote.path.join(cert_dir, cert_name)
    key_rpath = remote.path.join(key_dir, key_name)

    changed = False
    changed |= fs.upload_file(cert, cert_rpath).changed
    changed |= fs.upload_file(key, key_rpath).changed
    changed |= fs.chmod(key_rpath, 0o640).changed
    changed |= fs.chown(key_rpath, uid='root', gid='ssl-cert').changed

    if changed:
        return Changed(
            msg='Uploaded key pair {}/{}'.format(cert_name, key_name))

    return Unchanged(
        msg='Key pair {}/{} already uploaded'.format(cert_name, key_name))
Example #8
0
File: upload.py Project: mbr/remand
 def upload_buffer(self, buf, remote_path):
     raise ConfigurationError('{} does not support buffer uploads.'.format(
         self.__class__.__name__))
Example #9
0
File: upload.py Project: mbr/remand
 def upload_file(self, local_path, remote_path):
     raise ConfigurationError('{} does not support file uploads.'.format(
         self.__class__.__name__))