parent
8f7a6c5647
commit
b2903c1490
13 changed files with 2089 additions and 28 deletions
@ -0,0 +1,6 @@ |
|||||||
|
class InvalidInput(Exception): |
||||||
|
pass |
||||||
|
|
||||||
|
|
||||||
|
class UnknownCommand(Exception): |
||||||
|
pass |
@ -0,0 +1,389 @@ |
|||||||
|
# Imports |
||||||
|
|
||||||
|
from commonkit import parse_jinja_template, read_file |
||||||
|
from jinja2 import TemplateNotFound, TemplateError |
||||||
|
import logging |
||||||
|
import os |
||||||
|
|
||||||
|
log = logging.getLogger(__name__) |
||||||
|
|
||||||
|
# Exports |
||||||
|
|
||||||
|
__all__ = ( |
||||||
|
"EXCLUDED_KWARGS", |
||||||
|
"run", |
||||||
|
"Command", |
||||||
|
"ItemizedCommand", |
||||||
|
"Sudo", |
||||||
|
"Template", |
||||||
|
) |
||||||
|
|
||||||
|
# Constants |
||||||
|
|
||||||
|
EXCLUDED_KWARGS = [ |
||||||
|
"cd", |
||||||
|
"comment", |
||||||
|
"condition", |
||||||
|
"prefix", |
||||||
|
"register", |
||||||
|
"stop", |
||||||
|
"sudo", |
||||||
|
"tags", |
||||||
|
] |
||||||
|
|
||||||
|
# Functions |
||||||
|
|
||||||
|
|
||||||
|
def run(statement, **kwargs): |
||||||
|
"""Run any statement. |
||||||
|
|
||||||
|
- statement (str): The statement to be executed. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "run statement") |
||||||
|
return Command(statement, **kwargs) |
||||||
|
|
||||||
|
# Classes |
||||||
|
|
||||||
|
|
||||||
|
class Command(object): |
||||||
|
|
||||||
|
def __init__(self, statement, cd=None, comment=None, condition=None, prefix=None, register=None, stop=False, sudo=None, tags=None, **kwargs): |
||||||
|
self.cd = cd |
||||||
|
self.comment = comment |
||||||
|
self.condition = condition |
||||||
|
self.prefix = prefix |
||||||
|
self.register = register |
||||||
|
self.statement = statement |
||||||
|
self.stop = stop |
||||||
|
self.tags = tags or list() |
||||||
|
|
||||||
|
if isinstance(sudo, Sudo): |
||||||
|
self.sudo = sudo |
||||||
|
elif type(sudo) is str: |
||||||
|
self.sudo = Sudo(enabled=True, user=sudo) |
||||||
|
elif sudo is True: |
||||||
|
self.sudo = Sudo(enabled=True) |
||||||
|
else: |
||||||
|
self.sudo = Sudo() |
||||||
|
|
||||||
|
self.options = kwargs |
||||||
|
|
||||||
|
def __getattr__(self, item): |
||||||
|
return self.options.get(item) |
||||||
|
|
||||||
|
def __repr__(self): |
||||||
|
if self.comment: |
||||||
|
return "<%s %s>" % (self.__class__.__name__, self.comment) |
||||||
|
|
||||||
|
return "<%s>" % self.__class__.__name__ |
||||||
|
|
||||||
|
def get_statement(self, cd=True, include_comment=True, include_register=True, include_stop=True): |
||||||
|
"""Get the full statement. |
||||||
|
|
||||||
|
:param cd: Include the directory change, if given. |
||||||
|
:type cd: bool |
||||||
|
|
||||||
|
:param suppress_comment: Don't include the comment. |
||||||
|
:type suppress_comment: bool |
||||||
|
|
||||||
|
:rtype: str |
||||||
|
|
||||||
|
""" |
||||||
|
a = list() |
||||||
|
|
||||||
|
if cd and self.cd is not None: |
||||||
|
a.append("( cd %s &&" % self.cd) |
||||||
|
|
||||||
|
if self.prefix is not None: |
||||||
|
a.append("%s &&" % self.prefix) |
||||||
|
|
||||||
|
if self.sudo: |
||||||
|
statement = "%s %s" % (self.sudo, self._get_statement()) |
||||||
|
else: |
||||||
|
statement = self._get_statement() |
||||||
|
|
||||||
|
a.append("%s" % statement) |
||||||
|
|
||||||
|
if cd and self.cd is not None: |
||||||
|
a.append(")") |
||||||
|
|
||||||
|
b = list() |
||||||
|
if self.comment is not None and include_comment: |
||||||
|
b.append("# %s" % self.comment) |
||||||
|
|
||||||
|
if self.condition is not None: |
||||||
|
b.append("if [[ %s ]]; then %s; fi;" % (self.condition, " ".join(a))) |
||||||
|
else: |
||||||
|
b.append(" ".join(a)) |
||||||
|
|
||||||
|
if self.register is not None and include_register: |
||||||
|
b.append("%s=$?;" % self.register) |
||||||
|
|
||||||
|
if self.stop and include_stop: |
||||||
|
b.append("if [[ $%s -gt 0 ]]; exit 1; fi;" % self.register) |
||||||
|
elif self.stop and include_stop: |
||||||
|
b.append("if [[ $? -gt 0 ]]; exit 1; fi;") |
||||||
|
else: |
||||||
|
pass |
||||||
|
|
||||||
|
return "\n".join(b) |
||||||
|
|
||||||
|
@property |
||||||
|
def is_itemized(self): |
||||||
|
"""Always returns ``False``.""" |
||||||
|
return False |
||||||
|
|
||||||
|
def _get_statement(self): |
||||||
|
"""By default, get the statement passed upon command initialization. |
||||||
|
|
||||||
|
:rtype: str |
||||||
|
|
||||||
|
""" |
||||||
|
return self.statement |
||||||
|
|
||||||
|
|
||||||
|
class Sudo(object): |
||||||
|
"""Helper class for defining sudo options.""" |
||||||
|
|
||||||
|
def __init__(self, enabled=False, user="root"): |
||||||
|
"""Initialize the helper. |
||||||
|
|
||||||
|
:param enabled: Indicates sudo is enabled. |
||||||
|
:type enabled: bool |
||||||
|
|
||||||
|
:param user: The user to be invoked. |
||||||
|
:type user: str |
||||||
|
|
||||||
|
""" |
||||||
|
self.enabled = enabled |
||||||
|
self.user = user |
||||||
|
|
||||||
|
def __bool__(self): |
||||||
|
return self.enabled |
||||||
|
|
||||||
|
def __str__(self): |
||||||
|
if self.enabled: |
||||||
|
return "sudo -u %s" % self.user |
||||||
|
|
||||||
|
return "" |
||||||
|
|
||||||
|
|
||||||
|
class ItemizedCommand(object): |
||||||
|
"""An itemized command represents multiple commands of with the same statement but different parameters.""" |
||||||
|
|
||||||
|
def __init__(self, callback, items, *args, name=None, **kwargs): |
||||||
|
"""Initialize the command. |
||||||
|
|
||||||
|
:param callback: The function to be used to generate the command. |
||||||
|
|
||||||
|
:param items: The command arguments. |
||||||
|
:type items: list[str] |
||||||
|
|
||||||
|
:param name: The name of the command from the mapping. Not used and not required for programmatic use, but |
||||||
|
automatically assigned during factory instantiation. |
||||||
|
:type name: str |
||||||
|
|
||||||
|
:param args: The itemized arguments. ``$item`` should be included. |
||||||
|
|
||||||
|
Keyword arguments are passed to the command class upon instantiation. |
||||||
|
|
||||||
|
""" |
||||||
|
self.args = args |
||||||
|
self.callback = callback |
||||||
|
self.items = items |
||||||
|
self.kwargs = kwargs |
||||||
|
self.name = name |
||||||
|
|
||||||
|
# Set defaults for when ItemizedCommand is referenced directly before individual commands are instantiated. For |
||||||
|
# example, when command filtering occurs. |
||||||
|
self.kwargs.setdefault("tags", list()) |
||||||
|
|
||||||
|
def __getattr__(self, item): |
||||||
|
return self.kwargs.get(item) |
||||||
|
|
||||||
|
def __repr__(self): |
||||||
|
return "<%s %s>" % (self.__class__.__name__, self.callback.__name__) |
||||||
|
|
||||||
|
def get_commands(self): |
||||||
|
"""Get the commands to be executed. |
||||||
|
|
||||||
|
:rtype: list[BaseType(Command)] |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs = self.kwargs.copy() |
||||||
|
|
||||||
|
a = list() |
||||||
|
for item in self.items: |
||||||
|
args = list() |
||||||
|
for arg in self.args: |
||||||
|
args.append(arg.replace("$item", item)) |
||||||
|
|
||||||
|
command = self.callback(*args, **kwargs) |
||||||
|
a.append(command) |
||||||
|
|
||||||
|
return a |
||||||
|
|
||||||
|
def get_statement(self, cd=True, include_comment=True, include_register=True, include_stop=True): |
||||||
|
"""Override to get multiple commands.""" |
||||||
|
kwargs = self.kwargs.copy() |
||||||
|
comment = kwargs.pop("comment", "execute multiple commands") |
||||||
|
|
||||||
|
a = list() |
||||||
|
# a.append("# %s" % comment) |
||||||
|
|
||||||
|
commands = self.get_commands() |
||||||
|
for c in commands: |
||||||
|
a.append(c.get_statement(cd=cd, include_comment=False, include_register=include_register, include_stop=include_stop)) |
||||||
|
a.append("") |
||||||
|
|
||||||
|
return "\n".join(a) |
||||||
|
|
||||||
|
@property |
||||||
|
def is_itemized(self): |
||||||
|
"""Always returns ``True``.""" |
||||||
|
return True |
||||||
|
|
||||||
|
|
||||||
|
class Template(object): |
||||||
|
|
||||||
|
PARSER_JINJA = "jinja2" |
||||||
|
PARSER_PYTHON = "python" |
||||||
|
PARSER_SIMPLE = "simple" |
||||||
|
|
||||||
|
def __init__(self, source, target, backup=True, parser=PARSER_JINJA, **kwargs): |
||||||
|
self.backup_enabled = backup |
||||||
|
self.context = kwargs.pop("context", dict()) |
||||||
|
self.name = "template" |
||||||
|
self.parser = parser |
||||||
|
self.language = kwargs.pop("lang", None) |
||||||
|
self.locations = kwargs.pop("locations", list()) |
||||||
|
self.source = os.path.expanduser(source) |
||||||
|
self.target = target |
||||||
|
|
||||||
|
sudo = kwargs.pop("sudo", None) |
||||||
|
if isinstance(sudo, Sudo): |
||||||
|
self.sudo = sudo |
||||||
|
elif type(sudo) is str: |
||||||
|
self.sudo = Sudo(enabled=True, user=sudo) |
||||||
|
elif sudo is True: |
||||||
|
self.sudo = Sudo(enabled=True) |
||||||
|
else: |
||||||
|
self.sudo = Sudo() |
||||||
|
|
||||||
|
self.kwargs = kwargs |
||||||
|
|
||||||
|
def __getattr__(self, item): |
||||||
|
return self.kwargs.get(item) |
||||||
|
|
||||||
|
def __str__(self): |
||||||
|
return "template" |
||||||
|
|
||||||
|
def get_content(self): |
||||||
|
"""Parse the template. |
||||||
|
|
||||||
|
:rtype: str | None |
||||||
|
|
||||||
|
""" |
||||||
|
template = self.get_template() |
||||||
|
|
||||||
|
if self.parser == self.PARSER_SIMPLE: |
||||||
|
content = read_file(template) |
||||||
|
for key, value in self.context.items(): |
||||||
|
replace = "$%s$" % key |
||||||
|
content = content.replace(replace, str(value)) |
||||||
|
|
||||||
|
return content |
||||||
|
|
||||||
|
if self.parser == self.PARSER_PYTHON: |
||||||
|
content = read_file(template) |
||||||
|
return content % self.context |
||||||
|
|
||||||
|
try: |
||||||
|
return parse_jinja_template(template, self.context) |
||||||
|
except TemplateNotFound: |
||||||
|
log.error("Template not found: %s" % template) |
||||||
|
return None |
||||||
|
except TemplateError as e: |
||||||
|
log.error("Could not parse %s template: %s" % (template, e)) |
||||||
|
return None |
||||||
|
|
||||||
|
# noinspection PyUnusedLocal |
||||||
|
def get_statement(self, cd=True, include_comment=True, include_register=True, include_stop=True): |
||||||
|
lines = list() |
||||||
|
if include_comment and self.comment is not None: |
||||||
|
lines.append("# %s" % self.comment) |
||||||
|
|
||||||
|
# TODO: Backing up a template's target is currently specific to bash. |
||||||
|
if self.backup_enabled: |
||||||
|
command = "%s mv %s %s.b" % (self.sudo, self.target, self.target) |
||||||
|
lines.append('if [[ -f "%s" ]]; then %s; fi;' % (self.target, command.lstrip())) |
||||||
|
|
||||||
|
# Get the content; e.g. parse the template. |
||||||
|
content = self.get_content() |
||||||
|
|
||||||
|
# Templates that are bash scripts will fail to write because of the shebang. |
||||||
|
if content.startswith("#!"): |
||||||
|
_content = content.split("\n") |
||||||
|
first_line = _content.pop(0) |
||||||
|
command = '%s echo "%s" > %s' % (self.sudo, first_line, self.target) |
||||||
|
lines.append(command.lstrip()) |
||||||
|
command = "%s cat > %s << EOF" % (self.sudo, self.target) |
||||||
|
lines.append(command.lstrip()) |
||||||
|
lines.append("\n".join(_content)) |
||||||
|
lines.append("EOF") |
||||||
|
else: |
||||||
|
command = "%s cat > %s << EOF" % (self.sudo, self.target) |
||||||
|
lines.append(command.lstrip()) |
||||||
|
lines.append(content) |
||||||
|
lines.append("EOF") |
||||||
|
|
||||||
|
if include_register and self.register is not None: |
||||||
|
lines.append("%s=$?;" % self.register) |
||||||
|
|
||||||
|
if include_stop and self.stop: |
||||||
|
lines.append("if [[ $%s -gt 0 ]]; exit 1; fi;" % self.register) |
||||||
|
elif include_stop and self.stop: |
||||||
|
lines.append("if [[ $? -gt 0 ]]; exit 1; fi;") |
||||||
|
else: |
||||||
|
pass |
||||||
|
|
||||||
|
return "\n".join(lines) |
||||||
|
|
||||||
|
def get_target_language(self): |
||||||
|
if self.language is not None: |
||||||
|
return self.language |
||||||
|
|
||||||
|
if self.target.endswith(".conf"): |
||||||
|
return "conf" |
||||||
|
elif self.target.endswith(".ini"): |
||||||
|
return "ini" |
||||||
|
elif self.target.endswith(".php"): |
||||||
|
return "php" |
||||||
|
elif self.target.endswith(".py"): |
||||||
|
return "python" |
||||||
|
elif self.target.endswith(".sh"): |
||||||
|
return "bash" |
||||||
|
elif self.target.endswith(".yml"): |
||||||
|
return "yaml" |
||||||
|
else: |
||||||
|
return "text" |
||||||
|
|
||||||
|
def get_template(self): |
||||||
|
"""Get the template path. |
||||||
|
|
||||||
|
:rtype: str |
||||||
|
|
||||||
|
""" |
||||||
|
source = self.source |
||||||
|
for location in self.locations: |
||||||
|
_source = os.path.join(location, self.source) |
||||||
|
if os.path.exists(_source): |
||||||
|
return _source |
||||||
|
|
||||||
|
return source |
||||||
|
|
||||||
|
@property |
||||||
|
def is_itemized(self): |
||||||
|
# return "$item" in self.target |
||||||
|
return False |
@ -0,0 +1,279 @@ |
|||||||
|
# Imports |
||||||
|
|
||||||
|
from commonkit import split_csv |
||||||
|
from .base import Command, Template |
||||||
|
from .django import DJANGO_MAPPINGS |
||||||
|
from .mysql import MYSQL_MAPPINGS |
||||||
|
from .pgsql import PGSQL_MAPPINGS |
||||||
|
from .posix import POSIX_MAPPINGS |
||||||
|
|
||||||
|
# Exports |
||||||
|
|
||||||
|
__all__ = ( |
||||||
|
"MAPPINGS", |
||||||
|
"apache", |
||||||
|
"apache_reload", |
||||||
|
"apache_restart", |
||||||
|
"apache_start", |
||||||
|
"apache_stop", |
||||||
|
"apache_test", |
||||||
|
"command_exists", |
||||||
|
"service_reload", |
||||||
|
"service_restart", |
||||||
|
"service_start", |
||||||
|
"service_stop", |
||||||
|
"system", |
||||||
|
"system_install", |
||||||
|
"system_reboot", |
||||||
|
"system_update", |
||||||
|
"system_upgrade", |
||||||
|
"system_uninstall", |
||||||
|
"template", |
||||||
|
"user", |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
def command_exists(name): |
||||||
|
"""Indicates whether a given command exists in this overlay. |
||||||
|
|
||||||
|
:param name: The name of the command. |
||||||
|
:type name: str |
||||||
|
|
||||||
|
:rtype: bool |
||||||
|
|
||||||
|
""" |
||||||
|
return name in MAPPINGS |
||||||
|
|
||||||
|
|
||||||
|
def apache(op, **kwargs): |
||||||
|
"""Execute an Apache-related command. |
||||||
|
|
||||||
|
- op (str): The operation to perform; reload, restart, start, stop, test. |
||||||
|
|
||||||
|
""" |
||||||
|
if op == "reload": |
||||||
|
return apache_reload(**kwargs) |
||||||
|
elif op == "restart": |
||||||
|
return apache_restart(**kwargs) |
||||||
|
elif op == "start": |
||||||
|
return apache_start(**kwargs) |
||||||
|
elif op == "stop": |
||||||
|
return apache_stop(**kwargs) |
||||||
|
elif op == "test": |
||||||
|
return apache_test(**kwargs) |
||||||
|
else: |
||||||
|
raise NameError("Unrecognized or unsupported apache operation: %s" % op) |
||||||
|
|
||||||
|
|
||||||
|
def apache_reload(**kwargs): |
||||||
|
kwargs.setdefault("comment", "reload apache") |
||||||
|
kwargs.setdefault("register", "apache_reloaded") |
||||||
|
|
||||||
|
return Command("apachectl –k reload", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_restart(**kwargs): |
||||||
|
kwargs.setdefault("comment", "restart apache") |
||||||
|
kwargs.setdefault("register", "apache_restarted") |
||||||
|
|
||||||
|
return Command("apachectl –k restart", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_start(**kwargs): |
||||||
|
kwargs.setdefault("comment", "start apache") |
||||||
|
kwargs.setdefault("register", "apache_started") |
||||||
|
|
||||||
|
return Command("apachectl –k start", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_stop(**kwargs): |
||||||
|
kwargs.setdefault("comment", "stop apache") |
||||||
|
|
||||||
|
return Command("apachectl –k stop", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_test(**kwargs): |
||||||
|
kwargs.setdefault("comment", "check apache configuration") |
||||||
|
kwargs.setdefault("register", "apache_checks_out") |
||||||
|
|
||||||
|
return Command("apachectl configtest", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def service_reload(name, **kwargs): |
||||||
|
"""Reload a service. |
||||||
|
|
||||||
|
- name (str): The service name. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "reload %s service" % name) |
||||||
|
kwargs.setdefault("register", "%s_reloaded" % name) |
||||||
|
|
||||||
|
return Command("systemctl reload %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def service_restart(name, **kwargs): |
||||||
|
"""Restart a service. |
||||||
|
|
||||||
|
- name (str): The service name. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "restart %s service" % name) |
||||||
|
kwargs.setdefault("register", "%s_restarted" % name) |
||||||
|
|
||||||
|
return Command("ssystemctl restart %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def service_start(name, **kwargs): |
||||||
|
"""Start a service. |
||||||
|
|
||||||
|
- name (str): The service name. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "start %s service" % name) |
||||||
|
kwargs.setdefault("register", "%s_started" % name) |
||||||
|
|
||||||
|
return Command("systemctl start %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def service_stop(name, **kwargs): |
||||||
|
"""Stop a service. |
||||||
|
|
||||||
|
- name (str): The service name. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "stop %s service" % name) |
||||||
|
kwargs.setdefault("register", "%s_stopped" % name) |
||||||
|
|
||||||
|
return Command("systemctl stop %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def system(op, **kwargs): |
||||||
|
"""Perform a system operation. |
||||||
|
|
||||||
|
- op (str): The operation to perform; reboot, update, upgrade. |
||||||
|
|
||||||
|
""" |
||||||
|
if op == "reboot": |
||||||
|
return system_reboot(**kwargs) |
||||||
|
elif op == "update": |
||||||
|
return system_update(**kwargs) |
||||||
|
elif op == "upgrade": |
||||||
|
return system_upgrade(**kwargs) |
||||||
|
else: |
||||||
|
raise NameError("Unrecognized or unsupported system operation: %s" % op) |
||||||
|
|
||||||
|
|
||||||
|
def system_install(name, **kwargs): |
||||||
|
"""Install a system-level package. |
||||||
|
|
||||||
|
- name (str): The name of the package to install. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "install system package %s" % name) |
||||||
|
|
||||||
|
return Command("yum install -y %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def system_reboot(**kwargs): |
||||||
|
kwargs.setdefault("comment", "reboot the system") |
||||||
|
|
||||||
|
return Command("reboot", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def system_uninstall(name, **kwargs): |
||||||
|
"""Uninstall a system-level package. |
||||||
|
|
||||||
|
- name (str): The name of the package to uninstall. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "remove system package %s" % name) |
||||||
|
|
||||||
|
return Command("yum remove -y %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def system_update(**kwargs): |
||||||
|
kwargs.setdefault("comment", "update system package info") |
||||||
|
|
||||||
|
return Command("yum check-update", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def system_upgrade(**kwargs): |
||||||
|
kwargs.setdefault("comment", "upgrade the system") |
||||||
|
|
||||||
|
return Command("yum update -y", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def template(source, target, backup=True, parser=None, **kwargs): |
||||||
|
"""Create a file from a template. |
||||||
|
|
||||||
|
- source (str): The path to the template file. |
||||||
|
- target (str): The path to where the new file should be created. |
||||||
|
- backup (bool): Indicates whether a backup should be made if the target file already exists. |
||||||
|
- parser (str): The parser to use ``jinja`` (the default) or ``simple``. |
||||||
|
|
||||||
|
""" |
||||||
|
return Template(source, target, backup=backup, parser=parser, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def user(name, groups=None, home=None, op="add", password=None, **kwargs): |
||||||
|
"""Create or remove a user. |
||||||
|
|
||||||
|
- name (str): The user name. |
||||||
|
- groups (str | list): A list of groups to which the user should belong. |
||||||
|
- home (str): The path to the user's home directory. |
||||||
|
- op (str); The operation to perform; ``add`` or ``remove``. |
||||||
|
- password (str): The user's password. (NOT IMPLEMENTED) |
||||||
|
|
||||||
|
""" |
||||||
|
if op == "add": |
||||||
|
kwargs.setdefault("comment", "create a user named %s" % name) |
||||||
|
|
||||||
|
commands = list() |
||||||
|
|
||||||
|
a = list() |
||||||
|
a.append('adduser %s' % name) |
||||||
|
if home is not None: |
||||||
|
a.append("--home %s" % home) |
||||||
|
|
||||||
|
commands.append(Command(" ".join(a), **kwargs)) |
||||||
|
|
||||||
|
if type(groups) is str: |
||||||
|
groups = split_csv(groups, smart=False) |
||||||
|
|
||||||
|
if type(groups) in [list, tuple]: |
||||||
|
for group in groups: |
||||||
|
commands.append(Command("gpasswd -a %s %s" % (name, group), **kwargs)) |
||||||
|
|
||||||
|
a = list() |
||||||
|
for c in commands: |
||||||
|
a.append(c.get_statement(include_comment=True)) |
||||||
|
|
||||||
|
return Command("\n".join(a), **kwargs) |
||||||
|
elif op == "remove": |
||||||
|
kwargs.setdefault("comment", "remove a user named %s" % name) |
||||||
|
return Command("userdel -r %s" % name, **kwargs) |
||||||
|
else: |
||||||
|
raise NameError("Unsupported or unrecognized operation: %s" % op) |
||||||
|
|
||||||
|
|
||||||
|
MAPPINGS = { |
||||||
|
'apache': apache, |
||||||
|
'install': system_install, |
||||||
|
'reboot': system_reboot, |
||||||
|
'reload': service_reload, |
||||||
|
'restart': service_restart, |
||||||
|
'start': service_start, |
||||||
|
'stop': service_stop, |
||||||
|
'system': system, |
||||||
|
'template': template, |
||||||
|
'update': system_update, |
||||||
|
'uninstall': system_uninstall, |
||||||
|
'upgrade': system_upgrade, |
||||||
|
'user': user, |
||||||
|
} |
||||||
|
|
||||||
|
MAPPINGS.update(COMMON_MAPPINGS) |
||||||
|
MAPPINGS.update(DJANGO_MAPPINGS) |
||||||
|
MAPPINGS.update(MYSQL_MAPPINGS) |
||||||
|
MAPPINGS.update(PGSQL_MAPPINGS) |
||||||
|
MAPPINGS.update(POSIX_MAPPINGS) |
@ -0,0 +1,92 @@ |
|||||||
|
""" |
||||||
|
[run django checks] |
||||||
|
django: check |
||||||
|
|
||||||
|
[export fixtures] |
||||||
|
django: dump lookups.Category |
||||||
|
|
||||||
|
[import fixtures] |
||||||
|
django: load lookups.Category |
||||||
|
|
||||||
|
[migrate the database] |
||||||
|
django: migrate |
||||||
|
|
||||||
|
[collect static files] |
||||||
|
django: static |
||||||
|
|
||||||
|
[create super user (ad hoc command)] |
||||||
|
django: createsuperuser root |
||||||
|
|
||||||
|
""" |
||||||
|
from .base import EXCLUDED_KWARGS, Command |
||||||
|
|
||||||
|
|
||||||
|
def django(management_command, *args, excluded_kwargs=None, **kwargs): |
||||||
|
# The excluded parameters (filtered below) may vary based on implementation. We do, however, need a default. |
||||||
|
excluded_kwargs = excluded_kwargs or EXCLUDED_KWARGS |
||||||
|
|
||||||
|
# Django's management commands can have a number of options. We need to filter out internal parameters so that these |
||||||
|
# are not used as options for the management command. |
||||||
|
_kwargs = dict() |
||||||
|
for key in excluded_kwargs: |
||||||
|
if key in kwargs: |
||||||
|
_kwargs[key] = kwargs.pop(key) |
||||||
|
|
||||||
|
if 'comment' not in _kwargs: |
||||||
|
_kwargs['comment'] = "run %s django management command" % management_command |
||||||
|
|
||||||
|
a = list() |
||||||
|
a.append("./manage.py %s" % management_command) |
||||||
|
for key, value in kwargs.items(): |
||||||
|
key = key.replace("_", "-") |
||||||
|
if type(value) is bool and value is True: |
||||||
|
a.append("--%s" % key) |
||||||
|
elif type(value) is str: |
||||||
|
a.append('--%s="%s"' % (key, value)) |
||||||
|
else: |
||||||
|
a.append('--%s=%s' % (key, value)) |
||||||
|
|
||||||
|
_args = list(args) |
||||||
|
if len(_args) > 0: |
||||||
|
a.append(" ".join(_args)) |
||||||
|
|
||||||
|
statement = " ".join(a) |
||||||
|
|
||||||
|
return Command(statement, **_kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def django_check(**kwargs): |
||||||
|
kwargs.setdefault("comment", "run django checks") |
||||||
|
kwargs.setdefault("register", "django_checks_out") |
||||||
|
return django("check", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def django_dump(target, path=None, **kwargs): |
||||||
|
kwargs.setdefault("comment", "dump app/model data") |
||||||
|
kwargs.setdefault("format", "json") |
||||||
|
kwargs.setdefault("indent", 4) |
||||||
|
|
||||||
|
if path is None: |
||||||
|
path = "../deploy/fixtures/%s.%s" % (target, kwargs['format']) |
||||||
|
|
||||||
|
return django("dumpdata", target, "> %s" % path, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def django_load(target, path=None, **kwargs): |
||||||
|
kwargs.setdefault("comment", "load app/model data") |
||||||
|
input_format = kwargs.pop("format", "json") |
||||||
|
if path is None: |
||||||
|
path = "../deploy/fixtures/%s.%s" % (target, input_format) |
||||||
|
|
||||||
|
return django("loaddata", path, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def django_migrate(**kwargs): |
||||||
|
kwargs.setdefault("comment", "apply database migrations") |
||||||
|
return django("migrate", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def django_static(**kwargs): |
||||||
|
kwargs.setdefault("comment", "collect static files") |
||||||
|
kwargs.setdefault("noinput", True) |
||||||
|
return django("collectstatic", **kwargs) |
@ -0,0 +1,51 @@ |
|||||||
|
from .base import Command |
||||||
|
from ...exceptions import InvalidInput |
||||||
|
|
||||||
|
|
||||||
|
def dialog(message, height=15, title="Message", width=100, **kwargs): |
||||||
|
statement = list() |
||||||
|
statement.append("dialog --clear") |
||||||
|
statement.append('--backtitle "%s"' % title) |
||||||
|
statement.append('--msgbox "%s" %s %s;' % (message, height, width)) |
||||||
|
statement.append("clear;") |
||||||
|
|
||||||
|
return Command(" ".join(statement), **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def echo(message, **kwargs): |
||||||
|
return Command('echo "%s"' % message, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def explain(message, heading=None, **kwargs): |
||||||
|
kwargs['heading'] = heading |
||||||
|
return Command(message, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def screenshot(image, caption=None, **kwargs): |
||||||
|
kwargs['caption'] = caption |
||||||
|
|
||||||
|
return Command(image, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def slack(message, url=None, **kwargs): |
||||||
|
if url is None: |
||||||
|
raise InvalidInput("Slack command requires a url parameter.") |
||||||
|
|
||||||
|
statement = list() |
||||||
|
statement.append("curl -X POST -H 'Content-type: application/json' --data") |
||||||
|
statement.append('{"text": "%s"}' % message) |
||||||
|
statement.append(url) |
||||||
|
|
||||||
|
return Command(statement, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def twist(message, title="Notice", url=None, **kwargs): |
||||||
|
if url is None: |
||||||
|
raise InvalidInput("Twist command requires a url parameter.") |
||||||
|
|
||||||
|
statement = list() |
||||||
|
statement.append("curl -X POST -H 'Content-type: application/json' --data") |
||||||
|
statement.append('{"content": "%s", "title": "%s"' % (message, title)) |
||||||
|
statement.append(url) |
||||||
|
|
||||||
|
return Command(" ".join(statement), **kwargs) |
@ -0,0 +1,173 @@ |
|||||||
|
from ...exceptions import InvalidInput |
||||||
|
from .base import EXCLUDED_KWARGS, Command |
||||||
|
|
||||||
|
|
||||||
|
__all__ = ( |
||||||
|
"mysql_create", |
||||||
|
"mysql_dump", |
||||||
|
"mysql_exists", |
||||||
|
"mysql_load", |
||||||
|
"mysql_user", |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
def mysql(command, *args, host="localhost", excluded_kwargs=None, password=None, port=3306, user="root", **kwargs): |
||||||
|
# The excluded parameters (filtered below) may vary based on implementation. We do, however, need a default. |
||||||
|
excluded_kwargs = excluded_kwargs or EXCLUDED_KWARGS |
||||||
|
|
||||||
|
# if 'comment' not in kwargs: |
||||||
|
# kwargs['comment'] = "run %s mysql command" % command |
||||||
|
|
||||||
|
# Allow additional command line switches to pass through? |
||||||
|
# Django's management commands can have a number of options. We need to filter out internal parameters so that these |
||||||
|
# are not used as options for the management command. |
||||||
|
_kwargs = dict() |
||||||
|
for key in excluded_kwargs: |
||||||
|
if key in kwargs: |
||||||
|
_kwargs[key] = kwargs.pop(key) |
||||||
|
|
||||||
|
# MySQL commands always run without sudo because the --user may be provided. |
||||||
|
_kwargs['sudo'] = False |
||||||
|
|
||||||
|
a = list() |
||||||
|
|
||||||
|
a.append(command) |
||||||
|
a.append("--user %s --host=%s --port=%s" % (user, host, port)) |
||||||
|
|
||||||
|
if password: |
||||||
|
a.append('--password="%s"' % password) |
||||||
|
|
||||||
|
for key, value in kwargs.items(): |
||||||
|
key = key.replace("_", "-") |
||||||
|
if type(value) is bool and value is True: |
||||||
|
a.append("--%s" % key) |
||||||
|
elif type(value) is str: |
||||||
|
a.append('--%s="%s"' % (key, value)) |
||||||
|
else: |
||||||
|
a.append('--%s=%s' % (key, value)) |
||||||
|
|
||||||
|
_args = list(args) |
||||||
|
if len(_args) > 0: |
||||||
|
a.append(" ".join(_args)) |
||||||
|
|
||||||
|
statement = " ".join(a) |
||||||
|
|
||||||
|
return Command(statement, **_kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def mysql_create(database, owner=None, **kwargs): |
||||||
|
kwargs.setdefault("comment", "create mysql database") |
||||||
|
|
||||||
|
command = mysql("mysqladmin create", database, **kwargs) |
||||||
|
|
||||||
|
if owner is not None: |
||||||
|
grant = mysql_grant(owner, database=database, **kwargs) |
||||||
|
command.statement += " && " + grant.statement |
||||||
|
|
||||||
|
return command |
||||||
|
|
||||||
|
|
||||||
|
def mysql_drop(database, **kwargs): |
||||||
|
kwargs.setdefault("comment", "drop %s mysql database" % database) |
||||||
|
|
||||||
|
return mysql("mysqladmin drop", database, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def mysql_dump(database, path=None, **kwargs): |
||||||
|
kwargs.setdefault("comment", "dump mysql database") |
||||||
|
kwargs.setdefault("complete_inserts", True) |
||||||
|
|
||||||
|
if path is None: |
||||||
|
path = "%s.sql" % database |
||||||
|
|
||||||
|
return mysql("mysqldump", database, "> %s" % path, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def mysql_exists(database, **kwargs): |
||||||
|
kwargs.setdefault("comment", "determine if %s mysql database exists" % database) |
||||||
|
kwargs.setdefault("register", "%s_exists" % database) |
||||||
|
|
||||||
|
command = mysql("mysql", **kwargs) |
||||||
|
|
||||||
|
sql = "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '%s'" % database |
||||||
|
|
||||||
|
command.statement += '--execute="%s"' % sql |
||||||
|
|
||||||
|
return command |
||||||
|
|
||||||
|
|
||||||
|
def mysql_grant(to, database=None, privileges="ALL", **kwargs): |
||||||
|
"""Grant privileges to a user. |
||||||
|
|
||||||
|
- to (str): The user name to which privileges are granted. |
||||||
|
- database (str): The database name. |
||||||
|
- host (str): The database host name or IP address. |
||||||
|
- password (str): The password for the user with sufficient access privileges to execute the command. |
||||||
|
- port (int): The TCP port number of the MySQL service running on the host. |
||||||
|
- privileges (str): The privileges to be granted. |
||||||
|
- user (str): The name of the user with sufficient access privileges to execute the command. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "grant mysql privileges to %s" % to) |
||||||
|
|
||||||
|
host = kwargs.get("host", "localhost") |
||||||
|
|
||||||
|
command = mysql("mysql", **kwargs) |
||||||
|
|
||||||
|
# See https://dev.mysql.com/doc/refman/5.7/en/grant.html |
||||||
|
_database = database or "*" |
||||||
|
sql = "GRANT %(privileges)s ON %(database)s.* TO '%(user)s'@'%(host)s'" % { |
||||||
|
'database': _database, |
||||||
|
'host': host, |
||||||
|
'privileges': privileges, |
||||||
|
'user': to, |
||||||
|
} |
||||||
|
command.statement += ' --execute="%s"' % sql |
||||||
|
|
||||||
|
return command |
||||||
|
|
||||||
|
|
||||||
|
def mysql_load(database, path, **kwargs): |
||||||
|
kwargs.setdefault("comment", "load data into a mysql database") |
||||||
|
|
||||||
|
return mysql("psql", database, "< %s" % path, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def mysql_user(name, admin_pass=None, admin_user="root", op="create", password=None, **kwargs): |
||||||
|
host = kwargs.get("host", "localhost") |
||||||
|
|
||||||
|
if op == "create": |
||||||
|
kwargs.setdefault("comment", "create %s mysql user" % name) |
||||||
|
|
||||||
|
command = mysql("mysql", password=admin_pass, user=admin_user, **kwargs) |
||||||
|
|
||||||
|
sql = "CREATE USER IF NOT EXISTS '%s'@'%s'" % (name, host) |
||||||
|
if password is not None: |
||||||
|
sql += " IDENTIFIED BY PASSWORD('%s')" % password |
||||||
|
|
||||||
|
command.statement += ' --execute="%s"' % sql |
||||||
|
|
||||||
|
return command |
||||||
|
elif op == "drop": |
||||||
|
kwargs.setdefault("comment", "remove %s mysql user" % name) |
||||||
|
|
||||||
|
command = mysql("mysql", password=admin_pass, user=admin_user, **kwargs) |
||||||
|
|
||||||
|
sql = "DROP USER IF EXISTS '%s'@'%s'" % (name, host) |
||||||
|
|
||||||
|
command.statement += ' --execute="%s"' % sql |
||||||
|
|
||||||
|
return command |
||||||
|
elif op == "exists": |
||||||
|
kwargs.setdefault("comment", "determine if %s mysql user exists" % name) |
||||||
|
kwargs.setdefault("register", "mysql_use_exists") |
||||||
|
|
||||||
|
command = mysql("mysql", password=admin_pass, user=admin_user, **kwargs) |
||||||
|
|
||||||
|
sql = "SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '%s')" % name |
||||||
|
|
||||||
|
command.statement += ' --execute "%s"' % sql |
||||||
|
|
||||||
|
return command |
||||||
|
else: |
||||||
|
raise InvalidInput("Unrecognized or unsupported MySQL user operation: %s" % op) |
@ -0,0 +1,155 @@ |
|||||||
|
""" |
||||||
|
[run django checks] |
||||||
|
django: check |
||||||
|
|
||||||
|
[export fixtures] |
||||||
|
django: dump lookups.Category |
||||||
|
|
||||||
|
[import fixtures] |
||||||
|
django: load lookups.Category |
||||||
|
|
||||||
|
[migrate the database] |
||||||
|
django: migrate |
||||||
|
|
||||||
|
[collect static files] |
||||||
|
django: static |
||||||
|
|
||||||
|
[create super user (ad hoc command)] |
||||||
|
django: createsuperuser root |
||||||
|
|
||||||
|
""" |
||||||
|
from ...exceptions import InvalidInput |
||||||
|
from .base import EXCLUDED_KWARGS, Command |
||||||
|
|
||||||
|
|
||||||
|
__all__ = ( |
||||||
|
"pgsql_create", |
||||||
|
"pgsql_drop", |
||||||
|
"pgsql_dump", |
||||||
|
"pgsql_exists", |
||||||
|
"pgsql_load", |
||||||
|
"pgsql_user", |
||||||
|
) |
||||||
|
|
||||||
|
def pgsql(command, *args, host="localhost", excluded_kwargs=None, password=None, port=5432, user="postgres", **kwargs): |
||||||
|
# The excluded parameters (filtered below) may vary based on implementation. We do, however, need a default. |
||||||
|
excluded_kwargs = excluded_kwargs or EXCLUDED_KWARGS |
||||||
|
|
||||||
|
# if 'comment' not in kwargs: |
||||||
|
# kwargs['comment'] = "run %s postgres command" % command |
||||||
|
|
||||||
|
# Allow additional command line switches to pass through? |
||||||
|
# Django's management commands can have a number of options. We need to filter out internal parameters so that these |
||||||
|
# are not used as options for the management command. |
||||||
|
_kwargs = dict() |
||||||
|
for key in excluded_kwargs: |
||||||
|
if key in kwargs: |
||||||
|
_kwargs[key] = kwargs.pop(key) |
||||||
|
|
||||||
|
# Postgres commands always run without sudo because the -U may be provided. |
||||||
|
_kwargs['sudo'] = False |
||||||
|
|
||||||
|
a = list() |
||||||
|
|
||||||
|
if password is not None: |
||||||
|
a.append('export PGPASSWORD="%s" &&' % password) |
||||||
|
|
||||||
|
a.append(command) |
||||||
|
a.append("-U %s --host=%s --port=%s" % (user, host, port)) |
||||||
|
for key, value in kwargs.items(): |
||||||
|
key = key.replace("_", "-") |
||||||
|
if type(value) is bool and value is True: |
||||||
|
a.append("--%s" % key) |
||||||
|
elif type(value) is str: |
||||||
|
a.append('--%s="%s"' % (key, value)) |
||||||
|
else: |
||||||
|
a.append('--%s=%s' % (key, value)) |
||||||
|
|
||||||
|
_args = list(args) |
||||||
|
if len(_args) > 0: |
||||||
|
a.append(" ".join(_args)) |
||||||
|
|
||||||
|
statement = " ".join(a) |
||||||
|
|
||||||
|
return Command(statement, **_kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def pgsql_create(database, owner=None, template=None, **kwargs): |
||||||
|
kwargs.setdefault("comment", "create %s postgres database" % database) |
||||||
|
|
||||||
|
if owner is not None: |
||||||
|
kwargs['owner'] = owner |
||||||
|
|
||||||
|
if template is not None: |
||||||
|
kwargs['template'] = template |
||||||
|
|
||||||
|
return pgsql("createdb", database, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def pgsql_drop(database, **kwargs): |
||||||
|
kwargs.setdefault("comment", "drop %s postgres database" % database) |
||||||
|
|
||||||
|
return pgsql("dropdb", database, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def pgsql_dump(database, path=None, **kwargs): |
||||||
|
kwargs.setdefault("comment", "dump postgres database") |
||||||
|
kwargs.setdefault("column_inserts", True) |
||||||
|
|
||||||
|
if path is None: |
||||||
|
path = "%s.sql" % database |
||||||
|
|
||||||
|
kwargs['dbname'] = database |
||||||
|
kwargs['file'] = path |
||||||
|
|
||||||
|
return pgsql("pg_dump", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def pgsql_exists(database, **kwargs): |
||||||
|
kwargs.setdefault("comment", "determine if %s postgres database exists" % database) |
||||||
|
kwargs.setdefault("register", "%s_exists" % database) |
||||||
|
|
||||||
|
command = pgsql("psql", **kwargs) |
||||||
|
command.statement += r" -lqt | cut -d \| -f 1 | grep -qw %s" % database |
||||||
|
|
||||||
|
return command |
||||||
|
|
||||||
|
|
||||||
|
def pgsql_load(database, path, **kwargs): |
||||||
|
kwargs.setdefault("comment", "load data into a postgres database") |
||||||
|
|
||||||
|
kwargs['dbname'] = database |
||||||
|
kwargs['file'] = path |
||||||
|
|
||||||
|
return pgsql("psql", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def pgsql_user(name, admin_pass=None, admin_user="postgres", op="create", password=None, **kwargs): |
||||||
|
if op == "create": |
||||||
|
kwargs.setdefault("comment", "create %s postgres user" % name) |
||||||
|
|
||||||
|
command = pgsql("createuser", "-DRS %s" % name, password=admin_pass, user=admin_user, **kwargs) |
||||||
|
|
||||||
|
if password is not None: |
||||||
|
extra = pgsql("psql", password=admin_pass, user=admin_user, **kwargs) |
||||||
|
command.statement += " && " + extra.statement |
||||||
|
command.statement += " -c \"ALTER USER %s WITH ENCRYPTED PASSWORD '%s';\"" % (name, password) |
||||||
|
|
||||||
|
return command |
||||||
|
elif op == "drop": |
||||||
|
kwargs.setdefault("comment", "remove %s postgres user" % name) |
||||||
|
|
||||||
|
return pgsql("dropuser", name, password=admin_pass, user=admin_user, **kwargs) |
||||||
|
elif op == "exists": |
||||||
|
kwargs.setdefault("comment", "determine if %s postgres user exists" % name) |
||||||
|
kwargs.setdefault("register", "pgsql_use_exists") |
||||||
|
|
||||||
|
command = pgsql("psql", password=admin_pass, user=admin_user, **kwargs) |
||||||
|
|
||||||
|
sql = "SELECT 1 FROM pgsql_roles WHERE rolname='%s'" % name |
||||||
|
|
||||||
|
command.statement += ' -c "%s"' % sql |
||||||
|
|
||||||
|
return command |
||||||
|
else: |
||||||
|
raise InvalidInput("Unrecognized or unsupported Postgres user operation: %s" % op) |
@ -0,0 +1,532 @@ |
|||||||
|
import os |
||||||
|
from .base import Command |
||||||
|
|
||||||
|
|
||||||
|
def append(path, content=None, **kwargs): |
||||||
|
"""Append content to a file. |
||||||
|
|
||||||
|
- path (str): The path to the file. |
||||||
|
- content (str): The content to be appended. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "append to %s" % path) |
||||||
|
|
||||||
|
statement = 'echo "%s" >> %s' % (content or "", path) |
||||||
|
|
||||||
|
return Command(statement, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def archive(from_path, absolute=False, exclude=None, file_name="archive.tgz", strip=None, to_path=".", view=False, |
||||||
|
**kwargs): |
||||||
|
"""Create a file archive. |
||||||
|
|
||||||
|
- from_path (str): The path that should be archived. |
||||||
|
- absolute (bool): Set to ``True`` to preserve the leading slash. |
||||||
|
- exclude (str): A pattern to be excluded from the archive. |
||||||
|
- strip (int): Remove the specified number of leading elements from the path. |
||||||
|
- to_path (str): Where the archive should be created. This should *not* include the file name. |
||||||
|
- view (bool): View the output of the command as it happens. |
||||||
|
|
||||||
|
""" |
||||||
|
tokens = ["tar"] |
||||||
|
switches = ["-cz"] |
||||||
|
|
||||||
|
if absolute: |
||||||
|
switches.append("P") |
||||||
|
|
||||||
|
if view: |
||||||
|
switches.append("v") |
||||||
|
|
||||||
|
tokens.append("".join(switches)) |
||||||
|
|
||||||
|
if exclude: |
||||||
|
tokens.append("--exclude %s" % exclude) |
||||||
|
|
||||||
|
if strip: |
||||||
|
tokens.append("--strip-components %s" % strip) |
||||||
|
|
||||||
|
to_path = "%s/%s" % (to_path, file_name) |
||||||
|
tokens.append('-f %s %s' % (to_path, from_path)) |
||||||
|
|
||||||
|
name = " ".join(tokens) |
||||||
|
|
||||||
|
return Command(name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def certbot(domain_name, email=None, webroot=None, **kwargs): |
||||||
|
"""Get new SSL certificate from Let's Encrypt. |
||||||
|
|
||||||
|
- domain_name (str): The domain name for which the SSL certificate is requested. |
||||||
|
- email (str): The email address of the requester sent to the certificate authority. Required. |
||||||
|
- webroot (str): The directory where the challenge file will be created. |
||||||
|
|
||||||
|
""" |
||||||
|
_email = email or os.environ.get("SCRIPTTEASE_CERTBOT_EMAIL", None) |
||||||
|
_webroot = webroot or os.path.join("/var", "www", "domains", domain_name.replace(".", "_"), "www") |
||||||
|
|
||||||
|
if not _email: |
||||||
|
raise ValueError("Email is required for certbot command.") |
||||||
|
|
||||||
|
template = "certbot certonly --agree-tos --email %(email)s -n --webroot -w %(webroot)s -d %(domain_name)s" |
||||||
|
statement = template % { |
||||||
|
'domain_name': domain_name, |
||||||
|
'email': _email, |
||||||
|
'webroot': _webroot, |
||||||
|
} |
||||||
|
|
||||||
|
return Command(statement, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def copy(from_path, to_path, overwrite=False, recursive=False, **kwargs): |
||||||
|
"""Copy a file or directory. |
||||||
|
|
||||||
|
- from_path (str): The file or directory to be copied. |
||||||
|
- to_path (str): The location to which the file or directory should be copied. |
||||||
|
- overwrite (bool): Indicates files and directories should be overwritten if they exist. |
||||||
|
- recursive (bool): Copy sub-directories. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "copy %s to %s" % (from_path, to_path)) |
||||||
|
|
||||||
|
a = list() |
||||||
|
a.append("cp") |
||||||
|
|
||||||
|
if not overwrite: |
||||||
|
a.append("-n") |
||||||
|
|
||||||
|
if recursive: |
||||||
|
a.append("-R") |
||||||
|
|
||||||
|
a.append(from_path) |
||||||
|
a.append(to_path) |
||||||
|
|
||||||
|
return Command(" ".join(a), **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def dir(path, group=None, mode=None, owner=None, recursive=True, **kwargs): |
||||||
|
"""Create a directory. |
||||||
|
|
||||||
|
- path (str): The path to be created. |
||||||
|
- mode (int | str): The access permissions of the new directory. |
||||||
|
- recursive (bool): Create all directories along the path. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "create directory %s" % path) |
||||||
|
|
||||||
|
statement = ["mkdir"] |
||||||
|
if mode is not None: |
||||||
|
statement.append("-m %s" % mode) |
||||||
|
|
||||||
|
if recursive: |
||||||
|
statement.append("-p") |
||||||
|
|
||||||
|
if group: |
||||||
|
if recursive: |
||||||
|
statement.append("&& chgrp -R %s" % group) |
||||||
|
else: |
||||||
|
statement.append("&& chgrp %s" % group) |
||||||
|
|
||||||
|
if owner: |
||||||
|
if recursive: |
||||||
|
statement.append("&& chown -R %s" % owner) |
||||||
|
else: |
||||||
|
statement.append("&& chown %s" % owner) |
||||||
|
|
||||||
|
statement.append(path) |
||||||
|
|
||||||
|
return Command(" ".join(statement), **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def extract(from_path, absolute=False, exclude=None, strip=None, to_path=None, view=False, **kwargs): |
||||||
|
"""Extract a file archive. |
||||||
|
|
||||||
|
- from_path (str): The path that should be archived. |
||||||
|
- absolute (bool): Set to ``True`` to preserve the leading slash. |
||||||
|
- exclude (str): A pattern to be excluded from the archive. |
||||||
|
- strip (int): Remove the specified number of leading elements from the path. |
||||||
|
- to_path (str): Where the archive should be extracted. This should *not* include the file name. |
||||||
|
- view (bool): View the output of the command as it happens. |
||||||
|
|
||||||
|
""" |
||||||
|
_to_path = to_path or "./" |
||||||
|
|
||||||
|
tokens = ["tar"] |
||||||
|
switches = ["-xz"] |
||||||
|
|
||||||
|
if absolute: |
||||||
|
switches.append("P") |
||||||
|
|
||||||
|
if view: |
||||||
|
switches.append("v") |
||||||
|
|
||||||
|
tokens.append("".join(switches)) |
||||||
|
|
||||||
|
if exclude: |
||||||
|
tokens.append("--exclude %s" % exclude) |
||||||
|
|
||||||
|
if strip: |
||||||
|
tokens.append("--strip-components %s" % strip) |
||||||
|
|
||||||
|
tokens.append('-f %s %s' % (from_path, _to_path)) |
||||||
|
|
||||||
|
statement = " ".join(tokens) |
||||||
|
|
||||||
|
return Command(statement, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def link(source, force=False, target=None, **kwargs): |
||||||
|
"""Create a symlink. |
||||||
|
|
||||||
|
- source (str): The source of the link. |
||||||
|
- force (bool): Force the creation of the link. |
||||||
|
- target (str): The name or path of the target. Defaults to the base name of the source path. |
||||||
|
|
||||||
|
""" |
||||||
|
_target = target or os.path.basename(source) |
||||||
|
|
||||||
|
kwargs.setdefault("comment", "link to %s" % source) |
||||||
|
|
||||||
|
statement = ["ln -s"] |
||||||
|
|
||||||
|
if force: |
||||||
|
statement.append("-f") |
||||||
|
|
||||||
|
statement.append(source) |
||||||
|
statement.append(_target) |
||||||
|
|
||||||
|
return Command(" ".join(statement), **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def move(from_path, to_path, **kwargs): |
||||||
|
"""Move a file or directory. |
||||||
|
|
||||||
|
- from_path (str): The current path. |
||||||
|
- to_path (str): The new path. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "move %s to %s" % (from_path, to_path)) |
||||||
|
statement = "mv %s %s" % (from_path, to_path) |
||||||
|
|
||||||
|
return Command(statement, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def perms(path, group=None, mode=None, owner=None, recursive=False, **kwargs): |
||||||
|
"""Set permissions on a file or directory. |
||||||
|
|
||||||
|
- path (str): The path to be changed. |
||||||
|
- group (str): The name of the group to be applied. |
||||||
|
- mode (int | str): The access permissions of the file or directory. |
||||||
|
- owner (str): The name of the user to be applied. |
||||||
|
- recursive: Create all directories along the path. |
||||||
|
|
||||||
|
""" |
||||||
|
commands = list() |
||||||
|
|
||||||
|
kwargs['comment'] = "set permissions on %s" % path |
||||||
|
|
||||||
|
if group is not None: |
||||||
|
statement = ["chgrp"] |
||||||
|
|
||||||
|
if recursive: |
||||||
|
statement.append("-R") |
||||||
|
|
||||||
|
statement.append(group) |
||||||
|
statement.append(path) |
||||||
|
|
||||||
|
commands.append(Command(" ".join(statement), **kwargs)) |
||||||
|
|
||||||
|
if owner is not None: |
||||||
|
statement = ["chown"] |
||||||
|
|
||||||
|
if recursive: |
||||||
|
statement.append("-R") |
||||||
|
|
||||||
|
statement.append(owner) |
||||||
|
statement.append(path) |
||||||
|
|
||||||
|
commands.append(Command(" ".join(statement), **kwargs)) |
||||||
|
|
||||||
|
if mode is not None: |
||||||
|
statement = ["chmod"] |
||||||
|
|
||||||
|
if recursive: |
||||||
|
statement.append("-R") |
||||||
|
|
||||||
|
statement.append(str(mode)) |
||||||
|
statement.append(path) |
||||||
|
|
||||||
|
commands.append(Command(" ".join(statement), **kwargs)) |
||||||
|
|
||||||
|
kwargs.setdefault("comment", "set permissions on %s" % path) |
||||||
|
|
||||||
|
a = list() |
||||||
|
for c in commands: |
||||||
|
a.append(c.get_statement(include_comment=True)) |
||||||
|
|
||||||
|
return Command("\n".join(a), **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def remove(path, force=False, recursive=False, **kwargs): |
||||||
|
"""Remove a file or directory. |
||||||
|
|
||||||
|
- path (str): The path to be removed. |
||||||
|
- force (bool): Force the removal. |
||||||
|
- recursive (bool): Remove all directories along the path. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "remove %s" % path) |
||||||
|
|
||||||
|
statement = ["rm"] |
||||||
|
|
||||||
|
if force: |
||||||
|
statement.append("-f") |
||||||
|
|
||||||
|
if recursive: |
||||||
|
statement.append("-r") |
||||||
|
|
||||||
|
statement.append(path) |
||||||
|
|
||||||
|
return Command(" ".join(statement), **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def replace(path, backup=".b", delimiter="/", find=None, replace=None, **kwargs): |
||||||
|
"""Find and replace text in a file. |
||||||
|
|
||||||
|
- path (str): The path to the file to be edited. |
||||||
|
- backup (str): The backup file extension to use. |
||||||
|
- delimiter (str): The pattern delimiter. |
||||||
|
- find (str): The old text. Required. |
||||||
|
- replace (str): The new text. Required. |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
kwargs.setdefault("comment", "find and replace in %s" % path) |
||||||
|
|
||||||
|
context = { |
||||||
|
'backup': backup, |
||||||
|
'delimiter': delimiter, |
||||||
|
'path': path, |
||||||
|
'pattern': find, |
||||||
|
'replace': replace, |
||||||
|
} |
||||||
|
|
||||||
|
template = "sed -i %(backup)s 's%(delimiter)s%(pattern)s%(delimiter)s%(replace)s%(delimiter)sg' %(path)s" |
||||||
|
|
||||||
|
statement = template % context |
||||||
|
|
||||||
|
return Command(statement, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def rsync(source, target, delete=False, exclude=None, host=None, key_file=None, links=True, port=22, |
||||||
|
recursive=True, user=None, **kwargs): |
||||||
|
"""Synchronize a directory structure. |
||||||
|
|
||||||
|
- source (str): The source directory. |
||||||
|
- target (str): The target directory. |
||||||
|
- delete (bool): Indicates target files that exist in source but not in target should be removed. |
||||||
|
- exclude (str): The path to an exclude file. |
||||||
|
- host (str): The host name or IP address. This causes the command to run over SSH. |
||||||
|
- key_file (str): The privacy SSH key (path) for remote connections. User expansion is automatically applied. |
||||||
|
- links (bool): Include symlinks in the sync. |
||||||
|
- port (int): The SSH port to use for remote connections. |
||||||
|
- recursive (bool): Indicates source contents should be recursively synchronized. |
||||||
|
- user (str): The user name to use for remote connections. |
||||||
|
|
||||||
|
""" |
||||||
|
# - guess: When ``True``, the ``host``, ``key_file``, and ``user`` will be guessed based on the base name of |
||||||
|
# the source path. |
||||||
|
# :type guess: bool |
||||||
|
# if guess: |
||||||
|
# host = host or os.path.basename(source).replace("_", ".") |
||||||
|
# key_file = key_file or os.path.expanduser(os.path.join("~/.ssh", os.path.basename(source))) |
||||||
|
# user = user or os.path.basename(source) |
||||||
|
# else: |
||||||
|
# host = host |
||||||
|
# key_file = key_file |
||||||
|
# user = user |
||||||
|
|
||||||
|
kwargs.setdefault("comment", "sync %s with %s" % (source, target)) |
||||||
|
|
||||||
|
# rsync -e "ssh -i $(SSH_KEY) -p $(SSH_PORT)" -P -rvzc --delete |
||||||
|
# $(OUTPUTH_PATH) $(SSH_USER)@$(SSH_HOST):$(UPLOAD_PATH) --cvs-exclude; |
||||||
|
|
||||||
|
tokens = list() |
||||||
|
tokens.append("rsync") |
||||||
|
tokens.append("--cvs-exclude") |
||||||
|
tokens.append("--checksum") |
||||||
|
tokens.append("--compress") |
||||||
|
|
||||||
|
if links: |
||||||
|
tokens.append("--copy-links") |
||||||
|
|
||||||
|
if delete: |
||||||
|
tokens.append("--delete") |
||||||
|
|
||||||
|
if exclude is not None: |
||||||
|
tokens.append("--exclude-from=%s" % exclude) |
||||||
|
|
||||||
|
# --partial and --progress |
||||||
|
tokens.append("-P") |
||||||
|
|
||||||
|
if recursive: |
||||||
|
tokens.append("--recursive") |
||||||
|
|
||||||
|
tokens.append(source) |
||||||
|
|
||||||
|
conditions = [ |
||||||
|
host is not None, |
||||||
|
key_file is not None, |
||||||
|
user is not None, |
||||||
|
] |
||||||
|
if all(conditions): |
||||||
|
tokens.append('-e "ssh -i %s -p %s"' % (key_file, port)) |
||||||
|
tokens.append("%s@%s:%s" % (user, host, target)) |
||||||
|
else: |
||||||
|
tokens.append(target) |
||||||
|
|
||||||
|
statement = " ".join(tokens) |
||||||
|
|
||||||
|
return Command(statement, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def scopy(from_path, to_path, host=None, key_file=None, port=22, user=None, **kwargs): |
||||||
|
"""Copy a file or directory to a remote server. |
||||||
|
|
||||||
|
- from_path (str): The source directory. |
||||||
|
- to_path (str): The target directory. |
||||||
|
- host (str): The host name or IP address. Required. |
||||||
|
- key_file (str): The privacy SSH key (path) for remote connections. User expansion is automatically applied. |
||||||
|
- port (int): The SSH port to use for remote connections. |
||||||
|
- user (str): The user name to use for remote connections. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "copy %s to remote %s" % (from_path, to_path)) |
||||||
|
|
||||||
|
# TODO: What to do to force local versus remote commands? |
||||||
|
# kwargs['local'] = True |
||||||
|
|
||||||
|
kwargs['sudo'] = False |
||||||
|
|
||||||
|
statement = ["scp"] |
||||||
|
|
||||||
|
if key_file is not None: |
||||||
|
statement.append("-i %s" % key_file) |
||||||
|
|
||||||
|
statement.append("-P %s" % port) |
||||||
|
statement.append(from_path) |
||||||
|
|
||||||
|
if host is not None and user is not None: |
||||||
|
statement.append("%s@%s:%s" % (user, host, to_path)) |
||||||
|
elif host is not None: |
||||||
|
statement.append("%s:%s" % (host, to_path)) |
||||||
|
else: |
||||||
|
raise ValueError("Host is a required keyword argument.") |
||||||
|
|
||||||
|
return Command(" ".join(statement), **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def sync(source, target, delete=False, exclude=None, links=True, recursive=True, **kwargs): |
||||||
|
"""Synchronize a local directory structure. |
||||||
|
|
||||||
|
- source (str): The source directory. |
||||||
|
- target (str): The target directory. |
||||||
|
- delete (bool): Indicates target files that exist in source but not in target should be removed. |
||||||
|
- exclude (str): The path to an exclude file. |
||||||
|
- host (str): The host name or IP address. This causes the command to run over SSH. |
||||||
|
- key_file (str): The privacy SSH key (path) for remote connections. User expansion is automatically applied. |
||||||
|
- links (bool): Include symlinks in the sync. |
||||||
|
- port (int): The SSH port to use for remote connections. |
||||||
|
- recursive (bool): Indicates source contents should be recursively synchronized. |
||||||
|
- user (str): The user name to use for remote connections. |
||||||
|
|
||||||
|
""" |
||||||
|
# - guess: When ``True``, the ``host``, ``key_file``, and ``user`` will be guessed based on the base name of |
||||||
|
# the source path. |
||||||
|
# :type guess: bool |
||||||
|
# if guess: |
||||||
|
# host = host or os.path.basename(source).replace("_", ".") |
||||||
|
# key_file = key_file or os.path.expanduser(os.path.join("~/.ssh", os.path.basename(source))) |
||||||
|
# user = user or os.path.basename(source) |
||||||
|
# else: |
||||||
|
# host = host |
||||||
|
# key_file = key_file |
||||||
|
# user = user |
||||||
|
|
||||||
|
kwargs.setdefault("comment", "sync %s with %s" % (source, target)) |
||||||
|
|
||||||
|
# rsync -e "ssh -i $(SSH_KEY) -p $(SSH_PORT)" -P -rvzc --delete |
||||||
|
# $(OUTPUTH_PATH) $(SSH_USER)@$(SSH_HOST):$(UPLOAD_PATH) --cvs-exclude; |
||||||
|
|
||||||
|
tokens = list() |
||||||
|
tokens.append("rsync") |
||||||
|
tokens.append("--cvs-exclude") |
||||||
|
tokens.append("--checksum") |
||||||
|
tokens.append("--compress") |
||||||
|
|
||||||
|
if links: |
||||||
|
tokens.append("--copy-links") |
||||||
|
|
||||||
|
if delete: |
||||||
|
tokens.append("--delete") |
||||||
|
|
||||||
|
if exclude is not None: |
||||||
|
tokens.append("--exclude-from=%s" % exclude) |
||||||
|
|
||||||
|
# --partial and --progress |
||||||
|
tokens.append("-P") |
||||||
|
|
||||||
|
if recursive: |
||||||
|
tokens.append("--recursive") |
||||||
|
|
||||||
|
tokens.append(source) |
||||||
|
tokens.append(target) |
||||||
|
|
||||||
|
statement = " ".join(tokens) |
||||||
|
|
||||||
|
return Command(statement, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def touch(path, **kwargs): |
||||||
|
"""Touch a file or directory. |
||||||
|
|
||||||
|
- path (str): The file or directory to touch. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "touch %s" % path) |
||||||
|
|
||||||
|
return Command("touch %s" % path, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def wait(seconds, **kwargs): |
||||||
|
"""Pause execution for a number of seconds. |
||||||
|
|
||||||
|
- seconds (int): The number of seconds to wait. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "pause for %s seconds" % seconds) |
||||||
|
|
||||||
|
return Command("sleep %s" % seconds, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def write(path, content=None, **kwargs): |
||||||
|
"""Write to a file. |
||||||
|
|
||||||
|
- path (str): The file to be written. |
||||||
|
- content (str): The content to be written. Note: If omitted, this command is equivalent to ``touch``. |
||||||
|
|
||||||
|
""" |
||||||
|
_content = content or "" |
||||||
|
|
||||||
|
kwargs.setdefault("comment", "write to %s" % path) |
||||||
|
|
||||||
|
a = list() |
||||||
|
|
||||||
|
if len(_content.split("\n")) > 1: |
||||||
|
a.append("cat > %s << EOF" % path) |
||||||
|
a.append(_content) |
||||||
|
a.append("EOF") |
||||||
|
else: |
||||||
|
a.append('echo "%s" > %s' % (_content, path)) |
||||||
|
|
||||||
|
return Command(" ".join(a), **kwargs) |
||||||
|
|
@ -0,0 +1,39 @@ |
|||||||
|
from .base import Command |
||||||
|
|
||||||
|
|
||||||
|
def python_pip(name, op="install", upgrade=False, venv=None, version=3, **kwargs): |
||||||
|
"""Use pip to install or uninstall a Python package. |
||||||
|
|
||||||
|
- name (str): The name of the package. |
||||||
|
- op (str): The operation to perform; install, uninstall |
||||||
|
- upgrade (bool): Upgrade an installed package. |
||||||
|
- venv (str): The name of the virtual environment to load. |
||||||
|
- version (int): The Python version to use, e.g. ``2`` or ``3``. |
||||||
|
|
||||||
|
""" |
||||||
|
manager = "pip" |
||||||
|
if version == 3: |
||||||
|
manager = "pip3" |
||||||
|
|
||||||
|
if upgrade: |
||||||
|
statement = "%s install --upgrade %s" % (manager, name) |
||||||
|
else: |
||||||
|
statement = "%s %s %s" % (manager, op, name) |
||||||
|
|
||||||
|
if venv is not None: |
||||||
|
kwargs['prefix'] = "source %s/bin/activate" % venv |
||||||
|
|
||||||
|
kwargs.setdefault("comment", "%s %s" % (op, name)) |
||||||
|
|
||||||
|
return Command(statement, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def python_virtualenv(name, **kwargs): |
||||||
|
"""Create a Python virtual environment. |
||||||
|
|
||||||
|
- name (str): The name of the environment to create. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "create %s virtual environment" % name) |
||||||
|
|
||||||
|
return Command("virtualenv %s" % name, **kwargs) |
@ -0,0 +1,337 @@ |
|||||||
|
# Imports |
||||||
|
|
||||||
|
from commonkit import split_csv |
||||||
|
from .base import Command, Template |
||||||
|
from .common import COMMON_MAPPINGS |
||||||
|
from .django import DJANGO_MAPPINGS |
||||||
|
from .mysql import MYSQL_MAPPINGS |
||||||
|
from .pgsql import PGSQL_MAPPINGS |
||||||
|
from .posix import POSIX_MAPPINGS |
||||||
|
|
||||||
|
# Exports |
||||||
|
|
||||||
|
__all__ = ( |
||||||
|
"MAPPINGS", |
||||||
|
"apache", |
||||||
|
"apache_disable_module", |
||||||
|
"apache_disable_site", |
||||||
|
"apache_enable_module", |
||||||
|
"apache_enable_site", |
||||||
|
"apache_reload", |
||||||
|
"apache_restart", |
||||||
|
"apache_start", |
||||||
|
"apache_stop", |
||||||
|
"apache_test", |
||||||
|
"command_exists", |
||||||
|
"service_reload", |
||||||
|
"service_restart", |
||||||
|
"service_start", |
||||||
|
"service_stop", |
||||||
|
"system", |
||||||
|
"system_install", |
||||||
|
"system_reboot", |
||||||
|
"system_update", |
||||||
|
"system_upgrade", |
||||||
|
"system_uninstall", |
||||||
|
"template", |
||||||
|
"user", |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
def command_exists(name): |
||||||
|
"""Indicates whether a given command exists in this overlay. |
||||||
|
|
||||||
|
:param name: The name of the command. |
||||||
|
:type name: str |
||||||
|
|
||||||
|
:rtype: bool |
||||||
|
|
||||||
|
""" |
||||||
|
return name in MAPPINGS |
||||||
|
|
||||||
|
|
||||||
|
def apache(op, **kwargs): |
||||||
|
"""Execute an Apache-related command. |
||||||
|
|
||||||
|
- op (str): The operation to perform; reload, restart, start, stop, test. |
||||||
|
|
||||||
|
""" |
||||||
|
if op == "reload": |
||||||
|
return apache_reload(**kwargs) |
||||||
|
elif op == "restart": |
||||||
|
return apache_restart(**kwargs) |
||||||
|
elif op == "start": |
||||||
|
return apache_start(**kwargs) |
||||||
|
elif op == "stop": |
||||||
|
return apache_stop(**kwargs) |
||||||
|
elif op == "test": |
||||||
|
return apache_test(**kwargs) |
||||||
|
else: |
||||||
|
raise NameError("Unrecognized or unsupported apache operation: %s" % op) |
||||||
|
|
||||||
|
|
||||||
|
def apache_disable_module(name, **kwargs): |
||||||
|
"""Disable an Apache module. |
||||||
|
|
||||||
|
- name (str): The module name. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "disable %s apache module" % name) |
||||||
|
|
||||||
|
return Command("a2dismod %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_disable_site(name, **kwargs): |
||||||
|
"""Disable an Apache site. |
||||||
|
|
||||||
|
- name (str): The domain name. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "disable %s apache site" % name) |
||||||
|
|
||||||
|
return Command("a2dissite %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_enable_module(name, **kwargs): |
||||||
|
"""Enable an Apache module. |
||||||
|
|
||||||
|
- name (str): The module name. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "enable %s apache module" % name) |
||||||
|
|
||||||
|
return Command("a2enmod %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_enable_site(name, **kwargs): |
||||||
|
"""Enable an Apache site. |
||||||
|
|
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "enable %s apache module" % name) |
||||||
|
|
||||||
|
return Command("a2ensite %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_reload(**kwargs): |
||||||
|
kwargs.setdefault("comment", "reload apache") |
||||||
|
kwargs.setdefault("register", "apache_reloaded") |
||||||
|
|
||||||
|
return Command("service apache2 reload", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_restart(**kwargs): |
||||||
|
kwargs.setdefault("comment", "restart apache") |
||||||
|
kwargs.setdefault("register", "apache_restarted") |
||||||
|
|
||||||
|
return Command("service apache2 restart", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_start(**kwargs): |
||||||
|
kwargs.setdefault("comment", "start apache") |
||||||
|
kwargs.setdefault("register", "apache_started") |
||||||
|
|
||||||
|
return Command("service apache2 start", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_stop(**kwargs): |
||||||
|
kwargs.setdefault("comment", "stop apache") |
||||||
|
|
||||||
|
return Command("service apache2 stop", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def apache_test(**kwargs): |
||||||
|
kwargs.setdefault("comment", "check apache configuration") |
||||||
|
kwargs.setdefault("register", "apache_checks_out") |
||||||
|
|
||||||
|
return Command("apachectl configtest", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def service_reload(name, **kwargs): |
||||||
|
"""Reload a service. |
||||||
|
|
||||||
|
- name (str): The service name. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "reload %s service" % name) |
||||||
|
kwargs.setdefault("register", "%s_reloaded" % name) |
||||||
|
|
||||||
|
return Command("service %s reload" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def service_restart(name, **kwargs): |
||||||
|
"""Restart a service. |
||||||
|
|
||||||
|
- name (str): The service name. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "restart %s service" % name) |
||||||
|
kwargs.setdefault("register", "%s_restarted" % name) |
||||||
|
|
||||||
|
return Command("service %s restart" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def service_start(name, **kwargs): |
||||||
|
"""Start a service. |
||||||
|
|
||||||
|
- name (str): The service name. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "start %s service" % name) |
||||||
|
kwargs.setdefault("register", "%s_started" % name) |
||||||
|
|
||||||
|
return Command("service %s start" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def service_stop(name, **kwargs): |
||||||
|
"""Stop a service. |
||||||
|
|
||||||
|
- name (str): The service name. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "stop %s service" % name) |
||||||
|
kwargs.setdefault("register", "%s_stopped" % name) |
||||||
|
|
||||||
|
return Command("service %s stop" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def system(op, **kwargs): |
||||||
|
"""Perform a system operation. |
||||||
|
|
||||||
|
- op (str): The operation to perform; reboot, update, upgrade. |
||||||
|
|
||||||
|
""" |
||||||
|
if op == "reboot": |
||||||
|
return system_reboot(**kwargs) |
||||||
|
elif op == "update": |
||||||
|
return system_update(**kwargs) |
||||||
|
elif op == "upgrade": |
||||||
|
return system_upgrade(**kwargs) |
||||||
|
else: |
||||||
|
raise NameError("Unrecognized or unsupported system operation: %s" % op) |
||||||
|
|
||||||
|
|
||||||
|
def system_install(name, **kwargs): |
||||||
|
"""Install a system-level package. |
||||||
|
|
||||||
|
- name (str): The name of the package to install. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "install system package %s" % name) |
||||||
|
|
||||||
|
return Command("apt-get install -y %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def system_reboot(**kwargs): |
||||||
|
kwargs.setdefault("comment", "reboot the system") |
||||||
|
|
||||||
|
return Command("reboot", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def system_uninstall(name, **kwargs): |
||||||
|
"""Uninstall a system-level package. |
||||||
|
|
||||||
|
- name (str): The name of the package to uninstall. |
||||||
|
|
||||||
|
""" |
||||||
|
kwargs.setdefault("comment", "remove system package %s" % name) |
||||||
|
|
||||||
|
return Command("apt-get uninstall -y %s" % name, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def system_update(**kwargs): |
||||||
|
kwargs.setdefault("comment", "update system package info") |
||||||
|
|
||||||
|
return Command("apt-get update -y", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def system_upgrade(**kwargs): |
||||||
|
kwargs.setdefault("comment", "upgrade the system") |
||||||
|
|
||||||
|
return Command("apt-get upgrade -y", **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def template(source, target, backup=True, parser=None, **kwargs): |
||||||
|
"""Create a file from a template. |
||||||
|
|
||||||
|
- source (str): The path to the template file. |
||||||
|
- target (str): The path to where the new file should be created. |
||||||
|
- backup (bool): Indicates whether a backup should be made if the target file already exists. |
||||||
|
- parser (str): The parser to use ``jinja`` (the default) or ``simple``. |
||||||
|
|
||||||
|
""" |
||||||
|
return Template(source, target, backup=backup, parser=parser, **kwargs) |
||||||
|
|
||||||
|
|
||||||
|
def user(name, groups=None, home=None, op="add", password=None, **kwargs): |
||||||
|
"""Create or remove a user. |
||||||
|
|
||||||
|
- name (str): The user name. |
||||||
|
- groups (str | list): A list of groups to which the user should belong. |
||||||
|
- home (str): The path to the user's home directory. |
||||||
|
- op (str); The operation to perform; ``add`` or ``remove``. |
||||||
|
- password (str): The user's password. (NOT IMPLEMENTED) |
||||||
|
|
||||||
|
""" |
||||||
|
if op == "add": |
||||||
|
kwargs.setdefault("comment", "create a user named %s" % name) |
||||||
|
|
||||||
|
commands = list() |
||||||
|
|
||||||
|
# The gecos switch eliminates the prompts. |
||||||
|
a = list() |
||||||
|
a.append('adduser %s --disabled-password --gecos ""' % name) |
||||||
|
if home is not None: |
||||||
|
a.append("--home %s" % home) |
||||||
|
|
||||||
|
commands.append(Command(" ".join(a), **kwargs)) |
||||||
|
|
||||||
|
if type(groups) is str: |
||||||
|
groups = split_csv(groups, smart=False) |
||||||
|
|
||||||
|
if type(groups) in [list, tuple]: |
||||||
|
for group in groups: |
||||||
|
commands.append(Command("adduser %s %s" % (name, group), **kwargs)) |
||||||
|
|
||||||
|
a = list() |
||||||
|
for c in commands: |
||||||
|
a.append(c.get_statement(include_comment=True)) |
||||||
|
|
||||||
|
return Command("\n".join(a), **kwargs) |
||||||
|
elif op == "remove": |
||||||
|
kwargs.setdefault("comment", "remove a user named %s" % name) |
||||||
|
return Command("deluser %s" % name, **kwargs) |
||||||
|
else: |
||||||
|
raise NameError("Unsupported or unrecognized operation: %s" % op) |
||||||
|
|
||||||
|
|
||||||
|
MAPPINGS = { |
||||||
|
'apache': apache, |
||||||
|
'apache.disable_module': apache_disable_module, |
||||||
|
'apache.disable_site': apache_disable_site, |
||||||
|
'apache.enable_module': apache_enable_module, |
||||||
|
'apache.enable_site': apache_enable_site, |
||||||
|
'apache.reload': apache_reload, |
||||||
|
'apache.restart': apache_restart, |
||||||
|
'apache.start': apache_start, |
||||||
|
'apache.stop': apache_stop, |
||||||
|
'apache.test': apache_test, |
||||||
|
'install': system_install, |
||||||
|
'reboot': system_reboot, |
||||||
|
'reload': service_reload, |
||||||
|
'restart': service_restart, |
||||||
|
'start': service_start, |
||||||
|
'stop': service_stop, |
||||||
|
'system': system, |
||||||
|
'template': template, |
||||||
|
'update': system_update, |
||||||
|
'uninstall': system_uninstall, |
||||||
|
'upgrade': system_upgrade, |
||||||
|
'user': user, |
||||||
|
} |
||||||
|
|
||||||
|
MAPPINGS.update(COMMON_MAPPINGS) |
||||||
|
MAPPINGS.update(DJANGO_MAPPINGS) |
||||||
|
MAPPINGS.update(MYSQL_MAPPINGS) |
||||||
|
MAPPINGS.update(PGSQL_MAPPINGS) |
||||||
|
MAPPINGS.update(POSIX_MAPPINGS) |
Loading…
Reference in new issue