19
19
import os
20
20
import subprocess
21
21
22
- from .utils import systemctl_is_active , systemctl_is_installed
23
-
24
- OPENVSWITCH_OVS_VSCTL = '/usr/bin/ovs-vsctl'
25
- OPENVSWITCH_OVSDB_SERVER_UNIT = 'ovsdb-server.service'
22
+ OPENVSWITCH_OVS_VSCTL = 'ovs-vsctl'
26
23
# Defaults for non-optional settings, as defined here:
27
24
# http://www.openvswitch.org/ovs-vswitchd.conf.db.5.pdf
28
25
DEFAULTS = {
@@ -46,25 +43,43 @@ class OvsDbServerNotInstalled(Exception):
46
43
pass
47
44
48
45
46
+ def _ovs_vsctl_path (): # pragma: nocover
47
+ if os .path .exists ('/snap/bin/' + OPENVSWITCH_OVS_VSCTL ):
48
+ return '/snap/bin/' + OPENVSWITCH_OVS_VSCTL
49
+ else :
50
+ return '/usr/bin/' + OPENVSWITCH_OVS_VSCTL
51
+
52
+
53
+ OVS_VSCTL_PATH = _ovs_vsctl_path ()
54
+
55
+
56
+ def _ovs_installed (): # pragma: nocover
57
+ return os .path .exists (OVS_VSCTL_PATH )
58
+
59
+
60
+ def _ovs_active (): # pragma: nocover
61
+ return subprocess .call ([OVS_VSCTL_PATH , 'show' ], stdout = subprocess .DEVNULL , stderr = subprocess .DEVNULL ) == 0
62
+
63
+
49
64
def _del_col (type , iface , column , value ):
50
65
"""Cleanup values from a column (i.e. "column=value")"""
51
66
default = DEFAULTS .get (column )
52
67
if default is None :
53
68
# removes the exact value only if it was set by netplan
54
- cmd = [OPENVSWITCH_OVS_VSCTL , 'remove' , type , iface , column , value ]
69
+ cmd = [OVS_VSCTL_PATH , 'remove' , type , iface , column , value ]
55
70
logging .debug ('Running: %s' % ' ' .join (cmd ))
56
71
subprocess .check_call (cmd )
57
72
elif default and default != value :
58
73
# reset to default, if its not the default already
59
- cmd = [OPENVSWITCH_OVS_VSCTL , 'set' , type , iface , '%s=%s' % (column , default )]
74
+ cmd = [OVS_VSCTL_PATH , 'set' , type , iface , '%s=%s' % (column , default )]
60
75
logging .debug ('Running: %s' % ' ' .join (cmd ))
61
76
subprocess .check_call (cmd )
62
77
63
78
64
79
def _del_dict (type , iface , column , key , value ):
65
80
"""Cleanup values from a dictionary (i.e. "column:key=value")"""
66
81
# removes the exact value only if it was set by netplan
67
- cmd = [OPENVSWITCH_OVS_VSCTL , 'remove' , type , iface , column , '%s=\" %s\" ' % (key , value )]
82
+ cmd = [OVS_VSCTL_PATH , 'remove' , type , iface , column , '%s=\" %s\" ' % (key , value )]
68
83
logging .debug ('Running: %s' % ' ' .join (cmd ))
69
84
subprocess .check_call (cmd )
70
85
@@ -76,8 +91,8 @@ def _del_global(type, iface, key, value):
76
91
iface = None
77
92
78
93
if del_cmd :
79
- args_get = [OPENVSWITCH_OVS_VSCTL , get_cmd ]
80
- args_del = [OPENVSWITCH_OVS_VSCTL , del_cmd ]
94
+ args_get = [OVS_VSCTL_PATH , get_cmd ]
95
+ args_del = [OVS_VSCTL_PATH , del_cmd ]
81
96
if iface :
82
97
args_get .append (iface )
83
98
args_del .append (iface )
@@ -112,7 +127,7 @@ def clear_setting(type, iface, setting, value):
112
127
else :
113
128
_del_col (type , iface , split [1 ], value )
114
129
# Cleanup the tag itself (i.e. "netplan/column[/key]")
115
- subprocess .check_call ([OPENVSWITCH_OVS_VSCTL , 'remove' , type , iface , 'external-ids' , setting ])
130
+ subprocess .check_call ([OVS_VSCTL_PATH , 'remove' , type , iface , 'external-ids' , setting ])
116
131
117
132
118
133
def is_ovs_interface (iface , np_interface_dict ):
@@ -129,11 +144,11 @@ def apply_ovs_cleanup(config_manager, ovs_old, ovs_current): # pragma: nocover
129
144
Also filter for individual settings tagged netplan/<column>[/<key]=value
130
145
in external-ids and clear them if they have been set by netplan.
131
146
"""
132
- if not systemctl_is_installed ( OPENVSWITCH_OVSDB_SERVER_UNIT ):
133
- raise OvsDbServerNotInstalled ("Cannot apply OVS cleanup: %s is 'not-found'" %
134
- OPENVSWITCH_OVSDB_SERVER_UNIT )
135
- if not systemctl_is_active ( OPENVSWITCH_OVSDB_SERVER_UNIT ):
136
- raise OvsDbServerNotRunning ('{} is not running' . format ( OPENVSWITCH_OVSDB_SERVER_UNIT ) )
147
+ if not _ovs_installed ( ):
148
+ raise OvsDbServerNotInstalled ("Cannot apply OpenvSwitch cleanup: ovs-vsctl is 'not-found'" )
149
+
150
+ if not _ovs_active ( ):
151
+ raise OvsDbServerNotRunning ('OpenvSwitch database is not running' )
137
152
138
153
config_manager .parse ()
139
154
ovs_ifaces = set ()
@@ -144,47 +159,42 @@ def apply_ovs_cleanup(config_manager, ovs_old, ovs_current): # pragma: nocover
144
159
# Tear down old OVS interfaces, not defined in the current config.
145
160
# Use 'del-br' on the Interface table, to delete any netplan created VLAN fake bridges.
146
161
# Use 'del-bond-iface' on the Interface table, to delete netplan created patch port interfaces
147
- if os .path .isfile (OPENVSWITCH_OVS_VSCTL ):
148
- # Step 1: Delete all interfaces, which are not part of the current OVS config
149
- for t in (('Port' , 'del-port' ), ('Bridge' , 'del-br' ), ('Interface' , 'del-br' )):
150
- out = subprocess .check_output ([OPENVSWITCH_OVS_VSCTL , '--columns=name,external-ids' ,
151
- '-f' , 'csv' , '-d' , 'bare' , '--no-headings' , 'list' , t [0 ]],
152
- text = True )
153
- for line in out .splitlines ():
154
- if 'netplan=true' in line :
155
- iface = line .split (',' )[0 ]
156
- # Skip cleanup if this OVS interface is part of the current netplan OVS config
157
- if iface in ovs_ifaces :
158
- continue
159
- if t [0 ] == 'Interface' and subprocess .run ([OPENVSWITCH_OVS_VSCTL , 'br-exists' , iface ]).returncode > 0 :
160
- subprocess .check_call ([OPENVSWITCH_OVS_VSCTL , '--if-exists' , 'del-bond-iface' , iface ])
161
- else :
162
- subprocess .check_call ([OPENVSWITCH_OVS_VSCTL , '--if-exists' , t [1 ], iface ])
163
-
164
- # Step 2: Clean up the settings of the remaining interfaces
165
- for t in ('Port' , 'Bridge' , 'Interface' , 'Open_vSwitch' , 'Controller' ):
166
- cols = 'name,external-ids'
167
- if t == 'Open_vSwitch' :
168
- cols = 'external-ids'
169
- elif t == 'Controller' :
170
- cols = '_uuid,external-ids' # handle _uuid as if it would be the iface 'name'
171
- out = subprocess .check_output ([OPENVSWITCH_OVS_VSCTL , '--columns=%s' % cols ,
172
- '-f' , 'csv' , '-d' , 'bare' , '--no-headings' , 'list' , t ],
173
- text = True )
174
- for line in out .splitlines ():
175
- if 'netplan/' in line :
176
- iface = '.'
177
- extids = line
178
- if t != 'Open_vSwitch' :
179
- iface , extids = line .split (',' , 1 )
180
- # Check each line (interface) if it contains any netplan tagged settings, e.g.:
181
- # ovs0,"iface-id=myhostname netplan=true netplan/external-ids/iface-id=myhostname"
182
- # ovs1,"netplan=true netplan/global/set-fail-mode=standalone netplan/mcast_snooping_enable=false"
183
- for entry in extids .strip ('"' ).split (' ' ):
184
- if entry .startswith ('netplan/' ) and '=' in entry :
185
- setting , val = entry .split ('=' , 1 )
186
- clear_setting (t , iface , setting , val )
187
-
188
- # Show the warning only if we are or have been working with OVS definitions
189
- elif ovs_old or ovs_current :
190
- logging .warning ('ovs-vsctl is missing, cannot tear down old OpenVSwitch interfaces' )
162
+ # Step 1: Delete all interfaces, which are not part of the current OVS config
163
+ for t in (('Port' , 'del-port' ), ('Bridge' , 'del-br' ), ('Interface' , 'del-br' )):
164
+ out = subprocess .check_output ([OVS_VSCTL_PATH , '--columns=name,external-ids' ,
165
+ '-f' , 'csv' , '-d' , 'bare' , '--no-headings' , 'list' , t [0 ]],
166
+ text = True )
167
+ for line in out .splitlines ():
168
+ if 'netplan=true' in line :
169
+ iface = line .split (',' )[0 ]
170
+ # Skip cleanup if this OVS interface is part of the current netplan OVS config
171
+ if iface in ovs_ifaces :
172
+ continue
173
+ if t [0 ] == 'Interface' and subprocess .run ([OVS_VSCTL_PATH , 'br-exists' , iface ]).returncode > 0 :
174
+ subprocess .check_call ([OVS_VSCTL_PATH , '--if-exists' , 'del-bond-iface' , iface ])
175
+ else :
176
+ subprocess .check_call ([OVS_VSCTL_PATH , '--if-exists' , t [1 ], iface ])
177
+
178
+ # Step 2: Clean up the settings of the remaining interfaces
179
+ for t in ('Port' , 'Bridge' , 'Interface' , 'Open_vSwitch' , 'Controller' ):
180
+ cols = 'name,external-ids'
181
+ if t == 'Open_vSwitch' :
182
+ cols = 'external-ids'
183
+ elif t == 'Controller' :
184
+ cols = '_uuid,external-ids' # handle _uuid as if it would be the iface 'name'
185
+ out = subprocess .check_output ([OVS_VSCTL_PATH , '--columns=%s' % cols ,
186
+ '-f' , 'csv' , '-d' , 'bare' , '--no-headings' , 'list' , t ],
187
+ text = True )
188
+ for line in out .splitlines ():
189
+ if 'netplan/' in line :
190
+ iface = '.'
191
+ extids = line
192
+ if t != 'Open_vSwitch' :
193
+ iface , extids = line .split (',' , 1 )
194
+ # Check each line (interface) if it contains any netplan tagged settings, e.g.:
195
+ # ovs0,"iface-id=myhostname netplan=true netplan/external-ids/iface-id=myhostname"
196
+ # ovs1,"netplan=true netplan/global/set-fail-mode=standalone netplan/mcast_snooping_enable=false"
197
+ for entry in extids .strip ('"' ).split (' ' ):
198
+ if entry .startswith ('netplan/' ) and '=' in entry :
199
+ setting , val = entry .split ('=' , 1 )
200
+ clear_setting (t , iface , setting , val )
0 commit comments