Charmed-Kubernetes/etcd/actions/compact

145 lines
3.4 KiB
Plaintext
Executable File

#!/usr/local/sbin/charm-env python3
import os
import re
import shlex
import subprocess
import sys
from charms import layer
from etcdctl import EtcdCtl
from charmhelpers.core.hookenv import (
action_get,
action_set,
action_fail,
action_name
)
CTL = EtcdCtl()
def action_fail_now(*args, **kw):
'''Call action_fail() and exit immediately.
'''
action_fail(*args, **kw)
sys.exit(0)
def requires_etcd_version(version_regex, human_version=None):
'''Decorator that enforces a specific version of etcdctl be present.
The decorated function will only be executed if the required version
of etcdctl is present. Otherwise, action_fail() will be called and
the process will exit immediately.
'''
def wrap(f):
def wrapped_f(*args):
version = CTL.version()
if not re.match(version_regex, version):
required_version = human_version or version_regex
action_fail_now(
'This action requires etcd version {}'.format(
required_version))
f(*args)
return wrapped_f
return wrap
requires_etcd_v2 = requires_etcd_version(r'2\..*', human_version='2.x')
requires_etcd_v3 = requires_etcd_version(r'3\..*', human_version='3.x')
@requires_etcd_v3
def alarm_disarm():
'''Call `etcdctl alarm disarm`.
'''
try:
output = CTL.run('alarm disarm')
action_set(dict(output=output))
except subprocess.CalledProcessError as e:
action_fail_now(e.output)
@requires_etcd_v3
def alarm_list():
'''Call `etcdctl alarm list`.
'''
try:
output = CTL.run('alarm list')
action_set(dict(output=output))
except subprocess.CalledProcessError as e:
action_fail_now(e.output)
@requires_etcd_v3
def compact():
'''Call `etcdctl compact`.
'''
def get_latest_revision():
try:
output = CTL.run('endpoint status --write-out json')
except subprocess.CalledProcessError as e:
action_fail_now(
'Failed to determine latest revision for '
'compaction: {}'.format(e))
m = re.search(r'"revision":(\d*)', output)
if not m:
action_fail_now(
"Failed to get revision from 'endpoint status' "
"output: {}".format(output))
return m.group(1)
revision = action_get('revision') or get_latest_revision()
physical = 'true' if action_get('physical') else 'false'
command = 'compact {} --physical={}'.format(revision, physical)
try:
output = CTL.run(command)
action_set(dict(output=output))
except subprocess.CalledProcessError as e:
action_fail_now(e.output)
@requires_etcd_v3
def defrag():
'''Call `etcdctl defrag`.
'''
try:
output = CTL.run('defrag')
action_set(dict(output=output))
except subprocess.CalledProcessError as e:
action_fail_now(e.output)
def health():
'''Call etcdctl cluster-health
'''
try:
output = CTL.cluster_health(True)
action_set(dict(output=output))
except subprocess.CalledProcessError as e:
action_fail_now(e.output)
if __name__ == '__main__':
ACTIONS = {
'alarm-disarm': alarm_disarm,
'alarm-list': alarm_list,
'compact': compact,
'defrag': defrag,
'health': health,
}
action = action_name()
ACTIONS[action]()