]>
git.proxmox.com Git - mirror_ovs.git/blob - xenserver/etc_xapi.d_plugins_openvswitch-cfg-update
3 # xapi plugin script to update the cache of configuration items in the
4 # ovs-vswitchd configuration that are managed in the xapi database when
5 # integrated with Citrix management tools.
7 # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2020 Nicira, Inc.
9 # Licensed under the Apache License, Version 2.0 (the "License");
10 # you may not use this file except in compliance with the License.
11 # You may obtain a copy of the License at:
13 # http://www.apache.org/licenses/LICENSE-2.0
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS,
17 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 # See the License for the specific language governing permissions and
19 # limitations under the License.
21 # TBD: - error handling needs to be improved. Currently this can leave
22 # TBD: the system in a bad state if anything goes wrong.
30 vsctl
= '/usr/bin/ovs-vsctl'
31 ofctl
= '/usr/bin/ovs-ofctl'
32 cacert_filename
= '/etc/openvswitch/vswitchd.cacert'
36 # Delete the CA certificate, so that we go back to boot-strapping mode
39 os
.remove(cacert_filename
)
41 # Ignore error if file doesn't exist
45 def update(session
, args
):
46 # Refresh bridge network UUIDs in case this host joined or left a pool.
47 script
= '/opt/xensource/libexec/interface-reconfigure'
49 retval
= subprocess
.call([script
, 'rewrite'])
51 syslog
.syslog('%s exited with status %d' % (script
, retval
))
53 syslog
.syslog('%s: failed to execute (%s)' % (script
, e
.strerror
))
55 pools
= session
.xenapi
.pool
.get_all()
56 # We assume there is only ever one pool...
58 raise XenAPIPlugin
.Failure('NO_POOL_FOR_HOST', [])
60 raise XenAPIPlugin
.Failure('MORE_THAN_ONE_POOL_FOR_HOST', [])
61 new_controller
= False
62 pool
= session
.xenapi
.pool
.get_record(pools
[0])
63 controller
= pool
.get('vswitch_controller')
65 currentControllers
= vswitchCurrentControllers()
67 if not controller
and currentControllers
:
70 emergency_reset(session
, None)
74 ret_str
+= 'Successfully removed controller config. '
75 # controller cannot be empty, otherwise, this will always be True.
76 elif controller
and controller
not in currentControllers
:
79 emergency_reset(session
, None)
82 setControllerCfg(controller
)
84 ret_str
+= 'Successfully set controller to %s. ' % controller
87 pool_fail_mode
= pool
['other_config']['vswitch-controller-fail-mode']
93 for rec
in session
.xenapi
.network
.get_all_records().values():
95 bton
[rec
['bridge']] = rec
99 # If new controller, get management MAC addresses from XAPI now
100 # in case fail_mode set to secure which may affect XAPI access
103 host_mgmt_device
= None
106 query
= 'field "management"="true"'
107 recs
= session
.xenapi
.PIF
.get_all_records_where(query
)
108 for rec
in recs
.itervalues():
109 pool_mgmt_macs
[rec
.get('MAC')] = rec
.get('device')
112 fail_mode_changed
= False
113 for bridge
in vswitchCfgQuery(['list-br']).split():
114 network
= bton
[bridge
]
115 bridge
= vswitchCfgQuery(['br-to-parent', bridge
])
117 xapi_dib
= network
['other_config'].get('vswitch-disable-in-band')
121 ovs_dib
= vswitchCfgQuery(['--', '--if-exists', 'get', 'Bridge',
123 'other_config:disable-in-band']).strip('"')
125 # Do nothing if setting is invalid, and warn the user.
126 if xapi_dib
not in ['true', 'false', '']:
127 ret_str
+= '"' + xapi_dib
+ '"' + \
128 ' is an invalid value for vswitch-disable-in-band on ' + \
131 # Change bridge disable-in-band option if XAPI and OVS states differ.
132 elif xapi_dib
!= ovs_dib
:
135 vswitchCfgMod(['--', 'set', 'Bridge', bridge
,
136 'other_config:disable-in-band=' + xapi_dib
])
139 vswitchCfgMod(['--', 'remove', 'Bridge', bridge
,
140 'other_config', 'disable-in-band'])
143 # Change bridge fail_mode if XAPI state differs from OVS state.
144 bridge_fail_mode
= vswitchCfgQuery(['get', 'Bridge',
145 bridge
, 'fail_mode']).strip('[]"')
148 other_config
= bton
[bridge
]['other_config']
149 fail_mode
= other_config
['vswitch-controller-fail-mode']
153 if fail_mode
not in ['secure', 'standalone']:
154 fail_mode
= pool_fail_mode
156 if fail_mode
!= 'secure':
157 fail_mode
= 'standalone'
159 if bridge_fail_mode
!= fail_mode
:
160 vswitchCfgMod(['--', 'set', 'Bridge', bridge
,
161 'fail_mode=%s' % fail_mode
])
162 fail_mode_changed
= True
164 # Determine local mgmt MAC address if host being added to secure
165 # pool so we can add default flows to allow management traffic
166 if new_controller
and fail_mode_changed
and pool_fail_mode
== 'secure':
167 oc
= vswitchCfgQuery(['get', 'Bridge', bridge
, 'other-config'])
168 m
= re
.match('.*hwaddr="([0-9a-fA-F:].*)".*', oc
)
169 if m
and m
.group(1) in pool_mgmt_macs
.keys():
171 host_mgmt_mac
= m
.group(1)
172 host_mgmt_device
= pool_mgmt_macs
[host_mgmt_mac
]
174 if (host_mgmt_mac
is not None and mgmt_bridge
is not None and
175 host_mgmt_device
is not None):
176 tp
= 'idle_timeout=0,priority=0'
177 port
= vswitchCfgQuery(['get', 'interface', host_mgmt_device
,
180 addFlow(mgmt_bridge
, '%s,in_port=%s,arp,nw_proto=1,actions=local' %
182 addFlow(mgmt_bridge
, '%s,in_port=local,arp,dl_src=%s,actions=%s' %
183 (tp
, host_mgmt_mac
, port
))
184 addFlow(mgmt_bridge
, '%s,in_port=%s,dl_dst=%s,actions=local' %
185 (tp
, port
, host_mgmt_mac
))
186 addFlow(mgmt_bridge
, '%s,in_port=local,dl_src=%s,actions=%s' %
187 (tp
, host_mgmt_mac
, port
))
190 ret_str
+= 'Updated in-band management. '
191 if fail_mode_changed
:
192 ret_str
+= 'Updated fail_mode. '
197 return 'No change to configuration'
200 def vswitchCurrentControllers():
201 controllers
= vswitchCfgQuery(['get-manager'])
203 def parse_controller(controller
):
204 if controller
.startswith('ssl:'):
205 return controller
.split(':')[1]
207 return controller
.split(':')[0]
209 return [parse_controller(controller
)
210 for controller
in controllers
.split('\n')
214 def removeControllerCfg():
215 vswitchCfgMod(['--', 'del-manager',
219 def setControllerCfg(controller
):
220 # /etc/xensource/xapi-ssl.pem is mentioned twice below because it
221 # contains both the private key and the certificate.
222 vswitchCfgMod(['--', 'del-manager',
224 '--', '--bootstrap', 'set-ssl',
225 '/etc/xensource/xapi-ssl.pem',
226 '/etc/xensource/xapi-ssl.pem',
228 '--', 'set-manager', 'ssl:' + controller
+ ':' + ovsdb_port
])
231 def vswitchCfgQuery(action_args
):
232 cmd
= [vsctl
, '-vconsole:off'] + action_args
233 output
= subprocess
.Popen(cmd
, stdout
=subprocess
.PIPE
).communicate()
234 if len(output
) == 0 or output
[0] is None:
237 output
= output
[0].strip()
241 def vswitchCfgMod(action_args
):
242 cmd
= [vsctl
, '--timeout=5', '-vconsole:off'] + action_args
243 exitcode
= subprocess
.call(cmd
)
245 raise XenAPIPlugin
.Failure('VSWITCH_CONFIG_MOD_FAILURE',
246 [str(exitcode
), str(action_args
)])
249 def emergency_reset(session
, args
):
250 cmd
= [vsctl
, '--timeout=5', 'emer-reset']
251 exitcode
= subprocess
.call(cmd
)
253 raise XenAPIPlugin
.Failure('VSWITCH_EMER_RESET_FAILURE',
256 return 'Successfully reset configuration'
259 def addFlow(switch
, flow
):
260 cmd
= [ofctl
, 'add-flow', switch
, flow
]
261 exitcode
= subprocess
.call(cmd
)
263 raise XenAPIPlugin
.Failure('VSWITCH_ADD_FLOW_FAILURE',
264 [str(exitcode
), str(switch
), str(flow
)])
267 if __name__
== '__main__':
268 XenAPIPlugin
.dispatch({'update': update
,
269 'emergency_reset': emergency_reset
})