__  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

[email protected]: ~ $
"""ansible enables running on first boot either ansible-pull"""

import abc
import logging
import os
import re
import sys
import sysconfig
from copy import deepcopy
from typing import Optional

from cloudinit import lifecycle, signal_handler, subp
from cloudinit.cloud import Cloud
from cloudinit.config import Config
from cloudinit.config.schema import MetaSchema
from cloudinit.distros import ALL_DISTROS, Distro
from cloudinit.settings import PER_INSTANCE
from cloudinit.util import get_cfg_by_path

meta: MetaSchema = {
    "id": "cc_ansible",
    "frequency": PER_INSTANCE,
    "distros": [ALL_DISTROS],
    "activate_by_schema_keys": ["ansible"],
}

LOG = logging.getLogger(__name__)
CFG_OVERRIDE = "ansible_config"


class AnsiblePull(abc.ABC):
    def __init__(self, distro: Distro):
        self.cmd_pull = ["ansible-pull"]
        self.cmd_version = ["ansible-pull", "--version"]
        self.distro = distro
        self.env = {}
        self.run_user: Optional[str] = None

        # some ansible modules directly reference os.environ["HOME"]
        # and cloud-init might not have that set, default: /root
        self.env["HOME"] = os.environ.get("HOME", "/root")

    def get_version(self) -> Optional[lifecycle.Version]:
        stdout, _ = self.do_as(self.cmd_version)
        first_line = stdout.splitlines().pop(0)
        matches = re.search(r"([\d\.]+)", first_line)
        if matches:
            version = matches.group(0)
            return lifecycle.Version.from_str(version)
        return None

    def pull(self, *args) -> str:
        stdout, _ = self.do_as([*self.cmd_pull, *args])
        return stdout

    def check_deps(self):
        if not self.is_installed():
            raise ValueError("command: ansible is not installed")

    def do_as(self, command: list, **kwargs):
        if not self.run_user:
            return self.subp(command, **kwargs)
        return self.distro.do_as(command, self.run_user, **kwargs)

    def subp(self, command, **kwargs):
        with signal_handler.suspend_crash():
            return subp.subp(command, update_env=self.env, **kwargs)

    @abc.abstractmethod
    def is_installed(self):
        pass

    @abc.abstractmethod
    def install(self, pkg_name: str):
        pass


class AnsiblePullPip(AnsiblePull):
    def __init__(self, distro: Distro, user: Optional[str]):
        super().__init__(distro)
        self.run_user = user
        self.add_pip_install_site_to_path()

    def add_pip_install_site_to_path(self):
        if self.run_user:
            user_base, _ = self.do_as(
                [
                    sys.executable,
                    "-c",
                    "import site; print(site.getuserbase())",
                ]
            )
            ansible_path = f"{user_base}/bin/"

            old_path = self.env.get("PATH")
            if old_path:
                self.env["PATH"] = ":".join([old_path, ansible_path])
            else:
                self.env["PATH"] = ansible_path

    def bootstrap_pip_if_required(self):
        try:
            import pip  # noqa: F401
        except ImportError:
            self.distro.install_packages([self.distro.pip_package_name])

    def install(self, pkg_name: str):
        """should cloud-init grow an interface for non-distro package
        managers? this seems reusable
        """
        self.bootstrap_pip_if_required()

        if not self.is_installed():
            cmd = [
                sys.executable,
                "-m",
                "pip",
                "install",
            ]

            if os.path.exists(
                os.path.join(
                    sysconfig.get_path("stdlib"), "EXTERNALLY-MANAGED"
                )
            ):
                cmd.append("--break-system-packages")
            if self.run_user:
                cmd.append("--user")

            self.do_as([*cmd, "--upgrade", "pip"])
            self.do_as([*cmd, pkg_name])

    def is_installed(self) -> bool:
        cmd = [sys.executable, "-m", "pip", "list"]

        if self.run_user:
            cmd.append("--user")

        stdout, _ = self.do_as(cmd)
        return "ansible" in stdout


