Skip to content

Commit 3608b88

Browse files
committed
Add customizations for distributed mode
1 parent fa26cc8 commit 3608b88

File tree

5 files changed

+101
-36
lines changed

5 files changed

+101
-36
lines changed

wfb_ng/cluster.py

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,34 @@
2020
import itertools
2121
from jinja2 import Environment, StrictUndefined
2222

23+
from .common import search_attr
2324
from .services import parse_services, hash_link_domain, bandwidth_map
2425
from .conf import settings
2526

2627
def parse_cluster_services(profiles):
2728
if not settings.cluster.nodes:
2829
raise Exception('Cluster is empty!')
2930

30-
if not settings.cluster.server_address:
31-
raise Exception('Server IP address is not set!')
32-
3331
udp_port_allocator = itertools.count(settings.cluster.base_port_server)
3432
services = list((profile, parse_services(profile, udp_port_allocator)) for profile in profiles)
3533
port_allocators = {}
3634
cluster_nodes = {}
3735

3836
def update_node(node, profile, service_name, link_id, tx_port_base, wlans, srv_cfg):
37+
server_address = search_attr('server_address',
38+
settings.cluster.nodes[node],
39+
settings.cluster.__dict__)
40+
41+
if not server_address:
42+
raise Exception('Server IP address is not set!')
43+
3944
d = dict(wlans = wlans,
4045
link_id = link_id,
4146
bandwidth = srv_cfg.bandwidth,
4247
stream_tx = srv_cfg.stream_tx,
4348
stream_rx = srv_cfg.stream_rx,
4449
tx_port_base = tx_port_base,
45-
rx_fwd = (settings.cluster.server_address, srv_cfg.udp_port_auto))
50+
rx_fwd = (server_address, srv_cfg.udp_port_auto))
4651

4752
if node not in cluster_nodes:
4853
cluster_nodes[node] = {}
@@ -86,7 +91,7 @@ def get_allocator(node):
8691

8792
script_template = '''\
8893
#!/bin/bash
89-
set -em
94+
set -emb
9095
9196
export LC_ALL=C
9297
@@ -103,22 +108,22 @@ def get_allocator(node):
103108
trap _cleanup EXIT
104109
105110
iw reg set {{ settings.common.wifi_region }}
106-
107-
for wlan in {{ wlans|join(' ') }}
108-
do
109-
if which nmcli > /dev/null && ! nmcli device show $wlan | grep -q '(unmanaged)'
110-
then
111-
nmcli device set $wlan managed no
112-
fi
113-
114-
ip link set $wlan down
115-
iw dev $wlan set monitor otherbss
116-
ip link set $wlan up
117-
iw dev $wlan set channel {{ settings.common.wifi_channel }} {{ ht_mode }}
118-
{% if settings.common.wifi_txpower != None %}
119-
iw dev $wlan set txpower fixed {{ settings.common.wifi_txpower }}
111+
{% for wlan in wlans %}
112+
113+
# init {{ wlan }}
114+
if which nmcli > /dev/null && ! nmcli device show {{ wlan }} | grep -q '(unmanaged)'
115+
then
116+
nmcli device set {{ wlan }} managed no
117+
fi
118+
119+
ip link set {{ wlan }} down
120+
iw dev {{ wlan }} set monitor otherbss
121+
ip link set {{ wlan }} up
122+
iw dev {{ wlan }} set channel {{ channel[wlan] }} {{ ht_mode }}
123+
{% if txpower[wlan] != None %}
124+
iw dev {{ wlan }} set txpower fixed {{ txpower[wlan] }}
120125
{% endif %}
121-
done
126+
{% endfor %}
122127
{% for service, attrs in services.items() %}
123128
124129
# {{ service }}
@@ -130,10 +135,12 @@ def get_allocator(node):
130135
{% endif %}
131136
{% endfor %}
132137
133-
# Fail in case of connection loss
138+
# Will fail in case of connection loss
134139
(sleep 1; exec cat > /dev/null) &
135140
141+
echo "WFB-ng init done"
136142
wait -n
143+
137144
'''
138145

