Add some actions
This commit is contained in:
parent
2c894b5d1d
commit
e5127602f0
@ -4,7 +4,7 @@ import os
|
||||
|
||||
import click
|
||||
|
||||
from autonomic.command import init
|
||||
from autonomic.command import actions, init
|
||||
|
||||
|
||||
@click.group()
|
||||
@ -31,3 +31,4 @@ def autonomic(ctx, debug):
|
||||
|
||||
|
||||
autonomic.add_command(init.init)
|
||||
autonomic.add_command(actions.actions)
|
||||
|
12
autonomic/ansible.py
Normal file
12
autonomic/ansible.py
Normal file
@ -0,0 +1,12 @@
|
||||
"""Ansible management module."""
|
||||
|
||||
from autonomic.settings import INFRASTRUCTURE_PATH
|
||||
from autonomic.system import run_command
|
||||
|
||||
|
||||
def run_ansible_playbook(play, extra_env=None):
|
||||
"""Run ansible-playbook against a play."""
|
||||
command = [".venv/bin/ansible-playbook", play]
|
||||
run_command(
|
||||
command, cwd=INFRASTRUCTURE_PATH, output=True, extra_env=extra_env
|
||||
)
|
65
autonomic/command/actions.py
Normal file
65
autonomic/command/actions.py
Normal file
@ -0,0 +1,65 @@
|
||||
"""Ansible Actions module."""
|
||||
|
||||
import click
|
||||
from PyInquirer import prompt
|
||||
|
||||
from autonomic import logger
|
||||
from autonomic.ansible import run_ansible_playbook
|
||||
from autonomic.passstore import get_from_pass
|
||||
from autonomic.settings import ACTIONS_PATH
|
||||
|
||||
log = logger.get_logger(__name__)
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.pass_context
|
||||
def actions(ctx):
|
||||
"""Run an Ansible action."""
|
||||
question = [
|
||||
{
|
||||
"type": "list",
|
||||
"name": "action",
|
||||
"message": "Which Ansible action do you want to run?",
|
||||
"choices": [
|
||||
{"name": "addusers"},
|
||||
{"name": "newhetzner"},
|
||||
{"name": "rmhetzner"},
|
||||
{"name": "newdokku"},
|
||||
],
|
||||
"filter": lambda val: val.lower(),
|
||||
}
|
||||
]
|
||||
action_answer = prompt(question)
|
||||
|
||||
env = {}
|
||||
if (
|
||||
action_answer["action"] == "newhetzner"
|
||||
or action_answer["action"] == "rmhetzner"
|
||||
):
|
||||
question = [
|
||||
{
|
||||
"type": "list",
|
||||
"name": "key",
|
||||
"message": "Which Hetzner API key do you need?",
|
||||
"choices": [
|
||||
{"name": "prod"},
|
||||
{"name": "test"},
|
||||
{"name": "cicd"},
|
||||
],
|
||||
"filter": lambda val: val.lower(),
|
||||
}
|
||||
]
|
||||
|
||||
key_answer = prompt(question)
|
||||
path = "logins/hetzner/{}/api_key".format(key_answer["key"])
|
||||
secret = get_from_pass(path)
|
||||
env["HCLOUD_TOKEN"] = secret
|
||||
|
||||
play = "{}/{}.yml".format(ACTIONS_PATH, action_answer["action"])
|
||||
|
||||
run_ansible_playbook(play, extra_env=env)
|
||||
|
||||
# TODO(decentral1se):
|
||||
# git commit and push on infrastructure if we:
|
||||
# 1. ran an action that adds something new to the pass store
|
||||
# 2. added another machine to the inventory
|
@ -15,7 +15,7 @@ from autonomic.settings import (
|
||||
INFRASTRUCTURE_PATH,
|
||||
INFRASTRUCTURE_REPOSITORY,
|
||||
)
|
||||
from autonomic.system import ensure_installed, run_command
|
||||
from autonomic.system import run_command
|
||||
|
||||
log = logger.get_logger(__name__)
|
||||
|
||||
@ -25,9 +25,10 @@ log = logger.get_logger(__name__)
|
||||
def init(ctx):
|
||||
"""Initialise the toolbelt."""
|
||||
create_configuration_directory()
|
||||
clone_infrastructure_repo()
|
||||
create_configuration_file()
|
||||
clone_infrastructure_repo()
|
||||
ask_to_login()
|
||||
install_dependencies()
|
||||
|
||||
|
||||
def create_configuration_directory():
|
||||
@ -39,13 +40,13 @@ def create_configuration_directory():
|
||||
def clone_infrastructure_repo():
|
||||
"""Clone the infrastructure repository."""
|
||||
if not os.path.exists(INFRASTRUCTURE_PATH):
|
||||
ensure_installed("git")
|
||||
run_command(
|
||||
["git", "clone", INFRASTRUCTURE_REPOSITORY, INFRASTRUCTURE_PATH]
|
||||
)
|
||||
else:
|
||||
os.chdir(INFRASTRUCTURE_PATH)
|
||||
run_command(["git", "pull", "origin", "master"])
|
||||
run_command(
|
||||
["git", "pull", "origin", "master"], cwd=INFRASTRUCTURE_PATH
|
||||
)
|
||||
|
||||
|
||||
def ask_to_login():
|
||||
@ -75,3 +76,20 @@ def create_configuration_file():
|
||||
if not os.path.exists(AUTONOMIC_YAML):
|
||||
with open(AUTONOMIC_YAML, "w") as handle:
|
||||
handle.write("---")
|
||||
|
||||
|
||||
def install_dependencies():
|
||||
"""Install infrastructure dependencies."""
|
||||
run_command(
|
||||
["/usr/bin/python3", "-m", "venv", ".venv"], cwd=INFRASTRUCTURE_PATH,
|
||||
)
|
||||
|
||||
run_command(
|
||||
[".venv/bin/pip", "install", "-r", "requirements.txt"],
|
||||
cwd=INFRASTRUCTURE_PATH,
|
||||
)
|
||||
|
||||
run_command(
|
||||
[".venv/bin/ansible-galaxy", "install", "-r", "requirements.yml"],
|
||||
cwd=INFRASTRUCTURE_PATH,
|
||||
)
|
||||
|
@ -32,3 +32,17 @@ def add_to_config(data):
|
||||
|
||||
with open(AUTONOMIC_YAML, "w") as handle:
|
||||
yaml.dump(config, handle)
|
||||
|
||||
|
||||
def get_from_config(key):
|
||||
"""Get values from the autonomic.yml file."""
|
||||
ensure_config()
|
||||
|
||||
with open(AUTONOMIC_YAML, "r") as handle:
|
||||
config = yaml.load(handle.read())
|
||||
|
||||
try:
|
||||
return config[key]
|
||||
except KeyError:
|
||||
msg = "Unable to retrieve {} from {}".format(key, AUTONOMIC_YAML)
|
||||
exit_with_msg(msg)
|
||||
|
22
autonomic/passstore.py
Normal file
22
autonomic/passstore.py
Normal file
@ -0,0 +1,22 @@
|
||||
"""Password store management module."""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from autonomic.settings import INFRASTRUCTURE_PATH, PASSWORD_STORE_PATH
|
||||
from autonomic.system import exit_with_msg
|
||||
|
||||
|
||||
def get_from_pass(path):
|
||||
"""Retrieve a password from the password store."""
|
||||
env = os.environ.copy()
|
||||
env.update({"PASSWORD_STORE_DIR": PASSWORD_STORE_PATH})
|
||||
|
||||
try:
|
||||
os.chdir(INFRASTRUCTURE_PATH)
|
||||
command = ["pass", "show", path]
|
||||
output = subprocess.check_output(command, env=env)
|
||||
return output.decode("utf-8").strip()
|
||||
except subprocess.CalledProcessError as exception:
|
||||
msg = "{} failed! Saw {}".format(" ".join(command), str(exception))
|
||||
exit_with_msg(msg)
|
@ -10,4 +10,8 @@ INFRASTRUCTURE_REPOSITORY = (
|
||||
)
|
||||
INFRASTRUCTURE_PATH = "{}/infrastructure".format(CONFIG_PATH)
|
||||
MEMBERS_YAML = "{}/resources/members.yml".format(INFRASTRUCTURE_PATH)
|
||||
ACTIONS_PATH = "{}/actions".format(INFRASTRUCTURE_PATH)
|
||||
AUTONOMIC_YAML = "{}/autonomic.yml".format(CONFIG_PATH)
|
||||
PASSWORD_STORE_PATH = "{}/credentials/password-store".format(
|
||||
INFRASTRUCTURE_PATH
|
||||
)
|
||||
|
@ -1,26 +1,43 @@
|
||||
"""System related functions."""
|
||||
|
||||
import shutil
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from autonomic import logger
|
||||
from autonomic.settings import PASSWORD_STORE_PATH
|
||||
|
||||
log = logger.get_logger(__name__)
|
||||
|
||||
|
||||
def ensure_installed(package):
|
||||
"""Ensure a system dependency is installed"""
|
||||
if shutil.which(package) is None:
|
||||
msg = "{} is not installed?".format(package)
|
||||
exit_with_msg(msg)
|
||||
|
||||
|
||||
def run_command(command):
|
||||
def run_command(command, cwd=None, output=False, extra_env=None):
|
||||
"""Run a command."""
|
||||
from autonomic.config import get_from_config
|
||||
|
||||
username = get_from_config("username")
|
||||
|
||||
env = os.environ.copy()
|
||||
env.update({"PASSWORD_STORE_DIR": PASSWORD_STORE_PATH})
|
||||
env.update({"REMOTE_USER": username})
|
||||
env.update({"ANSIBLE_USER": username})
|
||||
|
||||
for key, val in extra_env.items():
|
||||
env.update({key: val})
|
||||
|
||||
try:
|
||||
log.info("Running '{}'".format(" ".join(command)))
|
||||
subprocess.check_output(command)
|
||||
if cwd:
|
||||
os.chdir(cwd)
|
||||
|
||||
log.info(
|
||||
"Running {}{}".format(
|
||||
" ".join(command), " in {}".format(cwd) if cwd else ""
|
||||
)
|
||||
)
|
||||
|
||||
if output:
|
||||
subprocess.call(command, env=env)
|
||||
else:
|
||||
subprocess.check_output(command, env=env, stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as exception:
|
||||
msg = "{} failed! Saw {}".format(" ".join(command), str(exception))
|
||||
exit_with_msg(msg)
|
||||
|
Reference in New Issue
Block a user