class AnsiblePullDistro(AnsiblePull):
    def __init__(self, distro: Distro, user: Optional[str]):
        super().__init__(distro)
        self.run_user = user

    def install(self, pkg_name: str):
        if not self.is_installed():
            self.distro.install_packages([pkg_name])

    def is_installed(self) -> bool:
        return bool(subp.which("ansible"))


def handle(name: str, cfg: Config, cloud: Cloud, args: list) -> None:

    ansible_cfg: dict = cfg.get("ansible", {})
    ansible_user = ansible_cfg.get("run_user")
    install_method = ansible_cfg.get("install_method")
    setup_controller = ansible_cfg.get("setup_controller")

    galaxy_cfg = ansible_cfg.get("galaxy")
    pull_cfg = ansible_cfg.get("pull")
    package_name = ansible_cfg.get("package_name", "")

    if ansible_cfg:
        ansible: AnsiblePull
        validate_config(ansible_cfg)

        distro: Distro = cloud.distro
        if install_method == "pip":
            ansible = AnsiblePullPip(distro, ansible_user)
        else:
            ansible = AnsiblePullDistro(distro, ansible_user)
        ansible.install(package_name)
        ansible.check_deps()
        ansible_config = ansible_cfg.get("ansible_config", "")

        if ansible_config:
            ansible.env[CFG_OVERRIDE] = ansible_config

        if galaxy_cfg:
            ansible_galaxy(galaxy_cfg, ansible)

        if pull_cfg:
            run_ansible_pull(ansible, deepcopy(pull_cfg))

        if setup_controller:
            ansible_controller(setup_controller, ansible)


def validate_config(cfg: dict):
    required_keys = (
        "install_method",
        "package_name",
    )
    for key in required_keys:
        if not get_cfg_by_path(cfg, key):
            raise ValueError(f"Missing required key '{key}' from {cfg}")
    if cfg.get("pull"):
        for key in "pull/url", "pull/playbook_name":
            if not get_cfg_by_path(cfg, key):
                raise ValueError(f"Missing required key '{key}' from {cfg}")

    controller_cfg = cfg.get("setup_controller")
    if controller_cfg:
        if not any(
            [
                controller_cfg.get("repositories"),
                controller_cfg.get("run_ansible"),
            ]
        ):
            raise ValueError(f"Missing required key from {controller_cfg}")

    install = cfg["install_method"]
    if install not in ("pip", "distro"):
        raise ValueError("Invalid install method {install}")


def filter_args(cfg: dict) -> dict:
    """remove boolean false values"""
    return {
        key.replace("_", "-"): value
        for (key, value) in cfg.items()
        if value is not False
    }


def run_ansible_pull(pull: AnsiblePull, cfg: dict):
    playbook_name: str = cfg.pop("playbook_name")

    v = pull.get_version()
    if not v:
        LOG.warning("Cannot parse ansible version")
    elif v < lifecycle.Version(2, 7, 0):
        # diff was added in commit edaa0b52450ade9b86b5f63097ce18ebb147f46f
        if cfg.get("diff"):
            raise ValueError(
                f"Ansible version {v.major}.{v.minor}.{v.patch}"
                "doesn't support --diff flag, exiting."
            )
    stdout = pull.pull(
        *[
            f"--{key}={value}" if value is not True else f"--{key}"
            for key, value in filter_args(cfg).items()
        ],
        playbook_name,
    )
    if stdout:
        sys.stdout.write(f"{stdout}")


def ansible_galaxy(cfg: dict, ansible: AnsiblePull):
    actions = cfg.get("actions", [])

    if not actions:
        LOG.warning("Invalid config: %s", cfg)
    for command in actions:
        ansible.do_as(command)


