ifstate 1.12.0__tar.gz → 1.13.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ifstate-1.12.0 → ifstate-1.13.0}/PKG-INFO +1 -1
- {ifstate-1.12.0 → ifstate-1.13.0}/ifstate/ifstate.py +39 -27
- ifstate-1.13.0/ifstate/vrrp.py +166 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/ifstate.egg-info/PKG-INFO +1 -1
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/__init__.py +2 -10
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/parser/base.py +7 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/parser/yaml.py +3 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/routing/__init__.py +2 -2
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/util.py +19 -1
- {ifstate-1.12.0 → ifstate-1.13.0}/schema/ifstate.conf.schema.json +27 -1
- ifstate-1.12.0/ifstate/vrrp.py +0 -113
- {ifstate-1.12.0 → ifstate-1.13.0}/LICENSE +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/README.md +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/ifstate/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/ifstate/shell.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/ifstate.egg-info/SOURCES.txt +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/ifstate.egg-info/dependency_links.txt +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/ifstate.egg-info/entry_points.txt +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/ifstate.egg-info/requires.txt +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/ifstate.egg-info/top_level.txt +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/address/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/bpf/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/bpf/ctypes.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/bpf/map.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/brport/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/exception.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/fdb/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/link/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/link/base.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/link/dsa.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/link/physical.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/link/tun.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/link/veth.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/log.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/neighbour/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/netns/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/parser/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/sysctl/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/tc/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/wireguard/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/libifstate/xdp/__init__.py +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/setup.cfg +0 -0
- {ifstate-1.12.0 → ifstate-1.13.0}/setup.py +0 -0
@@ -24,16 +24,18 @@ class Actions():
|
|
24
24
|
SHOWALL = "showall"
|
25
25
|
VRRP = "vrrp"
|
26
26
|
VRRP_FIFO = "vrrp-fifo"
|
27
|
+
VRRP_WORKER = "vrrp-worker"
|
27
28
|
SHELL = "shell"
|
28
29
|
|
29
30
|
ACTIONS_HELP = {
|
30
|
-
"CHECK"
|
31
|
-
"APPLY"
|
32
|
-
"SHOW"
|
33
|
-
"SHOWALL"
|
34
|
-
"VRRP"
|
35
|
-
"VRRP_FIFO": "run as keepalived notify_fifo_script",
|
36
|
-
"
|
31
|
+
"CHECK" : "dry run update the network config",
|
32
|
+
"APPLY" : "update the network config",
|
33
|
+
"SHOW" : "show running network config",
|
34
|
+
"SHOWALL" : "show running network config (more settings)",
|
35
|
+
"VRRP" : "run as keepalived notify script",
|
36
|
+
"VRRP_FIFO" : "run as keepalived notify_fifo_script",
|
37
|
+
"VRRP_WORKER": "worker process for vrrp-fifo",
|
38
|
+
"SHELL" : "launch interactive python shell (pyroute2)",
|
37
39
|
}
|
38
40
|
|
39
41
|
class IfsConfigHandler():
|
@@ -41,23 +43,22 @@ class IfsConfigHandler():
|
|
41
43
|
self.fn = fn
|
42
44
|
self.soft_schema = soft_schema
|
43
45
|
|
46
|
+
# require to be called from the root netns
|
47
|
+
try:
|
48
|
+
# assume init runs in the root netns
|
49
|
+
if os.readlink('/proc/1/ns/net') != os.readlink(f'/proc/{os.getpid()}/ns/net'):
|
50
|
+
logger.error("Must not be run from inside a netns!")
|
51
|
+
raise NetNSNotRoot()
|
52
|
+
except OSError as ex:
|
53
|
+
logger.debug(f'root netns test: {ex}')
|
54
|
+
pass
|
55
|
+
|
44
56
|
self.ifs = self.load_config()
|
45
57
|
self.cb = None
|
46
58
|
|
47
|
-
def set_callback(self, cb):
|
48
|
-
self.cb = cb
|
49
|
-
|
50
|
-
def sighup_handler(self, signum, frame):
|
51
|
-
logger.info("SIGHUP: reloading configuration")
|
52
|
-
try:
|
53
|
-
self.ifs = self.load_config()
|
54
|
-
self.cb(self.ifs)
|
55
|
-
except:
|
56
|
-
logger.exception("failed to reload configuration")
|
57
|
-
|
58
59
|
def load_config(self):
|
59
60
|
try:
|
60
|
-
parser = YamlParser(self.fn)
|
61
|
+
self.parser = YamlParser(self.fn)
|
61
62
|
except ParserOpenError as ex:
|
62
63
|
logger.error(
|
63
64
|
"Config loading from {} failed: {}".format(ex.fn, ex.msg))
|
@@ -71,10 +72,8 @@ class IfsConfigHandler():
|
|
71
72
|
raise ex
|
72
73
|
|
73
74
|
try:
|
74
|
-
ifstates = parser.config()
|
75
|
-
|
76
75
|
ifs = IfState()
|
77
|
-
ifs.update(
|
76
|
+
ifs.update(self.parser.config(), self.soft_schema)
|
78
77
|
return ifs
|
79
78
|
except ParserValidationError as ex:
|
80
79
|
logger.error("Config validation failed for {}".format(ex.detail))
|
@@ -83,10 +82,14 @@ class IfsConfigHandler():
|
|
83
82
|
logger.error(
|
84
83
|
"Config uses unavailable feature: {}".format(ex.feature))
|
85
84
|
raise ex
|
86
|
-
except NetNSNotRoot as ex:
|
87
|
-
logger.error("Must not be run from inside a netns!")
|
88
|
-
raise ex
|
89
85
|
|
86
|
+
def dump_config(self, fn):
|
87
|
+
umask = os.umask(0o077)
|
88
|
+
try:
|
89
|
+
with open(fn, "w") as fh:
|
90
|
+
self.parser.dump(fh)
|
91
|
+
finally:
|
92
|
+
os.umask(umask)
|
90
93
|
|
91
94
|
def shell():
|
92
95
|
from ifstate.shell import IfStateConsole
|
@@ -151,6 +154,12 @@ def main():
|
|
151
154
|
action_parsers[Actions.VRRP_FIFO].add_argument(
|
152
155
|
"fifo", type=str, help="named FIFO to read state changes from")
|
153
156
|
|
157
|
+
# Parameters for the vrrp-worker action
|
158
|
+
action_parsers[Actions.VRRP_WORKER].add_argument(
|
159
|
+
"type", type=str.lower, choices=["group", "instance"], help="type of vrrp notification")
|
160
|
+
action_parsers[Actions.VRRP_WORKER].add_argument(
|
161
|
+
"name", type=str, help="name of the vrrp group or instance")
|
162
|
+
|
154
163
|
args = parser.parse_args()
|
155
164
|
if args.verbose:
|
156
165
|
lvl = logging.DEBUG
|
@@ -181,7 +190,7 @@ def main():
|
|
181
190
|
ifslog.quit()
|
182
191
|
exit(0)
|
183
192
|
|
184
|
-
if args.action in [Actions.CHECK, Actions.APPLY, Actions.VRRP, Actions.VRRP_FIFO]:
|
193
|
+
if args.action in [Actions.CHECK, Actions.APPLY, Actions.VRRP, Actions.VRRP_FIFO, Actions.VRRP_WORKER]:
|
185
194
|
try:
|
186
195
|
ifs_config = IfsConfigHandler(args.config, args.soft_schema)
|
187
196
|
except (ParserOpenError,
|
@@ -203,7 +212,10 @@ def main():
|
|
203
212
|
exit(ex.exit_code())
|
204
213
|
elif args.action == Actions.VRRP_FIFO:
|
205
214
|
from ifstate.vrrp import vrrp_fifo
|
206
|
-
vrrp_fifo(args.fifo, ifs_config
|
215
|
+
vrrp_fifo(args.fifo, ifs_config)
|
216
|
+
elif args.action == Actions.VRRP_WORKER:
|
217
|
+
from ifstate.vrrp import vrrp_worker
|
218
|
+
vrrp_worker(args.type, args.name, ifs_config)
|
207
219
|
else:
|
208
220
|
# ignore some well-known signals to prevent interruptions (i.e. due to ssh connection loss)
|
209
221
|
signal.signal(signal.SIGHUP, signal.SIG_IGN)
|
@@ -0,0 +1,166 @@
|
|
1
|
+
from libifstate.util import logger, IfStateLogging
|
2
|
+
|
3
|
+
import atexit
|
4
|
+
from copy import deepcopy
|
5
|
+
import logging
|
6
|
+
import multiprocessing as mp
|
7
|
+
import threading
|
8
|
+
import os
|
9
|
+
import re
|
10
|
+
from setproctitle import setproctitle
|
11
|
+
import signal
|
12
|
+
import subprocess
|
13
|
+
import sys
|
14
|
+
|
15
|
+
class VrrpFifoProcess():
|
16
|
+
'''
|
17
|
+
Process for vrrp group/instance configuration.
|
18
|
+
'''
|
19
|
+
def __init__(self, worker_args):
|
20
|
+
self.worker_args = worker_args
|
21
|
+
self.logger_extra = {'iface': f'{worker_args[-2]} "{worker_args[-1]}"'}
|
22
|
+
self.state_queue = mp.Queue()
|
23
|
+
self.worker_proc = None
|
24
|
+
|
25
|
+
worker_io = threading.Thread(target=self.dequeue)
|
26
|
+
worker_io.start()
|
27
|
+
|
28
|
+
def vrrp_update(self, vrrp_state):
|
29
|
+
self.state_queue.put(vrrp_state)
|
30
|
+
|
31
|
+
def dequeue(self):
|
32
|
+
while True:
|
33
|
+
state = self.state_queue.get()
|
34
|
+
|
35
|
+
# Should we terminate?
|
36
|
+
if state is None:
|
37
|
+
self.worker_proc.stdin.close()
|
38
|
+
self.worker_proc.wait()
|
39
|
+
return
|
40
|
+
|
41
|
+
# Restart ifstate vrrp-worker if not alive alive?
|
42
|
+
if self.worker_proc.poll() is not None:
|
43
|
+
logger.warning("worker died", extra=self.logger_extra)
|
44
|
+
self.start()
|
45
|
+
|
46
|
+
logger.info(f'state => {state}', extra=self.logger_extra)
|
47
|
+
self.worker_proc.stdin.write(f'{state}\n')
|
48
|
+
self.worker_proc.stdin.flush()
|
49
|
+
logger.warning("dequeue terminated")
|
50
|
+
|
51
|
+
def start(self):
|
52
|
+
logger.info("spawning worker", extra=self.logger_extra)
|
53
|
+
self.worker_proc = subprocess.Popen(self.worker_args, stdin=subprocess.PIPE, stderr=sys.stderr, text=True)
|
54
|
+
|
55
|
+
|
56
|
+
class VrrpStates():
|
57
|
+
'''
|
58
|
+
Tracks processes and states for vrrp groups/instances.
|
59
|
+
'''
|
60
|
+
def __init__(self, ifs_config):
|
61
|
+
self.ifs_config = ifs_config
|
62
|
+
self.processes = {}
|
63
|
+
self.states = {}
|
64
|
+
self.pid_file = f"/run/libifstate/vrrp/{os.getpid()}.pid"
|
65
|
+
self.cfg_file = f"/run/libifstate/vrrp/{os.getpid()}.cfg"
|
66
|
+
self.worker_args = (
|
67
|
+
sys.argv[0],
|
68
|
+
'-c', self.cfg_file,
|
69
|
+
'vrrp-worker')
|
70
|
+
if logger.level == logging.DEBUG:
|
71
|
+
self.worker_args.append('-v')
|
72
|
+
|
73
|
+
def update(self, vrrp_type, vrrp_name, vrrp_state):
|
74
|
+
'''
|
75
|
+
Updates the state for a group/instance. A new VrrpFifoProcess is spawned on-demand
|
76
|
+
if a group/instance is called the first time.
|
77
|
+
'''
|
78
|
+
key = (vrrp_type, vrrp_name)
|
79
|
+
if not key in self.processes:
|
80
|
+
worker_args = self.worker_args + key
|
81
|
+
self.processes[key] = VrrpFifoProcess(worker_args)
|
82
|
+
self.processes[key].start()
|
83
|
+
|
84
|
+
self.states[key] = vrrp_state
|
85
|
+
self.processes[key].vrrp_update(vrrp_state)
|
86
|
+
|
87
|
+
def reconfigure(self, *argv):
|
88
|
+
'''
|
89
|
+
Reconfigure all known groups/instances using their last known state by spawning
|
90
|
+
new worker Processes.
|
91
|
+
'''
|
92
|
+
|
93
|
+
# save new config to temp file
|
94
|
+
try:
|
95
|
+
self.ifs_config.load_config()
|
96
|
+
self.ifs_config.dump_config(self.cfg_file)
|
97
|
+
except Exception as ex:
|
98
|
+
logger.error(f'failed to reload config: {ex}')
|
99
|
+
return
|
100
|
+
|
101
|
+
for key, state in self.states.items():
|
102
|
+
worker_args = self.worker_args + key
|
103
|
+
self.processes[key].vrrp_update(None)
|
104
|
+
self.processes[key] = VrrpFifoProcess(worker_args)
|
105
|
+
self.processes[key].start()
|
106
|
+
self.processes[key].vrrp_update(self.states[key])
|
107
|
+
|
108
|
+
def cleanup_run(self, *argv):
|
109
|
+
"""
|
110
|
+
"""
|
111
|
+
for file in [self.pid_file, self.cfg_file]:
|
112
|
+
try:
|
113
|
+
os.unlink(file)
|
114
|
+
except OSError as ex:
|
115
|
+
if ex.errno != 2:
|
116
|
+
logger.warning(f"cannot cleanup {file}: {ex}")
|
117
|
+
|
118
|
+
def vrrp_fifo(args_fifo, ifs_config):
|
119
|
+
vrrp_states = VrrpStates(ifs_config)
|
120
|
+
|
121
|
+
signal.signal(signal.SIGHUP, vrrp_states.reconfigure)
|
122
|
+
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
|
123
|
+
signal.signal(signal.SIGTERM, vrrp_states.cleanup_run)
|
124
|
+
|
125
|
+
try:
|
126
|
+
os.makedirs("/run/libifstate/vrrp", exist_ok=True)
|
127
|
+
|
128
|
+
with open(vrrp_states.pid_file, "w", encoding="utf-8") as fh:
|
129
|
+
fh.write(args_fifo)
|
130
|
+
atexit.register(vrrp_states.cleanup_run)
|
131
|
+
|
132
|
+
ifs_config.dump_config(vrrp_states.cfg_file)
|
133
|
+
except IOError as err:
|
134
|
+
logger.exception(f'failed to write pid file {vrrp_states.pid_file}: {err}')
|
135
|
+
|
136
|
+
try:
|
137
|
+
status_pattern = re.compile(
|
138
|
+
r'(group|instance) "([^"]+)" (unknown|fault|backup|master|stop)( \d+)?$', re.IGNORECASE)
|
139
|
+
|
140
|
+
with open(args_fifo) as fifo:
|
141
|
+
logger.debug("entering fifo loop...")
|
142
|
+
for line in fifo:
|
143
|
+
m = status_pattern.match(line.strip())
|
144
|
+
if m:
|
145
|
+
vrrp_type = m.group(1)
|
146
|
+
vrrp_name = m.group(2)
|
147
|
+
vrrp_state = m.group(3)
|
148
|
+
|
149
|
+
vrrp_states.update(vrrp_type, vrrp_name, vrrp_state)
|
150
|
+
else:
|
151
|
+
logger.warning(f'failed to parse fifo input: {line.strip()}')
|
152
|
+
mp.active_children()
|
153
|
+
finally:
|
154
|
+
vrrp_states.cleanup_run()
|
155
|
+
|
156
|
+
def vrrp_worker(vrrp_type, vrrp_name, ifs_config):
|
157
|
+
instance_title = "vrrp-{}-{}".format(vrrp_type, vrrp_name)
|
158
|
+
setproctitle("ifstate-{}".format(instance_title))
|
159
|
+
|
160
|
+
logger.info('worker is alive')
|
161
|
+
for state in sys.stdin:
|
162
|
+
vrrp_state = state.strip()
|
163
|
+
|
164
|
+
ifstate = deepcopy(ifs_config.ifs)
|
165
|
+
ifstate.apply(vrrp_type, vrrp_name, vrrp_state)
|
166
|
+
logger.info('terminating')
|
@@ -6,7 +6,7 @@ from libifstate.neighbour import Neighbours
|
|
6
6
|
from libifstate.routing import Tables, Rules, RTLookups
|
7
7
|
from libifstate.parser import Parser
|
8
8
|
from libifstate.tc import TC
|
9
|
-
from libifstate.exception import netlinkerror_classes
|
9
|
+
from libifstate.exception import netlinkerror_classes
|
10
10
|
import bisect
|
11
11
|
import os
|
12
12
|
import pyroute2
|
@@ -48,7 +48,7 @@ import json
|
|
48
48
|
import errno
|
49
49
|
import logging
|
50
50
|
|
51
|
-
__version__ = "1.
|
51
|
+
__version__ = "1.13.0"
|
52
52
|
|
53
53
|
|
54
54
|
class IfState():
|
@@ -120,14 +120,6 @@ class IfState():
|
|
120
120
|
|
121
121
|
self._update(self.root_netns, ifstates)
|
122
122
|
if 'namespaces' in ifstates:
|
123
|
-
# require to called from the root netns
|
124
|
-
try:
|
125
|
-
# assume init runs in the root netns
|
126
|
-
if os.readlink('/proc/1/ns/net') != os.readlink(f'/proc/{os.getpid()}/ns/net'):
|
127
|
-
raise NetNSNotRoot()
|
128
|
-
except OSError as ex:
|
129
|
-
logger.debug(f'root netns test: {ex}')
|
130
|
-
pass
|
131
123
|
self.namespaces = {}
|
132
124
|
self.new_namespaces = []
|
133
125
|
for netns_name, netns_ifstates in ifstates['namespaces'].items():
|
@@ -61,7 +61,7 @@ class RTLookup():
|
|
61
61
|
self.str2id = {}
|
62
62
|
self.id2str = {}
|
63
63
|
|
64
|
-
for basedir in ['/usr/lib/iproute2', '/etc/iproute2']:
|
64
|
+
for basedir in ['/usr/share/iproute2', '/usr/lib/iproute2', '/etc/iproute2']:
|
65
65
|
fn = os.path.join(basedir, name)
|
66
66
|
try:
|
67
67
|
with open(fn, 'r') as fp:
|
@@ -307,7 +307,7 @@ class Tables(collections.abc.Mapping):
|
|
307
307
|
|
308
308
|
kroutes = self.kernel_routes(table)
|
309
309
|
|
310
|
-
for route in croutes:
|
310
|
+
for route in sorted(croutes, key=lambda x: [x.get('via', ''), x['dst']]):
|
311
311
|
if 'oif' in route and type(route['oif']) == str:
|
312
312
|
oif = next(
|
313
313
|
iter(self.netns.ipr.link_lookup(ifname=route['oif'])), None)
|
@@ -23,6 +23,7 @@ import struct
|
|
23
23
|
import array
|
24
24
|
import struct
|
25
25
|
import typing
|
26
|
+
import os
|
26
27
|
|
27
28
|
# ethtool helper
|
28
29
|
ETHTOOL_GDRVINFO = 0x00000003 # Get driver info
|
@@ -64,6 +65,23 @@ class IPRouteExt(IPRoute):
|
|
64
65
|
|
65
66
|
self.__sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
66
67
|
|
68
|
+
|
69
|
+
|
70
|
+
# def fork_before():
|
71
|
+
# import sys
|
72
|
+
# print(f"FORK[{os.getpid()}] before", file=sys.stderr)
|
73
|
+
|
74
|
+
# def fork_parent():
|
75
|
+
# import sys
|
76
|
+
# print(f"FORK[{os.getpid()}] parent", file=sys.stderr)
|
77
|
+
|
78
|
+
# def fork_child():
|
79
|
+
# import sys
|
80
|
+
# print(f"FORK[{os.getpid()}] after", file=sys.stderr)
|
81
|
+
|
82
|
+
# os.register_at_fork(before=fork_before, after_in_parent=fork_parent, after_in_child=fork_child)
|
83
|
+
|
84
|
+
|
67
85
|
def del_filter_by_info(self, index=0, handle=0, info=0, parent=0):
|
68
86
|
msg = tcmsg()
|
69
87
|
msg['index'] = index
|
@@ -173,7 +191,7 @@ class IPRouteExt(IPRoute):
|
|
173
191
|
try:
|
174
192
|
return next(iter(self.get_links(*argv, **kwarg)), None)
|
175
193
|
except Exception as err:
|
176
|
-
if not isinstance(err, netlinkerror_classes):
|
194
|
+
if not isinstance(err, libifstate.exception.netlinkerror_classes):
|
177
195
|
raise
|
178
196
|
|
179
197
|
return None
|
@@ -2,7 +2,7 @@
|
|
2
2
|
"$id": "https://ifstate.net/schema/ifstate.conf.schema.json",
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
4
4
|
"title": "ifstate.conf",
|
5
|
-
"description": "IfState 1.
|
5
|
+
"description": "IfState 1.13 Configuration Schema",
|
6
6
|
"type": "object",
|
7
7
|
"required": [
|
8
8
|
"interfaces"
|
@@ -3015,6 +3015,32 @@
|
|
3015
3015
|
"description": "specifies the maximum number of FDB entries (0: none)",
|
3016
3016
|
"default": 0
|
3017
3017
|
},
|
3018
|
+
"vxlan_port": {
|
3019
|
+
"description": "specifies the UDP destination port to communicate to the remote VXLAN tunnel endpoint",
|
3020
|
+
"type": "integer",
|
3021
|
+
"minimum": 0,
|
3022
|
+
"maximum": 65535
|
3023
|
+
},
|
3024
|
+
"vxlan_port_range": {
|
3025
|
+
"description": "specifies the range of port numbers to use as UDP source ports to communicate to the remote VXLAN tunnel endpoint",
|
3026
|
+
"required": [
|
3027
|
+
"low",
|
3028
|
+
"high"
|
3029
|
+
],
|
3030
|
+
"additionalProperties": false,
|
3031
|
+
"properties": {
|
3032
|
+
"low": {
|
3033
|
+
"type": "integer",
|
3034
|
+
"minimum": 0,
|
3035
|
+
"maximum": 65535
|
3036
|
+
},
|
3037
|
+
"high": {
|
3038
|
+
"type": "integer",
|
3039
|
+
"minimum": 0,
|
3040
|
+
"maximum": 65535
|
3041
|
+
}
|
3042
|
+
}
|
3043
|
+
},
|
3018
3044
|
"vxlan_proxy": {
|
3019
3045
|
"type": "integer",
|
3020
3046
|
"minimum": 0,
|
ifstate-1.12.0/ifstate/vrrp.py
DELETED
@@ -1,113 +0,0 @@
|
|
1
|
-
from libifstate.util import logger, IfStateLogging
|
2
|
-
|
3
|
-
from copy import deepcopy
|
4
|
-
import logging
|
5
|
-
import multiprocessing as mp
|
6
|
-
import os
|
7
|
-
import re
|
8
|
-
from setproctitle import setproctitle
|
9
|
-
import signal
|
10
|
-
|
11
|
-
class VrrpFifoProcess(mp.Process):
|
12
|
-
'''
|
13
|
-
Process for vrrp group/instance configuration.
|
14
|
-
'''
|
15
|
-
def __init__(self, vrrp_type, vrrp_name, ifstate, log_level):
|
16
|
-
self.vrrp_type = vrrp_type
|
17
|
-
self.vrrp_name = vrrp_name
|
18
|
-
self.ifstate = ifstate
|
19
|
-
self.log_level = log_level
|
20
|
-
self.queue = mp.Queue()
|
21
|
-
super().__init__(target=self.vrrp_worker, name=f'ifstate-vrrp-fifo|{vrrp_type}.{vrrp_name}', daemon=True)
|
22
|
-
|
23
|
-
def vrrp_update(self, vrrp_state):
|
24
|
-
self.queue.put(vrrp_state)
|
25
|
-
|
26
|
-
def vrrp_worker(self):
|
27
|
-
instance_title = "vrrp-{}-{}".format(self.vrrp_type, self.vrrp_name)
|
28
|
-
setproctitle("ifstate-{}".format(instance_title))
|
29
|
-
ifslog = IfStateLogging(self.log_level, action=instance_title, log_stderr=False)
|
30
|
-
logger.info('worker spawned')
|
31
|
-
while True:
|
32
|
-
vrrp_state = self.queue.get()
|
33
|
-
if vrrp_state is None:
|
34
|
-
logger.info('terminating')
|
35
|
-
return
|
36
|
-
else:
|
37
|
-
ifstate = deepcopy(self.ifstate)
|
38
|
-
ifstate.apply(self.vrrp_type, self.vrrp_name, vrrp_state)
|
39
|
-
|
40
|
-
class VrrpStates():
|
41
|
-
'''
|
42
|
-
Tracks processes and states for vrrp groups/instances.
|
43
|
-
'''
|
44
|
-
def __init__(self, ifstate, log_level):
|
45
|
-
self.ifstate = ifstate
|
46
|
-
self.log_level = log_level
|
47
|
-
self.processes = {}
|
48
|
-
self.states = {}
|
49
|
-
|
50
|
-
def update(self, vrrp_type, vrrp_name, vrrp_state):
|
51
|
-
'''
|
52
|
-
Updates the state for a group/instance. A new VrrpFifoProcess is spawned on-demand
|
53
|
-
if a group/instance is called the first time.
|
54
|
-
'''
|
55
|
-
key = (vrrp_type, vrrp_name)
|
56
|
-
if not key in self.processes:
|
57
|
-
self.processes[key] = VrrpFifoProcess(vrrp_type, vrrp_name, self.ifstate, self.log_level)
|
58
|
-
self.processes[key].start()
|
59
|
-
|
60
|
-
self.states[key] = vrrp_state
|
61
|
-
self.processes[key].vrrp_update(vrrp_state)
|
62
|
-
|
63
|
-
def reconfigure(self, ifstate):
|
64
|
-
'''
|
65
|
-
Reconfigure all known groups/instances using their last known state by spawning
|
66
|
-
new worker Processes.
|
67
|
-
'''
|
68
|
-
self.ifstate = ifstate
|
69
|
-
for key, state in self.states.items():
|
70
|
-
self.processes[key].vrrp_update(None)
|
71
|
-
self.processes[key] = VrrpFifoProcess(*key, ifstate, self.log_level)
|
72
|
-
self.processes[key].start()
|
73
|
-
self.processes[key].vrrp_update(self.states[key])
|
74
|
-
|
75
|
-
def vrrp_fifo(args_fifo, ifs_config, log_level):
|
76
|
-
vrrp_states = VrrpStates(ifs_config.ifs, log_level)
|
77
|
-
ifs_config.set_callback(vrrp_states.reconfigure)
|
78
|
-
|
79
|
-
signal.signal(signal.SIGHUP, ifs_config.sighup_handler)
|
80
|
-
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
|
81
|
-
signal.signal(signal.SIGTERM, signal.SIG_IGN)
|
82
|
-
|
83
|
-
pid_file = f"/run/libifstate/vrrp/{os.getpid()}.pid"
|
84
|
-
try:
|
85
|
-
os.makedirs("/run/libifstate/vrrp", exist_ok=True)
|
86
|
-
|
87
|
-
with open(pid_file, "w", encoding="utf-8") as fh:
|
88
|
-
fh.write(args_fifo)
|
89
|
-
except IOError as err:
|
90
|
-
logger.exception(f'failed to write pid file {pid_file}: {err}')
|
91
|
-
|
92
|
-
try:
|
93
|
-
status_pattern = re.compile(
|
94
|
-
r'(group|instance) "([^"]+)" (unknown|fault|backup|master)( \d+)?$', re.IGNORECASE)
|
95
|
-
|
96
|
-
with open(args_fifo) as fifo:
|
97
|
-
logger.debug("entering fifo loop...")
|
98
|
-
for line in fifo:
|
99
|
-
m = status_pattern.match(line.strip())
|
100
|
-
if m:
|
101
|
-
vrrp_type = m.group(1)
|
102
|
-
vrrp_name = m.group(2)
|
103
|
-
vrrp_state = m.group(3)
|
104
|
-
|
105
|
-
vrrp_states.update(vrrp_type, vrrp_name, vrrp_state)
|
106
|
-
else:
|
107
|
-
logger.warning(f'failed to parse fifo input: {line.strip()}')
|
108
|
-
mp.active_children()
|
109
|
-
finally:
|
110
|
-
try:
|
111
|
-
os.remove(pid_file)
|
112
|
-
except IOError:
|
113
|
-
pass
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|