fabric/modules/utils.py
2018-10-17 22:52:00 +03:00

412 lines
10 KiB
Python

import os
import sys
import errno
import logging
import fabric.contrib.files
from contextlib import contextmanager as _contextmanager
from fabric.api import env, prefix, local
from fabric.operations import run, sudo
def printvar(name, value, exit=False):
print("%s : %s" % (name, value))
if exit:
sys.exit()
def printerr(message="", errcode=-2, exit=True):
""" prints error message and error code then exits
Keyword Arguments:
message -- error message
errcode -- the error code
exit -- if we do a sys.exit
"""
message = "Error\n\t{message}\n\tExiting with code: {errcode}\n".format(
message=message, errcode=errcode)
print
print(message)
print
sys.exit(errcode)
def loggify(module, func, prefix=""):
"""
I'm tired of rewriting this logging code in every single function, so I
decided to just dump it here, and return a logger that can be used and
thrown away when it's done
module - name of the module being used, ie 'nginx', 'deploy', etc
func - the name of the function this logger is going to be used in
prefix - anything you want to add to the front of the logger, ie '\n'
returns a logging object
"""
loggername = '{module}.{func}'.format(
module=module, func=func)
str_logging = '{prefix}%(levelname)s: {loggername} %(message)s'.format(
prefix=prefix,
loggername=loggername)
logging.basicConfig(
format=str_logging,
level=logging.DEBUG)
return logging.getLogger(loggername)
def print_console(string, prepend="\n\n", append="\n\n", sep="-", numsep=44):
"""
helper function to take a string, and format it so it prints to the console
in a way that is pleasing to the eye.
string - the string to be printed
prepend - defaults to two line spaces, can be anything
append - defaults to two lines spaces after the string is printed
sep - the character used to print out one line above the string and
one line after
numsep - number of times the separator is printed out on a line
"""
print(prepend)
if sep:
print(sep * numsep)
print(string)
if sep:
print(sep * numsep)
print(append)
def print_debug(debugstr, module, function):
print("%s:%s:%s" % (module, function, debugstr))
def executize(config_execute):
"""
A couple of times using fabric I've found that I'll need to switch between
sudo, run or local depending on where I'm executing the function, because
repeating this code in every funcion that needs it can be straingint on the
eyes, I'm putting it here for use.
config_execute - a string that can represent the value of 'sudo',
'run', or 'local'
return the fabric command corresponding to the string value
in config_execute
"""
_execute = local
if config_execute == 'sudo':
_execute = sudo
elif config_execute == 'run':
_execute = run
elif config_execute == 'local':
_execute = local
return _execute
def booleanize(value):
"""
take the argument and return it as either True or False
if the argument is neither, return False by default and warn the user that
there is a problem
"""
true_values = ("y", "yes", "true", "1")
false_values = ("n", "no", "false", "0")
if isinstance(value, bool):
return value
if value.lower() in true_values:
return True
elif value.lower() in false_values:
return False
raise TypeError("Cannot booleanize ambiguous value '%s'" % value)
def ensure_dir(directory):
"""
Create a directory if it's not exists
"""
try:
if not os.path.exists(directory):
print("creating directory: %s" % directory)
os.makedirs(directory)
except OSError, e:
if e.errno != errno.EEXIST:
print("Error occurred while creating directory: %s"
% directory)
raise
def ensure_file(f):
"""
Simulates linux 'touch' command
"""
if not os.path.exists(f):
open(f, 'w').close()
def upload_template(filename, destination, context, use_jinja,
use_sudo, backup, template_dir, debug=False):
if env.debug:
logging.basicConfig(
format='\n%(levelname)s: utils.upload_template %(message)s',
level=logging.DEBUG)
command_msg = "\n\tupload_template(" \
"\n\tfilename={filename}," \
"\n\tdestination={destination_available}," \
"\n\tcontext={context}," \
"\n\tuse_jinja={use_jinja}," \
"\n\tuse_sudo={use_sudo}," \
"\n\tbackup={backup}," \
"\n\ttemplate_dir={template_dir})\n".format(
filename=filename,
destination_available=destination,
context=context,
use_jinja=use_jinja,
use_sudo=use_sudo,
backup=backup,
template_dir=template_dir)
if debug:
return command_msg
else:
fabric.contrib.files.upload_template(
filename=filename,
destination=destination,
context=context,
use_jinja=use_jinja,
use_sudo=use_sudo,
backup=backup,
template_dir=template_dir)
def get_upload_template_msg(filename, destination, context, use_jinja,
use_sudo, backup, template_dir, debug=False):
command_msg = "\n\tupload_template(" \
"\n\tfilename={filename}," \
"\n\tdestination={destination_available}," \
"\n\tcontext={context}," \
"\n\tuse_jinja={use_jinja}," \
"\n\tuse_sudo={use_sudo}," \
"\n\tbackup={backup}," \
"\n\ttemplate_dir={template_dir})\n".format(
filename=filename,
destination_available=destination,
context=context,
use_jinja=use_jinja,
use_sudo=use_sudo,
backup=backup,
template_dir=template_dir)
return command_msg
@_contextmanager
def virtualenv_source():
with prefix("source virtualenvwrapper.sh"):
yield
@_contextmanager
def virtualenv():
configuration = env.config
with virtualenv_source():
with prefix("workon %s" % configuration.virtualenv.name):
yield
# with prefix("/bin/bash -c -l 'source %s'" %
# configuration.virtualenv.activate):
# yield
# with prefix("/bin/bash -c -l 'source /usr/local/bin/' \
# 'virtualenvwrapper.sh ' \
# '&& workon %s'" % configuration.virtualenv.name):
# yield
def generate_template_build_path(section, template_name='conf'):
"""
helper function to automate creation of build path
section - the template section we are building off of
template_name - by default this is "conf", but can be different, for
example, the 'database' section has 3 different template names
returns a path to where the template should be placed
"""
import os
configuration = env.config
conf_section = getattr(configuration.templates, section)
conf_section_templatename = getattr(conf_section, template_name)
build_path = os.path.join(
conf_section.path.remote,
'build',
conf_section_templatename.dst)
return build_path
def generate_template_files_path(section):
"""
helper function to automate creation of build path
section - the template section we are building off of
returns a path to where the template jinja file is located
"""
import os
configuration = env.config
conf_section = getattr(configuration.templates, section)
files_path = os.path.join(
conf_section.path.local,
'files')
return files_path
def print_run(command, prefix="\"\n\t", suffix="\n\t\""):
"""
helper function for when I want a string that has the form
"\n\t run(some_command_string) \t\n"
where "somce_command_string" is a bash script commmand or something like
that
"""
return "run ({prefix}{command}{suffix})".format(
prefix=prefix,
suffix=suffix,
command=command)
def handle_help(param, message, values=None):
values_default = ['-h', '--help']
if values is None:
values = values_default
if isinstance(param, str):
if param.lower() in values:
print(message)
return True
return False
def is_help(key):
help_keys = ['-h', '--help']
return key in help_keys
def link_create(path_src, path_dst, debug=False):
"""
takes a source and destination path, then links it
if the destination path already exists and is a link,
then delete it. Otherwise sys.exit
path_src - source path
path_dst - destination path
returns: if debug=True then it returns a msg
"""
from fabric.contrib.files import is_link
from fabric.contrib.files import exists
from fabric.operations import run
cmd_rm = "rm {path_dst}".format(
path_dst=path_dst
)
cmd_link = "ln -sf {path_src} {path_dst}".format(
path_src=path_src,
path_dst=path_dst
)
msg_debug = ""
if exists(path_dst):
if is_link(path_dst):
if debug:
msg_debug += "link already exists at dst, removing\n" \
"link_create:cmd_rm : %s" % cmd_rm
else:
run(cmd_rm)
else:
msg_error = "something exists at dst - '%s' " \
"- and it's not a link\n kicking out".format(path_dst)
sys.exit(msg_error)
if debug:
msg_debug += "link_create:cmd_link : %s" % cmd_link
else:
run(cmd_link)
return msg_debug
def prompt_continue(message="Do you want to continue? Y/n", default="Y"):
""" prompts user if he wants to continue
Keyword Arguments:
message -- ask if user wants to continue
default -- what to do if the user hits enter without giving a value
"""
from fabric.operations import prompt
prompt_val = prompt(message)
if prompt_val == "":
prompt_val = default
if env.debug:
printvar(
"prompt_val", prompt_val,
not booleanize(prompt_val))
else:
if not booleanize(prompt_val):
sys.exit()
def check_debug(env):
if hasattr(env, 'debug'):
return env.debug
else:
return False