Esempio n. 1
0
def service(
    service,
    running=True,
    restarted=False,
    command=None,
):
    """
    Manage the state of systemd managed services.

    + service: name of the service to manage
    + running: whether the service should be running
    + restarted: whether the service should be restarted
    + command: custom command to pass like: ``launchctl <command> <service>``
    + enabled: whether this service should be enabled/disabled on boot
    """

    was_running = host.get_fact(LaunchdStatus).get(service, None)

    yield from handle_service_control(
        host,
        service,
        host.get_fact(LaunchdStatus),
        "launchctl {1} {0}",
        # No support for restart/reload/command
        running,
        None,
        None,
        None,
    )

    # No restart command, so just stop/start
    if restarted and was_running:
        yield "launchctl stop {0}".format(service)
        yield "launchctl start {0}".format(service)
Esempio n. 2
0
def get(
    src,
    dest,
    add_deploy_dir=True,
    create_local_dir=False,
    force=False,
):
    """
    Download a file from the remote system.

    + src: the remote filename to download
    + dest: the local filename to download the file to
    + add_deploy_dir: dest is relative to the deploy directory
    + create_local_dir: create the local directory if it doesn't exist
    + force: always download the file, even if the local copy matches

    Note:
        This operation is not suitable for large files as it may involve copying
        the remote file before downloading it.

    **Example:**

    .. code:: python

        files.get(
            name="Download a file from a remote",
            src="/etc/centos-release",
            dest="/tmp/whocares",
        )
    """

    if add_deploy_dir and state.cwd:
        dest = os.path.join(state.cwd, dest)

    if create_local_dir:
        local_pathname = os.path.dirname(dest)
        if not os.path.exists(local_pathname):
            os.makedirs(local_pathname)

    remote_file = host.get_fact(File, path=src)

    # No remote file, so assume exists and download it "blind"
    if not remote_file or force:
        yield FileDownloadCommand(
            src, dest, remote_temp_filename=state.get_temp_filename(dest))

    # No local file, so always download
    elif not os.path.exists(dest):
        yield FileDownloadCommand(
            src, dest, remote_temp_filename=state.get_temp_filename(dest))

    # Remote file exists - check if it matches our local
    else:
        local_sum = get_file_sha1(dest)
        remote_sum = host.get_fact(Sha1File, path=src)

        # Check sha1sum, upload if needed
        if local_sum != remote_sum:
            yield FileDownloadCommand(
                src, dest, remote_temp_filename=state.get_temp_filename(dest))
Esempio n. 3
0
def packages(
    packages,
    present=True,
):
    """
    Add or remove system packages. This command checks for the presence of all the
    system package managers ``pyinfra`` can handle and executes the relevant operation.

    + packages: list of packages to ensure
    + present: whether the packages should be installed

    **Example:**

    .. code:: python

        server.packages(
            name="Install Vim and vimpager",
            packages=["vimpager", "vim"],
        )
    """

    # TODO: improve this - use LinuxDistribution fact + mapping with fallback below?
    # Here to be preferred on openSUSE which also provides aptitude
    # See: https://github.com/Fizzadar/pyinfra/issues/799
    if host.get_fact(Which, command="zypper"):
        package_operation = zypper.packages

    elif host.get_fact(Which, command="apk"):
        package_operation = apk.packages

    elif host.get_fact(Which, command="apt"):
        package_operation = apt.packages

    elif host.get_fact(Which, command="brew"):
        package_operation = brew.packages

    elif host.get_fact(Which, command="dnf"):
        package_operation = dnf.packages

    elif host.get_fact(Which, command="pacman"):
        package_operation = pacman.packages

    elif host.get_fact(Which, command="xbps"):
        package_operation = xbps.packages

    elif host.get_fact(Which, command="yum"):
        package_operation = yum.packages

    elif host.get_fact(Which, command="pkg") or host.get_fact(
            Which, command="pkg_add"):
        package_operation = pkg.packages

    else:
        raise OperationError(
            ("No system package manager found "
             "(no apk, apt, brew, dnf, pacman, pkg, xbps, yum or zypper found)"
             ), )

    yield from package_operation(packages=packages, present=present)
