Repository URL to install this package:
Version:
1.0.0b1 ▾
|
# -*- coding: utf-8 -*-
import copy
import json
import os
import re
import subprocess
import sys
from collections import Mapping
from threading import Thread, Event
from plumbum import local
from six import string_types
try:
from queue import Queue
except (Exception):
# Python 2.7
from Queue import Queue
from pyckles.contexts import PycklesContext
FRECK_PATH = os.path.realpath(
os.path.join(os.path.dirname(__file__), "..", "external", "freck", "freck")
)
def cleanup_string(line):
regex = re.compile(r"(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]")
return regex.sub("", line)
class PipeReader(Thread):
def __init__(self, _fd):
super(PipeReader, self).__init__()
self._fd = _fd
self._queue = Queue()
self._stop_event = Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
def run(self):
for line in iter(self._fd.readline, None):
if line:
self._queue.put(line.decode("UTF-8"))
else:
if self.stopped():
break
class FreckContext(PycklesContext):
def __init__(
self,
pycklets_package_names=None,
config=None,
debug=None,
update_freckles=False,
**kwargs
):
super(FreckContext, self).__init__(
pycklets_package_names=pycklets_package_names, config=config, debug=debug
)
self._update_freckles = update_freckles
def _run(self, frecklet_list, inventory=None, run_config=None):
freck_args = ["freckles"]
# freck_args = []
config = copy.deepcopy(self.context_config)
config["repos"] = self.context_repos
if not self.debug and False:
config["callback"] = ["result"]
else:
config["callback"] = [
"result",
{"default": {"profile": "full", "use_stderr": True}},
]
if isinstance(run_config, string_types):
freck_args.append("--target")
freck_args.append(run_config)
elif isinstance(run_config, Mapping):
host = run_config.get("host", "localhost")
user = run_config.get("user", None)
if user is None:
target_string = host
else:
target_string = "{}@{}".format(user, host)
port = run_config.get("port", None)
if port is not None:
target_string = "{}:{}".format(target_string, port)
freck_args.append("--target")
freck_args.append(target_string)
if "become_pass" in run_config.keys():
raise Exception(
"'become_pass' provided, currently it is not possible to use 'become_pass' and 'login_pass' with the 'freck' pyckles context."
)
if "login_pass" in run_config.keys():
raise Exception(
"'login_pass' provided, currently it is not possible to use 'become_pass' and 'login_pass' with the 'freck' pyckles context."
)
if "ssh_key" in run_config.keys():
raise Exception(
"'ssh_key' provided, currently it is not possible to use 'ssh_key' with the 'freck' pyckles context."
)
if "elevated" in run_config.keys() and run_config["elvated"] is True:
freck_args.append("--elevated")
elif "elevated" in run_config.keys() and run_config["elvated"] is False:
freck_args.append("--not-elevated")
# freck_args.append("--no-run")
freck_args.append("--context")
freck_args.append(json.dumps(config))
freck_args.append("read-stdin")
freck = local[FRECK_PATH]
# freck = local["/home/markus/.local/share/freckles/bin/freckles"]
frecklet_data = json.dumps(frecklet_list)
try:
run_env = os.environ.copy()
run_env["SILENT"] = "true"
run_env["FRECK_HIDE_CURSOR"] = "false"
if self._update_freckles is True:
run_env["UPDATE"] = "true"
process = freck.popen(
freck_args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=run_env,
)
process.stdin.write(frecklet_data.encode(encoding="UTF-8"))
process.stdin.close()
stdout_reader = PipeReader(process.stdout)
stderr_reader = PipeReader(process.stderr)
stdout_reader.start()
stderr_reader.start()
stdout = []
stderr = []
while process.poll() is None:
if not stderr_reader._queue.empty():
line = stderr_reader._queue.get()
stderr.append(line)
sys.stdout.write(line)
# if not stdout_reader._queue.empty():
# line = stdout_reader._queue.get()
# stdout.append(line)
# sys.stdout.write(line)
process.wait()
stdout_reader.stop()
stderr_reader.stop()
stdout_reader.join()
stderr_reader.join()
while not stderr_reader._queue.empty():
line = stderr_reader._queue.get()
stderr.append(line)
stderr = "".join(stderr)
while not stdout_reader._queue.empty():
line = stdout_reader._queue.get()
stdout.append(line)
stdout = "".join(stdout)
rc = process.returncode
if rc != 0:
raise Exception(
"freckles run exit code non-zero ({}): {}".format(rc, stderr)
)
stdout = cleanup_string(stdout).strip()
if not stdout:
result = {}
else:
result = json.loads(stdout)
return result
except (Exception) as e:
raise e
# print("Exit code: {}".format(rc))
# if rc != 0:
# raise Exception("Error: {}".format(stdout + "\n" + stderr))
#
# stdout = cleanup_string(stdout).strip()
# print(stdout)
# result = json.loads(stdout)
#
# return result