139146
script_template = env.from_string(script_template)
@@ -144,6 +151,25 @@ def gen_cluster_scripts(cluster_nodes):
144151
for node, node_attrs in cluster_nodes.items():
145152
wlans = sorted(set().union(*[srv_attrs['wlans'] for srv_attrs in node_attrs.values()]))
146153
max_bw = max(srv_attrs['bandwidth'] for srv_attrs in node_attrs.values())
147-
res[node] = script_template.render(wlans=wlans, ht_mode=bandwidth_map[max_bw], services=node_attrs)
154+
155+
channel = search_attr('wifi_channel',
156+
settings.cluster.nodes[node],
157+
settings.common.__dict__)
158+
159+
if not isinstance(channel, dict):
160+
channel = dict((wlan, channel) for wlan in wlans)
161+
162+
txpower = search_attr('wifi_txpower',
163+
settings.cluster.nodes[node],
164+
settings.common.__dict__)
165+
166+
if not isinstance(txpower, dict):
167+
txpower = dict((wlan, txpower) for wlan in wlans)
168+
169+
res[node] = script_template.render(wlans=wlans,
170+
ht_mode=bandwidth_map[max_bw],
171+
services=node_attrs,
172+
txpower=txpower,
173+
channel=channel)
148174

149175
return res

wfb_ng/common.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,19 @@ def abort_on_crash(f, stop_reactor=True, warn_cancel=True):
4646
f = f.value.subFailure
4747

4848
if settings.common.debug:
49-
log.err(f, 'Stopping reactor due to fatal error')
49+
log.err(f, 'Stopping reactor due to fatal error', isError=1)
5050
else:
51-
log.msg('Stopping reactor due to fatal error: %s' % (f.value,))
51+
log.msg('Stopping reactor due to fatal error: %s' % (f.value,), isError=1)
5252

5353
fatal_error(stop_reactor)
5454

5555

5656
def df_sleep(timeout, res=None):
5757
return task.deferLater(reactor, timeout, lambda: res)
5858

59+
60+
def search_attr(key, *attrs):
61+
for a in attrs:
62+
if key in a:
63+
return a[key]
64+
raise KeyError('Attribute %r is not defined!' % (key,))

wfb_ng/conf/master.cfg

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ wifi_region = 'BO' # Set CRDA region
3939
wifi_txpower = None # Leave None to use default power settings from driver.
4040
# For 8812au set to -dBm * 100. I.e for 30dBm set to -3000
4141
# For 8812eu set to dBm * 100. I.e for 30dBm set to 3000
42+
# Also you can set own txpower for each wifi card, for example:
43+
# {'wlan0': -100, 'wlan1': 100}
44+
4245

4346
temp_measurement_interval = 10 # [s] (8812eu only) Internal RF path temp measurement.
4447
temp_overheat_warning = 60 # [*C] (8812eu only) Overheat warning threshold.
@@ -49,8 +52,13 @@ temp_overheat_warning = 60 # [*C] (8812eu only) Overheat warning threshold.
4952
[cluster]
5053

5154
nodes = {
52-
#'127.0.0.1': { 'wlans': ['wlan1', 'wlan2'] },
53-
#'10.5.1.1' : { 'wlans': ['wlan0', 'wlan1'] },
55+
# required host attrs: 'wlans'
56+
# optional host attrs (will override defaults): 'ssh', 'server_address', 'wifi_txpower', 'wifi_channel', 'ssh_user', 'ssh_port', 'ssh_key'
57+
# If ssh_user or ssh_port is set to None then node will not be automatically initialized in ssh mode.
58+
# If ssh_key is None, then ssh_agent will be used.
59+
60+
#'127.0.0.1': { 'wlans': ['wlan1', 'wlan2'], 'wifi_txpower': None},
61+
#'10.5.1.1' : { 'wlans': ['wlan0', 'wlan1']},
5462
}
5563