Esempio n. 4
0
def keyscan(hostname, force=False, port=22):
    """
    Check/add hosts to the ``~/.ssh/known_hosts`` file.

    + hostname: hostname that should have a key in ``known_hosts``
    + force: if the key already exists, remove and rescan

    **Example:**

    .. code:: python

        ssh.keyscan(
            name="Set add server two to known_hosts on one",
            hostname="two.example.com",
        )
    """

    homedir = host.get_fact(Home)

    yield from files.directory(
        "{0}/.ssh".format(homedir),
        mode=700,
    )

    hostname_present = host.get_fact(
        FindInFile,
        path="{0}/.ssh/known_hosts".format(homedir),
        pattern=hostname,
    )

    did_keyscan = False
    keyscan_command = "ssh-keyscan -p {0} {1} >> {2}/.ssh/known_hosts".format(
        port,
        hostname,
        homedir,
    )

    if not hostname_present:
        yield keyscan_command
        did_keyscan = True

    elif force:
        yield "ssh-keygen -R {0}".format(hostname)
        yield keyscan_command
        did_keyscan = True

    else:
        host.noop("host key for {0} already exists".format(hostname))

    if did_keyscan:
        host.create_fact(
            FindInFile,
            kwargs={
                "path": "{0}/.ssh/known_hosts".format(homedir),
                "pattern": hostname
            },
            data=["{0} unknown unknown".format(hostname)],
        )
Esempio n. 5
0
def service(
    service,
    running=True,
    restarted=False,
    reloaded=False,
    command=None,
    enabled=None,
):
    """
    Manage the state of services. This command checks for the presence of all the
    Linux init systems ``pyinfra`` can handle and executes the relevant operation.

    + service: name of the service to manage
    + running: whether the service should be running
    + restarted: whether the service should be restarted
    + reloaded: whether the service should be reloaded
    + command: custom command execute
    + enabled: whether this service should be enabled/disabled on boot

    **Example:**

    .. code:: python

        server.service(
            name="Enable open-vm-tools service",
            service="open-vm-tools",
            enabled=True,
        )
    """

    if host.get_fact(Which, command="systemctl"):
        service_operation = systemd.service

    elif host.get_fact(Which, command="rc-service"):
        service_operation = openrc.service

    elif host.get_fact(Which, command="initctl"):
        service_operation = upstart.service

    elif host.get_fact(Directory, path="/etc/init.d"):
        service_operation = sysvinit.service

    elif host.get_fact(Directory, path="/etc/rc.d"):
        service_operation = bsdinit.service

    else:
        raise OperationError(
            ("No init system found "
             "(no systemctl, initctl, /etc/init.d or /etc/rc.d found)"), )

    yield from service_operation(
        service,
        running=running,
        restarted=restarted,
        reloaded=reloaded,
        command=command,
        enabled=enabled,
    )
Esempio n. 6
0
def hostname(hostname, hostname_file=None):
    """
    Set the system hostname using ``hostnamectl`` or ``hostname`` on older systems.

    + hostname: the hostname that should be set
    + hostname_file: the file that permanently sets the hostname

    Hostname file:
        The hostname file only matters no systems that do not have ``hostnamectl``,
        which is part of ``systemd``.

        By default pyinfra will auto detect this by targeting ``/etc/hostname``
        on Linux and ``/etc/myname`` on OpenBSD.

        To completely disable writing the hostname file, set ``hostname_file=False``.

    **Example:**

    .. code:: python

        server.hostname(
            name="Set the hostname",
            hostname="server1.example.com",
        )
    """

    current_hostname = host.get_fact(Hostname)

    if host.get_fact(Which, command="hostnamectl"):
        if current_hostname != hostname:
            yield "hostnamectl set-hostname {0}".format(hostname)
            host.create_fact(Hostname, data=hostname)
        else:
            host.noop("hostname is set")
        return

    if hostname_file is None:
        os = host.get_fact(Os)

        if os == "Linux":
            hostname_file = "/etc/hostname"
        elif os == "OpenBSD":
            hostname_file = "/etc/myname"

    if current_hostname != hostname:
        yield "hostname {0}".format(hostname)
        host.create_fact(Hostname, data=hostname)
    else:
        host.noop("hostname is set")

    if hostname_file:
        # Create a whole new hostname file
        file = StringIO("{0}\n".format(hostname))

        # And ensure it exists
        yield from files.put(file, hostname_file)
