]> git.proxmox.com Git - ovs.git/blob - xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py
Fix ovs-dpctl-top by removing 3 wrong hunks in py3-compat.patch.
[ovs.git] / xenserver / usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py
1 # Copyright (c) 2009,2010,2011,2012,2013 Nicira, Inc.
2 # Copyright (c) 2007-2011 Citrix Systems Inc.
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; version 2 only.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
17 from XSConsoleLog import *
18
19 import os
20 import socket
21 import subprocess
22
23 vsctl="/usr/bin/ovs-vsctl"
24
25 if __name__ == "__main__":
26 raise Exception("This script is a plugin for xsconsole and cannot run independently")
27
28 from XSConsoleStandard import *
29
30 class VSwitchService:
31 service = {}
32
33 def __init__(self, name, processname=None):
34 self.name = name
35 self.processname = processname
36 if self.processname == None:
37 self.processname = name
38
39 def version(self):
40 try:
41 output = ShellPipe(["service", self.name, "version"]).Stdout()
42 except StandardError as e:
43 XSLogError("vswitch version retrieval error: " + str(e))
44 return "<unknown>"
45 for line in output:
46 if self.processname in line:
47 return line.split()[-1]
48 return "<unknown>"
49
50 def status(self):
51 try:
52 output = ShellPipe(["service", self.name, "status"]).Stdout()
53 except StandardError as e:
54 XSLogError("vswitch status retrieval error: " + str(e))
55 return "<unknown>"
56 if len(output) == 0:
57 return "<unknown>"
58 for line in output:
59 if self.processname not in line:
60 continue
61 elif "running" in line:
62 return "Running"
63 elif "stop" in line:
64 return "Stopped"
65 else:
66 return "<unknown>"
67 return "<unknown>"
68
69 def restart(self):
70 try:
71 ShellPipe(["service", self.name, "restart"]).Call()
72 except StandardError as e:
73 XSLogError("vswitch restart error: " + str(e))
74
75 @classmethod
76 def Inst(cls, name, processname=None):
77 key = name
78 if processname != None:
79 key = key + "-" + processname
80 if name not in cls.service:
81 cls.service[key] = VSwitchService(name, processname)
82 return cls.service[key]
83
84 class VSwitchConfig:
85
86 @staticmethod
87 def Get(action):
88 try:
89 arg = [vsctl, "-vconsole:off"] + action.split()
90 output = ShellPipe(arg).Stdout()
91 except StandardError as e:
92 XSLogError("config retrieval error: " + str(e))
93 return "<unknown>"
94
95 if len(output) == 0:
96 output = ""
97 else:
98 output = output[0].strip()
99 return output
100
101
102 class VSwitchControllerDialogue(Dialogue):
103 def __init__(self):
104 Dialogue.__init__(self)
105 data=Data.Inst()
106
107 self.hostsInPool = 0
108 self.hostsUpdated = 0
109 self.xs_version = data.host.software_version.product_version('')
110 pool = data.GetPoolForThisHost()
111 if pool is not None:
112 self.controller = pool.get("vswitch_controller", "")
113 else:
114 self.controller = ""
115
116 choiceDefs = [
117 ChoiceDef(Lang("Set pool-wide controller"),
118 lambda: self.getController()),
119 ChoiceDef(Lang("Delete pool-wide controller"),
120 lambda: self.deleteController()),
121 ChoiceDef(Lang("Resync server controller config"),
122 lambda: self.syncController()),
123 # ChoiceDef(Lang("Restart ovs-vswitchd"),
124 # lambda: self.restartService("vswitch")),
125 ]
126 self.menu = Menu(self, None, Lang("Configure Open vSwitch"), choiceDefs)
127
128 self.ChangeState("INITIAL")
129
130 def BuildPane(self):
131 pane = self.NewPane(DialoguePane(self.parent))
132 pane.TitleSet(Lang("Configure Open vSwitch"))
133 pane.AddBox()
134
135 def ChangeState(self, inState):
136 self.state = inState
137 self.BuildPane()
138 self.UpdateFields()
139
140 def UpdateFields(self):
141 self.Pane().ResetPosition()
142 getattr(self, "UpdateFields" + self.state)() # Dispatch method named 'UpdateFields'+self.state
143
144 def UpdateFieldsINITIAL(self):
145 pane = self.Pane()
146 pane.AddTitleField(Lang("Select an action"))
147 pane.AddMenuField(self.menu)
148 pane.AddKeyHelpField( { Lang("<Enter>") : Lang("OK"), Lang("<Esc>") : Lang("Cancel") } )
149
150 def UpdateFieldsGETCONTROLLER(self):
151 pane = self.Pane()
152 pane.ResetFields()
153
154 pane.AddTitleField(Lang("Enter IP address of controller"))
155 pane.AddInputField(Lang("Address", 16), self.controller, "address")
156 pane.AddKeyHelpField( { Lang("<Enter>") : Lang("OK"), Lang("<Esc>") : Lang("Exit") } )
157 if pane.CurrentInput() is None:
158 pane.InputIndexSet(0)
159
160 def HandleKey(self, inKey):
161 handled = False
162 if hasattr(self, "HandleKey" + self.state):
163 handled = getattr(self, "HandleKey" + self.state)(inKey)
164 if not handled and inKey == 'KEY_ESCAPE':
165 Layout.Inst().PopDialogue()
166 handled = True
167 return handled
168
169 def HandleKeyINITIAL(self, inKey):
170 return self.menu.HandleKey(inKey)
171
172 def HandleKeyGETCONTROLLER(self, inKey):
173 pane = self.Pane()
174 if pane.CurrentInput() is None:
175 pane.InputIndexSet(0)
176 if inKey == 'KEY_ENTER':
177 inputValues = pane.GetFieldValues()
178 self.controller = inputValues['address']
179 Layout.Inst().PopDialogue()
180
181 # Make sure the controller is specified as a valid dotted quad
182 try:
183 socket.inet_aton(self.controller)
184 except socket.error:
185 Layout.Inst().PushDialogue(InfoDialogue(Lang("Please enter in dotted quad format")))
186 return True
187
188 Layout.Inst().TransientBanner(Lang("Setting controller..."))
189 try:
190 self.SetController(self.controller)
191 Layout.Inst().PushDialogue(InfoDialogue(Lang("Setting controller successful")))
192 except Exception as e:
193 Layout.Inst().PushDialogue(InfoDialogue(Lang("Setting controller failed")))
194
195 self.ChangeState("INITIAL")
196 return True
197 else:
198 return pane.CurrentInput().HandleKey(inKey)
199
200 def restartService(self, name):
201 s = VSwitchService.Inst(name)
202 s.restart()
203 Layout.Inst().PopDialogue()
204
205 def getController(self):
206 self.ChangeState("GETCONTROLLER")
207 self.Pane().InputIndexSet(0)
208
209 def deleteController(self):
210 self.controller = ""
211 Layout.Inst().PopDialogue()
212 Layout.Inst().TransientBanner(Lang("Deleting controller..."))
213 try:
214 self.SetController(None)
215 Layout.Inst().PushDialogue(InfoDialogue(Lang("Controller deletion successful")))
216 except Exception as e:
217 Layout.Inst().PushDialogue(InfoDialogue(Lang("Controller deletion failed")))
218
219 def syncController(self):
220 Layout.Inst().PopDialogue()
221 Layout.Inst().TransientBanner(Lang("Resyncing controller setting..."))
222 try:
223 Task.Sync(lambda s: self._updateThisServer(s))
224 Layout.Inst().PushDialogue(InfoDialogue(Lang("Resyncing controller config successful")))
225 except Exception as e:
226 Layout.Inst().PushDialogue(InfoDialogue(Lang("Resyncing controller config failed")))
227
228 def SetController(self, ip):
229 self.hostsInPool = 0
230 self.hostsUpdated = 0
231 Task.Sync(lambda s: self._modifyPoolConfig(s, ip or ""))
232 # Should be done asynchronously, maybe with an external script?
233 Task.Sync(lambda s: self._updateActiveServers(s))
234
235 def _modifyPoolConfig(self, session, value):
236 """Modify pool configuration.
237
238 If value == "" then delete configuration, otherwise set to value.
239 """
240 pools = session.xenapi.pool.get_all()
241 # We assume there is only ever one pool...
242 if len(pools) == 0:
243 XSLogFatal(Lang("No pool found for host."))
244 return
245 if len(pools) > 1:
246 XSLogFatal(Lang("More than one pool for host."))
247 return
248 session.xenapi.pool.set_vswitch_controller(value)
249 Data.Inst().Update()
250
251 def _updateActiveServers(self, session):
252 hosts = session.xenapi.host.get_all()
253 self.hostsUpdated = 0
254 self.hostsInPool = len(hosts)
255 self.UpdateFields()
256 for host in hosts:
257 Layout.Inst().TransientBanner("Updating host %d out of %d"
258 % (self.hostsUpdated + 1, self.hostsInPool))
259 session.xenapi.host.call_plugin(host, "openvswitch-cfg-update", "update", {})
260 self.hostsUpdated = self.hostsUpdated + 1
261
262 def _updateThisServer(self, session):
263 data = Data.Inst()
264 host = data.host.opaqueref()
265 session.xenapi.host.call_plugin(host, "openvswitch-cfg-update", "update", {})
266
267
268 class XSFeatureVSwitch:
269
270 @classmethod
271 def StatusUpdateHandler(cls, inPane):
272 data = Data.Inst()
273 xs_version = data.host.software_version.product_version('')
274
275 inPane.AddTitleField(Lang("Open vSwitch"))
276
277 inPane.NewLine()
278
279 inPane.AddStatusField(Lang("Version", 20),
280 VSwitchService.Inst("openvswitch", "ovs-vswitchd").version())
281
282 inPane.NewLine()
283
284 pool = data.GetPoolForThisHost()
285 if pool is not None:
286 dbController = pool.get("vswitch_controller", "")
287 else:
288 dbController = ""
289
290 if dbController == "":
291 dbController = Lang("<None>")
292 inPane.AddStatusField(Lang("Controller (config)", 20), dbController)
293 controller = VSwitchConfig.Get("get-manager")
294
295 if controller == "":
296 controller = Lang("<None>")
297 elif controller[0:4] == "ssl:":
298 controller = controller.split(':')[1]
299 inPane.AddStatusField(Lang("Controller (in-use)", 20), controller)
300
301 inPane.NewLine()
302 inPane.AddStatusField(Lang("ovs-vswitchd status", 20),
303 VSwitchService.Inst("openvswitch", "ovs-vswitchd").status())
304 inPane.AddStatusField(Lang("ovsdb-server status", 20),
305 VSwitchService.Inst("openvswitch", "ovsdb-server").status())
306
307 inPane.AddKeyHelpField( {
308 Lang("<Enter>") : Lang("Reconfigure"),
309 Lang("<F5>") : Lang("Refresh")
310 })
311
312 @classmethod
313 def ActivateHandler(cls):
314 DialogueUtils.AuthenticatedOnly(lambda: Layout.Inst().PushDialogue(VSwitchControllerDialogue()))
315
316 def Register(self):
317 Importer.RegisterNamedPlugIn(
318 self,
319 'VSwitch', # Key of this plugin for replacement, etc.
320 {
321 'menuname' : 'MENU_NETWORK',
322 'menupriority' : 800,
323 'menutext' : Lang('Open vSwitch') ,
324 'statusupdatehandler' : self.StatusUpdateHandler,
325 'activatehandler' : self.ActivateHandler
326 }
327 )
328
329 # Register this plugin when module is imported, IFF vswitchd is running
330 if os.path.exists('/var/run/openvswitch/ovs-vswitchd.pid'):
331 XSFeatureVSwitch().Register()