Remove debops* bin…
This commit is contained in:
parent
b0d36ad389
commit
2eafc4907e
180
debops
180
debops
|
@ -1,180 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
debops: run ansible-playbook with some customization
|
||||
"""
|
||||
# Copyright (C) 2014-2015 Hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Part of the DebOps - https://debops.org/
|
||||
|
||||
# This program is free software; you can redistribute
|
||||
# it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 3 of the License,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will
|
||||
# be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public
|
||||
# License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General
|
||||
# Public License along with this program; if not,
|
||||
# write to the Free Software Foundation, Inc., 59
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# An on-line copy of the GNU General Public License can
|
||||
# be downloaded from the FSF web page at:
|
||||
# https://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import os
|
||||
import ConfigParser
|
||||
|
||||
import ansible
|
||||
|
||||
from debops import *
|
||||
from debops.cmds import *
|
||||
|
||||
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__copyright__ = "Copyright 2014-2015 by Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__licence__ = "GNU General Public License version 3 (GPL v3) or later"
|
||||
|
||||
|
||||
PATHSEP = ':'
|
||||
|
||||
ConfigFileHeader = """\
|
||||
# Ansible configuration file generated by DebOps, all changes will be lost.
|
||||
# You can manipulate the contents of this file via `.debops.cfg`.
|
||||
"""
|
||||
|
||||
def write_config(filename, config):
|
||||
cfgparser = ConfigParser.ConfigParser()
|
||||
for section, pairs in config.items():
|
||||
cfgparser.add_section(section)
|
||||
for option, value in pairs.items():
|
||||
cfgparser.set(section, option, value)
|
||||
|
||||
with open(filename, "w") as fh:
|
||||
print(ConfigFileHeader, file=fh)
|
||||
cfgparser.write(fh)
|
||||
|
||||
|
||||
def gen_ansible_cfg(filename, config, project_root, playbooks_path,
|
||||
inventory_path):
|
||||
# Generate Ansible configuration file
|
||||
|
||||
def custom_paths(type):
|
||||
if type in defaults:
|
||||
# prepend value from .debops.cfg
|
||||
yield defaults[type]
|
||||
yield os.path.join(project_root, "ansible", type)
|
||||
yield os.path.join(playbooks_path, type)
|
||||
yield os.path.join("/usr/share/ansible/", type)
|
||||
|
||||
# Add custom configuration options to ansible.cfg: Take values
|
||||
# from [ansible ...] sections of the .debops.cfg file
|
||||
# Note: To set debops default values, use debops.config.DEFAULTS
|
||||
cfg = dict((sect.split(None, 1)[1], pairs)
|
||||
for sect, pairs in config.items() if sect.startswith('ansible '))
|
||||
|
||||
defaults = cfg.setdefault('defaults', {})
|
||||
defaults['inventory'] = inventory_path
|
||||
defaults['roles_path'] = PATHSEP.join(filter(None, (
|
||||
defaults.get('roles_path'), # value from .debops.cfg or None
|
||||
os.path.join(project_root, "roles"),
|
||||
os.path.join(project_root, "ansible", "roles"),
|
||||
os.path.join(playbooks_path, "..", "roles"),
|
||||
os.path.join(playbooks_path, "roles"),
|
||||
"/etc/ansible/roles")))
|
||||
for plugin_type in ('action', 'callback', 'connection',
|
||||
'filter', 'lookup', 'vars'):
|
||||
plugin_type = plugin_type+"_plugins"
|
||||
defaults[plugin_type] = PATHSEP.join(custom_paths(plugin_type))
|
||||
|
||||
if ansible.__version__ >= "1.7":
|
||||
# work around a bug obviously introduced in 1.7, see
|
||||
# https://github.com/ansible/ansible/issues/8555
|
||||
if ' ' in defaults[plugin_type]:
|
||||
defaults[plugin_type] = PATHSEP.join(
|
||||
'"%s"' % p for p in defaults[plugin_type].split(PATHSEP))
|
||||
|
||||
defaults['library'] = PATHSEP.join(custom_paths('library'))
|
||||
|
||||
write_config(filename, cfg)
|
||||
|
||||
|
||||
def main(cmd_args):
|
||||
project_root = find_debops_project(required=True)
|
||||
config = read_config(project_root)
|
||||
playbooks_path = find_playbookpath(config, project_root, required=True)
|
||||
|
||||
# Make sure required commands are present
|
||||
require_commands('ansible-playbook')
|
||||
|
||||
def find_playbook(playbook):
|
||||
tries = [
|
||||
(project_root, "playbooks", playbook),
|
||||
(project_root, "ansible", "playbooks", playbook),
|
||||
(playbooks_path, playbook),
|
||||
]
|
||||
|
||||
if 'playbooks_path' in config['paths']:
|
||||
tries += [(custom_path, playbook) for custom_path in
|
||||
config['paths']['playbooks_path'].split(PATHSEP)]
|
||||
|
||||
for parts in tries:
|
||||
play = os.path.join(*parts)
|
||||
if os.path.isfile(play):
|
||||
return play
|
||||
|
||||
# Check if user specified a potential playbook name as the first
|
||||
# argument. If yes, use it as the playbook name and remove it from
|
||||
# the argument list
|
||||
play = None
|
||||
if len(cmd_args) > 0:
|
||||
maybe_play = cmd_args[0]
|
||||
if os.path.isfile(maybe_play):
|
||||
play = maybe_play
|
||||
else:
|
||||
play = find_playbook(maybe_play + ".yml")
|
||||
if play:
|
||||
cmd_args.pop(0)
|
||||
del maybe_play
|
||||
if not play:
|
||||
play = find_playbook("site.yml")
|
||||
|
||||
inventory_path = find_inventorypath(project_root)
|
||||
os.environ['ANSIBLE_HOSTS'] = inventory_path
|
||||
|
||||
ansible_config_file = os.path.join(project_root, ANSIBLE_CONFIG_FILE)
|
||||
os.environ['ANSIBLE_CONFIG'] = os.path.abspath(ansible_config_file)
|
||||
gen_ansible_cfg(ansible_config_file, config, project_root, playbooks_path,
|
||||
inventory_path)
|
||||
|
||||
# Allow insecure SSH connections if requested
|
||||
if INSECURE:
|
||||
os.environ['ANSIBLE_HOST_KEY_CHECKING'] = 'False'
|
||||
|
||||
# Create path to EncFS encrypted directory, based on inventory name
|
||||
encfs_encrypted = os.path.join(os.path.dirname(inventory_path),
|
||||
ENCFS_PREFIX + SECRET_NAME)
|
||||
|
||||
# Check if encrypted secret directory exists and use it
|
||||
revert_unlock = padlock_unlock(encfs_encrypted)
|
||||
try:
|
||||
# Run ansible-playbook with custom environment
|
||||
print("Running Ansible playbook from:")
|
||||
print(play, "...")
|
||||
return subprocess.call(['ansible-playbook', play] + cmd_args)
|
||||
finally:
|
||||
if revert_unlock:
|
||||
padlock_lock(encfs_encrypted)
|
||||
|
||||
|
||||
try:
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('... aborted')
|
111
debops-defaults
111
debops-defaults
|
@ -1,111 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
debops-defaults: aggregate all defaults from Ansible roles into one stream
|
||||
"""
|
||||
# Copyright (C) 2014-2015 Hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Part of the DebOps - https://debops.org/
|
||||
|
||||
# This program is free software; you can redistribute
|
||||
# it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 3 of the License,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will
|
||||
# be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public
|
||||
# License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General
|
||||
# Public License along with this program; if not,
|
||||
# write to the Free Software Foundation, Inc., 59
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# An on-line copy of the GNU General Public License can
|
||||
# be downloaded from the FSF web page at:
|
||||
# https://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import codecs
|
||||
import subprocess
|
||||
import glob
|
||||
import argparse
|
||||
import errno
|
||||
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf-8')
|
||||
|
||||
from debops import *
|
||||
from debops.cmds import *
|
||||
|
||||
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__copyright__ = "Copyright 2014-2015 by Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__licence__ = "GNU General Public License version 3 (GPL v3) or later"
|
||||
|
||||
def cat(filename, outstream):
|
||||
try:
|
||||
fh = codecs.open(filename, encoding=sys.getdefaultencoding())
|
||||
except IOError, e:
|
||||
# This should only happen if the user listed a unknown role.
|
||||
outstream.write('%s: %s\n' % (e.strerror, e.filename))
|
||||
return
|
||||
try:
|
||||
# Read input file as Unicode object and pass it to outstream.
|
||||
outstream.write(fh.read())
|
||||
finally:
|
||||
fh.close()
|
||||
|
||||
def aggregate_defaults(playbooks_path, role_list, outstream):
|
||||
# Aggregate role/defaults/main.yml files from all roles into one stream
|
||||
roles_path = os.path.normpath(os.path.join(playbooks_path, '..', 'roles'))
|
||||
if role_list:
|
||||
for role in role_list:
|
||||
if not '.' in role:
|
||||
role = ROLE_PREFIX + '.' + role
|
||||
fn = os.path.join(roles_path, role, 'defaults', 'main.yml')
|
||||
cat(fn, outstream=outstream)
|
||||
else:
|
||||
for fn in glob.glob(os.path.join(roles_path,
|
||||
'*', 'defaults', 'main.yml')):
|
||||
cat(fn, outstream=outstream)
|
||||
|
||||
# ---- DebOps environment setup ----
|
||||
|
||||
def main(role_list):
|
||||
project_root = find_debops_project(required=False)
|
||||
config = read_config(project_root)
|
||||
playbooks_path = find_playbookpath(config, project_root, required=True)
|
||||
|
||||
# Make sure required commands are present
|
||||
require_commands('view')
|
||||
|
||||
if sys.stdout.isatty():
|
||||
# if script is run as standalone, redirect to view
|
||||
view = subprocess.Popen(['view', '+set ft=yaml', '-'],
|
||||
stdin=subprocess.PIPE)
|
||||
try:
|
||||
aggregate_defaults(playbooks_path, role_list, view.stdin)
|
||||
except IOError, e:
|
||||
if e.errno not in (errno.EPIPE, errno.EINVAL):
|
||||
# "Invalid pipe" or "Invalid argument"
|
||||
raise
|
||||
finally:
|
||||
view.communicate()
|
||||
else:
|
||||
# else, send everything to stdout
|
||||
aggregate_defaults(playbooks_path, role_list, sys.stdout)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('role', nargs='*')
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
main(args.role)
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('... aborted')
|
205
debops-init
205
debops-init
|
@ -1,205 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
debops-init: create a new DebOps project directory
|
||||
"""
|
||||
# Copyright (C) 2014-2015 Hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Part of the DebOps - https://debops.org/
|
||||
|
||||
# This program is free software; you can redistribute
|
||||
# it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 3 of the License,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will
|
||||
# be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public
|
||||
# License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General
|
||||
# Public License along with this program; if not,
|
||||
# write to the Free Software Foundation, Inc., 59
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# An on-line copy of the GNU General Public License can
|
||||
# be downloaded from the FSF web page at:
|
||||
# https://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import codecs
|
||||
import subprocess
|
||||
import glob
|
||||
import argparse
|
||||
|
||||
from debops import *
|
||||
from debops.cmds import *
|
||||
|
||||
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__copyright__ = "Copyright 2014-2015 by Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__licence__ = "GNU General Public License version 3 (GPL v3) or later"
|
||||
|
||||
SKEL_DIRS = (
|
||||
os.path.join("ansible", INVENTORY, "group_vars", "all"),
|
||||
os.path.join("ansible", INVENTORY, "host_vars"),
|
||||
os.path.join("ansible", "playbooks"),
|
||||
os.path.join("ansible", "roles"),
|
||||
)
|
||||
|
||||
DEFAULT_DEBOPS_CONFIG = """
|
||||
# -*- conf -*-
|
||||
|
||||
[paths]
|
||||
;data-home: /opt/debops
|
||||
|
||||
[ansible defaults]
|
||||
display_skipped_hosts = False
|
||||
retry_files_enabled = False
|
||||
;callback_plugins = /my/plugins/callback
|
||||
;roles_path = /my/roles
|
||||
|
||||
[ansible paramiko]
|
||||
;record_host_keys=True
|
||||
|
||||
[ansible ssh_connection]
|
||||
;ssh_args = -o ControlMaster=auto -o ControlPersist=60s
|
||||
"""
|
||||
|
||||
DEFAULT_GITIGNORE = """\
|
||||
ansible/{SECRET_NAME}
|
||||
{SECRET_NAME}
|
||||
{ENCFS_PREFIX}{SECRET_NAME}
|
||||
ansible.cfg
|
||||
|
||||
#-- python
|
||||
*.py[co]
|
||||
|
||||
#-- vim
|
||||
[._]*.s[a-w][a-z]
|
||||
[._]s[a-w][a-z]
|
||||
*.un~
|
||||
Session.vim
|
||||
.netrwhist
|
||||
*~
|
||||
|
||||
#-- Emacs
|
||||
\#*\#
|
||||
/.emacs.desktop
|
||||
/.emacs.desktop.lock
|
||||
*.elc
|
||||
auto-save-list
|
||||
tramp
|
||||
.\#*
|
||||
|
||||
#-- SublimeText
|
||||
*.sublime-workspace
|
||||
#*.sublime-project
|
||||
|
||||
#-- sftp configuration file
|
||||
sftp-config.json
|
||||
"""
|
||||
|
||||
HOSTS_FILE_HEADER = """\
|
||||
# This is an Ansible inventory file in INI format. You can define a list of
|
||||
# hosts and groups to be managed by this particular inventory.
|
||||
|
||||
# Hosts listed under [debops_all_hosts] will have common DebOps plays
|
||||
# ran against them. It will include services such as iptables, DNS, Postfix,
|
||||
# sshd configuration and more.
|
||||
#
|
||||
# View the list here:
|
||||
# https://github.com/debops/debops-playbooks/blob/master/playbooks/common.yml
|
||||
#
|
||||
# You should check Getting Started guide for useful suggestions:
|
||||
# https://docs.debops.org/en/latest/debops-playbooks/docs/guides/getting-started.html
|
||||
"""
|
||||
|
||||
HOSTS_FILE_CONTENT_CONTROLER = """
|
||||
# Your host is eligible to be managed by DebOps' common playbook. If you want
|
||||
# that functionality and more, then uncomment your hostname below.
|
||||
|
||||
[debops_all_hosts]
|
||||
#%s ansible_connection=local
|
||||
""" % platform.node()
|
||||
|
||||
HOSTS_FILE_CONTENT_NO_CONTROLER = """
|
||||
# Your host was not detected as compatible with DebOps playbooks, so you will
|
||||
# not be able to leverage the above features on your current operating system.
|
||||
# You can however use a virtual machine as the Ansible Controller.
|
||||
|
||||
[debops_all_hosts]
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def write_file(filename, *content):
|
||||
"""
|
||||
If file:`filename` does not exist, create it and write
|
||||
var:`content` into it.
|
||||
"""
|
||||
if not os.path.exists(filename):
|
||||
with open(filename, "w") as fh:
|
||||
fh.writelines(content)
|
||||
|
||||
|
||||
def write_config_files(project_root):
|
||||
"""
|
||||
Create the default debops-config files in the dir:`project_root`
|
||||
directory.
|
||||
"""
|
||||
# Create .debops.cfg
|
||||
write_file(os.path.join(project_root, DEBOPS_CONFIG), DEFAULT_DEBOPS_CONFIG)
|
||||
# Create .gitignore
|
||||
write_file(os.path.join(project_root, '.gitignore'),
|
||||
DEFAULT_GITIGNORE.format(SECRET_NAME=SECRET_NAME, ENCFS_PREFIX=ENCFS_PREFIX))
|
||||
|
||||
hosts_filename = os.path.join(project_root, "ansible", INVENTORY, "hosts")
|
||||
# Swap in different hosts file content depending on the host's OS/distro
|
||||
if (platform.system() == "Linux" and
|
||||
platform.linux_distribution()[0].lower() in ("debian", "ubuntu")):
|
||||
write_file(hosts_filename,
|
||||
HOSTS_FILE_HEADER, HOSTS_FILE_CONTENT_CONTROLER)
|
||||
else:
|
||||
write_file(hosts_filename,
|
||||
HOSTS_FILE_HEADER, HOSTS_FILE_CONTENT_NO_CONTROLER)
|
||||
|
||||
|
||||
def main(project_root):
|
||||
orig_project_root = project_root
|
||||
project_root = os.path.abspath(project_root)
|
||||
|
||||
#-- Check for existing debops project directory
|
||||
debops_project_root = find_debops_project(project_root, required=False)
|
||||
|
||||
# Exit if DebOps configuration file has been found in project_dir
|
||||
if os.path.exists(os.path.join(project_root, DEBOPS_CONFIG)):
|
||||
error_msg("%s is already a DebOps project directory" % project_root)
|
||||
|
||||
# Exit if we are in a DebOps project dir and nested project would be created
|
||||
if debops_project_root:
|
||||
error_msg("You are inside %s project already" % debops_project_root)
|
||||
|
||||
#-- Main script
|
||||
|
||||
print("Creating new DebOps project directory in", orig_project_root, "...")
|
||||
|
||||
# Create base project directories
|
||||
for skel_dir in SKEL_DIRS:
|
||||
skel_dir = os.path.join(project_root, skel_dir)
|
||||
if not os.path.isdir(skel_dir):
|
||||
os.makedirs(skel_dir)
|
||||
# Write default config files
|
||||
write_config_files(project_root)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('project_dir', default=os.curdir)
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
main(args.project_dir)
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('... aborted')
|
187
debops-padlock
187
debops-padlock
|
@ -1,187 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
debops-padlock: encrypt secret directory with EncFS and GPG
|
||||
"""
|
||||
# Copyright (C) 2014-2015 Hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Part of the DebOps - https://debops.org/
|
||||
|
||||
# This program is free software; you can redistribute
|
||||
# it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 3 of the License,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will
|
||||
# be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public
|
||||
# License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General
|
||||
# Public License along with this program; if not,
|
||||
# write to the Free Software Foundation, Inc., 59
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# An on-line copy of the GNU General Public License can
|
||||
# be downloaded from the FSF web page at:
|
||||
# https://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import argparse
|
||||
import itertools
|
||||
import stat
|
||||
import sys
|
||||
import time
|
||||
from pkg_resources import resource_filename
|
||||
|
||||
from debops import *
|
||||
from debops.cmds import *
|
||||
|
||||
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__copyright__ = "Copyright 2014-2015 by Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__licence__ = "GNU General Public License version 3 (GPL v3) or later"
|
||||
|
||||
def gen_pwd():
|
||||
from string import ascii_letters, digits, punctuation
|
||||
import random
|
||||
ALLCHARS = digits + ascii_letters + punctuation
|
||||
ALLCHARS = digits + ascii_letters + '-_!@#$%^&*()_+{}|:<>?='
|
||||
pwd = ''.join(random.choice(ALLCHARS) for i in range(ENCFS_KEYFILE_LENGTH))
|
||||
return pwd
|
||||
|
||||
|
||||
# Randomness source for EncFS keyfile generation
|
||||
devrandom = os.environ.get('DEVRANDOM', "/dev/urandom")
|
||||
|
||||
SCRIPT_FILENAME = 'padlock-script'
|
||||
|
||||
# ---- DebOps environment setup ----
|
||||
|
||||
def main(subcommand_func, **kwargs):
|
||||
project_root = find_debops_project(required=True)
|
||||
# :todo: Source DebOps configuration file
|
||||
#[ -r ${debops_config} ] && source ${debops_config}
|
||||
|
||||
# ---- Main script ----
|
||||
|
||||
# Make sure required commands are present
|
||||
require_commands('encfs', 'find', 'fusermount', 'gpg')
|
||||
|
||||
inventory_path = find_inventorypath(project_root, required=False)
|
||||
# If inventory hasn't been found automatically, assume it's the default
|
||||
if not inventory_path:
|
||||
inventory_path = os.path.join(project_root, 'ansible', INVENTORY)
|
||||
|
||||
# Create names of EncFS encrypted and decrypted directories, based on
|
||||
# inventory name (absolute paths are specified)
|
||||
encfs_encrypted = os.path.join(os.path.dirname(inventory_path),
|
||||
ENCFS_PREFIX + SECRET_NAME)
|
||||
encfs_decrypted = os.path.join(os.path.dirname(inventory_path),
|
||||
SECRET_NAME)
|
||||
subcommand_func(encfs_decrypted, encfs_encrypted, **kwargs)
|
||||
|
||||
|
||||
def init(encfs_decrypted, encfs_encrypted, recipients):
|
||||
# EncFS cannot create encrypted directory if directory with
|
||||
# decrypted data is not empty
|
||||
if not os.path.exists(encfs_decrypted):
|
||||
os.makedirs(encfs_decrypted)
|
||||
elif os.listdir(encfs_decrypted):
|
||||
error_msg("secret directory not empty")
|
||||
|
||||
# Quit if encrypted directory already exists.
|
||||
if os.path.isdir(encfs_encrypted):
|
||||
error_msg("EncFS directory already exists")
|
||||
os.makedirs(encfs_encrypted)
|
||||
|
||||
encfs_keyfile = os.path.join(encfs_encrypted, ENCFS_KEYFILE)
|
||||
encfs_configfile = os.path.join(encfs_encrypted, ENCFS_CONFIGFILE)
|
||||
|
||||
# put a `-r` in front of each recipient for passing as args to gpg
|
||||
recipients = list(itertools.chain.from_iterable(['-r', r]
|
||||
for r in recipients))
|
||||
|
||||
# Generate a random password and encrypt it with GPG keys of recipients.
|
||||
print("Generating a random", ENCFS_KEYFILE_LENGTH, "char password")
|
||||
pwd = gen_pwd()
|
||||
gpg = subprocess.Popen(['gpg', '--encrypt', '--armor',
|
||||
'--output', encfs_keyfile] + recipients,
|
||||
stdin=subprocess.PIPE)
|
||||
gpg.communicate(pwd)
|
||||
|
||||
# Mount the encfs to the config file will be written. Tell encfs
|
||||
# it to ask gpg for the password.
|
||||
# NB1: Alternativly we could use --stdinpass, but using --extpass makes
|
||||
# the user check if she has the correct passphrase early.
|
||||
# NB2: We can not use padlock_unlock here, because the config file
|
||||
# does not yet exist.
|
||||
encfs = subprocess.Popen([
|
||||
'encfs', encfs_encrypted, encfs_decrypted,
|
||||
'--extpass', 'gpg --no-mdc-warning --output - '+shquote(encfs_keyfile)],
|
||||
stdin=subprocess.PIPE)
|
||||
encfs.communicate('p\n'+pwd)
|
||||
|
||||
# Create padlock-script
|
||||
padlock_script = os.path.join(encfs_encrypted, PADLOCK_CMD)
|
||||
|
||||
# :todo: use resource_stream
|
||||
shutil.copy(resource_filename('debops', SCRIPT_FILENAME), padlock_script)
|
||||
os.chmod(padlock_script,
|
||||
os.stat(padlock_script).st_mode|stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH)
|
||||
|
||||
# Lock the EncFS directory after creation
|
||||
time.sleep(0.5) # :fixme: why sleeping here?
|
||||
padlock_lock(encfs_encrypted)
|
||||
|
||||
# Protect the EncFS configuration file by also encrypting it with
|
||||
# the GPG keys of recipients.
|
||||
subprocess.call(['gpg', '--encrypt', '--armor',
|
||||
'--output', encfs_configfile+'.asc']
|
||||
+ recipients + [encfs_configfile])
|
||||
os.remove(encfs_configfile)
|
||||
|
||||
|
||||
def lock(encfs_decrypted, encfs_encrypted, verbose):
|
||||
# Unmount the directory if it is mounted
|
||||
if padlock_lock(encfs_encrypted):
|
||||
if verbose: print("Locked!")
|
||||
else:
|
||||
if verbose: print("Is already locked.")
|
||||
|
||||
|
||||
def unlock(encfs_decrypted, encfs_encrypted, verbose):
|
||||
# Mount the directory it if it is unmounted
|
||||
if padlock_unlock(encfs_encrypted):
|
||||
if verbose: print("Unlocked!")
|
||||
else:
|
||||
if verbose: print("Is already unlocked.")
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers(
|
||||
help='action to perform. Use `%(prog)s --help <action>` for further help.')
|
||||
|
||||
p = subparsers.add_parser('init')
|
||||
p.add_argument('recipients', nargs='*',
|
||||
help=("GPG recipients for which the secret key should be "
|
||||
"encrypted for (name, e-mail or key-id)"))
|
||||
p.set_defaults(subcommand_func=init)
|
||||
|
||||
p = subparsers.add_parser('unlock')
|
||||
p.add_argument('-v', '--verbose', action='store_true', help="be verbose")
|
||||
p.set_defaults(subcommand_func=unlock)
|
||||
|
||||
p = subparsers.add_parser('lock')
|
||||
p.add_argument('-v', '--verbose', action='store_true', help="be verbose")
|
||||
p.set_defaults(subcommand_func=lock)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
main(**vars(args))
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('... aborted')
|
74
debops-task
74
debops-task
|
@ -1,74 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
debops-task: run ansible with some customization
|
||||
"""
|
||||
# Copyright (C) 2014-2015 Hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Part of the DebOps - https://debops.org/
|
||||
|
||||
# This program is free software; you can redistribute
|
||||
# it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 3 of the License,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will
|
||||
# be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public
|
||||
# License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General
|
||||
# Public License along with this program; if not,
|
||||
# write to the Free Software Foundation, Inc., 59
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# An on-line copy of the GNU General Public License can
|
||||
# be downloaded from the FSF web page at:
|
||||
# https://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from debops import *
|
||||
from debops.cmds import *
|
||||
|
||||
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__copyright__ = "Copyright 2014-2015 by Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__licence__ = "GNU General Public License version 3 (GPL v3) or later"
|
||||
|
||||
|
||||
DEBOPS_RESERVED_NAMES = ["task", "init", "update", "defaults", "padlock"]
|
||||
|
||||
# ---- DebOps environment setup ----
|
||||
|
||||
# Find DebOps configuration file
|
||||
project_root = find_debops_project(required=True)
|
||||
# Source DebOps configuration file
|
||||
###----- todo: need to decide on semantics!
|
||||
#config = read_config(project_root)
|
||||
|
||||
|
||||
# ---- Main script ----
|
||||
|
||||
# Make sure required commands are present
|
||||
require_commands('ansible')
|
||||
|
||||
ansible_inventory = find_inventorypath(project_root)
|
||||
|
||||
# Get module name from the script name if script is named 'debops-*'
|
||||
module_name = SCRIPT_NAME.rsplit('-', 1)[-1]
|
||||
if module_name not in DEBOPS_RESERVED_NAMES:
|
||||
module = ["-m", module_name]
|
||||
else:
|
||||
module = []
|
||||
|
||||
os.environ['ANSIBLE_HOSTS'] = os.path.abspath(ansible_inventory)
|
||||
|
||||
# Allow insecure SSH connections if requested
|
||||
if INSECURE:
|
||||
os.environ['ANSIBLE_HOST_KEY_CHECKING'] = 'False'
|
||||
|
||||
# Run ansible with custom environment
|
||||
cmd = ['ansible'] + module + sys.argv[1:]
|
||||
subprocess.call(cmd)
|
247
debops-update
247
debops-update
|
@ -1,247 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
("""
|
||||
debops-update: install or update DebOps playbooks and roles
|
||||
"""
|
||||
# Copyright (C) 2014-2015 Hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||
# Part of the DebOps - https://debops.org/
|
||||
|
||||
|
||||
# This program is free software; you can redistribute
|
||||
# it and/or modify it under the terms of the
|
||||
# GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 3 of the License,
|
||||
# or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will
|
||||
# be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU General Public
|
||||
# License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General
|
||||
# Public License along with this program; if not,
|
||||
# write to the Free Software Foundation, Inc., 59
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# An on-line copy of the GNU General Public License can
|
||||
# be downloaded from the FSF web page at:
|
||||
# https://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
"""
|
||||
This script can be used to install or update installed DebOps playbooks and
|
||||
roles to current or specified version. By default it works on the installed
|
||||
playbook in users $HOME/.local/share/debops directory, but it can also be
|
||||
used on locally installed playbooks and roles in current directory.
|
||||
|
||||
Short usage guide:
|
||||
|
||||
- 'debops-update' will check if we are in DebOps project directory
|
||||
('.debops.cfg' exists)
|
||||
* if yes, it will check if 'debops-playbooks/playbooks/site.yml' exists
|
||||
* if yes, update playbooks and roles in $PWD
|
||||
* if no, check if DebOps playbooks are installed in known places,
|
||||
like ~/.local/share/debops
|
||||
* if yes, update playbooks in a place that they are installed at
|
||||
* if no, install DebOps playbooks in
|
||||
~/.local/share/debops/debops-playbooks
|
||||
|
||||
- 'debops-update path/to/dir' will check if specified directory exists
|
||||
* if no, create it
|
||||
* if yes, check if DebOps playbooks are installed at $path/debops-playbooks
|
||||
* if yes, update them
|
||||
* if no, install DebOps playbooks at $path/debops-playbooks
|
||||
|
||||
""")
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import argparse
|
||||
|
||||
from debops import *
|
||||
from debops.cmds import *
|
||||
|
||||
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__copyright__ = "Copyright 2014-2015 by Hartmut Goebel <h.goebel@crazy-compilers.com>"
|
||||
__licence__ = "GNU General Public License version 3 (GPL v3) or later"
|
||||
|
||||
|
||||
# ---- Configuration variables ----
|
||||
|
||||
# Default URI of DebOps (user https for server authentication)
|
||||
GIT_URI = "https://github.com/debops"
|
||||
|
||||
# Default git sources for debops-playbooks
|
||||
PLAYBOOKS_GIT_URI = GIT_URI + "/debops-playbooks"
|
||||
|
||||
# Default slug prefix for roles
|
||||
GIT_ROLE_PREFIX = "ansible-"
|
||||
|
||||
# Ansible Galaxy requirements file to use by default to download or update
|
||||
GALAXY_REQUIREMENTS = "galaxy/requirements.txt"
|
||||
|
||||
# Default Ansible Galaxy user account name
|
||||
GALAXY_ACCOUNT = "debops"
|
||||
|
||||
|
||||
# ---- Functions ----
|
||||
|
||||
def fetch_or_clone_roles(roles_path, requirements_file, dry_run=False):
|
||||
"""
|
||||
Efficiently fetch or clone a role
|
||||
"""
|
||||
with open(requirements_file) as fh:
|
||||
requirements = [r.strip().split() for r in fh.readlines()]
|
||||
num_roles = len(requirements)
|
||||
|
||||
for cnt, role_name in enumerate(requirements, 1):
|
||||
# Parse the requirements.txt file to extract the role name and version
|
||||
try:
|
||||
role_name, role_version = role_name[:2]
|
||||
except:
|
||||
role_name = role_name[0]
|
||||
role_version = 'master'
|
||||
|
||||
# :todo: rethink if we really want this
|
||||
if role_name.startswith(GALAXY_ACCOUNT + '.'):
|
||||
galaxy_name = role_name
|
||||
role_name = role_name.split('.', 1)[1]
|
||||
else:
|
||||
galaxy_name = GALAXY_ACCOUNT + '.' + role_name
|
||||
|
||||
remote_uri = GIT_URI + '/' + GIT_ROLE_PREFIX + role_name
|
||||
destination_dir = os.path.join(roles_path, galaxy_name)
|
||||
progress_label="[{role_version}] ({cnt}/{num_roles})".format(**locals())
|
||||
|
||||
# Either update or clone the role
|
||||
if os.path.exists(destination_dir):
|
||||
print("Updating", remote_uri, progress_label)
|
||||
update_git_repository(destination_dir, dry_run, remote_uri)
|
||||
else:
|
||||
print()
|
||||
print("Installing", remote_uri, progress_label)
|
||||
clone_git_repository(remote_uri, role_version, destination_dir, dry_run)
|
||||
print()
|
||||
|
||||
|
||||
def clone_git_repository(repo_uri, branch, destination, dry_run=False):
|
||||
if dry_run:
|
||||
print("Cloning '%s' to %s..." % (repo_uri, destination))
|
||||
else:
|
||||
subprocess.call(['git', 'clone', '--quiet', '--branch', branch,
|
||||
repo_uri, destination])
|
||||
|
||||
def update_git_repository(path, dry_run=False, remote_uri=False):
|
||||
"""
|
||||
Update an exiting git repository.
|
||||
|
||||
To get nice output, merge only of origin as updates.
|
||||
"""
|
||||
# Move into the role's directory
|
||||
old_pwd = os.getcwd()
|
||||
os.chdir(path)
|
||||
|
||||
if dry_run:
|
||||
subprocess.call(['git', 'fetch'])
|
||||
subprocess.call(['git', 'diff', 'HEAD', 'origin', '--stat'])
|
||||
else:
|
||||
# Get the current sha of the head branch
|
||||
current_sha = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip()
|
||||
|
||||
# Fetch it silently and store the new sha
|
||||
subprocess.call(['git', 'fetch', '--quiet'])
|
||||
fetch_sha = subprocess.check_output(['git', 'rev-parse', 'FETCH_HEAD']).strip()
|
||||
|
||||
if current_sha != fetch_sha:
|
||||
print()
|
||||
print('--')
|
||||
subprocess.call(['git', 'merge', fetch_sha])
|
||||
|
||||
if remote_uri:
|
||||
compare_uri = remote_uri + '/compare/' + current_sha[:7] + '...' + fetch_sha[:7]
|
||||
print()
|
||||
print("Compare:", compare_uri)
|
||||
|
||||
print('--')
|
||||
print()
|
||||
|
||||
# Move back to the initial directory
|
||||
os.chdir(old_pwd)
|
||||
|
||||
|
||||
# ---- Main script ----
|
||||
|
||||
def main(project_dir=None, dry_run=False):
|
||||
|
||||
# Check if user specified a directory as a parameter, if yes, use it as
|
||||
# a project directory and clone DebOps playbooks inside
|
||||
if project_dir:
|
||||
# If it's a new project, create the directory for it
|
||||
if not os.path.exists(project_dir):
|
||||
print ("Creating project directory in", project_dir)
|
||||
if not dry_run:
|
||||
os.makedirs(project_dir)
|
||||
|
||||
# Make sure that playbooks and roles will be installed in project
|
||||
# directory if it's specified
|
||||
install_path = os.path.join(project_dir, "debops-playbooks")
|
||||
|
||||
# If playbooks already are installed in specified location, set them as
|
||||
# currently used for eventual update
|
||||
if os.path.isfile(os.path.join(install_path, DEBOPS_SITE_PLAYBOOK)):
|
||||
playbooks_path = install_path
|
||||
else:
|
||||
playbooks_path = None
|
||||
|
||||
else:
|
||||
# If there's no project specified, look for playbooks in known locations
|
||||
project_root = find_debops_project(required=False)
|
||||
config = read_config(project_root)
|
||||
playbooks_path = find_playbookpath(config, project_root, required=False)
|
||||
if playbooks_path:
|
||||
install_path = os.path.dirname(playbooks_path)
|
||||
else:
|
||||
install_path = config['paths']['install-path']
|
||||
|
||||
roles_path = os.path.join(install_path, 'roles')
|
||||
|
||||
# ---- Create or update the playbooks and roles ----
|
||||
|
||||
# Playbooks have not been found, at this point assume playbooks are not
|
||||
# installed. Install them in user home directory
|
||||
if not playbooks_path:
|
||||
if dry_run:
|
||||
raise SystemExit("--dry-run requires DebOps playbooks.\n" \
|
||||
"Run debops-update without --dry-run first.")
|
||||
|
||||
# Download/clone main debops-playbooks repository
|
||||
print("DebOps playbooks have not been found, installing into",
|
||||
install_path)
|
||||
print()
|
||||
|
||||
clone_git_repository(PLAYBOOKS_GIT_URI, 'master', install_path, dry_run)
|
||||
os.chdir(install_path)
|
||||
os.makedirs(roles_path)
|
||||
else:
|
||||
# Update found debops-playbooks repository
|
||||
print("DebOps playbooks have been found in", install_path)
|
||||
update_git_repository(install_path, dry_run)
|
||||
print()
|
||||
os.chdir(install_path)
|
||||
|
||||
# Now install or update the roles into roles_path
|
||||
fetch_or_clone_roles(roles_path, GALAXY_REQUIREMENTS, dry_run)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--dry-run', action='store_true',
|
||||
help='perform a trial run with no changes made')
|
||||
parser.add_argument('project_dir', nargs='?')
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
main(args.project_dir, args.dry_run)
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('... aborted')
|
Loading…
Reference in New Issue