Esempio n. 7
0
def group(group, present=True, system=False, gid=None):
    """
    Add/remove system groups.

    + group: name of the group to ensure
    + present: whether the group should be present or not
    + system: whether to create a system group

    System users:
        System users don't exist on BSD, so the argument is ignored for BSD targets.

    **Examples:**

    .. code:: python

        server.group(
            name="Create docker group",
            group="docker",
        )

        # multiple groups
        for group in ["wheel", "lusers"]:
            server.group(
                name=f"Create the group {group}",
                group=group,
            )
    """

    groups = host.get_fact(Groups)
    is_present = group in groups

    # Group exists but we don't want them?
    if not present and is_present:
        yield "groupdel {0}".format(group)
        groups.remove(group)

    # Group doesn't exist and we want it?
    elif present and not is_present:
        args = []

        # BSD doesn't do system users
        if system and "BSD" not in host.get_fact(Os):
            args.append("-r")

        args.append(group)

        if gid:
            args.append("--gid {0}".format(gid))

        # Groups are often added by other operations (package installs), so check
        # for the group at runtime before adding.
        yield "grep '^{0}:' /etc/group || groupadd {1}".format(
            group,
            " ".join(args),
        )
        groups.append(group)
Esempio n. 8
0
def packages(packages=None, present=True, latest=False):
    """
    Add/remove/update gem packages.

    + packages: list of packages to ensure
    + present: whether the packages should be installed
    + latest: whether to upgrade packages without a specified version

    Versions:
        Package versions can be pinned like gem: ``<pkg>:<version>``.

    **Example:**

    .. code:: python

        # Note: Assumes that 'gem' is installed.
        gem.packages(
            name="Install rspec",
            packages=["rspec"],
        )
    """

    yield from ensure_packages(
        host,
        packages,
        host.get_fact(GemPackages),
        present,
        install_command="gem install",
        uninstall_command="gem uninstall",
        upgrade_command="gem update",
        version_join=":",
        latest=latest,
    )
Esempio n. 9
0
def packages(packages=None, present=True, latest=False):
    """
    Add/remove/update ``choco`` packages.

    + packages: list of packages to ensure
    + present: whether the packages should be installed
    + latest: whether to upgrade packages without a specified version

    Versions:
        Package versions can be pinned like gem: ``<pkg>:<version>``.

    **Example:**

    .. code:: python

        # Note: Assumes that 'choco' is installed and
        #       user has Administrator permission.
        choco.packages(
            name="Install Notepad++",
            packages=["notepadplusplus"],
        )
    """

    yield from ensure_packages(
        host,
        packages,
        host.get_fact(ChocoPackages),
        present,
        install_command="choco install -y",
        uninstall_command="choco uninstall -y -x",
        upgrade_command="choco update -y",
        version_join=":",
        latest=latest,
    )
Esempio n. 10
0
def repo(src, present=True, filename=None):
    """
    Add/remove apt repositories.

    + src: apt source string eg ``deb http://X hardy main``
    + present: whether the repo should exist on the system
    + filename: optional filename to use ``/etc/apt/sources.list.d/<filename>.list``. By
      default uses ``/etc/apt/sources.list``.

    **Example:**

    .. code:: python

        apt.repo(
            name="Install VirtualBox repo",
            src="deb https://download.virtualbox.org/virtualbox/debian bionic contrib",
        )
    """

    # Get the target .list file to manage
    if filename:
        filename = "/etc/apt/sources.list.d/{0}.list".format(filename)
    else:
        filename = "/etc/apt/sources.list"

    # Work out if the repo exists already
    apt_sources = host.get_fact(AptSources)

    is_present = False
    repo = parse_apt_repo(src)
    if repo and repo in apt_sources:
        is_present = True

    # Doesn't exist and we want it
    if not is_present and present:
        yield from files.line(
            filename,
            src,
            escape_regex_characters=True,
        )
        apt_sources.append(repo)

    # Exists and we don't want it
    elif is_present and not present:
        yield from files.line(
            filename,
            src,
            present=False,
            assume_present=True,
            escape_regex_characters=True,
        )
        apt_sources.remove(repo)

    else:
        host.noop(
            'apt repo "{0}" {1}'.format(
                src,
                "exists" if present else "does not exist",
            ), )
Esempio n. 11
0
def packages(
    packages=None,
    present=True,
    update=False,
    upgrade=False,
):
    """
    Add/remove pacman packages.

    + packages: list of packages to ensure
    + present: whether the packages should be installed
    + update: run ``pacman -Sy`` before installing packages
    + upgrade: run ``pacman -Su`` before installing packages

    Versions:
        Package versions can be pinned like pacman: ``<pkg>=<version>``.

    **Example:**

    .. code:: python

        pacman.packages(
            name="Install Vim and a plugin",
            packages=["vim-fugitive", "vim"],
            update=True,
        )
    """

    if update:
        yield from _update()

    if upgrade:
        yield from _upgrade()

    yield from ensure_packages(
        host,
        packages,
        host.get_fact(PacmanPackages),
        present,
        install_command="pacman --noconfirm -S",
        uninstall_command="pacman --noconfirm -R",
        expand_package_fact=lambda package: host.get_fact(
            PacmanUnpackGroup,
            name=package,
        ),
    )
