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)