def ansible_controller(cfg: dict, ansible: AnsiblePull):
    for repository in cfg.get("repositories", []):
        ansible.do_as(
            ["git", "clone", repository["source"], repository["path"]]
        )
    for args in cfg.get("run_ansible", []):
        playbook_dir = args.pop("playbook_dir")
        playbook_name = args.pop("playbook_name")
        command = [
            "ansible-playbook",
            playbook_name,
            *[f"--{key}={value}" for key, value in filter_args(args).items()],
        ]
        ansible.do_as(command, cwd=playbook_dir)

Filemanager

Name Type Size Permission Actions
__pycache__ Folder 0755
schemas Folder 0755
__init__.py File 40 B 0644
cc_ansible.py File 8.17 KB 0644
cc_apk_configure.py File 4.23 KB 0644
cc_apt_configure.py File 38.23 KB 0644
cc_apt_pipelining.py File 1.85 KB 0644
cc_bootcmd.py File 1.75 KB 0644
cc_byobu.py File 2.72 KB 0644
cc_ca_certs.py File 8.67 KB 0644
cc_chef.py File 13.19 KB 0644
cc_disable_ec2_metadata.py File 1.6 KB 0644
cc_disk_setup.py File 29.6 KB 0644
cc_fan.py File 1.95 KB 0644
cc_final_message.py File 2.5 KB 0644
cc_growpart.py File 18.37 KB 0644
cc_grub_dpkg.py File 5.42 KB 0644
cc_install_hotplug.py File 3.19 KB 0644
cc_keyboard.py File 1.49 KB 0644
cc_keys_to_console.py File 2.09 KB 0644
cc_landscape.py File 3.06 KB 0644
cc_locale.py File 1.18 KB 0644
cc_lxd.py File 13.47 KB 0644
cc_mcollective.py File 4.11 KB 0644
cc_mounts.py File 18.08 KB 0644
cc_ntp.py File 18.91 KB 0644
cc_package_update_upgrade_install.py File 3.99 KB 0644
cc_phone_home.py File 3.74 KB 0644
cc_power_state_change.py File 6.15 KB 0644
cc_puppet.py File 10.72 KB 0644
cc_reset_rmc.py File 4.33 KB 0644
cc_resizefs.py File 10.63 KB 0644
cc_resolv_conf.py File 3.13 KB 0644
cc_rh_subscription.py File 15.19 KB 0644
cc_rsyslog.py File 11.47 KB 0644
cc_runcmd.py File 1.6 KB 0644
cc_salt_minion.py File 3.96 KB 0644
cc_scripts_per_boot.py File 1.27 KB 0644
cc_scripts_per_instance.py File 1.26 KB 0644
cc_scripts_per_once.py File 1.24 KB 0644
cc_scripts_user.py File 1.25 KB 0644
cc_scripts_vendor.py File 1.26 KB 0644
cc_seed_random.py File 3 KB 0644
cc_set_hostname.py File 3.4 KB 0644
cc_set_passwords.py File 10.32 KB 0644
cc_snap.py File 3.36 KB 0644
cc_spacewalk.py File 2.64 KB 0644
cc_ssh.py File 10.96 KB 0644
cc_ssh_authkey_fingerprints.py File 3.76 KB 0644
cc_ssh_import_id.py File 5.42 KB 0644
cc_timezone.py File 1.13 KB 0644
cc_ubuntu_autoinstall.py File 1.27 KB 0644
cc_ubuntu_drivers.py File 4.08 KB 0644
cc_ubuntu_pro.py File 13.64 KB 0644
cc_update_etc_hosts.py File 2.46 KB 0644
cc_update_hostname.py File 2.18 KB 0644
cc_users_groups.py File 2.86 KB 0644
cc_wireguard.py File 6.67 KB 0644
cc_write_files.py File 6 KB 0644
cc_write_files_deferred.py File 1.28 KB 0644
cc_yum_add_repo.py File 4.53 KB 0644
cc_zypper_add_repo.py File 4.93 KB 0644
modules.py File 13.32 KB 0644
schema.py File 50.77 KB 0644
Filemanager