Esempio n. 12
0
def chain(
    chain,
    present=True,
    table="filter",
    policy=None,
    version=4,
):
    """
    Add/remove/update iptables chains.

    + chain: the name of the chain
    + present: whether the chain should exist
    + table: the iptables table this chain should belong to
    + policy: the policy this table should have
    + version: whether to target iptables or ip6tables

    Policy:
        These can only be applied to system chains (FORWARD, INPUT, OUTPUT, etc).
    """

    chains = (host.get_fact(IptablesChains, table=table)
              if version == 4 else host.get_fact(Ip6tablesChains, table=table))

    command = "iptables" if version == 4 else "ip6tables"
    command = "{0} -t {1}".format(command, table)

    if not present:
        if chain in chains:
            yield "{0} -X {1}".format(command, chain)
            chains.pop(chain)
        else:
            host.noop("iptables chain {0} does not exist".format(chain))
        return

    if present:
        if chain not in chains:
            yield "{0} -N {1}".format(command, chain)
            chains[chain] = None  # policy will be set below
        else:
            host.noop("iptables chain {0} exists".format(chain))

        if policy:
            if chain not in chains or chains[chain] != policy:
                yield "{0} -P {1} {2}".format(command, chain, policy)
                chains[chain] = policy
Esempio n. 13
0
def update(cache_time=None):
    """
    Updates apt repositories.

    + cache_time: cache updates for this many seconds

    **Example:**

    .. code:: python

        apt.update(
            name="Update apt repositories",
            cache_time=3600,
        )
    """

    # If cache_time check when apt was last updated, prevent updates if within time
    if cache_time:
        # Ubuntu provides this handy file
        cache_info = host.get_fact(File, path=APT_UPDATE_FILENAME)

        # Time on files is not tz-aware, and will be the same tz as the server's time,
        # so we can safely remove the tzinfo from the Date fact before comparison.
        host_cache_time = host.get_fact(Date).replace(tzinfo=None) - timedelta(
            seconds=cache_time)
        if cache_info and cache_info[
                "mtime"] and cache_info["mtime"] > host_cache_time:
            host.noop("apt is already up to date")
            return

    yield "apt-get update"

    # Some apt systems (Debian) have the /var/lib/apt/periodic directory, but
    # don't bother touching anything in there - so pyinfra does it, enabling
    # cache_time to work.
    if cache_time:
        yield "touch {0}".format(APT_UPDATE_FILENAME)
        if cache_info is None:
            host.create_fact(
                File,
                kwargs={"path": APT_UPDATE_FILENAME},
                data={"mtime": datetime.utcnow()},
            )
        else:
            cache_info["mtime"] = datetime.utcnow()
Esempio n. 14
0
def mount(
    path,
    mounted=True,
    options=None,
    # TODO: do we want to manage fstab here?
    # update_fstab=False, device=None, fs_type=None,
):
    """
    Manage mounted filesystems.

    + path: the path of the mounted filesystem
    + mounted: whether the filesystem should be mounted
    + options: the mount options

    Options:
        If the currently mounted filesystem does not have all of the provided
        options it will be remounted with the options provided.

    ``/etc/fstab``:
        This operation does not attempt to modify the on disk fstab file - for
        that you should use the `files.line operation <./files.html#files-line>`_.
    """

    options = options or []
    options_string = ",".join(options)

    mounts = host.get_fact(Mounts)
    is_mounted = path in mounts

    # Want mount but don't have?
    if mounted and not is_mounted:
        yield "mount{0} {1}".format(
            " -o {0}".format(options_string) if options_string else "",
            path,
        )
        mounts[path] = {"options": options}

    # Want no mount but mounted?
    elif mounted is False and is_mounted:
        yield "umount {0}".format(path)
        mounts.pop(path)

    # Want mount and is mounted! Check the options
    elif is_mounted and mounted and options:
        mounted_options = mounts[path]["options"]
        needed_options = set(options) - set(mounted_options)
        if needed_options:
            yield "mount -o remount,{0} {1}".format(options_string, path)
            mounts[path]["options"] = options

    else:
        host.noop(
            "filesystem {0} is {1}".format(
                path,
                "mounted" if mounted else "not mounted",
            ), )
