github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/acceptancetests/repository/charms/peer-xplod/hooks/update.py (about) 1 #!/usr/bin/env python 2 3 import datetime 4 import errno 5 import json 6 import os 7 import subprocess 8 import time 9 10 defaultMaximum = 1000 11 unitName = os.environ.get('JUJU_UNIT_NAME') 12 13 def run_json(cmd): 14 """run a command, treat the output as JSON and return the parsed result.""" 15 try: 16 out = subprocess.check_output(cmd + ['--format=json']) 17 except subprocess.CalledProcessError as e: 18 raise 19 return json.loads(out) 20 21 22 def juju_log(msg): 23 print msg 24 #subprocess.check_call(["juju-log", msg]) 25 26 27 STATE_MAINTENANCE = "maintenance" 28 STATE_BLOCKED = "blocked" 29 STATE_WAITING = "waiting" 30 STATE_ACTIVE = "active" 31 32 def set_unit_status(state, msg=""): 33 """Set the state of this unit and give a message. 34 35 For compatibility, this is a no-op if 'status-set' doesn't exist. 36 """ 37 try: 38 subprocess.check_call(["status-set", state, msg]) 39 except os.Error as e: 40 if e.errno == errno.ENOENT: 41 return 42 raise 43 44 45 def my_relation_id(): 46 """xplod is a peer relation, so we know there is only one relation-id.""" 47 relation_ids = run_json(["relation-ids", "xplod"]) 48 if len(relation_ids) == 0: 49 # This can happen in 'config-changed' before we join the peer relation 50 return None 51 assert len(relation_ids) == 1 52 return relation_ids[0] 53 54 def my_info(relation_id=None): 55 cmd = ["relation-get"] 56 if relation_id is not None: 57 cmd.extend(["-r", relation_id]) 58 cmd.extend(["-", unitName]) 59 return run_json(cmd) 60 61 def my_config(): 62 return run_json(["config-get"]) 63 64 def remote_info(): 65 return run_json(["relation-get", "-"]) 66 67 def relation_set(relation_id=None, **kwargs): 68 args = [] 69 for key in sorted(kwargs.keys()): 70 args.append('%s=%s' % (key, kwargs[key])) 71 cmd = ["relation-set"] 72 if relation_id is not None: 73 cmd.extend(["-r", relation_id]) 74 subprocess.check_call(cmd + args) 75 76 77 def check_if_started(info, relation_id=None): 78 """Check if info contains a 'started' field, and if not, create it.""" 79 if 'started' in info: 80 return 81 now = time.time() 82 utc_date = datetime.datetime.utcfromtimestamp(now) 83 relation_set(relation_id=relation_id, 84 started=utc_date.isoformat(), 85 started_timestamp=("%d"% (now,)), 86 ) 87 88 89 def determine_new_value(info, other): 90 my_v = int(info.get("v", 0)) 91 other_v = int(other.get("v", 0)) 92 if my_v > other_v: 93 juju_log("local v greater %s > %s" % (my_v, other_v)) 94 v = my_v 95 else: 96 v = other_v 97 return v + 1 98 99 100 def determine_maximum(config): 101 return int(config.get('maximum', defaultMaximum)) 102 103 104 def check_set_stopped(info, v, relation_id=None): 105 # Check if stopped has a value in it 106 if "stopped" in info and info["stopped"]: 107 return 108 now = time.time() 109 utc_date = datetime.datetime.utcfromtimestamp(now) 110 total = 0 111 if 'started_timestamp' in info: 112 started_timestamp = int(info['started_timestamp']) 113 total = now - started_timestamp 114 relation_set(relation_id=relation_id, 115 stopped=utc_date.isoformat(), 116 stopped_timestamp=("%d"% (now,)), 117 total_time=("%d"% (total,)), 118 v=v, 119 ) 120 121 122 def update_locally(): 123 """Not run in a relation context, so we have to determine more information.""" 124 relation_id = my_relation_id() 125 if relation_id is None: 126 juju_log("no relation-id, no peers visible") 127 set_unit_status(STATE_WAITING, "waiting for peers") 128 return 129 130 info = my_info(relation_id=relation_id) 131 check_if_started(info, relation_id=relation_id) 132 config = my_config() 133 maximum = determine_maximum(config) 134 v = int(info.get("v", 0)) + 1 135 check_set_v(v, maximum, info, relation_id=relation_id) 136 137 138 def check_set_v(v, maximum, info, relation_id=None): 139 if maximum <= 0 or v <= maximum: 140 juju_log("setting v %s.v=%s" % (unitName, v)) 141 relation_set(relation_id=relation_id, v=v, stopped="") 142 set_unit_status(STATE_ACTIVE) 143 else: 144 juju_log("maximum (%s) exceeded %s" % (maximum, v)) 145 check_set_stopped(info, maximum, relation_id=relation_id) 146 set_unit_status(STATE_WAITING, "reached maximum count %d" % (maximum,)) 147 148 149 def update_value(): 150 info = my_info() 151 check_if_started(info) 152 config = my_config() 153 other = remote_info() 154 maximum = determine_maximum(config) 155 v = determine_new_value(info, other) 156 check_set_v(v, maximum, info)