5664
# Cluster init can be auto (--cluster ssh) or manual (--cluster manual)

wfb_ng/protocols.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ def errReceived(self, data):
558558

559559
def processEnded(self, status):
560560
rc = status.value.exitCode
561-
log.msg('Stopped ssh %s with code %s' % (self.host, rc))
561+
log.msg('Stopped ssh %s with code %s' % (self.host, rc), isError=(rc != 0))
562562

563563
if rc == 0:
564564
self.df.callback(str(status.value))

wfb_ng/server.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from twisted.internet import reactor, defer
3131

3232
from . import _log_msg, ConsoleObserver, ErrorSafeLogFile, call_and_check_rc, ExecError, version_msg
33-
from .common import abort_on_crash, exit_status, df_sleep
33+
from .common import abort_on_crash, exit_status, df_sleep, search_attr
3434
from .protocols import StatsAndSelectorFactory, RFTempMeter, SSHClientProtocol
3535
from .services import parse_services, init_udp_direct_tx, init_udp_direct_rx, init_mavlink, init_tunnel, init_udp_proxy, hash_link_domain, bandwidth_map
3636
from .cluster import parse_cluster_services, gen_cluster_scripts
@@ -88,8 +88,15 @@ def init_wlans(max_bw, wlans):
8888

8989
yield call_and_check_rc('iw', 'dev', wlan, 'set', 'channel', str(channel), ht_mode)
9090

91-
if settings.common.wifi_txpower:
92-
yield call_and_check_rc('iw', 'dev', wlan, 'set', 'txpower', 'fixed', str(settings.common.wifi_txpower))
91+
# You can set own tx power for each card
92+
if isinstance(settings.common.wifi_txpower, dict):
93+
txpower = settings.common.wifi_txpower[wlan]
94+
else:
95+
txpower = settings.common.wifi_txpower
96+
97+
if txpower is not None:
98+
yield call_and_check_rc('iw', 'dev', wlan, 'set', 'txpower', 'fixed', str(txpower))
99+
93100
except ExecError as v:
94101
if v.stdout:
95102
log.msg(v.stdout, isError=1)
@@ -109,16 +116,34 @@ def init(profiles, wlans, cluster_mode):
109116
dl = []
110117
is_cluster = bool(cluster_mode)
111118

119+
def _ssh_exited(x, node):
120+
raise Exception('Connection to %s closed, aborting' % (node,))
121+
112122
if is_cluster:
113123
services, cluster_nodes = parse_cluster_services(profiles)
114124
if cluster_mode == 'ssh':
115125
for node, setup_script in gen_cluster_scripts(cluster_nodes).items():
116-
dl.append(SSHClientProtocol(node, settings.cluster.ssh_user,
117-
'/bin/bash',
118-
key=settings.cluster.ssh_key,
119-
port=settings.cluster.ssh_port,
120-
use_agent=settings.cluster.ssh_key is None,
121-
stdin=setup_script).start())
126+
ssh_user = search_attr('ssh_user',
127+
settings.cluster.nodes[node],
128+
settings.cluster.__dict__)
129+
130+
ssh_port = search_attr('ssh_port',
131+
settings.cluster.nodes[node],
132+
settings.cluster.__dict__)
133+
134+
ssh_key = search_attr('ssh_key',
135+
settings.cluster.nodes[node],
136+
settings.cluster.__dict__)
137+
138+
if ssh_user and ssh_port:
139+
dl.append(SSHClientProtocol(node,
140+
ssh_user,
141+
'/bin/bash',
142+
key=ssh_key,
143+
port=ssh_port,
144+
use_agent=ssh_key is None,
145+
stdin=setup_script).start()\
146+
.addBoth(_ssh_exited, node))
122147
else:
123148
services = list((profile, parse_services(profile, None)) for profile in profiles)
124149
# Do cards init

0 commit comments

Comments
 (0)