Esempio n. 15
0
def service(
    service,
    running=True,
    restarted=False,
    reloaded=False,
    command=None,
    enabled=None,
    runlevel="default",
):
    """
    Manage the state of OpenRC services.

    + service: name of the service to manage
    + running: whether the service should be running
    + restarted: whether the service should be restarted
    + reloaded: whether the service should be reloaded
    + command: custom command to pass like: ``rc-service <service> <command>``
    + enabled: whether this service should be enabled/disabled on boot
    + runlevel: runlevel to manage services for
    """

    yield from handle_service_control(
        host,
        service,
        host.get_fact(OpenrcStatus, runlevel=runlevel),
        "rc-service {0} {1}",
        running,
        restarted,
        reloaded,
        command,
    )

    if isinstance(enabled, bool):
        openrc_enabled = host.get_fact(OpenrcEnabled, runlevel=runlevel)
        is_enabled = openrc_enabled.get(service, False)

        if enabled and not is_enabled:
            yield "rc-update add {0}".format(service)
            openrc_enabled[service] = True

        if not enabled and is_enabled:
            yield "rc-update del {0}".format(service)
            openrc_enabled[service] = False
Esempio n. 16
0
def service(
    service,
    running=True,
    restarted=False,
    reloaded=False,
    command=None,
    enabled=None,
):
    """
    Manage the state of BSD init services.

    + service: name of the service to manage
    + running: whether the service should be running
    + restarted: whether the service should be restarted
    + reloaded: whether the service should be reloaded
    + command: custom command to pass like: ``/etc/rc.d/<service> <command>``
    + enabled: whether this service should be enabled/disabled on boot
    """

    status_argument = "status"
    if host.get_fact(Os) == "OpenBSD":
        status_argument = "check"

    yield from handle_service_control(
        host,
        service,
        host.get_fact(RcdStatus),
        "test -e /etc/rc.d/{0} && /etc/rc.d/{0} {1} || /usr/local/etc/rc.d/{0} {1}",
        running,
        restarted,
        reloaded,
        command,
        status_argument=status_argument,
    )

    # BSD init is simple, just add/remove <service>_enabled="YES"
    if isinstance(enabled, bool):
        yield from files.line(
            "/etc/rc.conf.local",
            "^{0}_enable=".format(service),
            replace='{0}_enable="YES"'.format(service),
            present=enabled,
        )
Esempio n. 17
0
def packages(
    packages=None,
    present=True,
    latest=False,
    update=False,
    upgrade=False,
):
    """
    Add/remove/update apk packages.

    + packages: list of packages to ensure
    + present: whether the packages should be installed
    + latest: whether to upgrade packages without a specified version
    + update: run ``apk update`` before installing packages
    + upgrade: run ``apk upgrade`` before installing packages

    Versions:
        Package versions can be pinned like apk: ``<pkg>=<version>``.

    **Examples:**

    .. code:: python

        # Update package list and install packages
        apk.packages(
            name="Install Asterisk and Vim",
            packages=["asterisk", "vim"],
            update=True,
        )

        # Install the latest versions of packages (always check)
        apk.packages(
            name="Install latest Vim",
            packages=["vim"],
            latest=True,
        )
    """

    if update:
        yield from _update()

    if upgrade:
        yield from _upgrade()

    yield from ensure_packages(
        host,
        packages,
        host.get_fact(ApkPackages),
        present,
        install_command="apk add",
        uninstall_command="apk del",
        upgrade_command="apk upgrade",
        version_join="=",
        latest=latest,
    )
Esempio n. 18
0
def packages(
    packages=None,
    present=True,
    latest=False,
    update=False,
    upgrade=False,
):
    """
    Add/remove/update brew packages.

    + packages: list of packages to ensure
    + present: whether the packages should be installed
    + latest: whether to upgrade packages without a specified version
    + update: run ``brew update`` before installing packages
    + upgrade: run ``brew upgrade`` before installing packages

    Versions:
        Package versions can be pinned like brew: ``<pkg>@<version>``.

    **Examples:**

    .. code:: python

        # Update package list and install packages
        brew.packages(
            name='Install Vim and vimpager',
            packages=["vimpager", "vim"],
            update=True,
        )

        # Install the latest versions of packages (always check)
        brew.packages(
            name="Install latest Vim",
            packages=["vim"],
            latest=True,
        )
    """

    if update:
        yield from _update()

    if upgrade:
        yield from _upgrade()

    yield from ensure_packages(
        host,
        packages,
        host.get_fact(BrewPackages),
        present,
        install_command="brew install",
        uninstall_command="brew uninstall",
        upgrade_command="brew upgrade",
        version_join="@",
        latest=latest,
    )
