diff options
| author | DmitriyEshenko <dmitriy.eshenko@vyos.io> | 2020-01-14 21:24:42 +0000 | 
|---|---|---|
| committer | DmitriyEshenko <dmitriy.eshenko@vyos.io> | 2020-01-14 21:24:42 +0000 | 
| commit | 187d34b82f80c9c251c81cf9b96aa8d52e9f21e2 (patch) | |
| tree | d73a378b2292f53465ae4021bb012ee31b7fcde8 | |
| parent | f7c3e427c19a0137f76a3291c888a21239b3a0db (diff) | |
| download | vyos-1x-187d34b82f80c9c251c81cf9b96aa8d52e9f21e2.tar.gz vyos-1x-187d34b82f80c9c251c81cf9b96aa8d52e9f21e2.zip  | |
vrrp: T1884: Keep transition-script native behaviour and implement transaction-script 'stop'
| -rw-r--r-- | interface-definitions/vrrp.xml.in | 8 | ||||
| -rw-r--r-- | python/vyos/keepalived.py | 31 | ||||
| -rwxr-xr-x | src/conf_mode/vrrp.py | 6 | ||||
| -rwxr-xr-x | src/op_mode/vrrp.py | 3 | ||||
| -rwxr-xr-x | src/system/vrrp-script-wrapper.py | 49 | 
5 files changed, 42 insertions, 55 deletions
diff --git a/interface-definitions/vrrp.xml.in b/interface-definitions/vrrp.xml.in index 2884ef613..89d22f79f 100644 --- a/interface-definitions/vrrp.xml.in +++ b/interface-definitions/vrrp.xml.in @@ -197,6 +197,14 @@                        </constraint>                      </properties>                    </leafNode> +                  <leafNode name="stop"> +                    <properties> +                      <help>Script to run on VRRP state transition to stop</help> +                      <constraint> +                        <validator name="script"/> +                      </constraint> +                    </properties> +                  </leafNode>                  </children>                </node>                <leafNode name="virtual-address"> diff --git a/python/vyos/keepalived.py b/python/vyos/keepalived.py index 4114aa736..3984ca792 100644 --- a/python/vyos/keepalived.py +++ b/python/vyos/keepalived.py @@ -26,8 +26,6 @@ state_file = '/tmp/keepalived.data'  stats_file = '/tmp/keepalived.stats'  json_file = '/tmp/keepalived.json' -state_dir = '/var/run/vyos/vrrp/' -  def vrrp_running():      if not os.path.exists(vyos.keepalived.pid_file) \        or not vyos.util.process_running(vyos.keepalived.pid_file): @@ -38,6 +36,15 @@ def vrrp_running():  def keepalived_running():      return vyos.util.process_running(pid_file) +## Clear VRRP data after showing +def remove_vrrp_data(data_file): +    if data_file == "json" and os.path.exists(json_file): +        os.remove(json_file) +    elif data_file == "stats" and os.path.exists(stats_file): +        os.remove(stats_file) +    elif data_file == "state" and os.path.exists(state_file): +        os.remove(state_file) +  def force_state_data_dump():      pid = vyos.util.read_file(pid_file)      os.kill(int(pid), signal.SIGUSR1) @@ -76,26 +83,6 @@ def decode_state(code):      return state -## The functions are mainly for transition script wrappers -## to compensate for the fact that keepalived doesn't keep persistent -## state between reloads. -def get_old_state(group): -    file = os.path.join(state_dir, "{0}.state".format(group)) -    if os.path.exists(file): -        with open(file, 'r') as f: -            data = f.read().strip() -            return data -    else: -       return None - -def save_state(group, state): -    if not os.path.exists(state_dir): -        os.makedirs(state_dir) - -    file = os.path.join(state_dir, "{0}.state".format(group)) -    with open(file, 'w') as f: -        f.write(state) -  ## These functions are for the old, and hopefully obsolete plaintext  ## (non machine-readable) data format introduced by Vyatta back in the days  ## They are kept here just in case, if JSON output option turns out or becomes diff --git a/src/conf_mode/vrrp.py b/src/conf_mode/vrrp.py index d31be4cfb..1d8477769 100755 --- a/src/conf_mode/vrrp.py +++ b/src/conf_mode/vrrp.py @@ -37,6 +37,7 @@ config_tmpl = """  global_defs {      dynamic_interfaces +    script_user root  }  {% for group in groups -%} @@ -117,6 +118,10 @@ vrrp_instance {{ group.name }} {      {% if group.fault_script -%}          notify_fault "/usr/libexec/vyos/system/vrrp-script-wrapper.py --state fault --group {{ group.name }} --interface {{ group.interface }} {{ group.fault_script }}"      {% endif -%} + +    {% if group.stop_script -%} +        notify_stop "/usr/libexec/vyos/system/vrrp-script-wrapper.py --state stop --group {{ group.name }} --interface {{ group.interface }} {{ group.stop_script }}" +    {% endif -%}  }  {% endfor -%} @@ -178,6 +183,7 @@ def get_config():          group["master_script"] = config.return_value("transition-script master")          group["backup_script"] = config.return_value("transition-script backup")          group["fault_script"] = config.return_value("transition-script fault") +        group["stop_script"] = config.return_value("transition-script stop")          if config.exists("no-preempt"):              group["preempt"] = False diff --git a/src/op_mode/vrrp.py b/src/op_mode/vrrp.py index 54e1bfb57..8d1369823 100755 --- a/src/op_mode/vrrp.py +++ b/src/op_mode/vrrp.py @@ -32,6 +32,7 @@ def print_summary():          # Replace with inotify or similar if it proves problematic          time.sleep(0.2)          json_data = vyos.keepalived.get_json_data() +        vyos.keepalived.remove_vrrp_data("json")      except:          print("VRRP information is not available")          sys.exit(1) @@ -63,6 +64,7 @@ def print_statistics():          time.sleep(0.2)          output = vyos.keepalived.get_statistics()          print(output) +        vyos.keepalived.remove_vrrp_data("stats")      except:          print("VRRP statistics are not available")          sys.exit(1) @@ -73,6 +75,7 @@ def print_state_data():          time.sleep(0.2)          output = vyos.keepalived.get_state_data()          print(output) +        vyos.keepalived.remove_vrrp_data("state")      except:          print("VRRP information is not available")          sys.exit(1) diff --git a/src/system/vrrp-script-wrapper.py b/src/system/vrrp-script-wrapper.py index ccd640128..c28ecba55 100755 --- a/src/system/vrrp-script-wrapper.py +++ b/src/system/vrrp-script-wrapper.py @@ -23,7 +23,6 @@ import argparse  import syslog  import vyos.util -import vyos.keepalived  parser = argparse.ArgumentParser() @@ -44,38 +43,22 @@ if not args.script or not args.state or not args.group \  # to pass arguments to the script  args.script = " ".join(args.script) -# Get the old state if it exists and compare it to the current state received -# in command line options to avoid executing scripts if no real transition occured. -# This is necessary because keepalived does not keep persistent state data even between -# config reloads and will cheerfully execute everything whether it's required or not. - -old_state = vyos.keepalived.get_old_state(args.group) - -if (old_state is None) or (old_state != args.state): -    exitcode = 0 - -    # Run the script and save the new state - -    # Change the process GID to the config owners group to avoid screwing up -    # running config permissions -    os.setgid(vyos.util.get_cfg_group_id()) - -    syslog.syslog(syslog.LOG_NOTICE, 'Running transition script {0} for VRRP group {1}'.format(args.script, args.group)) -    try: -       ret = subprocess.call("%s %s %s %s" % ( args.script, args.state, args.interface, args.group), shell=True) -       if ret != 0: -           syslog.syslog(syslog.LOG_ERR, "Transition script {0} failed, exit status: {1}".format(args.script, ret)) -           exitcode = ret -    except Exception as e: -        syslog.syslog(syslog.LOG_ERR, "Failed to execute transition script {0}: {1}".format(args.script, e)) -        exitcode = 1 - -    if exitcode == 0: -        syslog.syslog(syslog.LOG_NOTICE, "Transition script {0} executed successfully".format(args.script)) - -    vyos.keepalived.save_state(args.group, args.state) -else: -    syslog.syslog(syslog.LOG_NOTICE, "State of the group {0} has not changed, not running transition script".format(args.group)) +exitcode = 0 +# Change the process GID to the config owners group to avoid screwing up +# running config permissions +os.setgid(vyos.util.get_cfg_group_id()) +syslog.syslog(syslog.LOG_NOTICE, 'Running transition script {0} for VRRP group {1}'.format(args.script, args.group)) +try: +    ret = subprocess.call("%s %s %s %s" % ( args.script, args.state, args.interface, args.group), shell=True) +    if ret != 0: +        syslog.syslog(syslog.LOG_ERR, "Transition script {0} failed, exit status: {1}".format(args.script, ret)) +        exitcode = ret +except Exception as e: +    syslog.syslog(syslog.LOG_ERR, "Failed to execute transition script {0}: {1}".format(args.script, e)) +    exitcode = 1 + +if exitcode == 0: +    syslog.syslog(syslog.LOG_NOTICE, "Transition script {0} executed successfully".format(args.script))  syslog.closelog()  sys.exit(exitcode)  | 