Esempio n. 19
0
def container(
    id,
    present=True,
    image="ubuntu:16.04",
):
    """
    Add/remove LXD containers.

    Note: does not check if an existing container is based on the specified
    image.

    + id: name/identifier for the container
    + image: image to base the container on
    + present: whether the container should be present or absent

    **Example:**

    .. code:: python

        lxd.container(
            name="Add an ubuntu container",
            id="ubuntu19",
            image="ubuntu:19.10",
        )
    """

    current_containers = host.get_fact(LxdContainers)
    container = get_container_named(id, current_containers)

    # Container exists and we don't want it
    if not present:
        if container:
            if container["status"] == "Running":
                yield "lxc stop {0}".format(id)

            # Command to remove the container:
            yield "lxc delete {0}".format(id)

            current_containers.remove(container)
        else:
            host.noop("container {0} does not exist".format(id))

    # Container doesn't exist and we want it
    if present:
        if not container:
            # Command to create the container:
            yield "lxc launch {image} {id} < /dev/null".format(id=id,
                                                               image=image)
            current_containers.append({
                "name": id,
                "image": image,
            }, )
        else:
            host.noop("container {0} exists".format(id))
Esempio n. 20
0
def config(key, value, repo=None):
    """
    Manage git config for a repository or globally.

    + key: the key of the config to ensure
    + value: the value this key should have
    + repo: specify the git repo path to edit local config (defaults to global)

    **Example:**

    .. code:: python

        git.config(
            name="Ensure user name is set for a repo",
            key="user.name",
            value="Anon E. Mouse",
            repo="/usr/local/src/pyinfra",
        )

    """

    existing_config = {}

    if not repo:
        existing_config = host.get_fact(GitConfig)

    # Only get the config if the repo exists at this stage
    elif host.get_fact(Directory, path=unix_path_join(repo, ".git")):
        existing_config = host.get_fact(GitConfig, repo=repo)

    if existing_config.get(key) != value:
        if repo is None:
            yield 'git config --global {0} "{1}"'.format(key, value)
        else:
            yield 'cd {0} && git config --local {1} "{2}"'.format(
                repo, key, value)

        existing_config[key] = value

    else:
        host.noop("git config {0} is set to {1}".format(key, value))
Esempio n. 21
0
def packages(
    packages=None,
    present=True,
    latest=False,
    update=False,
    upgrade=False,
):
    """
    Add/remove/update pkgin packages.

    + packages: list of packages to ensure
    + present: whether the packages should be installed
    + latest: whether to upgrade packages without a specified version
    + update: run ``pkgin update`` before installing packages
    + upgrade: run ``pkgin upgrade`` before installing packages

    **Examples:**

    .. code:: python

        # Update package list and install packages
        pkgin.packages(
            name="Install tmux and Vim",
            packages=["tmux", "vim"],
            update=True,
        )

        # Install the latest versions of packages (always check)
        pkgin.packages(
            name="Install latest Vim",
            packages=["vim"],
            latest=True,
        )
    """

    if update:
        yield from _update()

    if upgrade:
        yield from _upgrade()

    # TODO support glob for specific versions (it isn't as simple
    # as apt-s, as pkgin supports something like 'mysql-server>=5.6<5.7')
    yield from ensure_packages(
        host,
        packages,
        host.get_fact(PkginPackages),
        present,
        install_command="pkgin -y install",
        uninstall_command="pkgin -y remove",
        upgrade_command="pkgin -y upgrade",
        latest=latest,
    )
Esempio n. 22
0
def modprobe(module, present=True, force=False):
    """
    Load/unload kernel modules.

    + module: name of the module to manage
    + present: whether the module should be loaded or not
    + force: whether to force any add/remove modules

    **Example:**

    .. code:: python

        server.modprobe(
            name="Silly example for modprobe",
            module="floppy",
        )
    """
    list_value = [module] if isinstance(module, str) else module

    # NOTE: https://docs.python.org/3/library/itertools.html#itertools-recipes
    def partition(predicate, iterable):
        t1, t2 = tee(iterable)
        return list(filter(predicate, t2)), list(filterfalse(predicate, t1))

    modules = host.get_fact(KernelModules)
    present_mods, missing_mods = partition(lambda mod: mod in modules,
                                           list_value)

    args = ""
    if force:
        args = " -f"

    # Module is loaded and we don't want it?
    if not present and present_mods:
        yield "modprobe{0} -r -a {1}".format(args, " ".join(present_mods))
        for mod in present_mods:
            modules.pop(mod)

    # Module isn't loaded and we want it?
    elif present and missing_mods:
        yield "modprobe{0} -a {1}".format(args, " ".join(missing_mods))
        for mod in missing_mods:
            modules[mod] = {}

    else:
        host.noop(
            "{0} {1} {2} {3}".format(
                "modules" if len(list_value) > 1 else "module",
                "/".join(list_value),
                "are" if len(list_value) > 1 else "is",
                "loaded" if present else "not loaded",
            ), )
Esempio n. 23
0
def service(
    service,
    running=True,
    restarted=False,
    reloaded=False,
    command=None,
    enabled=None,
):
    """
    Manage the state of upstart managed services.

    + service: name of the service to manage
    + running: whether the service should be running
    + restarted: whether the service should be restarted
    + reloaded: whether the service should be reloaded
    + command: custom command to pass like: ``/etc/rc.d/<service> <command>``
    + enabled: whether this service should be enabled/disabled on boot

    Enabling/disabling services:
        Upstart jobs define runlevels in their config files - as such there is no way to
        edit/list these without fiddling with the config. So pyinfra simply manages the
        existence of a ``/etc/init/<service>.override`` file, and sets its content to
        "manual" to disable automatic start of services.
    """

    yield from handle_service_control(
        host,
        service,
        host.get_fact(UpstartStatus),
        "initctl {1} {0}",
        running,
        restarted,
        reloaded,
        command,
    )

    # Upstart jobs are setup w/runlevels etc in their config files, so here we just check
    # there's no override file.
    if enabled is True:
        yield from files.file(
            "/etc/init/{0}.override".format(service),
            present=False,
        )

    # Set the override file to "manual" to disable automatic start
    elif enabled is False:
        file = StringIO("manual\n")
        yield from files.put(
            src=file,
            dest="/etc/init/{0}.override".format(service),
        )
Esempio n. 24
0
def bare_repo(
    path,
    user=None,
    group=None,
    present=True,
):
    """
    Create bare git repositories.

    + path: path to the folder
    + present: whether the bare repository should exist
    + user: chown files to this user after
    + group: chown files to this group after

    **Example:**

    .. code:: python

        git.bare_repo(
            name="Create bare repo",
            path="/home/git/test.git",
        )
    """

    yield from files.directory(path, present=present)

    if present:
        head_filename = unix_path_join(path, "HEAD")
        head_file = host.get_fact(File, path=head_filename)

        if not head_file:
            yield "git init --bare {0}".format(path)
            if user or group:
                yield chown(path, user, group, recursive=True)
        else:
            if (user and head_file["user"] != user) or (
                    group and head_file["group"] != group):
                yield chown(path, user, group, recursive=True)

        host.create_fact(
            File,
            kwargs={"path": head_filename},
            data={
                "user": user,
                "group": group,
                "mode": None
            },
        )
Esempio n. 25
0
def sysctl(
    key,
    value,
    persist=False,
    persist_file="/etc/sysctl.conf",
):
    """
    Edit sysctl configuration.

    + key: name of the sysctl setting to ensure
    + value: the value or list of values the sysctl should be
    + persist: whether to write this sysctl to the config
    + persist_file: file to write the sysctl to persist on reboot

    **Example:**

    .. code:: python

        server.sysctl(
            name="Change the fs.file-max value",
            key="fs.file-max",
            value=100000,
            persist=True,
        )
    """

    string_value = " ".join(["{0}".format(v) for v in value]) if isinstance(
        value, list) else value

    value = [try_int(v)
             for v in value] if isinstance(value, list) else try_int(value)

    existing_sysctls = host.get_fact(Sysctl)

    existing_value = existing_sysctls.get(key)
    if not existing_value or existing_value != value:
        yield "sysctl {0}='{1}'".format(key, string_value)
        existing_sysctls[key] = value
    else:
        host.noop("sysctl {0} is set to {1}".format(key, string_value))

    if persist:
        yield from files.line(
            path=persist_file,
            line="{0}[[:space:]]*=[[:space:]]*{1}".format(key, string_value),
            replace="{0} = {1}".format(key, string_value),
        )
Esempio n. 26
0
def packages(packages=None, present=True, pkg_path=None):
    """
    Install/remove/update pkg packages. This will use ``pkg ...`` where available
    (FreeBSD) and the ``pkg_*`` variants elsewhere.

    + packages: list of packages to ensure
    + present: whether the packages should be installed
    + pkg_path: the PKG_PATH environment variable to set

    pkg_path:
        By default this is autogenerated as follows (tested/working for OpenBSD):
        ``http://ftp.<OS>.org/pub/<OS>/<VERSION>/packages/<ARCH>/``. Note that OpenBSD's
        official mirrors only hold the latest two versions packages.

        NetBSD/FreeBSD helpfully use their own directory structures, so the default won't
        work.

    **Example:**

    .. code:: python

        pkg.packages(
            name="Install Vim and Vim Addon Manager",
            packages=["vim-addon-manager", "vim"],
        )

    """

    if present is True:
        if not pkg_path and not host.get_fact(File, path="/etc/installurl"):
            host_os = host.get_fact(Os) or ""
            pkg_path = "http://ftp.{http}.org/pub/{os}/{version}/packages/{arch}/".format(
                http=host_os.lower(),
                os=host_os,
                version=host.get_fact(OsVersion),
                arch=host.get_fact(Arch),
            )

    # FreeBSD used "pkg ..." and OpenBSD uses "pkg_[add|delete]"
    is_pkg = host.get_fact(Which, command="pkg")
    install_command = "pkg install -y" if is_pkg else "pkg_add"
    uninstall_command = "pkg delete -y" if is_pkg else "pkg_delete"

    if pkg_path:
        install_command = "PKG_PATH={0} {1}".format(pkg_path, install_command)

    yield from ensure_packages(
        host,
        packages,
        host.get_fact(PkgPackages),
        present,
        install_command=install_command,
        uninstall_command=uninstall_command,
    )
Esempio n. 27
0
def casks(
    casks=None,
    present=True,
    latest=False,
    upgrade=False,
):
    """
    Add/remove/update brew casks.

    + casks: list of casks to ensure
    + present: whether the casks should be installed
    + latest: whether to upgrade casks without a specified version
    + upgrade: run brew cask upgrade before installing casks

    Versions:
        Cask versions can be pinned like brew: ``<pkg>@<version>``.

    **Example:**

    .. code:: python

        brew.casks(
            name='Upgrade and install the latest cask',
            casks=["godot"],
            upgrade=True,
            latest=True,
        )

    """

    if upgrade:
        yield from cask_upgrade()

    args = cask_args(host)

    yield from ensure_packages(
        host,
        casks,
        host.get_fact(BrewCasks),
        present,
        install_command="brew %sinstall%s" % args,
        uninstall_command="brew %suninstall%s" % args,
        upgrade_command="brew %supgrade%s" % args,
        version_join="@",
        latest=latest,
    )
Esempio n. 28
0
def create(ctid, template=None):
    """
    Create OpenVZ containers.

    + ctid: CTID of the container to create
    """

    # Check we don't already have a container with this CTID
    current_containers = host.get_fact(OpenvzContainers)
    if ctid in current_containers:
        raise OperationError(
            "An OpenVZ container with CTID {0} already exists".format(ctid), )

    args = ["{0}".format(ctid)]

    if template:
        args.append("--ostemplate {0}".format(template))

    yield "vzctl create {0}".format(" ".join(args))
Esempio n. 29
0
def tap(src, present=True):
    """
    Add/remove brew taps.

    + src: the name of the tap
    + present: whether this tap should be present or not

    **Examples:**

    .. code:: python

        brew.tap(
            name="Add a brew tap",
            src="includeos/includeos",
        )

        # Multiple taps
        for tap in ["includeos/includeos", "ktr0731/evans"]:
            brew.tap(
                name={f"Add brew tap {tap}"},
                src=tap,
            )

    """

    taps = host.get_fact(BrewTaps)
    is_tapped = src in taps

    if present:
        if is_tapped:
            host.noop("tap {0} already exists".format(src))
        else:
            yield "brew tap {0}".format(src)
            taps.append(src)

    elif not present:
        if is_tapped:
            yield "brew untap {0}".format(src)
            taps.remove(src)
        else:
            host.noop("tap {0} does not exist".format(src))
Esempio n. 30
0
def packages(
    packages=None,
    present=True,
    update=False,
    upgrade=False,
):
    """
    Install/remove/update XBPS packages.

    + packages: list of packages to ensure
    + present: whether the packages should be installed
    + update: run ``xbps-install -S`` before installing packages
    + upgrade: run ``xbps-install -y -u`` before installing packages

    **Example:**

    .. code:: python

        xbps.packages(
            name="Install Vim and Vim Pager",
            packages=["vimpager", "vim"],
        )

    """

    if update:
        yield from _update()

    if upgrade:
        yield from _upgrade()

    yield from ensure_packages(
        host,
        packages,
        host.get_fact(XbpsPackages),
        present,
        install_command="xbps-install -y -u",
        uninstall_command="xbps-remove -y",
    )