openxenmanager/ 0000755 0001750 0001750 00000000000 11643117607 012271 5 ustar rrs rrs openxenmanager/xdot.py 0000644 0001750 0001750 00000254601 11636446664 013643 0 ustar rrs rrs #!/usr/bin/env python
#
# Copyright 2008 Jose Fonseca
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
#
'''Visualize dot graphs via the xdot format.'''
__author__ = "Jose Fonseca"
__version__ = "0.4"
import os
import sys
import subprocess
import math
import colorsys
import time
import re
import gobject
import gtk
import gtk.gdk
import gtk.keysyms
import cairo
import pango
import pangocairo
# See http://www.graphviz.org/pub/scm/graphviz-cairo/plugin/cairo/gvrender_cairo.c
# For pygtk inspiration and guidance see:
# - http://mirageiv.berlios.de/
# - http://comix.sourceforge.net/
class Pen:
"""Store pen attributes."""
def __init__(self):
# set default attributes
self.color = (0.0, 0.0, 0.0, 1.0)
self.fillcolor = (0.0, 0.0, 0.0, 1.0)
self.linewidth = 1.0
self.fontsize = 14.0
self.fontname = "Times-Roman"
self.dash = ()
def copy(self):
"""Create a copy of this pen."""
pen = Pen()
pen.__dict__ = self.__dict__.copy()
return pen
def highlighted(self):
pen = self.copy()
pen.color = (1, 0, 0, 1)
pen.fillcolor = (1, .8, .8, 1)
return pen
class Shape:
"""Abstract base class for all the drawing shapes."""
def __init__(self):
pass
def draw(self, cr, highlight=False):
"""Draw this shape with the given cairo context"""
raise NotImplementedError
def select_pen(self, highlight):
if highlight:
if not hasattr(self, 'highlight_pen'):
self.highlight_pen = self.pen.highlighted()
return self.highlight_pen
else:
return self.pen
class TextShape(Shape):
#fontmap = pangocairo.CairoFontMap()
#fontmap.set_resolution(72)
#context = fontmap.create_context()
LEFT, CENTER, RIGHT = -1, 0, 1
def __init__(self, pen, x, y, j, w, t):
Shape.__init__(self)
self.pen = pen.copy()
self.x = x
self.y = y
self.j = j
self.w = w
self.t = t
def draw(self, cr, highlight=False):
try:
layout = self.layout
except AttributeError:
layout = cr.create_layout()
# set font options
# see http://lists.freedesktop.org/archives/cairo/2007-February/009688.html
context = layout.get_context()
fo = cairo.FontOptions()
fo.set_antialias(cairo.ANTIALIAS_DEFAULT)
fo.set_hint_style(cairo.HINT_STYLE_NONE)
fo.set_hint_metrics(cairo.HINT_METRICS_OFF)
try:
pangocairo.context_set_font_options(context, fo)
except TypeError:
# XXX: Some broken pangocairo bindings show the error
# 'TypeError: font_options must be a cairo.FontOptions or None'
pass
# set font
font = pango.FontDescription()
font.set_family(self.pen.fontname)
font.set_absolute_size(self.pen.fontsize*pango.SCALE)
layout.set_font_description(font)
# set text
layout.set_text(self.t)
# cache it
self.layout = layout
else:
cr.update_layout(layout)
descent = 2 # XXX get descender from font metrics
width, height = layout.get_size()
width = float(width)/pango.SCALE
height = float(height)/pango.SCALE
# we know the width that dot thinks this text should have
# we do not necessarily have a font with the same metrics
# scale it so that the text fits inside its box
if width > self.w:
f = self.w / width
width = self.w # equivalent to width *= f
height *= f
descent *= f
else:
f = 1.0
if self.j == self.LEFT:
x = self.x
elif self.j == self.CENTER:
x = self.x - 0.5*width
elif self.j == self.RIGHT:
x = self.x - width
else:
assert 0
y = self.y - height + descent
cr.move_to(x, y)
cr.save()
cr.scale(f, f)
cr.set_source_rgba(*self.select_pen(highlight).color)
cr.show_layout(layout)
cr.restore()
if 0: # DEBUG
# show where dot thinks the text should appear
cr.set_source_rgba(1, 0, 0, .9)
if self.j == self.LEFT:
x = self.x
elif self.j == self.CENTER:
x = self.x - 0.5*self.w
elif self.j == self.RIGHT:
x = self.x - self.w
cr.move_to(x, self.y)
cr.line_to(x+self.w, self.y)
cr.stroke()
class ImageShape(Shape):
def __init__(self, pen, x0, y0, w, h, path):
Shape.__init__(self)
self.pen = pen.copy()
self.x0 = x0
self.y0 = y0
self.w = w
self.h = h
self.path = path
def draw(self, cr, highlight=False):
cr2 = gtk.gdk.CairoContext(cr)
pixbuf = gtk.gdk.pixbuf_new_from_file(self.path)
cr2.set_source_pixbuf(pixbuf, self.x0, self.y0-self.h)
cr2.paint()
class EllipseShape(Shape):
def __init__(self, pen, x0, y0, w, h, filled=False):
Shape.__init__(self)
self.pen = pen.copy()
self.x0 = x0
self.y0 = y0
self.w = w
self.h = h
self.filled = filled
def draw(self, cr, highlight=False):
cr.save()
cr.translate(self.x0, self.y0)
cr.scale(self.w, self.h)
cr.move_to(1.0, 0.0)
cr.arc(0.0, 0.0, 1.0, 0, 2.0*math.pi)
cr.restore()
pen = self.select_pen(highlight)
if self.filled:
cr.set_source_rgba(*pen.fillcolor)
cr.fill()
else:
cr.set_dash(pen.dash)
cr.set_line_width(pen.linewidth)
cr.set_source_rgba(*pen.color)
cr.stroke()
class PolygonShape(Shape):
def __init__(self, pen, points, filled=False):
Shape.__init__(self)
self.pen = pen.copy()
self.points = points
self.filled = filled
def draw(self, cr, highlight=False):
x0, y0 = self.points[-1]
cr.move_to(x0, y0)
for x, y in self.points:
cr.line_to(x, y)
cr.close_path()
pen = self.select_pen(highlight)
if self.filled:
cr.set_source_rgba(*pen.fillcolor)
cr.fill_preserve()
cr.fill()
else:
cr.set_dash(pen.dash)
cr.set_line_width(pen.linewidth)
cr.set_source_rgba(*pen.color)
cr.stroke()
class LineShape(Shape):
def __init__(self, pen, points):
Shape.__init__(self)
self.pen = pen.copy()
self.points = points
def draw(self, cr, highlight=False):
x0, y0 = self.points[0]
cr.move_to(x0, y0)
for x1, y1 in self.points[1:]:
cr.line_to(x1, y1)
pen = self.select_pen(highlight)
cr.set_dash(pen.dash)
cr.set_line_width(pen.linewidth)
cr.set_source_rgba(*pen.color)
cr.stroke()
class BezierShape(Shape):
def __init__(self, pen, points, filled=False):
Shape.__init__(self)
self.pen = pen.copy()
self.points = points
self.filled = filled
def draw(self, cr, highlight=False):
x0, y0 = self.points[0]
cr.move_to(x0, y0)
for i in xrange(1, len(self.points), 3):
x1, y1 = self.points[i]
x2, y2 = self.points[i + 1]
x3, y3 = self.points[i + 2]
cr.curve_to(x1, y1, x2, y2, x3, y3)
pen = self.select_pen(highlight)
if self.filled:
cr.set_source_rgba(*pen.fillcolor)
cr.fill_preserve()
cr.fill()
else:
cr.set_dash(pen.dash)
cr.set_line_width(pen.linewidth)
cr.set_source_rgba(*pen.color)
cr.stroke()
class CompoundShape(Shape):
def __init__(self, shapes):
Shape.__init__(self)
self.shapes = shapes
def draw(self, cr, highlight=False):
for shape in self.shapes:
shape.draw(cr, highlight=highlight)
class Url(object):
def __init__(self, item, url, highlight=None):
self.item = item
self.url = url
if highlight is None:
highlight = set([item])
self.highlight = highlight
class Jump(object):
def __init__(self, item, x, y, highlight=None):
self.item = item
self.x = x
self.y = y
if highlight is None:
highlight = set([item])
self.highlight = highlight
class Element(CompoundShape):
"""Base class for graph nodes and edges."""
def __init__(self, shapes):
CompoundShape.__init__(self, shapes)
def get_url(self, x, y):
return None
def get_jump(self, x, y):
return None
class Node(Element):
def __init__(self, x, y, w, h, shapes, url):
Element.__init__(self, shapes)
self.x = x
self.y = y
self.x1 = x - 0.5*w
self.y1 = y - 0.5*h
self.x2 = x + 0.5*w
self.y2 = y + 0.5*h
self.url = url
def is_inside(self, x, y):
return self.x1 <= x and x <= self.x2 and self.y1 <= y and y <= self.y2
def get_url(self, x, y):
if self.url is None:
return None
#print (x, y), (self.x1, self.y1), "-", (self.x2, self.y2)
if self.is_inside(x, y):
return Url(self, self.url)
return None
def get_jump(self, x, y):
if self.is_inside(x, y):
return Jump(self, self.x, self.y)
return None
def square_distance(x1, y1, x2, y2):
deltax = x2 - x1
deltay = y2 - y1
return deltax*deltax + deltay*deltay
class Edge(Element):
def __init__(self, src, dst, points, shapes):
Element.__init__(self, shapes)
self.src = src
self.dst = dst
self.points = points
RADIUS = 10
def get_jump(self, x, y):
if square_distance(x, y, *self.points[0]) <= self.RADIUS*self.RADIUS:
return Jump(self, self.dst.x, self.dst.y, highlight=set([self, self.dst]))
if square_distance(x, y, *self.points[-1]) <= self.RADIUS*self.RADIUS:
return Jump(self, self.src.x, self.src.y, highlight=set([self, self.src]))
return None
class Graph(Shape):
def __init__(self, width=1, height=1, shapes=(), nodes=(), edges=()):
Shape.__init__(self)
self.width = width
self.height = height
self.shapes = shapes
self.nodes = nodes
self.edges = edges
def get_size(self):
return self.width, self.height
def draw(self, cr, highlight_items=None):
if highlight_items is None:
highlight_items = ()
cr.set_source_rgba(0.0, 0.0, 0.0, 1.0)
cr.set_line_cap(cairo.LINE_CAP_BUTT)
cr.set_line_join(cairo.LINE_JOIN_MITER)
for shape in self.shapes:
shape.draw(cr)
for edge in self.edges:
edge.draw(cr, highlight=(edge in highlight_items))
for node in self.nodes:
node.draw(cr, highlight=(node in highlight_items))
def get_url(self, x, y):
for node in self.nodes:
url = node.get_url(x, y)
if url is not None:
return url
return None
def get_jump(self, x, y):
for edge in self.edges:
jump = edge.get_jump(x, y)
if jump is not None:
return jump
for node in self.nodes:
jump = node.get_jump(x, y)
if jump is not None:
return jump
return None
class XDotAttrParser:
"""Parser for xdot drawing attributes.
See also:
- http://www.graphviz.org/doc/info/output.html#d:xdot
"""
def __init__(self, parser, buf):
self.parser = parser
self.buf = self.unescape(buf)
self.pos = 0
self.pen = Pen()
self.shapes = []
def __nonzero__(self):
return self.pos < len(self.buf)
def unescape(self, buf):
buf = buf.replace('\\"', '"')
buf = buf.replace('\\n', '\n')
return buf
def read_code(self):
pos = self.buf.find(" ", self.pos)
res = self.buf[self.pos:pos]
self.pos = pos + 1
while self.pos < len(self.buf) and self.buf[self.pos].isspace():
self.pos += 1
return res
def read_number(self):
return int(self.read_code())
def read_float(self):
return float(self.read_code())
def read_point(self):
x = self.read_number()
y = self.read_number()
return self.transform(x, y)
def read_text(self):
num = self.read_number()
pos = self.buf.find("-", self.pos) + 1
self.pos = pos + num
res = self.buf[pos:self.pos]
while self.pos < len(self.buf) and self.buf[self.pos].isspace():
self.pos += 1
return res
def read_polygon(self):
n = self.read_number()
p = []
for i in range(n):
x, y = self.read_point()
p.append((x, y))
return p
def read_color(self):
# See http://www.graphviz.org/doc/info/attrs.html#k:color
c = self.read_text()
c1 = c[:1]
if c1 == '#':
hex2float = lambda h: float(int(h, 16)/255.0)
r = hex2float(c[1:3])
g = hex2float(c[3:5])
b = hex2float(c[5:7])
try:
a = hex2float(c[7:9])
except (IndexError, ValueError):
a = 1.0
return r, g, b, a
elif c1.isdigit() or c1 == ".":
# "H,S,V" or "H S V" or "H, S, V" or any other variation
h, s, v = map(float, c.replace(",", " ").split())
r, g, b = colorsys.hsv_to_rgb(h, s, v)
a = 1.0
return r, g, b, a
else:
return self.lookup_color(c)
def lookup_color(self, c):
try:
color = gtk.gdk.color_parse(c)
except ValueError:
pass
else:
s = 1.0/65535.0
r = color.red*s
g = color.green*s
b = color.blue*s
a = 1.0
return r, g, b, a
try:
dummy, scheme, index = c.split('/')
r, g, b = brewer_colors[scheme][int(index)]
except (ValueError, KeyError):
pass
else:
s = 1.0/255.0
r = r*s
g = g*s
b = b*s
a = 1.0
return r, g, b, a
sys.stderr.write("unknown color '%s'\n" % c)
return None
def parse(self):
s = self
while s:
op = s.read_code()
if op == "c":
color = s.read_color()
if color is not None:
self.handle_color(color, filled=False)
elif op == "C":
color = s.read_color()
if color is not None:
self.handle_color(color, filled=True)
elif op == "S":
# http://www.graphviz.org/doc/info/attrs.html#k:style
style = s.read_text()
if style.startswith("setlinewidth("):
lw = style.split("(")[1].split(")")[0]
lw = float(lw)
self.handle_linewidth(lw)
elif style in ("solid", "dashed"):
self.handle_linestyle(style)
elif op == "F":
size = s.read_float()
name = s.read_text()
self.handle_font(size, name)
elif op == "T":
x, y = s.read_point()
j = s.read_number()
w = s.read_number()
t = s.read_text()
self.handle_text(x, y, j, w, t)
elif op == "E":
x0, y0 = s.read_point()
w = s.read_number()
h = s.read_number()
self.handle_ellipse(x0, y0, w, h, filled=True)
elif op == "e":
x0, y0 = s.read_point()
w = s.read_number()
h = s.read_number()
self.handle_ellipse(x0, y0, w, h, filled=False)
elif op == "L":
points = self.read_polygon()
self.handle_line(points)
elif op == "B":
points = self.read_polygon()
self.handle_bezier(points, filled=False)
elif op == "b":
points = self.read_polygon()
self.handle_bezier(points, filled=True)
elif op == "P":
points = self.read_polygon()
self.handle_polygon(points, filled=True)
elif op == "p":
points = self.read_polygon()
self.handle_polygon(points, filled=False)
elif op == "I":
x0, y0 = s.read_point()
w = s.read_number()
h = s.read_number()
path = s.read_text()
self.handle_image(x0, y0, w, h, path)
else:
sys.stderr.write("unknown xdot opcode '%s'\n" % op)
break
return self.shapes
def transform(self, x, y):
return self.parser.transform(x, y)
def handle_color(self, color, filled=False):
if filled:
self.pen.fillcolor = color
else:
self.pen.color = color
def handle_linewidth(self, linewidth):
self.pen.linewidth = linewidth
def handle_linestyle(self, style):
if style == "solid":
self.pen.dash = ()
elif style == "dashed":
self.pen.dash = (6, ) # 6pt on, 6pt off
def handle_font(self, size, name):
self.pen.fontsize = size
self.pen.fontname = name
def handle_text(self, x, y, j, w, t):
self.shapes.append(TextShape(self.pen, x, y, j, w, t))
def handle_ellipse(self, x0, y0, w, h, filled=False):
if filled:
# xdot uses this to mean "draw a filled shape with an outline"
self.shapes.append(EllipseShape(self.pen, x0, y0, w, h, filled=True))
self.shapes.append(EllipseShape(self.pen, x0, y0, w, h))
def handle_image(self, x0, y0, w, h, path):
self.shapes.append(ImageShape(self.pen, x0, y0, w, h, path))
def handle_line(self, points):
self.shapes.append(LineShape(self.pen, points))
def handle_bezier(self, points, filled=False):
if filled:
# xdot uses this to mean "draw a filled shape with an outline"
self.shapes.append(BezierShape(self.pen, points, filled=True))
self.shapes.append(BezierShape(self.pen, points))
def handle_polygon(self, points, filled=False):
if filled:
# xdot uses this to mean "draw a filled shape with an outline"
self.shapes.append(PolygonShape(self.pen, points, filled=True))
self.shapes.append(PolygonShape(self.pen, points))
EOF = -1
SKIP = -2
class ParseError(Exception):
def __init__(self, msg=None, filename=None, line=None, col=None):
self.msg = msg
self.filename = filename
self.line = line
self.col = col
def __str__(self):
return ':'.join([str(part) for part in (self.filename, self.line, self.col, self.msg) if part != None])
class Scanner:
"""Stateless scanner."""
# should be overriden by derived classes
tokens = []
symbols = {}
literals = {}
ignorecase = False
def __init__(self):
flags = re.DOTALL
if self.ignorecase:
flags |= re.IGNORECASE
self.tokens_re = re.compile(
'|'.join(['(' + regexp + ')' for type, regexp, test_lit in self.tokens]),
flags
)
def next(self, buf, pos):
if pos >= len(buf):
return EOF, '', pos
mo = self.tokens_re.match(buf, pos)
if mo:
text = mo.group()
type, regexp, test_lit = self.tokens[mo.lastindex - 1]
pos = mo.end()
if test_lit:
type = self.literals.get(text, type)
return type, text, pos
else:
c = buf[pos]
return self.symbols.get(c, None), c, pos + 1
class Token:
def __init__(self, type, text, line, col):
self.type = type
self.text = text
self.line = line
self.col = col
class Lexer:
# should be overriden by derived classes
scanner = None
tabsize = 8
newline_re = re.compile(r'\r\n?|\n')
def __init__(self, buf = None, pos = 0, filename = None, fp = None):
if fp is not None:
try:
fileno = fp.fileno()
length = os.path.getsize(fp.name)
import mmap
except:
# read whole file into memory
buf = fp.read()
pos = 0
else:
# map the whole file into memory
if length:
# length must not be zero
buf = mmap.mmap(fileno, length, access = mmap.ACCESS_READ)
pos = os.lseek(fileno, 0, 1)
else:
buf = ''
pos = 0
if filename is None:
try:
filename = fp.name
except AttributeError:
filename = None
self.buf = buf
self.pos = pos
self.line = 1
self.col = 1
self.filename = filename
def next(self):
while True:
# save state
pos = self.pos
line = self.line
col = self.col
type, text, endpos = self.scanner.next(self.buf, pos)
assert pos + len(text) == endpos
self.consume(text)
type, text = self.filter(type, text)
self.pos = endpos
if type == SKIP:
continue
elif type is None:
msg = 'unexpected char '
if text >= ' ' and text <= '~':
msg += "'%s'" % text
else:
msg += "0x%X" % ord(text)
raise ParseError(msg, self.filename, line, col)
else:
break
return Token(type = type, text = text, line = line, col = col)
def consume(self, text):
# update line number
pos = 0
for mo in self.newline_re.finditer(text, pos):
self.line += 1
self.col = 1
pos = mo.end()
# update column number
while True:
tabpos = text.find('\t', pos)
if tabpos == -1:
break
self.col += tabpos - pos
self.col = ((self.col - 1)//self.tabsize + 1)*self.tabsize + 1
pos = tabpos + 1
self.col += len(text) - pos
class Parser:
def __init__(self, lexer):
self.lexer = lexer
self.lookahead = self.lexer.next()
def match(self, type):
if self.lookahead.type != type:
raise ParseError(
msg = 'unexpected token %r' % self.lookahead.text,
filename = self.lexer.filename,
line = self.lookahead.line,
col = self.lookahead.col)
def skip(self, type):
while self.lookahead.type != type:
self.consume()
def consume(self):
token = self.lookahead
self.lookahead = self.lexer.next()
return token
ID = 0
STR_ID = 1
HTML_ID = 2
EDGE_OP = 3
LSQUARE = 4
RSQUARE = 5
LCURLY = 6
RCURLY = 7
COMMA = 8
COLON = 9
SEMI = 10
EQUAL = 11
PLUS = 12
STRICT = 13
GRAPH = 14
DIGRAPH = 15
NODE = 16
EDGE = 17
SUBGRAPH = 18
class DotScanner(Scanner):
# token regular expression table
tokens = [
# whitespace and comments
(SKIP,
r'[ \t\f\r\n\v]+|'
r'//[^\r\n]*|'
r'/\*.*?\*/|'
r'#[^\r\n]*',
False),
# Alphanumeric IDs
(ID, r'[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*', True),
# Numeric IDs
(ID, r'-?(?:\.[0-9]+|[0-9]+(?:\.[0-9]*)?)', False),
# String IDs
(STR_ID, r'"[^"\\]*(?:\\.[^"\\]*)*"', False),
# HTML IDs
(HTML_ID, r'<[^<>]*(?:<[^<>]*>[^<>]*)*>', False),
# Edge operators
(EDGE_OP, r'-[>-]', False),
]
# symbol table
symbols = {
'[': LSQUARE,
']': RSQUARE,
'{': LCURLY,
'}': RCURLY,
',': COMMA,
':': COLON,
';': SEMI,
'=': EQUAL,
'+': PLUS,
}
# literal table
literals = {
'strict': STRICT,
'graph': GRAPH,
'digraph': DIGRAPH,
'node': NODE,
'edge': EDGE,
'subgraph': SUBGRAPH,
}
ignorecase = True
class DotLexer(Lexer):
scanner = DotScanner()
def filter(self, type, text):
# TODO: handle charset
if type == STR_ID:
text = text[1:-1]
# line continuations
text = text.replace('\\\r\n', '')
text = text.replace('\\\r', '')
text = text.replace('\\\n', '')
text = text.replace('\\r', '\r')
text = text.replace('\\n', '\n')
text = text.replace('\\t', '\t')
text = text.replace('\\', '')
type = ID
elif type == HTML_ID:
text = text[1:-1]
type = ID
return type, text
class DotParser(Parser):
def __init__(self, lexer):
Parser.__init__(self, lexer)
self.graph_attrs = {}
self.node_attrs = {}
self.edge_attrs = {}
def parse(self):
self.parse_graph()
self.match(EOF)
def parse_graph(self):
if self.lookahead.type == STRICT:
self.consume()
self.skip(LCURLY)
self.consume()
while self.lookahead.type != RCURLY:
self.parse_stmt()
self.consume()
def parse_subgraph(self):
id = None
if self.lookahead.type == SUBGRAPH:
self.consume()
if self.lookahead.type == ID:
id = self.lookahead.text
self.consume()
if self.lookahead.type == LCURLY:
self.consume()
while self.lookahead.type != RCURLY:
self.parse_stmt()
self.consume()
return id
def parse_stmt(self):
if self.lookahead.type == GRAPH:
self.consume()
attrs = self.parse_attrs()
self.graph_attrs.update(attrs)
self.handle_graph(attrs)
elif self.lookahead.type == NODE:
self.consume()
self.node_attrs.update(self.parse_attrs())
elif self.lookahead.type == EDGE:
self.consume()
self.edge_attrs.update(self.parse_attrs())
elif self.lookahead.type in (SUBGRAPH, LCURLY):
self.parse_subgraph()
else:
id = self.parse_node_id()
if self.lookahead.type == EDGE_OP:
self.consume()
node_ids = [id, self.parse_node_id()]
while self.lookahead.type == EDGE_OP:
node_ids.append(self.parse_node_id())
attrs = self.parse_attrs()
for i in range(0, len(node_ids) - 1):
self.handle_edge(node_ids[i], node_ids[i + 1], attrs)
elif self.lookahead.type == EQUAL:
self.consume()
self.parse_id()
else:
attrs = self.parse_attrs()
self.handle_node(id, attrs)
if self.lookahead.type == SEMI:
self.consume()
def parse_attrs(self):
attrs = {}
while self.lookahead.type == LSQUARE:
self.consume()
while self.lookahead.type != RSQUARE:
name, value = self.parse_attr()
attrs[name] = value
if self.lookahead.type == COMMA:
self.consume()
self.consume()
return attrs
def parse_attr(self):
name = self.parse_id()
if self.lookahead.type == EQUAL:
self.consume()
value = self.parse_id()
else:
value = 'true'
return name, value
def parse_node_id(self):
node_id = self.parse_id()
if self.lookahead.type == COLON:
self.consume()
port = self.parse_id()
if self.lookahead.type == COLON:
self.consume()
compass_pt = self.parse_id()
else:
compass_pt = None
else:
port = None
compass_pt = None
# XXX: we don't really care about port and compass point values when parsing xdot
return node_id
def parse_id(self):
self.match(ID)
id = self.lookahead.text
self.consume()
return id
def handle_graph(self, attrs):
pass
def handle_node(self, id, attrs):
pass
def handle_edge(self, src_id, dst_id, attrs):
pass
class XDotParser(DotParser):
def __init__(self, xdotcode):
lexer = DotLexer(buf = xdotcode)
DotParser.__init__(self, lexer)
self.nodes = []
self.edges = []
self.shapes = []
self.node_by_name = {}
self.top_graph = True
def handle_graph(self, attrs):
if self.top_graph:
try:
bb = attrs['bb']
except KeyError:
return
if not bb:
return
xmin, ymin, xmax, ymax = map(float, bb.split(","))
self.xoffset = -xmin
self.yoffset = -ymax
self.xscale = 1.0
self.yscale = -1.0
# FIXME: scale from points to pixels
self.width = xmax - xmin
self.height = ymax - ymin
self.top_graph = False
for attr in ("_draw_", "_ldraw_", "_hdraw_", "_tdraw_", "_hldraw_", "_tldraw_"):
if attr in attrs:
parser = XDotAttrParser(self, attrs[attr])
self.shapes.extend(parser.parse())
def handle_node(self, id, attrs):
try:
pos = attrs['pos']
except KeyError:
return
x, y = self.parse_node_pos(pos)
w = float(attrs['width'])*72
h = float(attrs['height'])*72
shapes = []
for attr in ("_draw_", "_ldraw_"):
if attr in attrs:
parser = XDotAttrParser(self, attrs[attr])
shapes.extend(parser.parse())
url = attrs.get('URL', None)
node = Node(x, y, w, h, shapes, url)
self.node_by_name[id] = node
if shapes:
self.nodes.append(node)
def handle_edge(self, src_id, dst_id, attrs):
try:
pos = attrs['pos']
except KeyError:
return
points = self.parse_edge_pos(pos)
shapes = []
for attr in ("_draw_", "_ldraw_", "_hdraw_", "_tdraw_", "_hldraw_", "_tldraw_"):
if attr in attrs:
parser = XDotAttrParser(self, attrs[attr])
shapes.extend(parser.parse())
if shapes:
src = self.node_by_name[src_id]
dst = self.node_by_name[dst_id]
self.edges.append(Edge(src, dst, points, shapes))
def parse(self):
DotParser.parse(self)
return Graph(self.width, self.height, self.shapes, self.nodes, self.edges)
def parse_node_pos(self, pos):
x, y = pos.split(",")
return self.transform(float(x), float(y))
def parse_edge_pos(self, pos):
points = []
for entry in pos.split(' '):
fields = entry.split(',')
try:
x, y = fields
except ValueError:
# TODO: handle start/end points
continue
else:
points.append(self.transform(float(x), float(y)))
return points
def transform(self, x, y):
# XXX: this is not the right place for this code
x = (x + self.xoffset)*self.xscale
y = (y + self.yoffset)*self.yscale
return x, y
class Animation(object):
step = 0.03 # seconds
def __init__(self, dot_widget):
self.dot_widget = dot_widget
self.timeout_id = None
def start(self):
self.timeout_id = gobject.timeout_add(int(self.step * 1000), self.tick)
def stop(self):
self.dot_widget.animation = NoAnimation(self.dot_widget)
if self.timeout_id is not None:
gobject.source_remove(self.timeout_id)
self.timeout_id = None
def tick(self):
self.stop()
class NoAnimation(Animation):
def start(self):
pass
def stop(self):
pass
class LinearAnimation(Animation):
duration = 0.6
def start(self):
self.started = time.time()
Animation.start(self)
def tick(self):
t = (time.time() - self.started) / self.duration
self.animate(max(0, min(t, 1)))
return (t < 1)
def animate(self, t):
pass
class MoveToAnimation(LinearAnimation):
def __init__(self, dot_widget, target_x, target_y):
Animation.__init__(self, dot_widget)
self.source_x = dot_widget.x
self.source_y = dot_widget.y
self.target_x = target_x
self.target_y = target_y
def animate(self, t):
sx, sy = self.source_x, self.source_y
tx, ty = self.target_x, self.target_y
self.dot_widget.x = tx * t + sx * (1-t)
self.dot_widget.y = ty * t + sy * (1-t)
self.dot_widget.queue_draw()
class ZoomToAnimation(MoveToAnimation):
def __init__(self, dot_widget, target_x, target_y):
MoveToAnimation.__init__(self, dot_widget, target_x, target_y)
self.source_zoom = dot_widget.zoom_ratio
self.target_zoom = self.source_zoom
self.extra_zoom = 0
middle_zoom = 0.5 * (self.source_zoom + self.target_zoom)
distance = math.hypot(self.source_x - self.target_x,
self.source_y - self.target_y)
rect = self.dot_widget.get_allocation()
visible = min(rect.width, rect.height) / self.dot_widget.zoom_ratio
visible *= 0.9
if distance > 0:
desired_middle_zoom = visible / distance
self.extra_zoom = min(0, 4 * (desired_middle_zoom - middle_zoom))
def animate(self, t):
a, b, c = self.source_zoom, self.extra_zoom, self.target_zoom
self.dot_widget.zoom_ratio = c*t + b*t*(1-t) + a*(1-t)
self.dot_widget.zoom_to_fit_on_resize = False
MoveToAnimation.animate(self, t)
class DragAction(object):
def __init__(self, dot_widget):
self.dot_widget = dot_widget
def on_button_press(self, event):
self.startmousex = self.prevmousex = event.x
self.startmousey = self.prevmousey = event.y
self.start()
def on_motion_notify(self, event):
if event.is_hint:
x, y, state = event.window.get_pointer()
else:
x, y, state = event.x, event.y, event.state
deltax = self.prevmousex - x
deltay = self.prevmousey - y
self.drag(deltax, deltay)
self.prevmousex = x
self.prevmousey = y
def on_button_release(self, event):
self.stopmousex = event.x
self.stopmousey = event.y
self.stop()
def draw(self, cr):
pass
def start(self):
pass
def drag(self, deltax, deltay):
pass
def stop(self):
pass
def abort(self):
pass
class NullAction(DragAction):
def on_motion_notify(self, event):
if event.is_hint:
x, y, state = event.window.get_pointer()
else:
x, y, state = event.x, event.y, event.state
dot_widget = self.dot_widget
item = dot_widget.get_url(x, y)
if item is None:
item = dot_widget.get_jump(x, y)
if item is not None:
dot_widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
dot_widget.set_highlight(item.highlight)
else:
dot_widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.ARROW))
dot_widget.set_highlight(None)
class PanAction(DragAction):
def start(self):
self.dot_widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
def drag(self, deltax, deltay):
self.dot_widget.x += deltax / self.dot_widget.zoom_ratio
self.dot_widget.y += deltay / self.dot_widget.zoom_ratio
self.dot_widget.queue_draw()
def stop(self):
self.dot_widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.ARROW))
abort = stop
class ZoomAction(DragAction):
def drag(self, deltax, deltay):
self.dot_widget.zoom_ratio *= 1.005 ** (deltax + deltay)
self.dot_widget.zoom_to_fit_on_resize = False
self.dot_widget.queue_draw()
def stop(self):
self.dot_widget.queue_draw()
class ZoomAreaAction(DragAction):
def drag(self, deltax, deltay):
self.dot_widget.queue_draw()
def draw(self, cr):
cr.save()
cr.set_source_rgba(.5, .5, 1.0, 0.25)
cr.rectangle(self.startmousex, self.startmousey,
self.prevmousex - self.startmousex,
self.prevmousey - self.startmousey)
cr.fill()
cr.set_source_rgba(.5, .5, 1.0, 1.0)
cr.set_line_width(1)
cr.rectangle(self.startmousex - .5, self.startmousey - .5,
self.prevmousex - self.startmousex + 1,
self.prevmousey - self.startmousey + 1)
cr.stroke()
cr.restore()
def stop(self):
x1, y1 = self.dot_widget.window2graph(self.startmousex,
self.startmousey)
x2, y2 = self.dot_widget.window2graph(self.stopmousex,
self.stopmousey)
self.dot_widget.zoom_to_area(x1, y1, x2, y2)
def abort(self):
self.dot_widget.queue_draw()
class DotWidget(gtk.DrawingArea):
"""PyGTK widget that draws dot graphs."""
__gsignals__ = {
'expose-event': 'override',
'clicked' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gtk.gdk.Event))
}
filter = 'dot'
def __init__(self):
gtk.DrawingArea.__init__(self)
self.graph = Graph()
self.openfilename = None
self.set_flags(gtk.CAN_FOCUS)
self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK)
self.connect("button-press-event", self.on_area_button_press)
self.connect("button-release-event", self.on_area_button_release)
self.add_events(gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK | gtk.gdk.BUTTON_RELEASE_MASK)
self.connect("motion-notify-event", self.on_area_motion_notify)
self.connect("scroll-event", self.on_area_scroll_event)
self.connect("size-allocate", self.on_area_size_allocate)
self.connect('key-press-event', self.on_key_press_event)
self.x, self.y = 0.0, 0.0
self.zoom_ratio = 1.0
self.zoom_to_fit_on_resize = False
self.animation = NoAnimation(self)
self.drag_action = NullAction(self)
self.presstime = None
self.highlight = None
def set_filter(self, filter):
self.filter = filter
def set_dotcode(self, dotcode, filename=''):
if isinstance(dotcode, unicode):
dotcode = dotcode.encode('utf8')
p = subprocess.Popen(
[self.filter, '-Txdot'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=False,
universal_newlines=True
)
xdotcode, error = p.communicate(dotcode)
if p.returncode != 0:
dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
message_format=error,
buttons=gtk.BUTTONS_OK)
dialog.set_title('Dot Viewer')
dialog.run()
dialog.destroy()
return False
try:
self.set_xdotcode(xdotcode)
except ParseError, ex:
dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
message_format=str(ex),
buttons=gtk.BUTTONS_OK)
dialog.set_title('Dot Viewer')
dialog.run()
dialog.destroy()
return False
else:
self.openfilename = filename
return True
def set_xdotcode(self, xdotcode):
#print xdotcode
parser = XDotParser(xdotcode)
self.graph = parser.parse()
self.zoom_image(self.zoom_ratio, center=True)
def reload(self):
if self.openfilename is not None:
try:
fp = file(self.openfilename, 'rt')
self.set_dotcode(fp.read(), self.openfilename)
fp.close()
except IOError:
pass
def do_expose_event(self, event):
cr = self.window.cairo_create()
# set a clip region for the expose event
cr.rectangle(
event.area.x, event.area.y,
event.area.width, event.area.height
)
cr.clip()
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.paint()
cr.save()
rect = self.get_allocation()
cr.translate(0.5*rect.width, 0.5*rect.height)
cr.scale(self.zoom_ratio, self.zoom_ratio)
cr.translate(-self.x, -self.y)
self.graph.draw(cr, highlight_items=self.highlight)
cr.restore()
self.drag_action.draw(cr)
return False
def get_current_pos(self):
return self.x, self.y
def set_current_pos(self, x, y):
self.x = x
self.y = y
self.queue_draw()
def set_highlight(self, items):
if self.highlight != items:
self.highlight = items
self.queue_draw()
def zoom_image(self, zoom_ratio, center=False, pos=None):
if center:
self.x = self.graph.width/2
self.y = self.graph.height/2
elif pos is not None:
rect = self.get_allocation()
x, y = pos
x -= 0.5*rect.width
y -= 0.5*rect.height
self.x += x / self.zoom_ratio - x / zoom_ratio
self.y += y / self.zoom_ratio - y / zoom_ratio
self.zoom_ratio = zoom_ratio
self.zoom_to_fit_on_resize = False
self.queue_draw()
def zoom_to_area(self, x1, y1, x2, y2):
rect = self.get_allocation()
width = abs(x1 - x2)
height = abs(y1 - y2)
self.zoom_ratio = min(
float(rect.width)/float(width),
float(rect.height)/float(height)
)
self.zoom_to_fit_on_resize = False
self.x = (x1 + x2) / 2
self.y = (y1 + y2) / 2
self.queue_draw()
def zoom_to_fit(self):
rect = self.get_allocation()
rect.x += self.ZOOM_TO_FIT_MARGIN
rect.y += self.ZOOM_TO_FIT_MARGIN
rect.width -= 2 * self.ZOOM_TO_FIT_MARGIN
rect.height -= 2 * self.ZOOM_TO_FIT_MARGIN
zoom_ratio = min(
float(rect.width)/float(self.graph.width),
float(rect.height)/float(self.graph.height)
)
self.zoom_image(zoom_ratio, center=True)
self.zoom_to_fit_on_resize = True
ZOOM_INCREMENT = 1.25
ZOOM_TO_FIT_MARGIN = 12
def on_zoom_in(self, action):
self.zoom_image(self.zoom_ratio * self.ZOOM_INCREMENT)
def on_zoom_out(self, action):
self.zoom_image(self.zoom_ratio / self.ZOOM_INCREMENT)
def on_zoom_fit(self, action):
self.zoom_to_fit()
def on_zoom_100(self, action):
self.zoom_image(1.0)
POS_INCREMENT = 100
def on_key_press_event(self, widget, event):
if event.keyval == gtk.keysyms.Left:
self.x -= self.POS_INCREMENT/self.zoom_ratio
self.queue_draw()
return True
if event.keyval == gtk.keysyms.Right:
self.x += self.POS_INCREMENT/self.zoom_ratio
self.queue_draw()
return True
if event.keyval == gtk.keysyms.Up:
self.y -= self.POS_INCREMENT/self.zoom_ratio
self.queue_draw()
return True
if event.keyval == gtk.keysyms.Down:
self.y += self.POS_INCREMENT/self.zoom_ratio
self.queue_draw()
return True
if event.keyval == gtk.keysyms.Page_Up:
self.zoom_image(self.zoom_ratio * self.ZOOM_INCREMENT)
self.queue_draw()
return True
if event.keyval == gtk.keysyms.Page_Down:
self.zoom_image(self.zoom_ratio / self.ZOOM_INCREMENT)
self.queue_draw()
return True
if event.keyval == gtk.keysyms.Escape:
self.drag_action.abort()
self.drag_action = NullAction(self)
return True
if event.keyval == gtk.keysyms.r:
self.reload()
return True
if event.keyval == gtk.keysyms.q:
gtk.main_quit()
return True
return False
def get_drag_action(self, event):
state = event.state
if event.button in (1, 2): # left or middle button
if state & gtk.gdk.CONTROL_MASK:
return ZoomAction
elif state & gtk.gdk.SHIFT_MASK:
return ZoomAreaAction
else:
return PanAction
return NullAction
def on_area_button_press(self, area, event):
self.animation.stop()
self.drag_action.abort()
action_type = self.get_drag_action(event)
self.drag_action = action_type(self)
self.drag_action.on_button_press(event)
self.presstime = time.time()
self.pressx = event.x
self.pressy = event.y
return False
def is_click(self, event, click_fuzz=4, click_timeout=1.0):
assert event.type == gtk.gdk.BUTTON_RELEASE
if self.presstime is None:
# got a button release without seeing the press?
return False
# XXX instead of doing this complicated logic, shouldn't we listen
# for gtk's clicked event instead?
deltax = self.pressx - event.x
deltay = self.pressy - event.y
return (time.time() < self.presstime + click_timeout
and math.hypot(deltax, deltay) < click_fuzz)
def on_area_button_release(self, area, event):
self.drag_action.on_button_release(event)
self.drag_action = NullAction(self)
if event.button == 1 and self.is_click(event):
x, y = int(event.x), int(event.y)
url = self.get_url(x, y)
if url is not None:
self.emit('clicked', unicode(url.url), event)
else:
jump = self.get_jump(x, y)
if jump is not None:
self.animate_to(jump.x, jump.y)
return True
if event.button == 1 or event.button == 2:
return True
return False
def on_area_scroll_event(self, area, event):
if event.direction == gtk.gdk.SCROLL_UP:
self.zoom_image(self.zoom_ratio * self.ZOOM_INCREMENT,
pos=(event.x, event.y))
return True
if event.direction == gtk.gdk.SCROLL_DOWN:
self.zoom_image(self.zoom_ratio / self.ZOOM_INCREMENT,
pos=(event.x, event.y))
return True
return False
def on_area_motion_notify(self, area, event):
self.drag_action.on_motion_notify(event)
return True
def on_area_size_allocate(self, area, allocation):
if self.zoom_to_fit_on_resize:
self.zoom_to_fit()
def animate_to(self, x, y):
self.animation = ZoomToAnimation(self, x, y)
self.animation.start()
def window2graph(self, x, y):
rect = self.get_allocation()
x -= 0.5*rect.width
y -= 0.5*rect.height
x /= self.zoom_ratio
y /= self.zoom_ratio
x += self.x
y += self.y
return x, y
def get_url(self, x, y):
x, y = self.window2graph(x, y)
return self.graph.get_url(x, y)
def get_jump(self, x, y):
x, y = self.window2graph(x, y)
return self.graph.get_jump(x, y)
class DotWindow(gtk.Window):
ui = '''
'''
def __init__(self, window):
#gtk.Window.__init__(self)
self.graph = Graph()
#window = self
#window.set_title('Dot Viewer')
#window.set_default_size(512, 512)
vbox = gtk.VBox()
window.add(vbox)
self.widget = DotWidget()
# Create a UIManager instance
uimanager = self.uimanager = gtk.UIManager()
# Add the accelerator group to the toplevel window
#accelgroup = uimanager.get_accel_group()
#window.add_accel_group(accelgroup)
# Create an ActionGroup
actiongroup = gtk.ActionGroup('Actions')
self.actiongroup = actiongroup
# Create actions
actiongroup.add_actions((
# ('Open', gtk.STOCK_OPEN, None, None, None, self.on_open),
('ZoomIn', gtk.STOCK_ZOOM_IN, None, None, None, self.widget.on_zoom_in),
('ZoomOut', gtk.STOCK_ZOOM_OUT, None, None, None, self.widget.on_zoom_out),
('ZoomFit', gtk.STOCK_ZOOM_FIT, None, None, None, self.widget.on_zoom_fit),
('Zoom100', gtk.STOCK_ZOOM_100, None, None, None, self.widget.on_zoom_100),
))
# Add the actiongroup to the uimanager
uimanager.insert_action_group(actiongroup, 0)
# Add a UI descrption
uimanager.add_ui_from_string(self.ui)
# Create a Toolbar
toolbar = uimanager.get_widget('/ToolBar')
toolbar.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#d5e5f7"))
vbox.pack_start(toolbar, False)
vbox.pack_start(self.widget)
#self.set_focus(self.widget)
#self.show_all()
self.widget.zoom_image(1.0)
def update(self, filename):
import os
if not hasattr(self, "last_mtime"):
self.last_mtime = None
current_mtime = os.stat(filename).st_mtime
if current_mtime != self.last_mtime:
self.last_mtime = current_mtime
self.open_file(filename)
return True
def set_filter(self, filter):
self.widget.set_filter(filter)
def set_dotcode(self, dotcode, filename=''):
if self.widget.set_dotcode(dotcode, filename):
#self.set_title(os.path.basename(filename) + ' - Dot Viewer')
#self.widget.zoom_to_fit()
self.widget.zoom_image(1.0)
def set_xdotcode(self, xdotcode, filename=''):
if self.widget.set_xdotcode(xdotcode):
#self.set_title(os.path.basename(filename) + ' - Dot Viewer')
self.widget.zoom_to_fit()
def open_file(self, filename):
try:
fp = file(filename, 'rt')
self.set_dotcode(fp.read(), filename)
fp.close()
except IOError, ex:
dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
message_format=str(ex),
buttons=gtk.BUTTONS_OK)
dlg.set_title('Dot Viewer')
dlg.run()
dlg.destroy()
def on_open(self, action):
chooser = gtk.FileChooserDialog(title="Open dot File",
action=gtk.FILE_CHOOSER_ACTION_OPEN,
buttons=(gtk.STOCK_CANCEL,
gtk.RESPONSE_CANCEL,
gtk.STOCK_OPEN,
gtk.RESPONSE_OK))
chooser.set_default_response(gtk.RESPONSE_OK)
filter = gtk.FileFilter()
filter.set_name("Graphviz dot files")
filter.add_pattern("*.dot")
chooser.add_filter(filter)
filter = gtk.FileFilter()
filter.set_name("All files")
filter.add_pattern("*")
chooser.add_filter(filter)
if chooser.run() == gtk.RESPONSE_OK:
filename = chooser.get_filename()
chooser.destroy()
self.open_file(filename)
else:
chooser.destroy()
def on_reload(self, action):
self.widget.reload()
def main():
import optparse
parser = optparse.OptionParser(
usage='\n\t%prog [file]',
version='%%prog %s' % __version__)
parser.add_option(
'-f', '--filter',
type='choice', choices=('dot', 'neato', 'twopi', 'circo', 'fdp'),
dest='filter', default='dot',
help='graphviz filter: dot, neato, twopi, circo, or fdp [default: %default]')
(options, args) = parser.parse_args(sys.argv[1:])
if len(args) > 1:
parser.error('incorrect number of arguments')
win = DotWindow()
win.connect('destroy', gtk.main_quit)
win.set_filter(options.filter)
if len(args) >= 1:
if args[0] == '-':
win.set_dotcode(sys.stdin.read())
else:
win.open_file(args[0])
gobject.timeout_add(1000, win.update, args[0])
gtk.main()
# Apache-Style Software License for ColorBrewer software and ColorBrewer Color
# Schemes, Version 1.1
#
# Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State
# University. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions as source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. The end-user documentation included with the redistribution, if any,
# must include the following acknowledgment:
#
# This product includes color specifications and designs developed by
# Cynthia Brewer (http://colorbrewer.org/).
#
# Alternately, this acknowledgment may appear in the software itself, if and
# wherever such third-party acknowledgments normally appear.
#
# 3. The name "ColorBrewer" must not be used to endorse or promote products
# derived from this software without prior written permission. For written
# permission, please contact Cynthia Brewer at cbrewer@psu.edu.
#
# 4. Products derived from this software may not be called "ColorBrewer",
# nor may "ColorBrewer" appear in their name, without prior written
# permission of Cynthia Brewer.
#
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CYNTHIA
# BREWER, MARK HARROWER, OR THE PENNSYLVANIA STATE UNIVERSITY BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
brewer_colors = {
'accent3': [(127, 201, 127), (190, 174, 212), (253, 192, 134)],
'accent4': [(127, 201, 127), (190, 174, 212), (253, 192, 134), (255, 255, 153)],
'accent5': [(127, 201, 127), (190, 174, 212), (253, 192, 134), (255, 255, 153), (56, 108, 176)],
'accent6': [(127, 201, 127), (190, 174, 212), (253, 192, 134), (255, 255, 153), (56, 108, 176), (240, 2, 127)],
'accent7': [(127, 201, 127), (190, 174, 212), (253, 192, 134), (255, 255, 153), (56, 108, 176), (240, 2, 127), (191, 91, 23)],
'accent8': [(127, 201, 127), (190, 174, 212), (253, 192, 134), (255, 255, 153), (56, 108, 176), (240, 2, 127), (191, 91, 23), (102, 102, 102)],
'blues3': [(222, 235, 247), (158, 202, 225), (49, 130, 189)],
'blues4': [(239, 243, 255), (189, 215, 231), (107, 174, 214), (33, 113, 181)],
'blues5': [(239, 243, 255), (189, 215, 231), (107, 174, 214), (49, 130, 189), (8, 81, 156)],
'blues6': [(239, 243, 255), (198, 219, 239), (158, 202, 225), (107, 174, 214), (49, 130, 189), (8, 81, 156)],
'blues7': [(239, 243, 255), (198, 219, 239), (158, 202, 225), (107, 174, 214), (66, 146, 198), (33, 113, 181), (8, 69, 148)],
'blues8': [(247, 251, 255), (222, 235, 247), (198, 219, 239), (158, 202, 225), (107, 174, 214), (66, 146, 198), (33, 113, 181), (8, 69, 148)],
'blues9': [(247, 251, 255), (222, 235, 247), (198, 219, 239), (158, 202, 225), (107, 174, 214), (66, 146, 198), (33, 113, 181), (8, 81, 156), (8, 48, 107)],
'brbg10': [(84, 48, 5), (0, 60, 48), (140, 81, 10), (191, 129, 45), (223, 194, 125), (246, 232, 195), (199, 234, 229), (128, 205, 193), (53, 151, 143), (1, 102, 94)],
'brbg11': [(84, 48, 5), (1, 102, 94), (0, 60, 48), (140, 81, 10), (191, 129, 45), (223, 194, 125), (246, 232, 195), (245, 245, 245), (199, 234, 229), (128, 205, 193), (53, 151, 143)],
'brbg3': [(216, 179, 101), (245, 245, 245), (90, 180, 172)],
'brbg4': [(166, 97, 26), (223, 194, 125), (128, 205, 193), (1, 133, 113)],
'brbg5': [(166, 97, 26), (223, 194, 125), (245, 245, 245), (128, 205, 193), (1, 133, 113)],
'brbg6': [(140, 81, 10), (216, 179, 101), (246, 232, 195), (199, 234, 229), (90, 180, 172), (1, 102, 94)],
'brbg7': [(140, 81, 10), (216, 179, 101), (246, 232, 195), (245, 245, 245), (199, 234, 229), (90, 180, 172), (1, 102, 94)],
'brbg8': [(140, 81, 10), (191, 129, 45), (223, 194, 125), (246, 232, 195), (199, 234, 229), (128, 205, 193), (53, 151, 143), (1, 102, 94)],
'brbg9': [(140, 81, 10), (191, 129, 45), (223, 194, 125), (246, 232, 195), (245, 245, 245), (199, 234, 229), (128, 205, 193), (53, 151, 143), (1, 102, 94)],
'bugn3': [(229, 245, 249), (153, 216, 201), (44, 162, 95)],
'bugn4': [(237, 248, 251), (178, 226, 226), (102, 194, 164), (35, 139, 69)],
'bugn5': [(237, 248, 251), (178, 226, 226), (102, 194, 164), (44, 162, 95), (0, 109, 44)],
'bugn6': [(237, 248, 251), (204, 236, 230), (153, 216, 201), (102, 194, 164), (44, 162, 95), (0, 109, 44)],
'bugn7': [(237, 248, 251), (204, 236, 230), (153, 216, 201), (102, 194, 164), (65, 174, 118), (35, 139, 69), (0, 88, 36)],
'bugn8': [(247, 252, 253), (229, 245, 249), (204, 236, 230), (153, 216, 201), (102, 194, 164), (65, 174, 118), (35, 139, 69), (0, 88, 36)],
'bugn9': [(247, 252, 253), (229, 245, 249), (204, 236, 230), (153, 216, 201), (102, 194, 164), (65, 174, 118), (35, 139, 69), (0, 109, 44), (0, 68, 27)],
'bupu3': [(224, 236, 244), (158, 188, 218), (136, 86, 167)],
'bupu4': [(237, 248, 251), (179, 205, 227), (140, 150, 198), (136, 65, 157)],
'bupu5': [(237, 248, 251), (179, 205, 227), (140, 150, 198), (136, 86, 167), (129, 15, 124)],
'bupu6': [(237, 248, 251), (191, 211, 230), (158, 188, 218), (140, 150, 198), (136, 86, 167), (129, 15, 124)],
'bupu7': [(237, 248, 251), (191, 211, 230), (158, 188, 218), (140, 150, 198), (140, 107, 177), (136, 65, 157), (110, 1, 107)],
'bupu8': [(247, 252, 253), (224, 236, 244), (191, 211, 230), (158, 188, 218), (140, 150, 198), (140, 107, 177), (136, 65, 157), (110, 1, 107)],
'bupu9': [(247, 252, 253), (224, 236, 244), (191, 211, 230), (158, 188, 218), (140, 150, 198), (140, 107, 177), (136, 65, 157), (129, 15, 124), (77, 0, 75)],
'dark23': [(27, 158, 119), (217, 95, 2), (117, 112, 179)],
'dark24': [(27, 158, 119), (217, 95, 2), (117, 112, 179), (231, 41, 138)],
'dark25': [(27, 158, 119), (217, 95, 2), (117, 112, 179), (231, 41, 138), (102, 166, 30)],
'dark26': [(27, 158, 119), (217, 95, 2), (117, 112, 179), (231, 41, 138), (102, 166, 30), (230, 171, 2)],
'dark27': [(27, 158, 119), (217, 95, 2), (117, 112, 179), (231, 41, 138), (102, 166, 30), (230, 171, 2), (166, 118, 29)],
'dark28': [(27, 158, 119), (217, 95, 2), (117, 112, 179), (231, 41, 138), (102, 166, 30), (230, 171, 2), (166, 118, 29), (102, 102, 102)],
'gnbu3': [(224, 243, 219), (168, 221, 181), (67, 162, 202)],
'gnbu4': [(240, 249, 232), (186, 228, 188), (123, 204, 196), (43, 140, 190)],
'gnbu5': [(240, 249, 232), (186, 228, 188), (123, 204, 196), (67, 162, 202), (8, 104, 172)],
'gnbu6': [(240, 249, 232), (204, 235, 197), (168, 221, 181), (123, 204, 196), (67, 162, 202), (8, 104, 172)],
'gnbu7': [(240, 249, 232), (204, 235, 197), (168, 221, 181), (123, 204, 196), (78, 179, 211), (43, 140, 190), (8, 88, 158)],
'gnbu8': [(247, 252, 240), (224, 243, 219), (204, 235, 197), (168, 221, 181), (123, 204, 196), (78, 179, 211), (43, 140, 190), (8, 88, 158)],
'gnbu9': [(247, 252, 240), (224, 243, 219), (204, 235, 197), (168, 221, 181), (123, 204, 196), (78, 179, 211), (43, 140, 190), (8, 104, 172), (8, 64, 129)],
'greens3': [(229, 245, 224), (161, 217, 155), (49, 163, 84)],
'greens4': [(237, 248, 233), (186, 228, 179), (116, 196, 118), (35, 139, 69)],
'greens5': [(237, 248, 233), (186, 228, 179), (116, 196, 118), (49, 163, 84), (0, 109, 44)],
'greens6': [(237, 248, 233), (199, 233, 192), (161, 217, 155), (116, 196, 118), (49, 163, 84), (0, 109, 44)],
'greens7': [(237, 248, 233), (199, 233, 192), (161, 217, 155), (116, 196, 118), (65, 171, 93), (35, 139, 69), (0, 90, 50)],
'greens8': [(247, 252, 245), (229, 245, 224), (199, 233, 192), (161, 217, 155), (116, 196, 118), (65, 171, 93), (35, 139, 69), (0, 90, 50)],
'greens9': [(247, 252, 245), (229, 245, 224), (199, 233, 192), (161, 217, 155), (116, 196, 118), (65, 171, 93), (35, 139, 69), (0, 109, 44), (0, 68, 27)],
'greys3': [(240, 240, 240), (189, 189, 189), (99, 99, 99)],
'greys4': [(247, 247, 247), (204, 204, 204), (150, 150, 150), (82, 82, 82)],
'greys5': [(247, 247, 247), (204, 204, 204), (150, 150, 150), (99, 99, 99), (37, 37, 37)],
'greys6': [(247, 247, 247), (217, 217, 217), (189, 189, 189), (150, 150, 150), (99, 99, 99), (37, 37, 37)],
'greys7': [(247, 247, 247), (217, 217, 217), (189, 189, 189), (150, 150, 150), (115, 115, 115), (82, 82, 82), (37, 37, 37)],
'greys8': [(255, 255, 255), (240, 240, 240), (217, 217, 217), (189, 189, 189), (150, 150, 150), (115, 115, 115), (82, 82, 82), (37, 37, 37)],
'greys9': [(255, 255, 255), (240, 240, 240), (217, 217, 217), (189, 189, 189), (150, 150, 150), (115, 115, 115), (82, 82, 82), (37, 37, 37), (0, 0, 0)],
'oranges3': [(254, 230, 206), (253, 174, 107), (230, 85, 13)],
'oranges4': [(254, 237, 222), (253, 190, 133), (253, 141, 60), (217, 71, 1)],
'oranges5': [(254, 237, 222), (253, 190, 133), (253, 141, 60), (230, 85, 13), (166, 54, 3)],
'oranges6': [(254, 237, 222), (253, 208, 162), (253, 174, 107), (253, 141, 60), (230, 85, 13), (166, 54, 3)],
'oranges7': [(254, 237, 222), (253, 208, 162), (253, 174, 107), (253, 141, 60), (241, 105, 19), (217, 72, 1), (140, 45, 4)],
'oranges8': [(255, 245, 235), (254, 230, 206), (253, 208, 162), (253, 174, 107), (253, 141, 60), (241, 105, 19), (217, 72, 1), (140, 45, 4)],
'oranges9': [(255, 245, 235), (254, 230, 206), (253, 208, 162), (253, 174, 107), (253, 141, 60), (241, 105, 19), (217, 72, 1), (166, 54, 3), (127, 39, 4)],
'orrd3': [(254, 232, 200), (253, 187, 132), (227, 74, 51)],
'orrd4': [(254, 240, 217), (253, 204, 138), (252, 141, 89), (215, 48, 31)],
'orrd5': [(254, 240, 217), (253, 204, 138), (252, 141, 89), (227, 74, 51), (179, 0, 0)],
'orrd6': [(254, 240, 217), (253, 212, 158), (253, 187, 132), (252, 141, 89), (227, 74, 51), (179, 0, 0)],
'orrd7': [(254, 240, 217), (253, 212, 158), (253, 187, 132), (252, 141, 89), (239, 101, 72), (215, 48, 31), (153, 0, 0)],
'orrd8': [(255, 247, 236), (254, 232, 200), (253, 212, 158), (253, 187, 132), (252, 141, 89), (239, 101, 72), (215, 48, 31), (153, 0, 0)],
'orrd9': [(255, 247, 236), (254, 232, 200), (253, 212, 158), (253, 187, 132), (252, 141, 89), (239, 101, 72), (215, 48, 31), (179, 0, 0), (127, 0, 0)],
'paired10': [(166, 206, 227), (106, 61, 154), (31, 120, 180), (178, 223, 138), (51, 160, 44), (251, 154, 153), (227, 26, 28), (253, 191, 111), (255, 127, 0), (202, 178, 214)],
'paired11': [(166, 206, 227), (106, 61, 154), (255, 255, 153), (31, 120, 180), (178, 223, 138), (51, 160, 44), (251, 154, 153), (227, 26, 28), (253, 191, 111), (255, 127, 0), (202, 178, 214)],
'paired12': [(166, 206, 227), (106, 61, 154), (255, 255, 153), (177, 89, 40), (31, 120, 180), (178, 223, 138), (51, 160, 44), (251, 154, 153), (227, 26, 28), (253, 191, 111), (255, 127, 0), (202, 178, 214)],
'paired3': [(166, 206, 227), (31, 120, 180), (178, 223, 138)],
'paired4': [(166, 206, 227), (31, 120, 180), (178, 223, 138), (51, 160, 44)],
'paired5': [(166, 206, 227), (31, 120, 180), (178, 223, 138), (51, 160, 44), (251, 154, 153)],
'paired6': [(166, 206, 227), (31, 120, 180), (178, 223, 138), (51, 160, 44), (251, 154, 153), (227, 26, 28)],
'paired7': [(166, 206, 227), (31, 120, 180), (178, 223, 138), (51, 160, 44), (251, 154, 153), (227, 26, 28), (253, 191, 111)],
'paired8': [(166, 206, 227), (31, 120, 180), (178, 223, 138), (51, 160, 44), (251, 154, 153), (227, 26, 28), (253, 191, 111), (255, 127, 0)],
'paired9': [(166, 206, 227), (31, 120, 180), (178, 223, 138), (51, 160, 44), (251, 154, 153), (227, 26, 28), (253, 191, 111), (255, 127, 0), (202, 178, 214)],
'pastel13': [(251, 180, 174), (179, 205, 227), (204, 235, 197)],
'pastel14': [(251, 180, 174), (179, 205, 227), (204, 235, 197), (222, 203, 228)],
'pastel15': [(251, 180, 174), (179, 205, 227), (204, 235, 197), (222, 203, 228), (254, 217, 166)],
'pastel16': [(251, 180, 174), (179, 205, 227), (204, 235, 197), (222, 203, 228), (254, 217, 166), (255, 255, 204)],
'pastel17': [(251, 180, 174), (179, 205, 227), (204, 235, 197), (222, 203, 228), (254, 217, 166), (255, 255, 204), (229, 216, 189)],
'pastel18': [(251, 180, 174), (179, 205, 227), (204, 235, 197), (222, 203, 228), (254, 217, 166), (255, 255, 204), (229, 216, 189), (253, 218, 236)],
'pastel19': [(251, 180, 174), (179, 205, 227), (204, 235, 197), (222, 203, 228), (254, 217, 166), (255, 255, 204), (229, 216, 189), (253, 218, 236), (242, 242, 242)],
'pastel23': [(179, 226, 205), (253, 205, 172), (203, 213, 232)],
'pastel24': [(179, 226, 205), (253, 205, 172), (203, 213, 232), (244, 202, 228)],
'pastel25': [(179, 226, 205), (253, 205, 172), (203, 213, 232), (244, 202, 228), (230, 245, 201)],
'pastel26': [(179, 226, 205), (253, 205, 172), (203, 213, 232), (244, 202, 228), (230, 245, 201), (255, 242, 174)],
'pastel27': [(179, 226, 205), (253, 205, 172), (203, 213, 232), (244, 202, 228), (230, 245, 201), (255, 242, 174), (241, 226, 204)],
'pastel28': [(179, 226, 205), (253, 205, 172), (203, 213, 232), (244, 202, 228), (230, 245, 201), (255, 242, 174), (241, 226, 204), (204, 204, 204)],
'piyg10': [(142, 1, 82), (39, 100, 25), (197, 27, 125), (222, 119, 174), (241, 182, 218), (253, 224, 239), (230, 245, 208), (184, 225, 134), (127, 188, 65), (77, 146, 33)],
'piyg11': [(142, 1, 82), (77, 146, 33), (39, 100, 25), (197, 27, 125), (222, 119, 174), (241, 182, 218), (253, 224, 239), (247, 247, 247), (230, 245, 208), (184, 225, 134), (127, 188, 65)],
'piyg3': [(233, 163, 201), (247, 247, 247), (161, 215, 106)],
'piyg4': [(208, 28, 139), (241, 182, 218), (184, 225, 134), (77, 172, 38)],
'piyg5': [(208, 28, 139), (241, 182, 218), (247, 247, 247), (184, 225, 134), (77, 172, 38)],
'piyg6': [(197, 27, 125), (233, 163, 201), (253, 224, 239), (230, 245, 208), (161, 215, 106), (77, 146, 33)],
'piyg7': [(197, 27, 125), (233, 163, 201), (253, 224, 239), (247, 247, 247), (230, 245, 208), (161, 215, 106), (77, 146, 33)],
'piyg8': [(197, 27, 125), (222, 119, 174), (241, 182, 218), (253, 224, 239), (230, 245, 208), (184, 225, 134), (127, 188, 65), (77, 146, 33)],
'piyg9': [(197, 27, 125), (222, 119, 174), (241, 182, 218), (253, 224, 239), (247, 247, 247), (230, 245, 208), (184, 225, 134), (127, 188, 65), (77, 146, 33)],
'prgn10': [(64, 0, 75), (0, 68, 27), (118, 42, 131), (153, 112, 171), (194, 165, 207), (231, 212, 232), (217, 240, 211), (166, 219, 160), (90, 174, 97), (27, 120, 55)],
'prgn11': [(64, 0, 75), (27, 120, 55), (0, 68, 27), (118, 42, 131), (153, 112, 171), (194, 165, 207), (231, 212, 232), (247, 247, 247), (217, 240, 211), (166, 219, 160), (90, 174, 97)],
'prgn3': [(175, 141, 195), (247, 247, 247), (127, 191, 123)],
'prgn4': [(123, 50, 148), (194, 165, 207), (166, 219, 160), (0, 136, 55)],
'prgn5': [(123, 50, 148), (194, 165, 207), (247, 247, 247), (166, 219, 160), (0, 136, 55)],
'prgn6': [(118, 42, 131), (175, 141, 195), (231, 212, 232), (217, 240, 211), (127, 191, 123), (27, 120, 55)],
'prgn7': [(118, 42, 131), (175, 141, 195), (231, 212, 232), (247, 247, 247), (217, 240, 211), (127, 191, 123), (27, 120, 55)],
'prgn8': [(118, 42, 131), (153, 112, 171), (194, 165, 207), (231, 212, 232), (217, 240, 211), (166, 219, 160), (90, 174, 97), (27, 120, 55)],
'prgn9': [(118, 42, 131), (153, 112, 171), (194, 165, 207), (231, 212, 232), (247, 247, 247), (217, 240, 211), (166, 219, 160), (90, 174, 97), (27, 120, 55)],
'pubu3': [(236, 231, 242), (166, 189, 219), (43, 140, 190)],
'pubu4': [(241, 238, 246), (189, 201, 225), (116, 169, 207), (5, 112, 176)],
'pubu5': [(241, 238, 246), (189, 201, 225), (116, 169, 207), (43, 140, 190), (4, 90, 141)],
'pubu6': [(241, 238, 246), (208, 209, 230), (166, 189, 219), (116, 169, 207), (43, 140, 190), (4, 90, 141)],
'pubu7': [(241, 238, 246), (208, 209, 230), (166, 189, 219), (116, 169, 207), (54, 144, 192), (5, 112, 176), (3, 78, 123)],
'pubu8': [(255, 247, 251), (236, 231, 242), (208, 209, 230), (166, 189, 219), (116, 169, 207), (54, 144, 192), (5, 112, 176), (3, 78, 123)],
'pubu9': [(255, 247, 251), (236, 231, 242), (208, 209, 230), (166, 189, 219), (116, 169, 207), (54, 144, 192), (5, 112, 176), (4, 90, 141), (2, 56, 88)],
'pubugn3': [(236, 226, 240), (166, 189, 219), (28, 144, 153)],
'pubugn4': [(246, 239, 247), (189, 201, 225), (103, 169, 207), (2, 129, 138)],
'pubugn5': [(246, 239, 247), (189, 201, 225), (103, 169, 207), (28, 144, 153), (1, 108, 89)],
'pubugn6': [(246, 239, 247), (208, 209, 230), (166, 189, 219), (103, 169, 207), (28, 144, 153), (1, 108, 89)],
'pubugn7': [(246, 239, 247), (208, 209, 230), (166, 189, 219), (103, 169, 207), (54, 144, 192), (2, 129, 138), (1, 100, 80)],
'pubugn8': [(255, 247, 251), (236, 226, 240), (208, 209, 230), (166, 189, 219), (103, 169, 207), (54, 144, 192), (2, 129, 138), (1, 100, 80)],
'pubugn9': [(255, 247, 251), (236, 226, 240), (208, 209, 230), (166, 189, 219), (103, 169, 207), (54, 144, 192), (2, 129, 138), (1, 108, 89), (1, 70, 54)],
'puor10': [(127, 59, 8), (45, 0, 75), (179, 88, 6), (224, 130, 20), (253, 184, 99), (254, 224, 182), (216, 218, 235), (178, 171, 210), (128, 115, 172), (84, 39, 136)],
'puor11': [(127, 59, 8), (84, 39, 136), (45, 0, 75), (179, 88, 6), (224, 130, 20), (253, 184, 99), (254, 224, 182), (247, 247, 247), (216, 218, 235), (178, 171, 210), (128, 115, 172)],
'puor3': [(241, 163, 64), (247, 247, 247), (153, 142, 195)],
'puor4': [(230, 97, 1), (253, 184, 99), (178, 171, 210), (94, 60, 153)],
'puor5': [(230, 97, 1), (253, 184, 99), (247, 247, 247), (178, 171, 210), (94, 60, 153)],
'puor6': [(179, 88, 6), (241, 163, 64), (254, 224, 182), (216, 218, 235), (153, 142, 195), (84, 39, 136)],
'puor7': [(179, 88, 6), (241, 163, 64), (254, 224, 182), (247, 247, 247), (216, 218, 235), (153, 142, 195), (84, 39, 136)],
'puor8': [(179, 88, 6), (224, 130, 20), (253, 184, 99), (254, 224, 182), (216, 218, 235), (178, 171, 210), (128, 115, 172), (84, 39, 136)],
'puor9': [(179, 88, 6), (224, 130, 20), (253, 184, 99), (254, 224, 182), (247, 247, 247), (216, 218, 235), (178, 171, 210), (128, 115, 172), (84, 39, 136)],
'purd3': [(231, 225, 239), (201, 148, 199), (221, 28, 119)],
'purd4': [(241, 238, 246), (215, 181, 216), (223, 101, 176), (206, 18, 86)],
'purd5': [(241, 238, 246), (215, 181, 216), (223, 101, 176), (221, 28, 119), (152, 0, 67)],
'purd6': [(241, 238, 246), (212, 185, 218), (201, 148, 199), (223, 101, 176), (221, 28, 119), (152, 0, 67)],
'purd7': [(241, 238, 246), (212, 185, 218), (201, 148, 199), (223, 101, 176), (231, 41, 138), (206, 18, 86), (145, 0, 63)],
'purd8': [(247, 244, 249), (231, 225, 239), (212, 185, 218), (201, 148, 199), (223, 101, 176), (231, 41, 138), (206, 18, 86), (145, 0, 63)],
'purd9': [(247, 244, 249), (231, 225, 239), (212, 185, 218), (201, 148, 199), (223, 101, 176), (231, 41, 138), (206, 18, 86), (152, 0, 67), (103, 0, 31)],
'purples3': [(239, 237, 245), (188, 189, 220), (117, 107, 177)],
'purples4': [(242, 240, 247), (203, 201, 226), (158, 154, 200), (106, 81, 163)],
'purples5': [(242, 240, 247), (203, 201, 226), (158, 154, 200), (117, 107, 177), (84, 39, 143)],
'purples6': [(242, 240, 247), (218, 218, 235), (188, 189, 220), (158, 154, 200), (117, 107, 177), (84, 39, 143)],
'purples7': [(242, 240, 247), (218, 218, 235), (188, 189, 220), (158, 154, 200), (128, 125, 186), (106, 81, 163), (74, 20, 134)],
'purples8': [(252, 251, 253), (239, 237, 245), (218, 218, 235), (188, 189, 220), (158, 154, 200), (128, 125, 186), (106, 81, 163), (74, 20, 134)],
'purples9': [(252, 251, 253), (239, 237, 245), (218, 218, 235), (188, 189, 220), (158, 154, 200), (128, 125, 186), (106, 81, 163), (84, 39, 143), (63, 0, 125)],
'rdbu10': [(103, 0, 31), (5, 48, 97), (178, 24, 43), (214, 96, 77), (244, 165, 130), (253, 219, 199), (209, 229, 240), (146, 197, 222), (67, 147, 195), (33, 102, 172)],
'rdbu11': [(103, 0, 31), (33, 102, 172), (5, 48, 97), (178, 24, 43), (214, 96, 77), (244, 165, 130), (253, 219, 199), (247, 247, 247), (209, 229, 240), (146, 197, 222), (67, 147, 195)],
'rdbu3': [(239, 138, 98), (247, 247, 247), (103, 169, 207)],
'rdbu4': [(202, 0, 32), (244, 165, 130), (146, 197, 222), (5, 113, 176)],
'rdbu5': [(202, 0, 32), (244, 165, 130), (247, 247, 247), (146, 197, 222), (5, 113, 176)],
'rdbu6': [(178, 24, 43), (239, 138, 98), (253, 219, 199), (209, 229, 240), (103, 169, 207), (33, 102, 172)],
'rdbu7': [(178, 24, 43), (239, 138, 98), (253, 219, 199), (247, 247, 247), (209, 229, 240), (103, 169, 207), (33, 102, 172)],
'rdbu8': [(178, 24, 43), (214, 96, 77), (244, 165, 130), (253, 219, 199), (209, 229, 240), (146, 197, 222), (67, 147, 195), (33, 102, 172)],
'rdbu9': [(178, 24, 43), (214, 96, 77), (244, 165, 130), (253, 219, 199), (247, 247, 247), (209, 229, 240), (146, 197, 222), (67, 147, 195), (33, 102, 172)],
'rdgy10': [(103, 0, 31), (26, 26, 26), (178, 24, 43), (214, 96, 77), (244, 165, 130), (253, 219, 199), (224, 224, 224), (186, 186, 186), (135, 135, 135), (77, 77, 77)],
'rdgy11': [(103, 0, 31), (77, 77, 77), (26, 26, 26), (178, 24, 43), (214, 96, 77), (244, 165, 130), (253, 219, 199), (255, 255, 255), (224, 224, 224), (186, 186, 186), (135, 135, 135)],
'rdgy3': [(239, 138, 98), (255, 255, 255), (153, 153, 153)],
'rdgy4': [(202, 0, 32), (244, 165, 130), (186, 186, 186), (64, 64, 64)],
'rdgy5': [(202, 0, 32), (244, 165, 130), (255, 255, 255), (186, 186, 186), (64, 64, 64)],
'rdgy6': [(178, 24, 43), (239, 138, 98), (253, 219, 199), (224, 224, 224), (153, 153, 153), (77, 77, 77)],
'rdgy7': [(178, 24, 43), (239, 138, 98), (253, 219, 199), (255, 255, 255), (224, 224, 224), (153, 153, 153), (77, 77, 77)],
'rdgy8': [(178, 24, 43), (214, 96, 77), (244, 165, 130), (253, 219, 199), (224, 224, 224), (186, 186, 186), (135, 135, 135), (77, 77, 77)],
'rdgy9': [(178, 24, 43), (214, 96, 77), (244, 165, 130), (253, 219, 199), (255, 255, 255), (224, 224, 224), (186, 186, 186), (135, 135, 135), (77, 77, 77)],
'rdpu3': [(253, 224, 221), (250, 159, 181), (197, 27, 138)],
'rdpu4': [(254, 235, 226), (251, 180, 185), (247, 104, 161), (174, 1, 126)],
'rdpu5': [(254, 235, 226), (251, 180, 185), (247, 104, 161), (197, 27, 138), (122, 1, 119)],
'rdpu6': [(254, 235, 226), (252, 197, 192), (250, 159, 181), (247, 104, 161), (197, 27, 138), (122, 1, 119)],
'rdpu7': [(254, 235, 226), (252, 197, 192), (250, 159, 181), (247, 104, 161), (221, 52, 151), (174, 1, 126), (122, 1, 119)],
'rdpu8': [(255, 247, 243), (253, 224, 221), (252, 197, 192), (250, 159, 181), (247, 104, 161), (221, 52, 151), (174, 1, 126), (122, 1, 119)],
'rdpu9': [(255, 247, 243), (253, 224, 221), (252, 197, 192), (250, 159, 181), (247, 104, 161), (221, 52, 151), (174, 1, 126), (122, 1, 119), (73, 0, 106)],
'rdylbu10': [(165, 0, 38), (49, 54, 149), (215, 48, 39), (244, 109, 67), (253, 174, 97), (254, 224, 144), (224, 243, 248), (171, 217, 233), (116, 173, 209), (69, 117, 180)],
'rdylbu11': [(165, 0, 38), (69, 117, 180), (49, 54, 149), (215, 48, 39), (244, 109, 67), (253, 174, 97), (254, 224, 144), (255, 255, 191), (224, 243, 248), (171, 217, 233), (116, 173, 209)],
'rdylbu3': [(252, 141, 89), (255, 255, 191), (145, 191, 219)],
'rdylbu4': [(215, 25, 28), (253, 174, 97), (171, 217, 233), (44, 123, 182)],
'rdylbu5': [(215, 25, 28), (253, 174, 97), (255, 255, 191), (171, 217, 233), (44, 123, 182)],
'rdylbu6': [(215, 48, 39), (252, 141, 89), (254, 224, 144), (224, 243, 248), (145, 191, 219), (69, 117, 180)],
'rdylbu7': [(215, 48, 39), (252, 141, 89), (254, 224, 144), (255, 255, 191), (224, 243, 248), (145, 191, 219), (69, 117, 180)],
'rdylbu8': [(215, 48, 39), (244, 109, 67), (253, 174, 97), (254, 224, 144), (224, 243, 248), (171, 217, 233), (116, 173, 209), (69, 117, 180)],
'rdylbu9': [(215, 48, 39), (244, 109, 67), (253, 174, 97), (254, 224, 144), (255, 255, 191), (224, 243, 248), (171, 217, 233), (116, 173, 209), (69, 117, 180)],
'rdylgn10': [(165, 0, 38), (0, 104, 55), (215, 48, 39), (244, 109, 67), (253, 174, 97), (254, 224, 139), (217, 239, 139), (166, 217, 106), (102, 189, 99), (26, 152, 80)],
'rdylgn11': [(165, 0, 38), (26, 152, 80), (0, 104, 55), (215, 48, 39), (244, 109, 67), (253, 174, 97), (254, 224, 139), (255, 255, 191), (217, 239, 139), (166, 217, 106), (102, 189, 99)],
'rdylgn3': [(252, 141, 89), (255, 255, 191), (145, 207, 96)],
'rdylgn4': [(215, 25, 28), (253, 174, 97), (166, 217, 106), (26, 150, 65)],
'rdylgn5': [(215, 25, 28), (253, 174, 97), (255, 255, 191), (166, 217, 106), (26, 150, 65)],
'rdylgn6': [(215, 48, 39), (252, 141, 89), (254, 224, 139), (217, 239, 139), (145, 207, 96), (26, 152, 80)],
'rdylgn7': [(215, 48, 39), (252, 141, 89), (254, 224, 139), (255, 255, 191), (217, 239, 139), (145, 207, 96), (26, 152, 80)],
'rdylgn8': [(215, 48, 39), (244, 109, 67), (253, 174, 97), (254, 224, 139), (217, 239, 139), (166, 217, 106), (102, 189, 99), (26, 152, 80)],
'rdylgn9': [(215, 48, 39), (244, 109, 67), (253, 174, 97), (254, 224, 139), (255, 255, 191), (217, 239, 139), (166, 217, 106), (102, 189, 99), (26, 152, 80)],
'reds3': [(254, 224, 210), (252, 146, 114), (222, 45, 38)],
'reds4': [(254, 229, 217), (252, 174, 145), (251, 106, 74), (203, 24, 29)],
'reds5': [(254, 229, 217), (252, 174, 145), (251, 106, 74), (222, 45, 38), (165, 15, 21)],
'reds6': [(254, 229, 217), (252, 187, 161), (252, 146, 114), (251, 106, 74), (222, 45, 38), (165, 15, 21)],
'reds7': [(254, 229, 217), (252, 187, 161), (252, 146, 114), (251, 106, 74), (239, 59, 44), (203, 24, 29), (153, 0, 13)],
'reds8': [(255, 245, 240), (254, 224, 210), (252, 187, 161), (252, 146, 114), (251, 106, 74), (239, 59, 44), (203, 24, 29), (153, 0, 13)],
'reds9': [(255, 245, 240), (254, 224, 210), (252, 187, 161), (252, 146, 114), (251, 106, 74), (239, 59, 44), (203, 24, 29), (165, 15, 21), (103, 0, 13)],
'set13': [(228, 26, 28), (55, 126, 184), (77, 175, 74)],
'set14': [(228, 26, 28), (55, 126, 184), (77, 175, 74), (152, 78, 163)],
'set15': [(228, 26, 28), (55, 126, 184), (77, 175, 74), (152, 78, 163), (255, 127, 0)],
'set16': [(228, 26, 28), (55, 126, 184), (77, 175, 74), (152, 78, 163), (255, 127, 0), (255, 255, 51)],
'set17': [(228, 26, 28), (55, 126, 184), (77, 175, 74), (152, 78, 163), (255, 127, 0), (255, 255, 51), (166, 86, 40)],
'set18': [(228, 26, 28), (55, 126, 184), (77, 175, 74), (152, 78, 163), (255, 127, 0), (255, 255, 51), (166, 86, 40), (247, 129, 191)],
'set19': [(228, 26, 28), (55, 126, 184), (77, 175, 74), (152, 78, 163), (255, 127, 0), (255, 255, 51), (166, 86, 40), (247, 129, 191), (153, 153, 153)],
'set23': [(102, 194, 165), (252, 141, 98), (141, 160, 203)],
'set24': [(102, 194, 165), (252, 141, 98), (141, 160, 203), (231, 138, 195)],
'set25': [(102, 194, 165), (252, 141, 98), (141, 160, 203), (231, 138, 195), (166, 216, 84)],
'set26': [(102, 194, 165), (252, 141, 98), (141, 160, 203), (231, 138, 195), (166, 216, 84), (255, 217, 47)],
'set27': [(102, 194, 165), (252, 141, 98), (141, 160, 203), (231, 138, 195), (166, 216, 84), (255, 217, 47), (229, 196, 148)],
'set28': [(102, 194, 165), (252, 141, 98), (141, 160, 203), (231, 138, 195), (166, 216, 84), (255, 217, 47), (229, 196, 148), (179, 179, 179)],
'set310': [(141, 211, 199), (188, 128, 189), (255, 255, 179), (190, 186, 218), (251, 128, 114), (128, 177, 211), (253, 180, 98), (179, 222, 105), (252, 205, 229), (217, 217, 217)],
'set311': [(141, 211, 199), (188, 128, 189), (204, 235, 197), (255, 255, 179), (190, 186, 218), (251, 128, 114), (128, 177, 211), (253, 180, 98), (179, 222, 105), (252, 205, 229), (217, 217, 217)],
'set312': [(141, 211, 199), (188, 128, 189), (204, 235, 197), (255, 237, 111), (255, 255, 179), (190, 186, 218), (251, 128, 114), (128, 177, 211), (253, 180, 98), (179, 222, 105), (252, 205, 229), (217, 217, 217)],
'set33': [(141, 211, 199), (255, 255, 179), (190, 186, 218)],
'set34': [(141, 211, 199), (255, 255, 179), (190, 186, 218), (251, 128, 114)],
'set35': [(141, 211, 199), (255, 255, 179), (190, 186, 218), (251, 128, 114), (128, 177, 211)],
'set36': [(141, 211, 199), (255, 255, 179), (190, 186, 218), (251, 128, 114), (128, 177, 211), (253, 180, 98)],
'set37': [(141, 211, 199), (255, 255, 179), (190, 186, 218), (251, 128, 114), (128, 177, 211), (253, 180, 98), (179, 222, 105)],
'set38': [(141, 211, 199), (255, 255, 179), (190, 186, 218), (251, 128, 114), (128, 177, 211), (253, 180, 98), (179, 222, 105), (252, 205, 229)],
'set39': [(141, 211, 199), (255, 255, 179), (190, 186, 218), (251, 128, 114), (128, 177, 211), (253, 180, 98), (179, 222, 105), (252, 205, 229), (217, 217, 217)],
'spectral10': [(158, 1, 66), (94, 79, 162), (213, 62, 79), (244, 109, 67), (253, 174, 97), (254, 224, 139), (230, 245, 152), (171, 221, 164), (102, 194, 165), (50, 136, 189)],
'spectral11': [(158, 1, 66), (50, 136, 189), (94, 79, 162), (213, 62, 79), (244, 109, 67), (253, 174, 97), (254, 224, 139), (255, 255, 191), (230, 245, 152), (171, 221, 164), (102, 194, 165)],
'spectral3': [(252, 141, 89), (255, 255, 191), (153, 213, 148)],
'spectral4': [(215, 25, 28), (253, 174, 97), (171, 221, 164), (43, 131, 186)],
'spectral5': [(215, 25, 28), (253, 174, 97), (255, 255, 191), (171, 221, 164), (43, 131, 186)],
'spectral6': [(213, 62, 79), (252, 141, 89), (254, 224, 139), (230, 245, 152), (153, 213, 148), (50, 136, 189)],
'spectral7': [(213, 62, 79), (252, 141, 89), (254, 224, 139), (255, 255, 191), (230, 245, 152), (153, 213, 148), (50, 136, 189)],
'spectral8': [(213, 62, 79), (244, 109, 67), (253, 174, 97), (254, 224, 139), (230, 245, 152), (171, 221, 164), (102, 194, 165), (50, 136, 189)],
'spectral9': [(213, 62, 79), (244, 109, 67), (253, 174, 97), (254, 224, 139), (255, 255, 191), (230, 245, 152), (171, 221, 164), (102, 194, 165), (50, 136, 189)],
'ylgn3': [(247, 252, 185), (173, 221, 142), (49, 163, 84)],
'ylgn4': [(255, 255, 204), (194, 230, 153), (120, 198, 121), (35, 132, 67)],
'ylgn5': [(255, 255, 204), (194, 230, 153), (120, 198, 121), (49, 163, 84), (0, 104, 55)],
'ylgn6': [(255, 255, 204), (217, 240, 163), (173, 221, 142), (120, 198, 121), (49, 163, 84), (0, 104, 55)],
'ylgn7': [(255, 255, 204), (217, 240, 163), (173, 221, 142), (120, 198, 121), (65, 171, 93), (35, 132, 67), (0, 90, 50)],
'ylgn8': [(255, 255, 229), (247, 252, 185), (217, 240, 163), (173, 221, 142), (120, 198, 121), (65, 171, 93), (35, 132, 67), (0, 90, 50)],
'ylgn9': [(255, 255, 229), (247, 252, 185), (217, 240, 163), (173, 221, 142), (120, 198, 121), (65, 171, 93), (35, 132, 67), (0, 104, 55), (0, 69, 41)],
'ylgnbu3': [(237, 248, 177), (127, 205, 187), (44, 127, 184)],
'ylgnbu4': [(255, 255, 204), (161, 218, 180), (65, 182, 196), (34, 94, 168)],
'ylgnbu5': [(255, 255, 204), (161, 218, 180), (65, 182, 196), (44, 127, 184), (37, 52, 148)],
'ylgnbu6': [(255, 255, 204), (199, 233, 180), (127, 205, 187), (65, 182, 196), (44, 127, 184), (37, 52, 148)],
'ylgnbu7': [(255, 255, 204), (199, 233, 180), (127, 205, 187), (65, 182, 196), (29, 145, 192), (34, 94, 168), (12, 44, 132)],
'ylgnbu8': [(255, 255, 217), (237, 248, 177), (199, 233, 180), (127, 205, 187), (65, 182, 196), (29, 145, 192), (34, 94, 168), (12, 44, 132)],
'ylgnbu9': [(255, 255, 217), (237, 248, 177), (199, 233, 180), (127, 205, 187), (65, 182, 196), (29, 145, 192), (34, 94, 168), (37, 52, 148), (8, 29, 88)],
'ylorbr3': [(255, 247, 188), (254, 196, 79), (217, 95, 14)],
'ylorbr4': [(255, 255, 212), (254, 217, 142), (254, 153, 41), (204, 76, 2)],
'ylorbr5': [(255, 255, 212), (254, 217, 142), (254, 153, 41), (217, 95, 14), (153, 52, 4)],
'ylorbr6': [(255, 255, 212), (254, 227, 145), (254, 196, 79), (254, 153, 41), (217, 95, 14), (153, 52, 4)],
'ylorbr7': [(255, 255, 212), (254, 227, 145), (254, 196, 79), (254, 153, 41), (236, 112, 20), (204, 76, 2), (140, 45, 4)],
'ylorbr8': [(255, 255, 229), (255, 247, 188), (254, 227, 145), (254, 196, 79), (254, 153, 41), (236, 112, 20), (204, 76, 2), (140, 45, 4)],
'ylorbr9': [(255, 255, 229), (255, 247, 188), (254, 227, 145), (254, 196, 79), (254, 153, 41), (236, 112, 20), (204, 76, 2), (153, 52, 4), (102, 37, 6)],
'ylorrd3': [(255, 237, 160), (254, 178, 76), (240, 59, 32)],
'ylorrd4': [(255, 255, 178), (254, 204, 92), (253, 141, 60), (227, 26, 28)],
'ylorrd5': [(255, 255, 178), (254, 204, 92), (253, 141, 60), (240, 59, 32), (189, 0, 38)],
'ylorrd6': [(255, 255, 178), (254, 217, 118), (254, 178, 76), (253, 141, 60), (240, 59, 32), (189, 0, 38)],
'ylorrd7': [(255, 255, 178), (254, 217, 118), (254, 178, 76), (253, 141, 60), (252, 78, 42), (227, 26, 28), (177, 0, 38)],
'ylorrd8': [(255, 255, 204), (255, 237, 160), (254, 217, 118), (254, 178, 76), (253, 141, 60), (252, 78, 42), (227, 26, 28), (177, 0, 38)],
}
if __name__ == '__main__':
main()
openxenmanager/window_menuitem.py 0000644 0001750 0001750 00000223521 11636446664 016074 0 ustar rrs rrs
# OpenXenManager
#
# Copyright (C) 2009 Alberto Gonzalez Rodriguez alberto@pesadilla.org
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------
#!/usr/bin/env python
import gtk
from oxcSERVER import *
import xtea
from thread import *
import pdb
class oxcWindowMenuItem:
"""
Class used to manage functions called from menuitems
"""
# HOST/SERVER
def on_m_repair_storage_activate(self, widget, data=None):
"""
Function called on "Repair storage"
"""
self.builder.get_object("cancelrepairstorage").set_label("Cancel")
self.builder.get_object("lblrepairerror").hide()
self.builder.get_object("repairstorage").show()
listrepairstorage = self.builder.get_object("listrepairstorage")
self.xc_servers[self.selected_host].fill_listrepairstorage(listrepairstorage, self.selected_ref)
def on_cancelrepairstorage_clicked(self, widget, data=None):
"""
Function called when you press cancel on "repair storage" window
"""
self.builder.get_object("repairstorage").hide()
def on_acceptrepairstorage_clicked(self, widget, data=None):
"""
Function called when you press Repair on "repair storage" window
"""
self.builder.get_object("lblrepairerror").show()
self.builder.get_object("lblrepairerror").set_markup(\
"Repairing... wait please.")
listrepairstorage = self.builder.get_object("listrepairstorage")
Thread(target=self.xc_servers[self.selected_host].repair_storage,
args=(listrepairstorage, self.selected_ref)).start()
self.builder.get_object("acceptrepairstorage").set_sensitive(False)
def on_m_remove_activate(self, widget, data=None):
"""
Called from "remove" menuitem of server
"""
# Remove server from configuration
del self.config_hosts[self.selected_name]
self.config['servers']['hosts'] = self.config_hosts
self.config.write()
# Remove from left treeview (treestore)
self.treestore.remove(self.selected_iter)
def on_m_forget_activate(self, widget, data=None):
"""
Forget password: dont remember password for server
"""
# Only put to "" the server password on oxc.conf
if self.selected_name in self.config_hosts:
self.config_hosts[self.selected_name][1] = ""
elif self.selected_ip in self.config_hosts:
self.config_hosts[self.selected_ip][1] = ""
elif self.selected_host in self.config_hosts:
self.config_hosts[self.selected_host][1] = ""
def on_m_addserver_activate(self, widget, data=None):
"""
Add server: show the window for add a new server
"""
self.builder.get_object("addserver").show()
# VM
# Make Into Template
def on_m_make_into_template_activate(self, widget, data=None):
"""
Called from "make into template" menuitem of VM
Call to method "make_into_template" of oxcSERVER with selected ref param (vm ref)
"""
self.xc_servers[self.selected_host].make_into_template(self.selected_ref)
# Copy VM
def on_m_snapshot_activate(self, widget, data=None):
"""
Called from "snapshot" menuitem of VM
Show snapshot dialog and set the name to empty
"""
self.builder.get_object("snapshotname").set_text("")
self.builder.get_object("dialogsnapshotname").show()
def on_m_copy_activate(self, widget, data=None):
"""
Called from "copy" menuitem of VM
"""
listcopystg = self.builder.get_object("listcopystg")
treecopystg = self.builder.get_object("treecopystg")
# Set name and description on copy window
self.builder.get_object("txtcopyvmname").set_text("Copy of " + self.selected_name)
self.builder.get_object("txtcopyvmdesc").set_text(
self.xc_servers[self.selected_host].all_vms[self.selected_ref]['name_description']
)
"""
Fill the treeview called "treecopystg" with model "listcopystg" with possible storage
This treeview is only used on "full copy"
fill_listcopystg return the number position of default storage
"""
defsr = self.xc_servers[self.selected_host].fill_listcopystg(listcopystg, self.selected_host)
# Select the default storage
treecopystg.set_cursor((defsr,), treecopystg.get_column(0))
treecopystg.get_selection().select_path((defsr, 0))
# Show the window copy window
self.builder.get_object("windowcopyvm").show()
def on_cancelforcejoinpool_clicked(self, widget, data=None):
"""
Cancel "force join to pool" dialog
"""
self.builder.get_object("forcejoinpool").hide()
def on_acceptforcejoinpool_clicked(self, widget, data=None):
"""
Accept "force join to pool" dialog
"""
last_pool_data = self.xc_servers[self.last_host_pool].last_pool_data
self.xc_servers[self.last_host_pool].add_server_to_pool_force(self.selected_ref, last_pool_data)
self.builder.get_object("forcejoinpool").hide()
def on_m_pool_add_server_activate(self, widget, data=None):
"""
Called from "Add Server" right menu (pool)
"""
for i in range(2,len(self.builder.get_object("menu_m_add_server").get_children())):
self.builder.get_object("menu_m_add_server").remove(self.builder.get_object("menu_m_add_server").get_children()[2])
for server in self.xc_servers:
if self.xc_servers[server].is_connected == True:
pool_ref = self.xc_servers[server].all_pools.keys()[0]
if self.xc_servers[server].all_pools[pool_ref]["name_label"] == "":
image = gtk.Image()
image.set_from_file("images/tree_running_16.png")
item = gtk.ImageMenuItem(gtk.STOCK_HELP,None)
item.use_underline = False
item.set_image(image)
# Host ref
ref = self.xc_servers[server].all_hosts.keys()[0]
self.builder.get_object("menu_m_add_server").append(item)
item.connect("activate", self.xc_servers[server].add_server_to_pool, ref, server, ref, self.selected_ip)
item.get_children()[0].set_label(self.xc_servers[server].all_hosts[ref]["name_label"])
item.show()
def on_m_add_to_pool_activate(self, widget, data=None):
"""
Called from "Add To pool" menuitem (server)
"""
for i in range(2,len(self.builder.get_object("menu_add_to_pool").get_children())):
self.builder.get_object("menu_add_to_pool").remove(self.builder.get_object("menu_add_to_pool").get_children()[2])
for server in self.xc_servers:
if self.xc_servers[server].is_connected == True:
pool_ref = self.xc_servers[server].all_pools.keys()[0]
if self.xc_servers[server].all_pools[pool_ref]["name_label"] != "":
image = gtk.Image()
image.set_from_file("images/poolconnected_16.png")
item = gtk.ImageMenuItem(gtk.STOCK_HELP,None)
item.use_underline = False
item.set_image(image)
# Host ref
pool = self.xc_servers[server].all_pools[pool_ref]["name_label"]
self.builder.get_object("menu_add_to_pool").append(item)
item.connect("activate", self.xc_servers[self.selected_ip].add_server_to_pool, pool_ref, self.selected_ip, self.selected_ref, server)
item.get_children()[0].set_label(pool)
item.show()
def on_menuitem_pool_add_server_activate(self, widget, data=None):
"""
Called from "Add Server" menuitem (pool)
"""
for i in range(2,len(self.builder.get_object("menu_add_server").get_children())):
self.builder.get_object("menu_add_server").remove(self.builder.get_object("menu_add_server").get_children()[2])
for server in self.xc_servers:
if self.xc_servers[server].is_connected == True:
pool_ref = self.xc_servers[server].all_pools.keys()[0]
if self.xc_servers[server].all_pools[pool_ref]["name_label"] == "":
image = gtk.Image()
image.set_from_file("images/tree_running_16.png")
item = gtk.ImageMenuItem(gtk.STOCK_HELP,None)
item.use_underline = False
item.set_image(image)
# Host ref
ref = self.xc_servers[server].all_hosts.keys()[0]
self.builder.get_object("menu_add_server").append(item)
item.connect("activate", self.xc_servers[server].add_server_to_pool, ref, server, ref, self.selected_ip)
item.get_children()[0].set_label(self.xc_servers[server].all_hosts[ref]["name_label"])
item.show()
def on_menuitem_server_add_to_pool_activate(self, widget, data=None):
"""
Called from "Add to pool" menuitem (server)
"""
for i in range(2,len(self.builder.get_object("menu_server_add_to_pool").get_children())):
self.builder.get_object("menu_server_add_to_pool").remove(self.builder.get_object("menu_server_add_to_pool").get_children()[2])
for server in self.xc_servers:
if self.xc_servers[server].is_connected == True:
pool_ref = self.xc_servers[server].all_pools.keys()[0]
if self.xc_servers[server].all_pools[pool_ref]["name_label"] != "":
image = gtk.Image()
image.set_from_file("images/poolconnected_16.png")
item = gtk.ImageMenuItem(gtk.STOCK_HELP,None)
item.use_underline = False
item.set_image(image)
# Host ref
pool = self.xc_servers[server].all_pools[pool_ref]["name_label"]
self.builder.get_object("menu_server_add_to_pool").append(item)
item.connect("activate", self.xc_servers[self.selected_ip].add_server_to_pool, pool_ref, self.selected_ip, self.selected_ref, server)
item.get_children()[0].set_label(pool)
item.show()
def on_m_resume_on_activate(self, widget, data=None):
"""
Called from "Resumen on" menuitem of VM
"""
# Remove the previous possible servers of submenu (right menu)
for i in range(2,len(self.builder.get_object("menu_resume_on").get_children())):
self.builder.get_object("menu_resume_on").remove(self.builder.get_object("menu_resume_on").get_children()[2])
# Go all servers and add to submenu (right menu)
for h in self.xc_servers[self.selected_host].all_hosts:
image = gtk.Image()
image.set_from_file("images/xen.gif")
item = gtk.ImageMenuItem(gtk.STOCK_HELP,None)
item.use_underline = False
item.set_image(image)
"""
Set the signal, when is clicked call to function "start_resumen_on" with params:
- Selected vm ref
- Host ref
"""
item.connect("activate", self.xc_servers[self.selected_host].resume_vm_on, self.selected_ref, h)
self.builder.get_object("menu_resume_on").append(item)
host_name = self.xc_servers[self.selected_host].all_hosts[h]['name_label']
"""
Can start function could return:
- Empty string means vm can start in that server
- Not empty string means means vm cannot start in that server (not memory or other error)
"""
can_start = self.xc_servers[self.selected_host].can_start(self.selected_ref, h)
if can_start:
item.get_children()[0].set_label(host_name + " : " + can_start)
else:
item.get_children()[0].set_label(host_name)
item.show()
# If server cannot be used to resume on it, disable server
if can_start != "":
item.set_sensitive(False)
def on_m_start_on_activate(self, widget, data=None):
"""
Called from "Start on" menuitem of VM
"""
# Remove the previous possible servers of submenu (right menu)
for i in range(2,len(self.builder.get_object("menu_start_on").get_children())):
self.builder.get_object("menu_start_on").remove(self.builder.get_object("menu_start_on").get_children()[2])
# Go all servers and add to submenu (right menu)
for h in self.xc_servers[self.selected_host].all_hosts:
image = gtk.Image()
image.set_from_file("images/xen.gif")
item = gtk.ImageMenuItem(gtk.STOCK_HELP,None)
item.use_underline = False
item.set_image(image)
"""
Set the signal, when is clicked call to function "start_resumen_on" with params:
- Selected vm ref
- Host ref
"""
item.connect("activate", self.xc_servers[self.selected_host].start_vm_on, self.selected_ref, h)
self.builder.get_object("menu_start_on").append(item)
host_name = self.xc_servers[self.selected_host].all_hosts[h]['name_label']
"""
Can start function could return:
- Empty string means vm can start in that server
- Not empty string means means vm cannot start in that server (not memory or other error)
"""
can_start = self.xc_servers[self.selected_host].can_start(self.selected_ref, h)
if can_start:
item.get_children()[0].set_label(host_name + " : " + can_start)
else:
item.get_children()[0].set_label(host_name)
item.show()
# If server cannot be used to resume on it, disable server
if can_start != "":
item.set_sensitive(False)
def on_m_pool_migrate_activate(self, widget, data=None):
"""
Called from "Start on" menuitem of VM
"""
# Remove the previous possible servers of submenu (right menu)
for i in range(2,len(self.builder.get_object("menu_pool_migrate").get_children())):
self.builder.get_object("menu_pool_migrate").remove(self.builder.get_object("menu_pool_migrate").get_children()[2])
# Go all servers and add to submenu (right menu)
for h in self.xc_servers[self.selected_host].all_hosts:
image = gtk.Image()
image.set_from_file("images/xen.gif")
item = gtk.ImageMenuItem(gtk.STOCK_HELP,None)
item.use_underline = False
item.set_image(image)
"""
Set the signal, when is clicked call to function "start_resumen_on" with params:
- Selected vm ref
- Host ref
"""
item.connect("activate", self.xc_servers[self.selected_host].migrate_vm, self.selected_ref, h)
self.builder.get_object("menu_pool_migrate").append(item)
host_name = self.xc_servers[self.selected_host].all_hosts[h]['name_label']
resident_on = self.xc_servers[self.selected_host].all_vms[self.selected_ref]['resident_on']
"""
Can start function could return:
- Empty string means vm can start in that server
- Not empty string means means vm cannot start in that server (not memory or other error)
"""
can_start = self.xc_servers[self.selected_host].can_start(self.selected_ref, h)
if can_start:
item.get_children()[0].set_label(host_name + " : " + can_start)
else:
item.get_children()[0].set_label(host_name)
item.show()
# If server cannot be used to resume on it, disable server
if can_start != "" or h == resident_on:
item.set_sensitive(False)
#TOOLBAR
def on_tb_start_clicked(self, widget, data=None):
"""
"Start" button on toolbar is pressed
Power on a VM
"""
self.xc_servers[self.selected_host].start_vm(self.selected_ref)
def on_tb_clean_shutdown_clicked(self, widget, data=None):
"""
"Clean shutdown" on toolbar is pressed
Clean shutdown a vm
"""
self.xc_servers[self.selected_host].clean_shutdown_vm(self.selected_ref)
def on_tb_hard_shutdown_clicked(self, widget, data=None):
"""
"Hard shutdown" on toolbar is pressed
Hard shutdown a vm
"""
self.xc_servers[self.selected_host].hard_shutdown_vm(self.selected_ref)
def on_tb_clean_reboot_clicked(self, widget, data=None):
"""
"Clean reboot" on toolbar is pressed
Clean reboot a vm
"""
self.xc_servers[self.selected_host].clean_reboot_vm(self.selected_ref)
def on_tb_hard_reboot_clicked(self, widget, data=None):
"""
"Hard reboot" on toolbar is pressed
hard reboot a vm
"""
self.xc_servers[self.selected_host].hard_reboot_vm(self.selected_ref)
def on_tb_suspend_clicked(self, widget, data=None):
"""
"Suspend" on toolbar is pressed
Suspend a vm
"""
self.xc_servers[self.selected_host].suspend_vm(self.selected_ref)
def on_tb_unpause_clicked(self, widget, data=None):
"""
"Resumen" on toolbar is pressed
Resume a suspended vm
"""
self.xc_servers[self.selected_host].unpause_vm(self.selected_ref)
def on_tbalerts_clicked(self, widget, data=None):
"""
Open the alert window
"""
self.builder.get_object("windowalerts").show()
def update_toolbar(self):
"""
This function is called when a VM, host, storage or template is selected
Toolbar buttons are called:
tb_action, e.g: tb_start
check if "start" (removing tb_) exists on possible actions of this VM/host/...
"""
toolbar = self.builder.get_object("toolbar")
# for each children of toolbar
for child in toolbar.get_children():
if gtk.Buildable.get_name(child)[0:3] == "tb_":
# self.selected_actions contains possible actions
# if not exists: disable button
# else: enable button
if not self.selected_actions or \
self.selected_actions.count(gtk.Buildable.get_name(child)[3:]) \
== 0:
child.set_sensitive(False)
else:
child.set_sensitive(True)
if gtk.Buildable.get_name(child)[3:] == "hard_shutdown":
if not self.selected_actions.count("clean_shutdown"):
self.builder.get_object("tb_clean_shutdown").hide()
self.builder.get_object("tb_hard_shutdown").show()
if gtk.Buildable.get_name(child)[3:] == "hard_reboot":
if not self.selected_actions.count("clean_reboot"):
self.builder.get_object("tb_clean_reboot").hide()
self.builder.get_object("tb_hard_reboot").show()
if gtk.Buildable.get_name(child)[3:] == "clean_shutdown":
self.builder.get_object("tb_clean_shutdown").show()
self.builder.get_object("tb_clean_reboot").show()
self.builder.get_object("tb_hard_reboot").hide()
self.builder.get_object("tb_hard_shutdown").hide()
# MENUBAR Actions
def on_m_start_activate(self, widget, data=None):
"""
"Start" menuitem pressed on right click menu
"""
self.xc_servers[self.selected_host].start_vm(self.selected_ref)
def on_m_clean_shutdown_activate(self, widget, data=None):
"""
"Clean shutdown" menuitem pressed on right click menu
"""
if self.selected_type == "vm":
self.xc_servers[self.selected_host].clean_shutdown_vm(self.selected_ref)
elif self.selected_type == "server" or self.selected_type == "host":
self.on_menuitem_server_shutdown_activate(widget, data)
def on_m_clean_reboot_activate(self, widget, data=None):
"""
"Clean reboot" menuitem pressed on right click menu
"""
if self.selected_type == "vm":
self.xc_servers[self.selected_host].clean_reboot_vm(self.selected_ref)
elif self.selected_type == "server" or self.selected_type == "host":
self.on_menuitem_server_reboot_activate(widget, data)
def on_m_suspend_activate(self, widget, data=None):
"""
"Suspend" menuitem pressed on right click menu
"""
self.xc_servers[self.selected_host].suspend_vm(self.selected_ref)
def on_m_unpause_activate(self, widget, data=None):
"""
"Unpause" menuitem pressed on right click menu
"""
self.xc_servers[self.selected_host].unpause_vm(self.selected_ref)
def on_m_hard_reboot_activate(self, widget, data=None):
"""
"Hard reboot" menuitem pressed on right click menu
"""
self.xc_servers[self.selected_host].hard_reboot_vm(self.selected_ref)
def on_m_hard_shutdown_activate(self, widget, data=None):
"""
"Hard shutdown" menuitem pressed on right click menu
"""
self.xc_servers[self.selected_host].hard_shutdown_vm(self.selected_ref)
def on_m_pause_activate(self, widget, data=None):
"""
"Pause" menuitem pressed on right click menu
"""
self.xc_servers[self.selected_host].pause_vm(self.selected_ref)
def on_m_unsuspend_activate(self, widget, data=None):
"""
"Resume" (unsuspend) menuitem pressed on right click menu
"""
self.xc_servers[self.selected_host].unsuspend_vm(self.selected_ref)
def on_m_resume_activate(self, widget, data=None):
"""
"Resume" menuitem pressed on right click menu
"""
self.xc_servers[self.selected_host].resume_vm(self.selected_ref)
def on_menuitem_tools_updatemanager_activate(self, widget, data=None):
"""
"Update Manager" menuitem pressed on right click menu
"""
listupdates = self.builder.get_object("listupdates")
treeupdates = self.builder.get_object("treeupdates")
self.xc_servers[self.selected_host].fill_list_updates(self.selected_ref, listupdates)
if listupdates.__len__():
treeupdates.set_cursor((0, ), treeupdates.get_column(0))
treeupdates.get_selection().select_path((0, ))
self.builder.get_object("updatemanager").show()
def on_installxenservertools_activate(self, widget, data=None):
"""
"Install XenServer Tools" menuitem pressed on right click menu
"""
self.xc_servers[self.selected_host].install_xenserver_tools(self.selected_ref)
def on_m_forget_activate(self, widget, data=None):
"""
"Forget Storage" menuitem pressed on right click menu
"""
target=self.xc_servers[self.selected_host].forget_storage(self.selected_ref)
def on_m_unplug_activate(self, widget, data=None):
"""
"Detach Storage" menuitem pressed on right click menu
"""
# Show confirmation dialog
self.builder.get_object("detachstorage").show()
def on_acceptdetachstorage_clicked(self, wwidget, data=None):
"""
Function called when you accept confirmation "detach storage" dialog
"""
#target=self.xc_servers[self.selected_host].detach_storage(self.selected_ref)
Thread(target=self.xc_servers[self.selected_host].detach_storage, args=(self.selected_ref,)).start()
self.builder.get_object("detachstorage").hide()
def on_canceldetachstorage_clicked(self, widget, data=None):
"""
Function called when you cancel confirmation "detach storage" dialog
"""
self.builder.get_object("detachstorage").hide()
def on_m_reattach_activate(self, widget, data=None):
"""
"Reattach Storage" menuitem pressed on right click menu
"""
stgtype = self.xc_servers[self.selected_host].all_storage[self.selected_ref]['type']
# If selected type is iso, you only can select "NFS ISO" or "CIFS ISO"
if stgtype == "iso":
disable = ["radionewstgnfsvhd", "radionewstgiscsi", "radionewstghwhba",
"radionewstgnetapp", "radionewstgdell"]
for widget in disable:
self.builder.get_object(widget).set_sensitive(False)
enable = ["radionewstgcifs", "radionewstgnfsiso"]
for widget in enable:
self.builder.get_object(widget).set_sensitive(True)
elif stgtype == "lvmoiscsi":
self.builder.get_object("radionewstgiscsi").set_active(True)
self.builder.get_object("txtiscsiname").set_text(self.selected_name)
self.on_nextnewstorage_clicked(self.builder.get_object("nextnewstorage"), data)
self.builder.get_object("previousnewstorage").set_sensitive(False)
elif stgtype == "nfs":
self.builder.get_object("radionewstgnfsvhd").set_active(True)
self.builder.get_object("txtnewstgnfsname").set_text(self.selected_name)
self.on_nextnewstorage_clicked(widget, data)
self.builder.get_object("previousnewstorage").set_sensitive(False)
else:
print stgtype
self.builder.get_object("radionewstgcifs").set_active(True)
# Flag variable to know if we will do a reattach
self.reattach_storage = True
self.builder.get_object("newstorage").show()
def on_m_importvm_activate(self, widget, data=None):
"""
"Import VM" menuitem pressed on right click menu
"""
blue = gtk.gdk.color_parse("#d5e5f7")
# Disable "next button", it will be enabled when file is selected
self.builder.get_object("nextvmimport").set_sensitive(False)
self.builder.get_object("eventimport0").modify_bg(gtk.STATE_NORMAL, blue)
# Set a filter, you only can selected *.xva files
self.builder.get_object("filefilterimportvm").add_pattern("*.xva")
# Show the import window
self.builder.get_object("vmimport").show()
# listimportservers contains the connected servers
listimportservers = self.builder.get_object("listimportservers")
listimportservers.clear()
# For each host in config..
for host in self.config_hosts:
# If we are connected to this server
if host in self.xc_servers:
# Then add to list
listimportservers.append([gtk.gdk.pixbuf_new_from_file("images/tree_connected_16.png"),
self.xc_servers[host].hostname,True,host]);
"""
else:
listimportservers.append([gtk.gdk.pixbuf_new_from_file("images/tree_disconnected_16.png"),
host,False]);
"""
# If we are connected to some server..
if listimportservers.__len__():
treeimportservers = self.builder.get_object("treeimportservers")
# Then selected the first
treeimportservers.set_cursor((0, ), treeimportservers.get_column(0))
treeimportservers.get_selection().select_path((0, ))
def on_m_export_activate(self, widget, data=None):
"""
"Export VM" menuitem pressed on right click menu
"""
# Set default name
self.filesave.set_current_name(self.selected_name + ".xva")
# Show the choose dialog
self.filesave.show()
def on_m_snap_newvm_activate(self, widget, data=None):
"""
"New VM From snapshot" menuitem pressed on "snapshot" menu (Snapshots tab of VM)
"""
# Show the "new vm" window
# TODO -> select vm with name_label
self.on_m_newvm_activate(widget, data)
def on_m_snap_createtpl_activate(self, widget, data=None):
"""
"Create template from snapshot" menuitem pressed on "snapshot" menu (Snapshots tab of VM)
"""
# set a default name
self.builder.get_object("snaptplname").set_text("Template from snapshot '" + \
self.xc_servers[self.selected_host].all_vms[self.selected_snap_ref]['name_label'] + "'")
# Shows a dialog to enter a name for new template
self.builder.get_object("dialogsnaptplname").show()
def on_m_snap_delete_activate(self, widget, data=None):
"""
"Delete snapshot" menuitem pressed on "snapshot" menu (Snapshots tab of VM)
"""
# Show a dialog asking confirmation
self.builder.get_object("dialogsnapshotdelete").show()
def on_m_destroy_activate(self, widget, data=None):
"""
"Destroy" menuitem pressed on right click menu (VM)
"""
# Show a dialog asking confirmation
if self.selected_type == "vm":
self.builder.get_object("dialogdeletevm").show()
self.builder.get_object("dialogdeletevm").set_markup("Are you sure you want to delete VM '" + self.selected_name + "' ?")
elif self.selected_type == "template" or self.selected_type == "custom_template":
self.builder.get_object("dialogdeletevm").show()
self.builder.get_object("dialogdeletevm").set_markup("Are you sure you want to delete template '" + self.selected_name + "' ?")
elif self.selected_type == "storage":
print "delete storage"
#self.treestore.remove(self.selected_iter)
#self.xc_servers[self.selected_host].destroy_vm(self.selected_ref)
def on_m_connect_activate(self, widget, data=None):
"""
"Connect" menuitem pressed on right click menu (Host)
"""
# Checks if exists a "master password"
# Master password if need to save reverse passwords with XTEA
# XTEA is a block cipher to save server password on oxc.conf
# If master password if used (saved on oxc.conf as md5) use it to xtea decrypt
if not self.selected_name in self.config_hosts:
return
if len(self.config_hosts[self.selected_name]) > 2:
self.builder.get_object("checksslconnection").set_active(str(self.config_hosts[self.selected_name][2]) == "True")
if self.password and self.config_hosts[self.selected_name][1]:
# Decrypt password to plain
# Use typed master password (previously checked with md5)
# Fill characters left with "X" to reach a 16 characters
decrypt_pw = xtea.crypt("X" * (16-len(self.password)) + self.password, \
self.config_hosts[self.selected_name][1].decode("hex"), self.iv)
# Call to add server with name, ip and decrypted password
# Add server try to connect to the server
self.add_server(self.selected_name, self.config_hosts[self.selected_name][0], \
decrypt_pw)
else:
# If master password is not set or server hasn't a saved password
# Empty entries
self.builder.get_object("addserverhostname").get_child().set_text(self.selected_name)
self.builder.get_object("addserverusername").set_text(self.config_hosts[self.selected_name][0])
self.builder.get_object("addserverpassword").set_text("")
# Show the add server window
addserver = self.builder.get_object("addserver").show_all()
self.builder.get_object("addserverpassword").grab_focus()
def on_m_disconnect_activate(self, widget, data=None):
"""
"Disconnect" menuitem pressed on right click menu (Host)
"""
# Checks if exists a "master password"
# get the ip/host (not virtual name)
host = self.xc_servers[self.selected_host].host
# Logout implies:
# - Unregister events to current session
# - Disconnect of server
self.xc_servers[self.selected_host].logout()
# Remove from list (and children)
if len(self.treestore.get_path(self.selected_iter)) == 2:
self.treestore.remove(self.selected_iter)
else:
path = (self.treestore.get_path(self.selected_iter)[0], self.treestore.get_path(self.selected_iter)[1])
iter = self.treestore.get_iter(path)
self.treestore.remove(iter)
# Add again the ip/host name
self.treestore.append(self.treeroot, ([gtk.gdk.pixbuf_new_from_file("images/tree_disconnected_16.png"), host, None, "server", "Disconnected", None, None, ["connect", "forgetpw", "remove"], None]))
# If copy window is showed.. hide
self.builder.get_object("windowcopyvm").hide()
self.treeview.set_cursor((0, ), self.treeview.get_column(0))
self.treeview.get_selection().select_path((0, ))
# Update tabs
self.selected_type = "home"
self.update_tabs()
# Delete alerts
self.builder.get_object("listalerts").clear()
for host in self.xc_servers:
if self.xc_servers[host].is_connected:
self.xc_servers[host].fill_alerts(self.listalerts)
self.update_n_alerts()
def on_m_newvm_activate(self, widget, data=None):
"""
"New VM" menuitem pressed on right click menu (Host)
"""
# self.newvmdata is used to set "new vm" parameters
self.newvmdata = {}
listtemplates = self.builder.get_object("listtemplates")
# Fill the "list of templates" to create a new VM
self.xc_servers[self.selected_host].fill_list_templates(listtemplates)
# Set to first page and setting "page_comple" next button is enabled
self.builder.get_object("tabboxnewvm").set_current_page(0)
# Select the first template by default
treetemplates = self.builder.get_object("treetemplates")
treetemplates.set_cursor((0, 1), treetemplates.get_column(1))
treetemplates.get_selection().select_path((0, 1))
# For some templates is needed use DVD Drive or ISO Images
# Fill the possible iso images to use
self.xc_servers[self.selected_host].fill_list_isoimages(self.listisoimage)
self.builder.get_object("radiobutton3_data").set_active(1)
# Fill the connected DVDS
self.xc_servers[self.selected_host].fill_list_phydvd(self.listphydvd)
# Default interfaces for the new vm, and set the first parameter: the number of the interfaces
self.xc_servers[self.selected_host].fill_list_networks(
self.listnetworks, self.listnetworkcolumn)
listnewvmhosts = self.builder.get_object("listnewvmhosts")
treenewvmhosts = self.builder.get_object("treenewvmhosts")
# A new vm could be started on some host (e.g a pool with servers)
# Fill the possible hosts where vm could be start
path = self.xc_servers[self.selected_host].fill_listnewvmhosts(listnewvmhosts)
# Set the default server
treenewvmhosts.set_cursor((path,1), treenewvmhosts.get_column(0))
treenewvmhosts.get_selection().select_path((path,1))
# Setting a default options
self.newvmdata['location'] = "radiobutton1"
self.newvmdata['vdi'] = ""
self.builder.get_object("lblnewvm0").set_markup(' %-35s' % "Template")
labels = ["Name", "Location", "Home Server", "CPU / Memory", "Virtual disks", "Virtual Interfaces", "Finish"]
for i in range(1, 8):
self.builder.get_object("lblnewvm" + str(i)).set_markup( " %-35s" % labels[i-1])
# Show the "new vm" assistent
self.newvm.show()
# MENUBAR checks
def on_checksavepassword_toggled(self, widget, data=None):
self.builder.get_object("label259").set_sensitive(widget.get_active())
self.builder.get_object("txtmasterpassword").set_sensitive(widget.get_active())
def on_checkshowxtpls_toggled(self, widget, data=None):
"""
Enable or disable show templates on left tree
"""
# Save enable or disable to configuration
self.config["gui"]["show_xs_templates"] = widget.get_active()
self.config.write()
# Call to "refilter" to hide/show the templates
self.modelfilter.refilter()
def on_checkshowhiddenvms_toggled(self, widget, data=None):
"""
Enable or disable show templates on left tree
"""
# Save enable or disable to configuration
self.config["gui"]["show_hidden_vms"] = widget.get_active()
self.config.write()
# Call to "refilter" to hide/show the templates
self.modelfilter.refilter()
def on_checkshowtoolbar_toggled(self, widget, data=None):
"""
Enable or disable show top toolbar
"""
self.config["gui"]["show_toolbar"] = widget.get_active()
# If is active, show the toolbar, else hide the toolbar
if widget.get_active():
self.builder.get_object("toolbar").show()
else:
self.builder.get_object("toolbar").hide()
# Save in configuration
self.config.write()
def on_checkshowcustomtpls_toggled(self, widget, data=None, a=None):
"""
Enable or disable show custom templates on left tree
"""
self.config["gui"]["show_custom_templates"] = widget.get_active()
# Save in configuration
self.config.write()
# Call to "refilter" to hide/show custom templates
self.modelfilter.refilter()
def on_checkshowlocalstorage_toggled(self, widget, data=None, a=None):
"""
Enable or disable show local storage on left tree
"""
self.config["gui"]["show_local_storage"] = widget.get_active()
# Save in configuration
self.config.write()
# Call to "refilter" to hide/show custom templates
self.modelfilter.refilter()
# MENUBAR
def on_menuitem_entermaintenancemode_activate(self, widget, data=None):
"""
"Enter Maintenance Mode" on menuitem is pressed
"""
listmaintenancemode = self.builder.get_object("listmaintenancemode")
self.xc_servers[self.selected_host].fill_vms_which_prevent_evacuation(self.selected_ref, listmaintenancemode)
self.builder.get_object("maintenancemode").show()
def on_cancelmaintenancemode_clicked(self, widget, data=None):
"""
Pressed "Cancel" button on maintenance window
"""
self.builder.get_object("maintenancemode").hide()
def on_acceptmaintenancemode_clicked(self, widget, data=None):
"""
Pressed "Accept" button on maintenance window
"""
self.xc_servers[self.selected_host].enter_maintancemode(self.selected_ref)
self.builder.get_object("maintenancemode").hide()
def on_menuitem_exitmaintenancemode_activate(self, widget, data=None):
"""
"Exit Maintenance Mode" on menuitem is pressed
"""
self.xc_servers[self.selected_host].exit_maintancemode(self.selected_ref)
def on_menuitem_vm_startrecovery_activate(self, widget, data=None):
"""
"Start" button on menuitem is pressed
Power on a VM
"""
self.xc_servers[self.selected_host].start_vm_recovery_mode(self.selected_ref)
def on_menuitem_stg_new_activate(self, widget, data=None):
"""
"New Storage Repository" menuitem pressed on menubar
"""
blue = gtk.gdk.color_parse("#d5e5f7")
# Disable "next button", it will be enabled when file is selected
enable= ["radionewstgnfsvhd", "radionewstgiscsi", "radionewstghwhba",
"radionewstgnetapp", "radionewstgdell", "radionewstgcifs",
"radionewstgnfsiso"]
for widget in enable:
self.builder.get_object(widget).set_sensitive(True)
self.reattach_storage = False
self.builder.get_object("nextnewstorage").set_sensitive(True)
self.builder.get_object("eventnewstg0").modify_bg(gtk.STATE_NORMAL, blue)
self.builder.get_object("tabboxnewstorage").set_current_page(0)
self.builder.get_object("newstorage").show()
def on_menuitem_dmesg_activate(self, widget, data=None):
dmesg = self.xc_servers[self.selected_host].get_dmesg(self.selected_ref)
self.builder.get_object("txthostdmesg").get_buffer().set_text(dmesg)
self.builder.get_object("hostdmesg").show()
def on_management_activate(self, widget, data=None):
"""
"Management interfaces" on server menu is rpressed
"""
listmgmtinterfaces = self.builder.get_object("listmgmtinterfaces")
treemgmtinterfaces = self.builder.get_object("treemgmtinterfaces")
# Fill the list of interfaces with "Management" option enabled
self.xc_servers[self.selected_host].fill_mamagement_ifs_list(listmgmtinterfaces)
# Set the top label with server selected
lblmgmtinterfaces = self.builder.get_object("lblmgmtinterfaces")
lblmgmtinterfaces.set_text(lblmgmtinterfaces.get_text().replace("{0}", self.selected_name))
# Show the window
self.builder.get_object("mgmtinterface").show()
# Select the first interface by default
selection = treemgmtinterfaces.get_selection()
treemgmtinterfaces.set_cursor((0, ), treemgmtinterfaces.get_column(0))
treemgmtinterfaces.get_selection().select_path((0, ))
# Get the reference of default interface
pif_ref = listmgmtinterfaces.get_value(selection.get_selected()[1],0)
combomgmtnetworks = self.builder.get_object("combomgmtnetworks")
listmgmtnetworks = self.builder.get_object("listmgmtnetworks")
# Get all information for this PIF
pif = self.xc_servers[self.selected_host].all_pif[pif_ref]
# Fill the network combo with possible networks
# fill_management_networks return the position where network reference of pif is located
current = self.xc_servers[self.selected_host].fill_management_networks(listmgmtnetworks, pif['network'])
# Set in combo the network for default PIF
combomgmtnetworks.set_active(current)
# If interface configuration is dhcp disable ip/mask/gw entries
if pif['ip_configuration_mode'] == "DHCP":
self.builder.get_object("txtmgmtip").set_sensitive(False)
self.builder.get_object("txtmgmtmask").set_sensitive(False)
self.builder.get_object("txtmgmtgw").set_sensitive(False)
# Although could be disabled, set the ip/netmask/gateway
self.builder.get_object("txtmgmtip").set_text(pif['IP'])
self.builder.get_object("txtmgmtmask").set_text(pif['netmask'])
self.builder.get_object("txtmgmtgw").set_text(pif['gateway'])
# If ip configuration is with dhcp set appropiate radio enabled
self.builder.get_object("radiomgmtipdhcp").set_active(pif['ip_configuration_mode'] == "DHCP")
self.builder.get_object("radiomgmtipmanual").set_active(pif['ip_configuration_mode'] != "DHCP")
# If dns configuration is with dhcp set appropiate radio enabled
self.builder.get_object("radiomgmtdnsdhcp").set_active(pif['DNS'] == "")
self.builder.get_object("radiomgmtdnsmanual").set_active(pif['DNS'] != "")
# If dns is manual..
if pif['DNS']:
# Fill the entries with dns ips
dns = pif['DNS'].split(",")
self.builder.get_object("txtmgmtdns1").set_text(dns[0])
if len(dns) > 1:
self.builder.get_object("txtmgmtdns2").set_text(dns[1])
else:
self.builder.get_object("txtmgmtdns2").set_text("")
else:
# If not, empty the entris and disable both entries
self.builder.get_object("txtmgmtdns1").set_sensitive(False)
self.builder.get_object("txtmgmtdns2").set_sensitive(False)
self.builder.get_object("txtmgmtdns1").set_text("")
self.builder.get_object("txtmgmtdns2").set_text("")
def on_menuitem_stg_default_activate(self, widget, data=None):
"""
"Set as Default Storage Repository" menu item is pressed (storage menu)
"""
self.xc_servers[self.selected_host].set_default_storage(self.selected_ref)
def on_menuitem_tools_statusreport_activate(self, widget, data=None):
"""
"Status report" menu item is pressed (tools menu)
"""
self.builder.get_object("statusreport").show()
listreport = self.builder.get_object("listreport")
self.xc_servers[self.selected_host].fill_list_report(self.selected_ref, listreport)
self.update_report_total_size_time()
def on_menuitem_tools_cad_activate(self, widget, data=None):
"""
"Send Ctrl-Alt-Del" menu item is pressed (tools menu)
"""
self.tunnel.send_data("\xfe\x01\x00\x00\x00\x00\x00\x1d")
self.tunnel.send_data("\xfe\x01\x00\x00\x00\x00\x00\x38")
self.tunnel.send_data("\xfe\x01\x00\x00\x00\x00\x00\xd3")
self.tunnel.send_data("\xfe\x00\x00\x00\x00\x00\x00\x1d")
self.tunnel.send_data("\xfe\x00\x00\x00\x00\x00\x00\x38")
self.tunnel.send_data("\xfe\x00\x00\x00\x00\x00\x00\xd3")
def on_menuitem_migratetool_activate(self, widget, data=None):
"""
"Migrate tool" menu item is pressed (tools menu)
"""
self.builder.get_object("spinmigratemem").set_value(256)
self.builder.get_object("spinmigratevcpus").set_value(1)
self.builder.get_object("checkmigrateoutputserver").set_sensitive(self.selected_type == "host")
self.builder.get_object("migratetool").show()
def on_menuitem_takescreenshot_activate(self, widget, data=None):
"""
"Take screenshot" menu item is pressed (tools menu)
"""
self.builder.get_object("savescreenshot").set_current_name("Screenshot_%s.jpg" \
% self.selected_name.replace('/', '_'))
self.builder.get_object("savescreenshot").show()
def on_cancelsavescreenshot_clicked(self, widget, data=None):
self.builder.get_object("savescreenshot").hide()
def on_acceptsavescreenshot_clicked(self, widget, data=None):
filename = self.builder.get_object("savescreenshot").get_filename()
if self.selected_type == "vm":
self.xc_servers[self.selected_host].save_screenshot(self.selected_ref, filename)
else:
#host
ref = self.xc_servers[self.selected_host].host_vm[self.selected_ref][0]
self.xc_servers[self.selected_host].save_screenshot(ref, filename)
self.builder.get_object("savescreenshot").hide()
def on_menuitem_options_activate(self, widget, data=None):
"""
"Options" menu item is pressed (tools menu)
"""
# Enable/disable the save password option
self.builder.get_object("checksavepassword").set_active(eval(self.config["gui"]["save_password"]))
# Show the options dialog
self.builder.get_object("dialogoptions").show()
def on_menuitem_delete_activate(self, widget, data=None):
"""
"Delete" menu item is pressed (only for Pool)
"""
# Delete the pool
self.xc_servers[self.selected_host].delete_pool(self.selected_ref)
def on_menuitem_connectall_activate(self, widget, data=None):
"""
"Connect all" menu item is pressed (server menu)
"""
# For each server: connect
# TODO: fix
self.treestore.foreach(self.foreach_connect, True)
def on_menuitem_disconnectall_activate(self, widget, data=None):
# For each server: disconnect
"""
"Disconnect all" menu item is pressed (server menu)
"""
# For each server: disconnect
# TODO: fix
self.treestore.foreach(self.foreach_connect, False)
def on_collapsechildren_activate(self, widget, data=None):
"""
"Collapse Children" menu item is pressed
"""
for child in range(0,self.treestore.iter_n_children(self.selected_iter)):
iter = self.treestore.iter_nth_child(self.selected_iter, child)
if self.treestore.iter_n_children(iter):
path = self.treestore.get_path(iter)
self.treeview.collapse_row(path)
def on_expandall_activate(self, widget, data=None):
"""
"Expand all" menu item is pressed
"""
for child in range(0,self.treestore.iter_n_children(self.selected_iter)):
iter = self.treestore.iter_nth_child(self.selected_iter, child)
if self.treestore.iter_n_children(iter):
path = self.treestore.get_path(iter)
self.treeview.expand_row(path, True)
def on_menuitem_changepw_activate(self, widget, data=None):
"""
"Change Server Password" menu item is pressed
"""
self.builder.get_object("lblwrongpw").hide()
self.builder.get_object("changepassword").show()
self.builder.get_object("txtcurrentpw").set_text("")
self.builder.get_object("txtnewpw").set_text("")
self.builder.get_object("txtrenewpw").set_text("")
self.builder.get_object("acceptchangepassword").set_sensitive(False)
label = self.builder.get_object("lblchangepw").get_label()
self.builder.get_object("lblchangepw").set_label(label.replace("{0}", self.selected_name))
def on_menuitem_install_xslic_activate(self, widget, data=None):
"""
"Install License Key" menu item is pressed
"""
# Show file chooser
if self.xc_servers[self.selected_host].all_hosts[self.selected_ref].get("license_server"):
licenserver = self.xc_servers[self.selected_host].all_hosts[self.selected_ref].get("license_server")
self.builder.get_object("licensehost").set_text(licenserver["address"])
self.builder.get_object("licenseport").set_text(licenserver["port"])
self.builder.get_object("dialoglicensehost").show()
else:
self.builder.get_object("filterfilelicensekey").add_pattern("*.xslic")
self.builder.get_object("filelicensekey").show()
def on_cancellicensehost_clicked(self, widget, data=None):
"""
Function called when you press cancel on license host dialog
"""
self.builder.get_object("dialoglicensehost").hide()
def on_acceptlicensehost_clicked(self, widget, data=None):
"""
Function called when you press cancel on license host dialog
"""
edition = "advanced"
for licwidget in ["advanced", "enterprise", "platinum", "enterprise-xd"]:
if self.builder.get_object(licwidget).get_active():
edition = licwidget
break
licensehost = self.builder.get_object("licensehost").get_text()
licenseport = self.builder.get_object("licenseport").get_text()
self.xc_servers[self.selected_host].set_license_host(self.selected_ref, licensehost, licenseport, edition)
self.builder.get_object("dialoglicensehost").hide()
def on_cancelfilelicensekey_clicked(self, widget, data=None):
"""
Function called when you press cancel on filchooser "install license key"
"""
# Hide the file chooser
self.builder.get_object("filelicensekey").hide()
def on_openfilelicensekey_clicked(self, widget, data=None):
"""
Function called when you press open on filchooser "install license key"
"""
filename = self.builder.get_object("filelicensekey").get_filename()
self.xc_servers[self.selected_host].install_license_key(self.selected_ref, filename)
#print open( self.builder.get_object("filelicensekey").get_filename(), "rb").read().encode("base64").replace("\n","")
# Hide the file chooser
self.builder.get_object("filelicensekey").hide()
def on_menuitem_restoreserver_activate(self, widget, data=None):
"""
"Restoreserver" menu item is pressed
"""
# Show select destination dialog
self.builder.get_object("filefilterrestoreserver").add_pattern("*.xbk")
self.builder.get_object("filerestoreserver").show()
def on_menuitem_backupserver_activate(self, widget, data=None):
"""
"Backup server" menu item is pressed
"""
# Show select destination dialog
filebackupserver = self.builder.get_object("filebackupserver")
filebackupserver.set_current_name(self.selected_name + ".xbk")
self.builder.get_object("filefilterbackupserver").add_pattern("*.xbk")
self.builder.get_object("filebackupserver").show()
def on_menuitem_downloadlogs_activate(self, widget, data=None):
"""
"Download logs" (host) menu item is pressed
"""
# Show select destination dialog
filedownloadlogs = self.builder.get_object("filedownloadlogs")
filedownloadlogs.set_current_name(self.selected_name + ".tar.gz")
self.builder.get_object("filedownloadlogs").show()
def on_cancelfilebackupserver_clicked(self, widget, data=None):
"""
Function called when you cancel dialog for save backup server
"""
self.builder.get_object("filebackupserver").hide()
def on_savefilebackupserver_clicked(self, widget, data=None):
"""
Function called when you accept dialog for save backup server
"""
filebackupserver = self.builder.get_object("filebackupserver")
filename = filebackupserver.get_filename()
self.xc_servers[self.selected_host].thread_backup_server(self.selected_ref, filename, self.selected_name)
self.builder.get_object("filebackupserver").hide()
def on_cancelfiledownloadlogs_clicked(self, widget, data=None):
"""
Function called when you cancel dialog for download logs
"""
self.builder.get_object("filedownloadlogs").hide()
def on_savefiledownloadlogs_clicked(self, widget, data=None):
"""
Function called when you accept dialog for download logs
"""
filedownloadlogs = self.builder.get_object("filedownloadlogs")
filename = filedownloadlogs.get_filename()
self.xc_servers[self.selected_host].thread_host_download_logs(self.selected_ref, filename, self.selected_name)
self.builder.get_object("filedownloadlogs").hide()
def on_cancelrestoreserver_clicked(self, widget, data=None):
"""
Function called when you cancel dialog for open file to restore server
"""
self.builder.get_object("filerestoreserver").hide()
def on_openfilerestoreserver_clicked(self, widget, data=None):
"""
Function called when you accept dialog for open file to restore server
"""
filename = self.builder.get_object("filerestoreserver").get_filename()
self.xc_servers[self.selected_host].thread_restore_server(self.selected_ref, filename, self.selected_name)
self.builder.get_object("filerestoreserver").hide()
def on_menuitem_server_reboot_activate(self, widget, data=None):
"""
"Reboot server" menu item is pressed
"""
self.builder.get_object("confirmreboot").show()
def on_cancelconfirmreboot_clicked(self, widget, data=None):
"""
Function called when you cancel dialog for reboot server
"""
self.builder.get_object("confirmreboot").hide()
def on_acceptconfirmreboot_clicked(self, widget, data=None):
"""
Function called when you cancel dialog for reboot server
"""
res = self.xc_servers[self.selected_host].reboot_server(self.selected_ref)
#res = "OK"
if res == "OK":
self.on_m_disconnect_activate(widget, data)
self.builder.get_object("confirmreboot").hide()
def on_menuitem_server_shutdown_activate(self, widget, data=None):
"""
"Reboot server" menu item is pressed
"""
self.builder.get_object("confirmshutdown").show()
def on_acceptconfirmshutdown_clicked(self, widget, data=None):
"""
"Reboot server" menu item is pressed
"""
res = self.xc_servers[self.selected_host].shutdown_server(self.selected_ref)
if res == "OK":
self.on_m_disconnect_activate(widget, data)
self.builder.get_object("confirmshutdown").hide()
def on_cancelconfirmshutdown_clicked(self, widget, data=None):
"""
Function called when you cancel dialog for shutdown server
"""
self.builder.get_object("confirmshutdown").hide()
def on_menuitem_checkforupdates_activate(self, widget, data=None):
"""
"Check for Updates" menu item is pressed (help)
"""
pool = []
hotfix = []
# Get pool and patch info
for server in self.xc_servers.values():
for host in server.all_hosts:
pool.append("pool_" + server.all_hosts[host]["software_version"]["product_version"] + "=1")
for patch in server.all_hosts[host]["patches"]:
host_patch = server.all_host_patch[patch]
if host_patch["applied"]:
hotfix.append("hotfix_" + server.all_pool_patch[host_patch["pool_patch"]]["uuid"] + "=1")
else:
hotfix.append("hotfix_" + server.all_pool_patch[host_patch["pool_patch"]]["uuid"] + "=0")
url = "http://updates.xensource.com/XenServer/5.5.2/XenCenter?%s;%s" % (";".join(pool), ";".join(hotfix))
import webbrowser
webbrowser.open(url)
def on_menuitem_xenserver_on_the_web_activate(self, widget, data=None):
"""
"Xenserver on the web" menu item is pressed (help)
"""
url = "www.xenserver.com"
import webbrowser
webbrowser.open(url)
def on_menuitem_help_activate(self, widget, data=None):
"""
"About" menu item is pressed (Help)
"""
# Show about dialog
self.builder.get_object("aboutdialog").show()
def on_menuitem_pool_remove_server_activate(self, widget, data=None):
"""
"Remove server" (from pool) menu item is pressed (pool)
"""
self.last_dialog_label = self.builder.get_object("removeserverfrompool").get_property("text")
label = self.builder.get_object("removeserverfrompool").get_property("text")
pool_ref = self.xc_servers[self.selected_host].all_pools.keys()[0]
self.builder.get_object("removeserverfrompool").set_markup(
label.replace("{0}", self.selected_name).replace("{1}",
self.xc_servers[self.selected_host].all_pools[pool_ref]["name_label"]) )
self.builder.get_object("removeserverfrompool").show()
def on_acceptremoveserverfrompool_clicked(self, widget, data=None):
"""
Function called when you accept remove server from pool
"""
Thread(target=self.xc_servers[self.selected_host].remove_server_from_pool,
args=(self.selected_ref,)).start()
self.builder.get_object("removeserverfrompool").hide()
self.builder.get_object("removeserverfrompool").set_markup(self.last_dialog_label)
def on_cancelremoveserverfrompool_clicked(self, widget, data=None):
"""
Function called when you accept remove server from pool
"""
self.builder.get_object("removeserverfrompool").hide()
self.builder.get_object("removeserverfrompool").set_markup(self.last_dialog_label)
def on_menuitem_pool_backupdb_activate(self, widget, data=None):
"""
"Backup database" menu item is pressed(pool)
"""
self.builder.get_object("filterfilepoolbackupdb").add_pattern("*.xml")
filepoolbackupdb = self.builder.get_object("filepoolbackupdb")
filepoolbackupdb.set_current_name(self.selected_name + "_backup_db.xml")
filepoolbackupdb.show()
def on_cancelfilepoolbackupdb_clicked(self, widget, data=None):
"""
"Cancel" press on file chooser dialog for database pool backup
"""
self.builder.get_object("filepoolbackupdb").hide()
def on_acceptfilepoolbackupdb_clicked(self, widget, data=None):
"""
"Cancel" press on file chooser dialog for database pool backup
"""
filename = self.builder.get_object("filepoolbackupdb").get_filename()
self.xc_servers[self.selected_host].pool_backup_database(self.selected_ref, filename, self.selected_name)
self.builder.get_object("filepoolbackupdb").hide()
def on_rebootconfirmpoolrestoredb_clicked(self, widget, data=None):
"""
"Reboot" press on dialog restore database pool (reboot/dry run/cancel)
"""
self.builder.get_object("confirmpoolrestoredb").hide()
filename = self.builder.get_object("filepoolrestoredb").get_filename()
Thread(target=self.xc_servers[self.selected_host].pool_restore_database, \
args=(self.selected_ref, filename, self.selected_name, "false")).start()
self.builder.get_object("filepoolrestoredb").hide()
def on_dryrunconfirmpoolrestoredb_clicked(self, widget, data=None):
"""
"Dry run" press on dialog restore database pool (reboot/dry run/cancel)
"""
self.builder.get_object("confirmpoolrestoredb").hide()
filename = self.builder.get_object("filepoolrestoredb").get_filename()
Thread(target=self.xc_servers[self.selected_host].pool_restore_database, \
args=(self.selected_ref, filename, self.selected_name, "true")).start()
self.builder.get_object("filepoolrestoredb").hide()
def on_cancelconfirmpoolrestoredb_clicked(self, widget, data=None):
"""
"Dry run" press on dialog restore database pool (reboot/dry run/cancel)
"""
self.builder.get_object("confirmpoolrestoredb").hide()
self.builder.get_object("filepoolbackupdb").hide()
def on_menuitem_pool_restoredb_activate(self, widget, data=None):
"""
"Restore database" menu item is pressed(pool)
"""
self.builder.get_object("filepoolrestoredb").show()
def on_cancelfilepoolrestoredb_clicked(self, widget, data=None):
"""
"Cancel" press on file chooser dialog for database pool restore
"""
self.builder.get_object("filepoolrestoredb").hide()
def on_acceptfilepoolrestoredb_clicked(self, widget, data=None):
"""
"Open" press on file chooser dialog for database pool restore
"""
self.builder.get_object("confirmpoolrestoredb").show()
self.builder.get_object("filepoolrestoredb").hide()
def on_menuitem_pool_disconnect_activate(self, widget, data=None):
"""
"Disconnect" (from pool) menu item is pressed
"""
self.on_m_disconnect_activate(widget, data)
def on_menuitem_pool_new_activate(self, widget, data=None):
"""
"New Pool..." menu item is pressed
"""
listpoolmaster = self.builder.get_object("listpoolmaster")
listpoolmaster.clear()
combopoolmaster = self.builder.get_object("combopoolmaster")
# For each server add to combobox master servers list
for host in self.config_hosts.keys():
# If server is connected..
if host in self.xc_servers:
# Add to combo
pool = False
for pool_ref in self.xc_servers[host].all_pools:
if self.xc_servers[host].all_pools[pool_ref]['name_label'] != "":
pool = True
if not pool:
listpoolmaster.append([host, self.xc_servers[host].hostname])
# Set the first as default
combopoolmaster.set_active(0)
ref = None
# If there are servers added to combobox, get the ref
if combopoolmaster.get_active_iter():
ref = listpoolmaster.get_value(combopoolmaster.get_active_iter(), 0)
listpoolvms = self.builder.get_object("listpoolvms")
listpoolvms.clear()
# For each server add to possible servers for pool
for host in self.config_hosts.keys():
if host not in self.xc_servers:
listpoolvms.append([None, host, 0, "Disconnected", False])
else:
if self.xc_servers[host].is_connected:
pool = False
for pool_ref in self.xc_servers[host].all_pools:
if self.xc_servers[host].all_pools[pool_ref]['name_label'] != "":
pool = True
if not pool:
if ref != host:
listpoolvms.append([host, self.xc_servers[host].hostname, False, "", True])
else:
listpoolvms.append([host, self.xc_servers[host].hostname, True, "Master", False])
else:
listpoolvms.append([host, self.xc_servers[host].hostname, False, "This server is already in a pool", False])
else:
listpoolvms.append([None, host, 0, "Disconnected", False])
# Show the "newpool" window
self.builder.get_object("newpool").show()
def update_menubar(self):
"""
This function is called when a VM, host, storage or template is selected
Depends if you selected a server, host (server connected), vm then
A menuitems are enabled and others are disabled
"""
show = {}
if self.selected_type == "pool":
show["menu5"] = ["menuitem_pool_new", "menuitem_pool_delete", "menuitem_pool_disconnect","menuitem_pool_prop", "menuitem_pool_backupdb", "menuitem_pool_restoredb", "menuitem_pool_add_server"]
# TODO: disable menuite_connectall
show["menu6"] = ["menuitem_addserver", "menuitem_disconnectall", "menuitem_connectall", "menuitem_forget", "menuitem_remove"]
show["menu7"] = ["menuitem_importvm2"]
show["menu8"] = [""]
show["menu9"] = [""]
show["menu10"] = ["menuitem_options", "menuitem_migratetool", "menuitem_tools_updatemanager"]
if self.selected_type == "home":
show["menu5"] = [""]
# TODO: disable menuite_connectall
show["menu6"] = ["menuitem_addserver", "menuitem_connectall", "menuitem_disconnectall"]
show["menu7"] = ["menuitem_importvm2"]
show["menu8"] = [""]
show["menu9"] = [""]
show["menu10"] = ["menuitem_options","menuitem_tools_alerts", "menuitem_migratetool"]
if self.selected_type == "server":
if self.selected_state == "Disconnected":
show["menu5"] = ["menuitem_pool_new"]
# TODO: disable menuite_connectall
show["menu6"] = ["menuitem_addserver", "menuitem_disconnectall", "menuitem_connectall", "menuitem_connect", "menuitem_forget", "menuitem_remove"]
show["menu7"] = ["menuitem_importvm2"]
show["menu8"] = [""]
show["menu9"] = [""]
show["menu10"] = ["menuitem_options", "menuitem_migratetool"]
if self.selected_type == "host":
show["menu5"] = ["menuitem_pool_new"]
# TODO: use allowed_operations reboot/shutdown
show["menu6"] = ["menuitem_addserver", "menuitem_disconnectall", "menuitem_disconnect", "menuitem_forget",\
"menuitem_remove", "menuitem_newvm", "menuitem_server_prop", "menuitem_mgmt_ifs", "menuitem_dmesg",\
"menuitem_server_reboot", "menuitem_server_shutdown", "menuitem_changepw","menuitem_backupserver", \
"menuitem_restoreserver","menuitem_install_xslic","menuitem_server_add_to_pool", \
"menuitem_downloadlogs"
]
show["menu7"] = ["menuitem_importvm2", "menuitem_newvm2"]
show["menu8"] = ["menuitem_stg_new"]
show["menu9"] = ["menuitem_tpl_import"]
show["menu10"] = ["menuitem_options","menuitem_tools_alerts", "menuitem_takescreenshot", "menuitem_migratetool", "menuitem_tools_statusreport", "menuitem_tools_updatemanager"]
pool_ref = self.xc_servers[self.selected_host].all_pools.keys()[0]
if self.xc_servers[self.selected_host].all_hosts[self.selected_ref]["enabled"]:
show["menu6"].append("menuitem_entermaintenancemode")
else:
show["menu6"].append("menuitem_exitmaintenancemode")
if self.xc_servers[self.selected_host].all_pools[pool_ref]["name_label"] != '' and \
self.xc_servers[self.selected_host].all_pools[pool_ref]["master"] != self.selected_ref:
show["menu5"].append("menuitem_pool_remove_server")
if self.selected_type == "vm":
show["menu6"] = ["menuitem_newvm", "menuitem_server_prop", "menuitem_mgmt_ifs", "menuitem_addserver", "menuitem_disconnectall"]
show["menu7"] = ["menuitem_importvm2", "menuitem_newvm2", "menuitem_vm_prop"]
show["menu8"] = ["menuitem_stg_new", "menuitem_stg_newvdi", "menuitem_stg_attachvdi"]
show["menu9"] = ["menuitem_tpl_import"]
show["menu10"] = ["menuitem_options","menuitem_tools_alerts", "menuitem_takescreenshot", "menuitem_migratetool"]
# Special case
# If in allowed operations of selected VM exists "start", then add the menu item "start in recovery mode"
for op in self.xc_servers[self.selected_host].all_vms[self.selected_ref]['allowed_operations']:
show["menu7"].append("menuitem_vm_" + op)
if op == "start":
show["menu7"].append("menuitem_vm_startrecovery")
if self.selected_state == "Running":
show["menu7"].append("menuitem_vm_install_xs_tools")
if self.selected_type == "storage":
show["menu5"] = ["menuitem_pool_new"]
show["menu6"] = ["menuitem_addserver", "menuitem_connectall", "menuitem_disconnectall","menuitem_newvm"]
show["menu7"] = ["menuitem_importvm2","menuitem_newvm2"]
show["menu8"] = ["menuitem_stg_new","menuitem_stg_newvdi", "menuitem_stg_attachvdi"]
show["menu9"] = [""]
show["menu10"] = ["menuitem_options","menuitem_tools_alerts", "menuitem_migratetool"]
if self.xc_servers[self.selected_host].all_storage[self.selected_ref]['allowed_operations'].count("vdi_create")>0:
show["menu8"].append("menuitem_stg_default")
if self.selected_type == "template":
show["menu5"] = ["menuitem_pool_new"]
show["menu6"] = ["menuitem_addserver", "menuitem_connectall", "menuitem_disconnectall","menuitem_newvm"]
show["menu7"] = ["menuitem_importvm2","menuitem_newvm2"]
show["menu8"] = ["menuitem_stg_new","", ""]
show["menu9"] = ["menuitem_tpl_newvm", "menuitem_tpl_import", "menuitem_tpl_export", "menuitem_tpl_copy", "menuitem_tpl_delete"]
show["menu10"] = ["menuitem_options","menuitem_tools_alerts", "menuitem_migratetool"]
# For each menu...
for menu in show:
# For each child of this menu..
for child in self.builder.get_object(menu).get_children():
# Check if is on "show" variable
if show[menu].count(gtk.Buildable.get_name(child)):
# If is on: enable menuitem
child.set_sensitive(True)
else:
# Else: disable menuitem
child.set_sensitive(False)
def on_tm_logwindow_activate(self, widget, data=None):
# TODO: fix it URGENT
for i in range(1, 1):
self.builder.get_object("logwindow").show()
vboxframe = gtk.Frame()
if i % 2 == 0:
vboxframe.set_size_request(500,100)
else:
vboxframe.set_size_request(500,80)
vboxchild = gtk.Fixed()
vboxchildlabel1 = gtk.Label()
vboxchildlabel2 = gtk.Label()
vboxchildlabel3 = gtk.Label()
vboxchildlabel4 = gtk.Label()
vboxchildlabel5 = gtk.Label()
#FIXME
#vboxchildprogressbar.set_style(1)
vboxchildlabel1.set_label("Starting ... ")
vboxchildlabel2.set_label("23:28 04/08/2009")
vboxchildlabel3.set_label("Details: problem starting..")
vboxchildlabel4.set_label("Time: 00:00:00")
vboxchild.put(vboxchildlabel1, 25, 12)
vboxchild.put(vboxchildlabel2, 800, 12)
vboxchild.put(vboxchildlabel3, 25, 32)
vboxchild.put(vboxchildlabel4, 25, 52)
# Active task
if i % 2 == 0:
vboxchildcancel = gtk.Button()
vboxchildprogressbar = gtk.ProgressBar()
vboxchildprogressbar.set_size_request(800,20)
vboxchildprogressbar.set_fraction(float(1/float(i)))
vboxchild.put(vboxchildcancel, 800, 32)
vboxchildcancel.set_label("Cancel")
vboxchildlabel5.set_label("Progress: ")
vboxchild.put(vboxchildprogressbar, 100, 72)
vboxchild.put(vboxchildlabel5, 25, 72)
vboxframe.add(vboxchild)
if i % 2 == 0:
vboxframe.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("red"))
else:
vboxframe.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("black"))
self.builder.get_object("vboxlog").add(vboxframe)
self.builder.get_object("vboxlog").show_all()
openxenmanager/window.py 0000644 0001750 0001750 00000234245 11636446664 014176 0 ustar rrs rrs #!/usr/bin/env python
# -----------------------------------------------------------------------
# OpenXenManager
#
# Copyright (C) 2009 Alberto Gonzalez Rodriguez alberto@pesadilla.org
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------
import sys
# Add paths for compatibility (centos, debian lenny..)
sys.path.append("/usr/local/lib/python2.5/site-packages/")
sys.path.append("gtk-2.0/")
sys.path.append("/usr/local/lib/python2.5/site-packages/gtk-2.0/")
import os
if os.path.dirname(sys.argv[0]):
os.chdir(os.path.dirname(sys.argv[0]))
import pygtk
# On next releases we will use gettext for translations
APP = 'oxc'
DIR = 'locale'
if sys.platform != "win32" and sys.platform != "darwin":
# If sys.platform is linux or unix
"""
if not os.path.exists("oxcgtkvnc.so"):
if platform.architecture()[0] == "32bit":
shutil.copy("32/oxcgtkvnc.so", "oxcgtkvnc.so")
shutil.copy("32/liboxcgtk-vnc-1.0.so.0", "liboxcgtk-vnc-1.0.so.0")
if platform.architecture()[0] == "64bit":
shutil.copy("64/oxcgtkvnc.so", "oxcgtkvnc.so")
shutil.copy("64/liboxcgtk-vnc-1.0.so.0", "liboxcgtk-vnc-1.0.so.0")
"""
import gtkvnc
# Only needed for translations
import gtk.glade
gtk.glade.bindtextdomain(APP, DIR)
elif sys.platform == "darwin":
# On MacOSX with macports sys.platform is "darwin", we need Popen for run tightvnc
from subprocess import Popen
else:
# On Windows we need right tightvnc and we need win32 libraries for move the window
from subprocess import Popen
import win32gui
import win32con
import gtk
import gobject
# For md5 and xtea
import hashlib, xtea
from oxcSERVER import *
from pprint import pprint
import signal
import atexit
import re
# For a TreeView Cell with image+text
from PixbufTextCellRenderer import PixbufTextCellRenderer
#import locale
import gettext
gettext.install('oxc', localedir="./locale")
if sys.platform != "win32":
# On unix is recommended run threads from gtk.gdk
gtk.gdk.threads_init()
else:
# On windows is needed run gobject threads
gobject.threads_init()
# Splitted classes for oxcWindow
from window_vm import *
from window_host import *
from window_properties import *
from window_storage import *
from window_alerts import *
from window_addserver import *
from window_newvm import *
from window_menuitem import *
from window_tools import *
import xdot
class MyDotWindow(xdot.DotWindow):
def __init__(self, window, liststore, treestore):
self.liststore = liststore
self.treestore = treestore
xdot.DotWindow.__init__(self, window)
self.widget.connect('button_press_event', self.on_double_clicked)
def on_double_clicked(self, widget, event):
# On doublie click go to element
if event.type == gtk.gdk._2BUTTON_PRESS:
x, y = int(event.x), int(event.y)
if widget.get_url(x, y):
url = widget.get_url(x, y).url
# Search ref and go to
self.liststore.foreach(self.search_ref, url)
return True
def search_ref(self, model, path, iter_ref, user_data):
if self.liststore.get_value(iter_ref, 6) == user_data:
self.treestore.get_selection().select_path(path)
event = gtk.gdk.Event(gtk.gdk.BUTTON_RELEASE)
event.x = float(-10)
event.y = float(-10)
self.treestore.emit("button_press_event", event)
class oxcWindow(oxcWindowVM,oxcWindowHost,oxcWindowProperties,oxcWindowStorage,oxcWindowAlerts,oxcWindowAddServer,oxcWindowNewVm,oxcWindowMenuItem,oxcWindowTools):
"""Main class to oxc window"""
xc_servers = {}
# When you select a element of left tree these variables are filled
selected_actions = None
selected_ref = None
selected_iter= None
selected_tab = None
selected_host = None
selected_type = None
selected_widget = None
selected_state = None
noclosevnc = False
# If "Use master password" is enabled, password typed is set on it
password = None
reattach_storage = False
# For New VM
newvmdata = {}
# On Host -> On general tab: "VMs" label hasn't a fixed width
# If host is included on "moved" variable then "VMs" label was moved
moved = []
# Flag variable to avoid select signals
set_active = False
# Flag variable to export snapshot
export_snap = False
export_snap_vm = False
# For windows only
hWnd = 0
# Used only for plugins..
delete_pages = []
# Used for pool join force
last_host_pool = None
# For XTEA only (needs a string with 8 characters)
iv = "OXCENTER"
# Tunnel VNC
tunnel = None
# For know if performance images was set
performance_updated = False
def __init__(self):
atexit.register(self.signal_handler)
signal.signal(15, self.signal_handler)
# Read the configuration from oxc.conf file
if sys.platform != "win32":
if not os.path.exists(os.path.join(os.path.expanduser("~"), ".config")):
os.mkdir(os.path.join(os.path.expanduser("~"), ".config"))
if not os.path.exists(os.path.join(os.path.expanduser("~"), ".config", "openxenmanager")):
os.mkdir(os.path.join(os.path.expanduser("~"), ".config", "openxenmanager"))
dirconfig = os.path.join(os.path.expanduser("~"), ".config", "openxenmanager")
pathconfig = os.path.join(os.path.expanduser("~"), ".config", "openxenmanager", "oxc.conf")
else:
if not os.path.exists(os.path.join(os.path.expanduser("~"), "openxenmanager")):
os.mkdir(os.path.join(os.path.expanduser("~"), "openxenmanager"))
dirconfig = os.path.join(os.path.expanduser("~"), "openxenmanager")
pathconfig = os.path.join(os.path.expanduser("~"), "openxenmanager", "oxc.conf")
if not os.path.exists(pathconfig):
shutil.copy("oxc.conf", pathconfig)
self.config = ConfigObj(pathconfig)
self.pathconfig = dirconfig
# Read from configuration saved servers
if self.config['servers']['hosts']:
self.config_hosts = self.config['servers']['hosts']
else:
self.config_hosts = {}
# Define the glade file
self.gladefile = "oxc.glade"
self.builder = gtk.Builder()
self.builder.set_translation_domain("oxc")
# Add the file to gtk.Builder object
self.builder.add_from_file(self.gladefile)
# Connect Windows and Dialog to delete-event (we want not destroy dialog/window)
# delete-event is called when you close the window with "x" button
# TODO: csun: eventually it should be possible not to do this: http://stackoverflow.com/questions/4657344/
for widget in self.builder.get_objects():
if isinstance(widget, gtk.Dialog) or \
isinstance(widget, gtk.Window) and gtk.Buildable.get_name(widget) != "window1":
widget.connect("delete-event", self.on_delete_event)
# Frequent objects
self.txttreefilter = self.builder.get_object("txttreefilter")
self.listphydvd = self.builder.get_object("listphydvd")
self.listisoimage = self.builder.get_object("listisoimage")
self.listnetworks = self.builder.get_object("listnewvmnetworks")
self.listnetworkcolumn = self.builder.get_object("listnewvmnetworkcolumn")
self.window = self.builder.get_object("window1")
self.listalerts = self.builder.get_object("listalerts")
self.treealerts = self.builder.get_object("treealerts")
self.filesave = self.builder.get_object("filesave")
self.fileopen = self.builder.get_object("fileopen")
self.newvm = self.builder.get_object("window_newvm")
self.treeview = self.builder.get_object("treevm")
self.treeprop = self.builder.get_object("treeprop")
self.listprop = self.builder.get_object("listprop")
self.statusbar = self.builder.get_object("statusbar1")
self.treesearch = self.builder.get_object("treesearch")
"""
for i in range(0,7):
if self.newvm.get_nth_page(i):
self.newvm.set_page_complete(self.newvm.get_nth_page(i), True)
"""
# Combo's style
style = gtk.rc_parse_string('''
style "my-style" { GtkComboBox::appears-as-list = 1 }
widget "*" style "my-style"
''')
self.builder.connect_signals(self)
# Create a new TreeStore
self.treestore = gtk.TreeStore(gtk.gdk.Pixbuf, str, str, str, str, str, str, str, str)
# Image,Name, uuid, type, state, host, ref, actions, ip
# Append default logo on created TreeStore
self.treeroot = self.treestore.append(None, ([gtk.gdk.pixbuf_new_from_file("images/xen.gif"), "OpenXenManager", None, "home", "home", None, None, ["addserver","connectall","disconnectall"], None]))
# Model Filter is used but show/hide templates/custom templates/local storage..
self.modelfilter = self.treestore.filter_new()
# Define the function to check if a element should be showed or not
self.modelfilter.set_visible_func(self.visible_func)
self.treeview.set_model(self.modelfilter)
self.modelfiltertpl = self.builder.get_object("listtemplates").filter_new()
self.builder.get_object("treetemplates").set_model(self.modelfiltertpl)
self.modelfiltertpl.set_visible_func(self.visible_func_templates)
self.builder.get_object("networkcolumn1").set_property("model", self.builder.get_object("listimportnetworkcolumn"))
self.builder.get_object("cellrenderercombo1").set_property("model", self.builder.get_object("listnewvmnetworkcolumn"))
# Same for properties treestore
self.propmodelfilter = self.listprop.filter_new()
self.propmodelfilter.set_visible_func(self.prop_visible_func)
self.treeprop.set_model(self.propmodelfilter)
# Fill defaults selection variables
self.selected_name = "OpenXenManager"
self.selected_type = "home"
self.selected_uuid = ""
self.headimage = self.builder.get_object("headimage")
self.headlabel = self.builder.get_object("headlabel")
self.headlabel.set_label(self.selected_name)
self.headimage.set_from_pixbuf(gtk.gdk.pixbuf_new_from_file("images/xen.gif"))
if "show_hidden_vms" not in self.config["gui"]:
self.config["gui"]["show_hidden_vms"] = "False"
self.config.write()
# Set menuitem checks to value from configuration
self.builder.get_object("checkshowxstpls").set_active(self.config["gui"]["show_xs_templates"] == "True")
self.builder.get_object("checkshowcustomtpls").set_active(self.config["gui"]["show_custom_templates"] == "True")
self.builder.get_object("checkshowlocalstorage").set_active(self.config["gui"]["show_local_storage"] == "True")
self.builder.get_object("checkshowtoolbar").set_active(self.config["gui"]["show_toolbar"] == "True")
self.builder.get_object("checkshowhiddenvms").set_active(self.config["gui"]["show_hidden_vms"] == "True")
if "maps" in self.config:
for check in self.config["maps"]:
self.builder.get_object(check).set_active(self.config["maps"][check] == "True")
# If "Show toolbar" is checked then show, else hide
if self.config["gui"]["show_toolbar"] != "False":
self.builder.get_object("toolbar").show()
else:
self.builder.get_object("toolbar").hide()
# Add to left tree the saved servers from configuration
for host in self.config_hosts.keys():
self.builder.get_object("listaddserverhosts").append([host])
self.treestore.append(self.treeroot, ([gtk.gdk.pixbuf_new_from_file("images/tree_disconnected_16.png"), host, None, "server", "Disconnected", None, None, ["connect", "forgetpw", "remove"], None]))
# Expand left tree and update menubar, tabs and toolbar
self.treeview.expand_all()
self.update_menubar()
self.update_tabs()
self.update_toolbar()
# Create a TreeStore for SERVER->Search tab
self.listsearch = gtk.TreeStore(gtk.gdk.Pixbuf, str, object, str, object, str, str, str, str, str, gtk.gdk.Color)
self.treesearch.set_model(self.listsearch)
#self.treesearch.get_column(0).set_cell_data_func(self.func_cell_data_treesearch, self.treesearch.get_cell(0))
# Add two columns with image/text from PixBufTextCellRenderer class
pbtcell = PixbufTextCellRenderer()
pbtcell.set_property('xpad', 15)
pbtcell.set_property('ypad', 13)
tvc = gtk.TreeViewColumn('CPU Usage', pbtcell, text=3, pixbuf=2, background=10)
tvc.set_widget(self.builder.get_object("lbltreesearch6"))
self.builder.get_object("lbltreesearch6").show()
tvc.set_reorderable(True)
tvc.set_sort_column_id(3)
self.treesearch.insert_column(tvc, 1)
pbtcell = PixbufTextCellRenderer()
pbtcell.set_property('xpad', 15)
pbtcell.set_property('ypad', 13)
tvc = gtk.TreeViewColumn('Used memory', pbtcell, text=5, pixbuf=4, background=10)
tvc.set_widget(self.builder.get_object("lbltreesearch7"))
tvc.set_reorderable(True)
tvc.set_sort_column_id(5)
self.treesearch.insert_column(tvc, 2)
# ComboBox created from GLADE needs a cellrenderertext
# and an attribute defining the column to show
combobox = self.builder.get_object("radiobutton2_data")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 0)
combobox.set_model(self.listphydvd)
combobox = self.builder.get_object("radiobutton3_data")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 0)
combobox.add_attribute(cell, 'rise', 2)
combobox.add_attribute(cell, 'sensitive', 3)
combobox.set_model(self.listisoimage)
combobox = self.builder.get_object("treeeditnetwork")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 1)
combobox.set_model(self.builder.get_object("listeditnetwork"))
combobox = self.builder.get_object("treeaddnetwork")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 1)
combobox.set_model(self.builder.get_object("listaddnetwork"))
combobox.set_active(0)
combobox = self.builder.get_object("combostgmode")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 1)
combobox.set_model(self.builder.get_object("liststgmode"))
combobox.set_active(0)
combobox = self.builder.get_object("combostgposition")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 0)
combobox.set_model(self.builder.get_object("liststgposition"))
combobox.set_active(0)
combobox.set_style(style)
combobox = self.builder.get_object("combomgmtnetworks")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 1)
combobox.set_model(self.builder.get_object("listmgmtnetworks"))
combobox.set_active(0)
combobox.set_style(style)
combobox = self.builder.get_object("combopoolmaster")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 1)
combobox.set_model(self.builder.get_object("listpoolmaster"))
combobox.set_active(0)
combobox.set_style(style)
combobox = self.builder.get_object("combotargetiqn")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 1)
combobox.set_model(self.builder.get_object("listtargetiqn"))
combobox.set_active(0)
combobox.set_style(style)
combobox = self.builder.get_object("combotargetlun")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 1)
combobox.set_model(self.builder.get_object("listtargetlun"))
combobox.set_active(0)
combobox.set_style(style)
combobox = self.builder.get_object("combonetworknic")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 1)
combobox.set_model(self.builder.get_object("listnetworknic"))
combobox.set_active(0)
combobox.set_style(style)
combobox = self.builder.get_object("combocustomfields")
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 0)
combobox.set_model(self.builder.get_object("listcombocustomfields"))
combobox.set_active(0)
combobox.set_style(style)
#print combobox.get_internal_child()
# If gtk version is 2.18.0 or higher then add "marks" to scale
if hasattr(self.builder.get_object("scalepropvmprio"), "add_mark"):
self.builder.get_object("scalepropvmprio").add_mark(0, gtk.POS_BOTTOM, "\nLowest")
self.builder.get_object("scalepropvmprio").add_mark(1, gtk.POS_BOTTOM, "")
self.builder.get_object("scalepropvmprio").add_mark(2, gtk.POS_BOTTOM, "")
self.builder.get_object("scalepropvmprio").add_mark(3, gtk.POS_BOTTOM, "")
self.builder.get_object("scalepropvmprio").add_mark(4, gtk.POS_BOTTOM, "\nNormal")
self.builder.get_object("scalepropvmprio").add_mark(5, gtk.POS_BOTTOM, "")
self.builder.get_object("scalepropvmprio").add_mark(6, gtk.POS_BOTTOM, "")
self.builder.get_object("scalepropvmprio").add_mark(7, gtk.POS_BOTTOM, "")
self.builder.get_object("scalepropvmprio").add_mark(8, gtk.POS_BOTTOM, "\nHighest")
# Manual function to set the default buttons on dialogs/window
# Default buttons could be pressed with enter without need do click
self.set_window_defaults()
# If we need a master password for connect to servers without password:
# Show the dialog asking master password
if str(self.config["gui"]["save_password"]) == "True":
self.builder.get_object("masterpassword").show()
self.windowmap = MyDotWindow(self.builder.get_object("viewportmap"), self.treestore, self.treeview)
def adjust_scrollbar_performance(self):
for widget in ["scrolledwindow47", "scrolledwindow48", "scrolledwindow49", "scrolledwindow50"]:
self.builder.get_object(widget).grab_focus()
adj = self.builder.get_object(widget).get_hadjustment()
adj.set_value(adj.upper - adj.page_size)
def func_cell_data_treesearch(self, column, cell, model, iter_ref, user_data):
# Test function don't used
print column, cell, model, iter_ref, user_data
def set_window_defaults(self):
"""
Function to define what button is the default for each window/dialog
Default button could be pressed with enter key
"""
widgets = ["addserverpassword","addserverusername","snaptplname", "snapshotname", "vmaddnewdisk_name",
"txtcopyvmname", "txtpropvmname", "txtnetworkname", "txtmasterpassword", "txtaskmasterpassword"
]
dialogs = {
"addserver" : "connectAddServer",
"newvmdisk" : "acceptnewvmdisk",
"vmaddnewdisk" : "acceptvmaddnewdisk",
"dialogsnapshotname" : "btacceptsnapshotname",
"dialogsnaptplname" : "btacceptsnaptplname",
"dialogsnapshotdelete" : "btacceptsnapshotdelete",
"vmattachdisk": "btacceptattachdisk",
"dialogdeletevm" : "dialogdelete_accept",
"dialogdeletevdi" : "dialogdeletevdi_accept",
"windowcopyvm" : "windowcopyvm_copy",
"dialogvmprop" : "btvmpropaccept",
"dialogdeletehostnetwork" : "acceptdialogdeletehostnetwork",
"dialogdeletehostnic" : "acceptdialogdeletehostnic",
"addbond" : "btacceptaddbond",
"newnetwork" : "acceptnewnetwork",
"dialogoptions" : "acceptdialogoptions",
"masterpassword" : "acceptmasterpassword",
"dialogeditnetwork" : "accepteditnetwork",
"dialognetworkrestart" : "acceptdialognetworkrestart",
"vmimport" : "nextvmimport",
"mgmtinterface" : "acceptmgmtinterface",
"newpool" : "acceptnewpool"
}
# For each dialog
for wid in dialogs:
# Set the flag indicating the widget could be a default button
self.builder.get_object(dialogs[wid]).set_flags(gtk.CAN_DEFAULT)
# If widget is a dialog
if type(self.builder.get_object(wid)) == type(gtk.Dialog()):
# Set the button with "id response = 1" as default
self.builder.get_object(wid).set_default_response(1)
else:
# If is a Gtk.Window set the indicated button as default
self.builder.get_object(wid).set_default(self.builder.get_object(dialogs[wid]))
for wid in widgets:
# For each button indicate that it may be the default button
self.builder.get_object(wid).set_activates_default(True)
def visible_func_templates(self, model, iter_ref, user_data=None):
name = self.builder.get_object("listtemplates").get_value(iter_ref, 1)
txttemplatesearch = self.builder.get_object("txttemplatesearch")
if txttemplatesearch.get_text().strip() == "":
return True
else:
return name.lower().count(txttemplatesearch.get_text().lower()) > 0
def visible_func(self, model, iter_ref, user_data=None):
"""
This function define if a element should be showed or not in left tree
This function checks configuration values and show/hide elements
Returning False you hide the element, returning True you show the element
"""
host = self.treestore.get_value(iter_ref, 5)
ref = self.treestore.get_value(iter_ref, 6)
seltype = self.treestore.get_value(iter_ref, 3)
if len(self.txttreefilter.get_text())>0 and \
((seltype == "vm" or seltype == "template" or seltype == "storage" or seltype == "custom_template") and
self.treestore.get_value(iter_ref, 1).lower().count(self.txttreefilter.get_text().lower()) == 0):
return False
if seltype == "vm" and str(self.config["gui"]["show_hidden_vms"]) == "False" and host and ref and \
self.xc_servers[host].all_vms[ref].get("other_config") and \
str(self.xc_servers[host].all_vms[ref]["other_config"].get("HideFromXenCenter")).lower() == "true":
return False
if seltype == "template":
if self.config["gui"]["show_xs_templates"] == "False" or \
not self.config["gui"]["show_xs_templates"]:
return False
elif seltype == "custom_template":
if self.config["gui"]["show_custom_templates"] == "False" or \
not self.config["gui"]["show_custom_templates"]:
return False
elif seltype == "storage":
if self.config["gui"]["show_local_storage"] == "False" or \
not self.config["gui"]["show_local_storage"]:
if host and ref:
if not self.xc_servers[host].all_storage[ref]['shared']:
return False
return True
def foreach_connect(self, model, path, iter_ref, user_data):
"""
This function connect or disconnect depends user_data value
if user_data is True then connect all disconnected servers
if user_data is False then disconnect all connected servers
No code commented because doesn't work so well..
"""
if self.treestore.get_value(iter_ref, 3) == "server":
if self.treestore.get_value(iter_ref, 4) == "Disconnected":
if user_data:
name = self.treestore.get_value(iter_ref, 1)
if self.config_hosts[name][1]:
path = self.modelfilter.convert_path_to_child_path(path)
self.treeview.get_selection().select_path(path)
iter_ref= self.treestore.get_iter(path)
self.selected_iter = iter_ref
self.selected_name = self.treestore.get_value(iter_ref, 1)
self.selected_uuid = self.treestore.get_value(iter_ref, 2)
self.selected_type = self.treestore.get_value(iter_ref, 3)
self.selected_state = self.treestore.get_value(iter_ref, 4)
self.selected_host = self.treestore.get_value(iter_ref, 5)
self.selected_ip = self.treestore.get_value(iter_ref, 8)
self.on_m_connect_activate(self.treestore, None)
self.treesearch.expand_all()
if self.treestore.get_value(iter_ref, 3) == "host" or self.treestore.get_value(iter_ref, 3) == "pool":
if self.treestore.get_value(iter_ref, 4) == "Running":
if not user_data:
path = self.modelfilter.convert_path_to_child_path(path)
self.treeview.get_selection().select_path(path)
iter_ref= self.treestore.get_iter(path)
self.selected_iter = iter_ref
self.selected_name = self.treestore.get_value(iter_ref, 1)
self.selected_uuid = self.treestore.get_value(iter_ref, 2)
self.selected_type = self.treestore.get_value(iter_ref, 3)
self.selected_state = self.treestore.get_value(iter_ref, 4)
self.selected_host = self.treestore.get_value(iter_ref, 5)
self.selected_ip = self.treestore.get_value(iter_ref, 8)
self.on_m_disconnect_activate(self.treestore, None)
self.treesearch.expand_all()
else:
print "**", self.treestore.get_value(iter_ref, 4)
def on_window1_configure_event(self, widget, data=None):
self.on_window1_size_request(widget, data)
def on_window1_size_request(self, widget, data=None):
if self.hWnd != 0:
console_area = self.builder.get_object("frameconsole")
console_area.realize()
console_alloc = console_area.get_allocation()
window_alloc = self.window.get_position()
x = console_alloc.x + window_alloc[0] + 10
y = console_alloc.y + window_alloc[1] + 47
win32gui.MoveWindow(self.hWnd, x, y, console_alloc.width-10, console_alloc.height-5, 1)
def on_console_area_key_press_event(self, widget, event):
self.tunnel.key = hex(event.hardware_keycode - 8)
def on_aboutdialog_close(self, widget, data=None):
"""
Function to hide about dialog when you close it
"""
self.builder.get_object("aboutdialog").hide()
def on_acceptmasterpassword_clicked(self, widget, data=None):
"""
Function what checks ff you typed a master password is right
"""
# Create a md5 object
m = hashlib.md5()
password = self.builder.get_object("txtaskmasterpassword").get_text()
# Add password typed to md5 object
m.update(password)
# m.hexdigest() is a md5 ascii password (as saved in the configuration)
if self.config["gui"]["master_password"] != m.hexdigest():
# If is wrong show the label indicating is a wrong password
self.builder.get_object("lblwrongpassword").show()
else:
# If is a good password set to global variable "password" and hide dialog
self.password = password
self.builder.get_object("masterpassword").hide()
def on_cancelmasterpassword_clicked(self, widget, data=None):
"""
Function called when you cancel the master password dialog.
"""
#If you cancel the dialog, then set global variable "password" to None
self.password = None
self.builder.get_object("masterpassword").hide()
def on_txtaskmasterpassword_changed(self, widget, data=None):
"""
Function called when you write or remove characters on master password entry
"""
# If you check "save server passwords" then you need specify a master password
# If len of master password is 0, then disable "Accept" button in options dialog
self.builder.get_object("acceptmasterpassword").set_sensitive(len(widget.get_text()))
def update_tabs(self):
"""
Function called when you select a element from left tree
Depending selected type show or hide differents tabs
"""
frames = ("framestggeneral", "framememory","framestgdisks","framevmgeneral", "framevmstorage", "framevmnetwork", "framehostgeneral", "framehostnetwork", "framehoststorage", "frameconsole", "framehostnics", "framesnapshots","frameperformance","frametplgeneral","framehome","frameconsole", "framepoolgeneral", "framelogs", "framesearch", "frameusers", "framemaps", "framehosthw")
showframes = {
"pool" : ["framepoolgeneral", "framelogs", "framesearch", "framemaps"],
"home" : ["framehome"],
"vm" : ["framevmgeneral", "framememory", "framevmstorage", "framevmnetwork", "framelogs", "framesnapshots","frameperformance"],
"host" : ["framesearch","framehostgeneral", "framehostnetwork", "framehoststorage", "framelogs", "frameconsole", "framehostnics", "frameperformance", "frameusers", "framemaps"],
"template" : ["frametplgeneral","framevmnetwork","framehostgeneral"],
"custom_template" : ["frametplgeneral","framevmnetwork", "framevmstorage", "framelogs"],
"storage" : ["framestggeneral","framestgdisks", "framelogs"],
}
if self.selected_type in showframes:
[self.builder.get_object(frame).show() for frame in showframes[self.selected_type]]
[self.builder.get_object(frame).hide() for frame in frames if frame not in showframes[self.selected_type]]
if self.selected_type == "pool":
self.xc_servers[self.selected_host].update_tab_pool_general(self.selected_ref, self.builder)
elif self.selected_type == "vm":
# If "VM" is running, show console tab, else hide
if self.selected_state == "Running":
self.builder.get_object("frameconsole").show()
else:
self.builder.get_object("frameconsole").hide()
self.xc_servers[self.selected_host].update_tab_vm_general(self.selected_ref, self.builder)
elif self.selected_type == "host":
self.xc_servers[self.selected_host].update_tab_host_general(self.selected_ref, self.builder)
if self.xc_servers[self.selected_host].has_hardware_script(self.selected_ref):
self.builder.get_object("framehosthw").show()
else:
self.builder.get_object("framehosthw").hide()
elif self.selected_type == "template":
self.xc_servers[self.selected_host].update_tab_template(self.selected_ref, self.builder)
elif self.selected_type == "custom_template":
self.xc_servers[self.selected_host].update_tab_template(self.selected_ref, self.builder)
elif self.selected_type == "storage":
operations = self.xc_servers[self.selected_host].all_storage[self.selected_ref]['allowed_operations']
if operations.count("vdi_create"):
self.builder.get_object("btstgnewdisk").show()
else:
self.builder.get_object("btstgnewdisk").hide()
self.xc_servers[self.selected_host].update_tab_storage(self.selected_ref, self.builder)
# Experimental only
try:
import webkit
import glob
for deletepage in self.delete_pages:
# FIXME: remove doesn't work
self.builder.get_object("tabbox").get_nth_page(deletepage).hide_all()
self.delete_pages = []
for infile in glob.glob("plugins/*.xml"):
data = open(infile).read()
"""
dom = xml.dom.minidom.parseString(data)
nodes = dom.getElementsByTagName("XenCenterPlugin")
applicable = False
if len(nodes[0].getElementsByTagName("TabPage")):
for tabpage in nodes[0].getElementsByTagName("TabPage"):
if tabpage.attributes.getNamedItem("search"):
search_uuid = tabpage.attributes.getNamedItem("search").value
tabname = tabpage.attributes.getNamedItem("name").value # REVISE
url = tabpage.attributes.getNamedItem("url").value # REVISE
if len(nodes[0].getElementsByTagName("Search")):
host = self.selected_host
[applicable, ip] = self.plugin_get_search(nodes, search_uuid, host, ref)
"""
host = self.selected_host
ref = self.selected_ref
[applicable, ip, url, tabname] = self.process_xml(data, host, ref)
if applicable:
view = webkit.WebView()
browser = gtk.ScrolledWindow()
url = url.replace("{$ip_address}", ip)
view.open(url)
browser.add_with_viewport(view)
tablabel = gtk.Label(tabname)
self.delete_pages.append( \
self.builder.get_object("tabbox").append_page(\
browser, tablabel))
browser.show_all()
except:
pass
def process_xml(self, data, host, ref):
dom = xml.dom.minidom.parseString(data)
if dom.documentElement.nodeName != u'XenCenterPlugin':
print "no XenCenterPlugin"
return
node = dom.documentElement
ip = None
applicable = False
for tabpage in node.getElementsByTagName("TabPage"):
search_uuid = tabpage.getAttribute('search')
tabname = tabpage.getAttribute("name") # REVISE
url = tabpage.getAttribute("url") # REVISE
if search_uuid and tabname and url:
for search in [e for e in node.getElementsByTagName("Search") if e.getAttribute("uuid") == search_uuid]:
for query in search.getElementsByTagName("Query"):
for queryscope in [e for e in query.getElementsByTagName("QueryScope")[0].childNodes if e.nodeType != dom.TEXT_NODE]:
if queryscope.nodeName == "LocalSR":
if self.selected_type == "storage":
shared = self.xc_servers[self.selected_host].all_storage[self.selected_ref]['shared']
if not shared:
applicable = True
elif queryscope.nodeName == "RemoteSR":
if self.selected_type == "storage":
shared = self.xc_servers[self.selected_host].all_storage[self.selected_ref]['shared']
if shared:
applicable = True
elif queryscope.nodeName == "Pool": # REVISE
if self.selected_type == "pool":
applicable = True
elif queryscope.nodeName == "Vm": # REVISE
if self.selected_type == "vm":
applicable = True
elif queryscope.nodeName == "Host": # REVISE
if self.selected_type == "host":
applicable = True
if applicable:
for enumpropertyquery in query.getElementsByTagName("EnumPropertyQuery"):
data = None
if self.selected_type == "storage":
data = self.xc_servers[host].all_storage[ref]
pbds = data['PBDs']
ip = ""
if "target" in self.xc_servers[host].all_pbd[pbds[0]]["device_config"]:
ip = self.xc_servers[host].all_pbd[pbds[0]]["device_config"]['target']
#ip = data["name_description"].split(" ")[2][1:]
elif self.selected_type == "vm":
data = self.xc_servers[host].all_vms[ref]
ip = self.selected_ip
if self.selected_type == "host":
data = self.xc_servers[host].all_hosts[ref]
ip = self.selected_ip
if self.selected_type == "pool":
data = self.xc_servers[host].all_pools[ref]
ip = self.selected_ip
if data:
prop = enumpropertyquery.attributes.getNamedItem("property").value
equals = enumpropertyquery.attributes.getNamedItem("equals").value
value = enumpropertyquery.attributes.getNamedItem("query").value
if prop in data:
if equals == "no":
if isinstance(data[prop], str):
applicable = data[prop].count(value)>0
else: # REVISE
applicable = False
else:
applicable = (data == value)
else:
if "XenCenter.CustomFields." + prop in data["other_config"]:
applicable = True
url = url.replace("{$%s}" % prop, data["other_config"]["XenCenter.CustomFields." + prop])
else:
applicable = False
return [applicable, ip, url, tabname]
def plugin_get_search(self, nodes, search_uuid, host, ref):
"""
Determine if plugin is applicable
"""
applicable = False
ip = None
for search in nodes[0].getElementsByTagName("Search"):
if search.attributes.getNamedItem("uuid").value == search_uuid:
for query in search.getElementsByTagName("Query"):
queryscopes = query.getElementsByTagName("QueryScope")
for queryscope in queryscopes[0].childNodes:
if queryscope.nodeName != "#text":
if queryscope.nodeName == "LocalSR":
if self.selected_type == "storage":
shared = self.xc_servers[host].all_storage[ref]['shared']
if not shared:
applicable = True
elif queryscope.nodeName == "RemoteSR":
if self.selected_type == "storage":
shared = self.xc_servers[host].all_storage[ref]['shared']
if shared:
applicable = True
elif queryscope.nodeName == "Pool": # REVISE
if self.selected_type == "pool":
applicable = True
elif queryscope.nodeName == "Vm": # REVISE
if self.selected_type == "VM":
applicable = True
elif queryscope.nodeName == "Host": # REVISE
if self.selected_type == "host":
applicable = True
if applicable:
for enumpropertyquery in query.getElementsByTagName("EnumPropertyQuery"):
data = None
if self.selected_type == "storage":
data = self.xc_servers[host].all_storage[ref]
ip = data["name_description"].split(" ")[2][1:]
elif self.selected_type == "vm":
data = self.xc_servers[host].all_vms[ref]
ip = self.selected_ip
if self.selected_type == "host":
data = self.xc_servers[host].all_hosts[ref]
ip = self.selected_ip
if self.selected_type == "pool":
data = self.xc_servers[host].all_pools[ref]
ip = self.selected_ip
if data:
prop = enumpropertyquery.attributes.getNamedItem("property").value
equals = enumpropertyquery.attributes.getNamedItem("equals").value
value = enumpropertyquery.attributes.getNamedItem("query").value
if prop in data:
if equals == "no":
if isinstance(data[prop], str):
applicable = data[prop].count(value)>0
else: # REVISE
applicable = False
else:
applicable = (data == value)
else:
applicable = False
return [applicable, ip]
def on_window_destroy(self, widget, data=None):
"""
Function called when you close the window or press Quit
"""
# For each server
if self.tunnel:
self.tunnel.close()
for sh in self.xc_servers:
# Stop the threads setting True the condition variables
self.xc_servers[sh].halt = True
self.xc_servers[sh].halt_search = True
self.xc_servers[sh].halt_import = True
self.xc_servers[sh].halt_performance = True
# Do a logout, remember logout disconnect to server and unregister events
self.xc_servers[sh].logout()
# For windows only: close the tightvnc console
if self.hWnd != 0:
win32gui.PostMessage(self.hWnd, win32con.WM_QUIT, 0, 0)
self.hWnd = 0
# Save unsaved changes
self.config.write()
# Exit!
gtk.main_quit()
if self.tunnel:
self.tunnel.close()
def count_list(self, model, path, iter_ref, user_data):
"""
Function to count elements from list..
"""
#TODO: remove and use __len__()
self.nelements = self.nelements + 1
def on_tabbox_focus_tab(self, widget, data=None, data2=None):
"""
Function called when you click on a tab
Tabbox contains all possible tabs, when you click on a tab first we will check the name
Depending of this name we will do differents actions
"""
# Get the Tab name
#tab_label = widget.get_tab_label(widget.get_nth_page(data2)).name
tab_label = gtk.Buildable.get_name(widget.get_tab_label(widget.get_nth_page(data2)))
# Set as selected
self.selected_tab = tab_label
if tab_label != "VM_Console":
if self.tunnel and not self.noclosevnc:
self.tunnel.close()
# If vnc console was opened and we change to another, close it
self.builder.get_object("menuitem_tools_cad").set_sensitive(False)
if hasattr(self,"vnc") and self.vnc and not self.noclosevnc:
self.vnc.destroy()
self.builder.get_object("windowvncundock").hide()
self.vnc = None
# Same on Windows
if self.hWnd != 0:
win32gui.PostMessage(self.hWnd, win32con.WM_QUIT, 0, 0)
self.hWnd = 0
if tab_label != "HOST_Search" and self.selected_host:
# If we change tab to another different to HOST Search, then stop the filling thread
self.xc_servers[self.selected_host].halt_search = True
if tab_label != "VM_Performance" and self.selected_host:
self.xc_servers[self.selected_host].halt_performance = True
if tab_label == "VM_Console":
self.builder.get_object("menuitem_tools_cad").set_sensitive(True)
self.treeview = self.builder.get_object("treevm")
if hasattr(self,"vnc") and self.vnc:
if self.tunnel:
self.tunnel.close()
self.vnc.destroy()
self.builder.get_object("windowvncundock").hide()
self.vnc = None
if self.treeview.get_cursor()[1]:
state = self.selected_state
host = self.selected_host
# First checks if VM is running
self.builder.get_object("btenterfullscreen").grab_focus()
self.builder.get_object("console_area").grab_focus()
if state == "Running":
if sys.platform != "win32" and sys.platform != "darwin":
# Create a gtkvnc object
self.vnc = gtkvnc.Display()
# Add to gtkvnc to a console area
console_area = self.builder.get_object("console_area")
console_area.add(self.vnc)
console_area.show_all()
self.vnc.activate()
self.vnc.grab_focus()
self.vnc.set_pointer_grab(False)
self.vnc.set_pointer_local(False)
self.vnc.set_keyboard_grab(True)
self.vnc.set_shared_flag(True)
self.vnc.connect("vnc-disconnected", self.vnc_disconnected)
self.vnc.connect("key_press_event", self.on_console_area_key_press_event)
from tunnel import Tunnel
if self.selected_type == "host":
ref = self.xc_servers[self.selected_host].host_vm[self.selected_ref][0]
else:
ref = self.selected_ref
if self.xc_servers[self.selected_host].all_vms[ref]["consoles"]:
console_ref = self.xc_servers[self.selected_host].all_vms[ref]["consoles"][0]
location = self.xc_servers[self.selected_host].all_console[console_ref]["location"]
self.tunnel = Tunnel(self.xc_servers[self.selected_host].session_uuid, location)
port = self.tunnel.get_free_port()
Thread(target=self.tunnel.listen, args=(port,)).start()
time.sleep(1)
# And open the connection
try:
self.vnc.set_depth(1)
except:
pass
self.vnc.connect("vnc-server-cut-text", self.vnc_button_release)
self.vnc.open_host("localhost", str(port))
else:
print "No console available"
elif sys.platform == "darwin":
from tunnel import Tunnel
if self.selected_type == "host":
ref = self.xc_servers[self.selected_host].host_vm[self.selected_ref][0]
else:
ref = self.selected_ref
# Run ./vncviewer with host, vm renf and session ref
if self.xc_servers[self.selected_host].all_vms[ref]["consoles"]:
console_ref = self.xc_servers[self.selected_host].all_vms[ref]["consoles"][0]
location = self.xc_servers[self.selected_host].all_console[console_ref]["location"]
self.tunnel = Tunnel(self.xc_servers[self.selected_host].session_uuid, location)
port = self.tunnel.get_free_port()
Thread(target=self.tunnel.listen, args=(port,)).start()
time.sleep(1)
os.spawnl(os.P_NOWAIT,"./vncviewer", "vncviewer", "localhost::%s" % port)
console_area = self.builder.get_object("console_area")
console_alloc = console_area.get_allocation()
else:
print "No console available"
else:
if self.selected_type == "host":
ref = self.xc_servers[self.selected_host].host_vm[self.selected_ref][0]
else:
ref = self.selected_ref
# Run vncviewer.exe with host, vm renf and session ref
param = self.xc_servers[host].get_connect_parameters(ref, self.selected_ip)
os.spawnl(os.P_NOWAIT,"vncviewer.exe", "vncviewer.exe", "%s" % (param))
console_area = self.builder.get_object("frameconsole")
console_area.realize()
console_alloc = console_area.get_allocation()
window_alloc = self.window.get_position()
x = console_alloc.x + window_alloc[0] + 10
y = console_alloc.y + window_alloc[1] + 47
# On windows we'll move the window..
while win32gui.FindWindow(None, "HVMXEN-%s" % (self.selected_uuid)) == 0 \
and win32gui.FindWindow(None, "XenServer Virtual Terminal") == 0:
pass
self.hWnd = win32gui.FindWindow(None, "HVMXEN-%s" % (self.selected_uuid))
if self.hWnd == 0:
self.hWnd = win32gui.FindWindow(None, "XenServer Virtual Terminal")
#win32gui.ShowWindow(self.hWnd, win32con.SW_HIDE)
win32gui.MoveWindow(self.hWnd, x, y, console_alloc.width-10, console_alloc.height-5, 1)
#win32gui.ShowWindow(self.hWnd, win32con.SW_SHOW)
else:
print state
if tab_label == "VM_Memory":
self.update_memory_tab()
if tab_label == "VM_Storage":
if self.treeview.get_cursor()[1]:
# liststorage contains the storage on VM
liststorage = self.builder.get_object("listvmstorage")
# liststoragdvd contains the possibles dvd/isos to mount on VM
liststoragedvd = self.builder.get_object("listvmstoragedvd")
#liststoragedvd.set_sort_func(1, self.compare_data)
host = self.selected_host
# Fill liststorage
self.xc_servers[host].fill_vm_storage(self.selected_ref, \
liststorage)
# Fill liststoragedvd, fill_vm_storage_dvd return the current dvd/iso mounted
active = self.xc_servers[host].fill_vm_storage_dvd(self.selected_ref, \
liststoragedvd)
# Flag variable to no emit signal
self.set_active = True
# Set as the active dvd/iso mounted
self.builder.get_object("combovmstoragedvd").set_active(active)
self.set_active = False
elif tab_label == "VM_Network":
if self.treeview.get_cursor()[1]:
treenetwork = self.builder.get_object("treevmnetwork")
# listvmnetwork contains the networks of a vm
listnetwork = self.builder.get_object("listvmnetwork")
host = self.selected_host
# Fill the list of networks
self.xc_servers[host].fill_vm_network(self.selected_ref, \
treenetwork, listnetwork)
elif tab_label == "VM_Snapshots":
if self.treeview.get_cursor()[1]:
treevmsnapshots = self.builder.get_object("treevmsnapshots")
# listvmsnapshots contains the snapshots of a vm
listvmsnapshots = self.builder.get_object("listvmsnapshots")
host = self.selected_host
# Fill the list of snapshots
self.xc_servers[host].fill_vm_snapshots(self.selected_ref, \
treevmsnapshots, listvmsnapshots)
elif tab_label == "VM_Performance":
if self.treeview.get_cursor()[1]:
# Thread to update performance images
ref = self.selected_ref
host = self.selected_host
if self.selected_type == "vm":
self.builder.get_object("scrolledwindow50").show()
self.builder.get_object("labeldiskusage").show()
Thread(target=self.xc_servers[host].update_performance, args=(self.selected_uuid, ref, \
self.selected_ip, False)).start()
else:
self.builder.get_object("scrolledwindow50").hide()
self.builder.get_object("labeldiskusage").hide()
if self.selected_host and self.selected_ref in self.xc_servers[self.selected_host].host_vm:
uuid = self.xc_servers[self.selected_host].host_vm[self.selected_ref][1]
Thread(target=self.xc_servers[host].update_performance, args=(uuid, ref, \
self.selected_ip, True)).start()
elif tab_label == "VM_Logs":
if self.treeview.get_cursor()[1]:
treeviewlog = self.builder.get_object("treeviewlog")
# listlog contains the snapshots of a vm/host
listlog = self.builder.get_object("listlog")
host = self.selected_host
# Fill the list of logs
if self.selected_type == "vm":
self.xc_servers[host].fill_vm_log(self.selected_uuid, \
treeviewlog, listlog)
else:
self.xc_servers[host].fill_vm_log(self.selected_uuid, \
treeviewlog, listlog)
elif tab_label == "HOST_Users":
if self.selected_type == "pool":
name = self.xc_servers[self.selected_host].all_pools[self.selected_ref]['name_label']
externalauth = self.xc_servers[self.selected_host].get_external_auth(self.xc_servers[self.selected_host]['master'])
else:
name = self.xc_servers[self.selected_host].all_hosts[self.selected_ref]['name_label']
externalauth = self.xc_servers[self.selected_host].get_external_auth(self.selected_ref)
listusers = self.builder.get_object("listusers")
self.xc_servers[self.selected_host].fill_domain_users(self.selected_ref, listusers)
if externalauth[0] == "":
self.builder.get_object("btjoindomain").set_sensitive(True)
self.builder.get_object("btleavedomain").set_sensitive(False)
self.builder.get_object("lblusersdomain").set_text("AD is not currently configured for '" + self.selected_name + "'. To enable AD authentication, click Join.")
else:
self.builder.get_object("btleavedomain").set_sensitive(True)
self.builder.get_object("btjoindomain").set_sensitive(False)
self.builder.get_object("lblusersdomain").set_text("Pool/host " + self.selected_name + " belongs to domain '" + externalauth[1] + "'. To enable AD authentication, click Join.")
elif tab_label == "HOST_Storage":
if self.treeview.get_cursor()[1]:
# listhoststorage contains the snapshots of a vm/host
liststorage = self.builder.get_object("listhoststorage")
host = self.selected_host
# Fill the list of storage
self.xc_servers[host].fill_host_storage(self.selected_ref, \
liststorage)
elif tab_label == "HOST_Nics":
if self.treeview.get_cursor()[1]:
"""
liststorage = self.builder.get_object("listhostnics")
host = self.selected_host
self.xc_servers[host].fill_host_nics(self.selected_ref, \
liststorage)
"""
# Call to update_tab_host_nics to fill the host nics
self.update_tab_host_nics()
elif tab_label == "HOST_Search":
if self.treeview.get_cursor()[1]:
host = self.selected_host
self.xc_servers[host].halt_search = False
# Host_Search contains a live monitoring status of VM
# Create a thread to fill "listsearch"
self.xc_servers[host].thread_host_search(self.selected_ref, self.listsearch)
# Expand "treesearch"
self.treesearch.expand_all()
elif tab_label == "HOST_Hardware":
if self.selected_host:
self.xc_servers[self.selected_host].fill_host_hardware(self.selected_ref)
elif tab_label == "HOST_Network":
# Call to update_tab_host_network to fill the host networks
self.update_tab_host_network()
elif tab_label == "Local_Storage":
if self.treeview.get_cursor()[1]:
# liststg contains the vdi under storage
liststg = self.builder.get_object("liststg")
liststg.set_sort_func(1, self.compare_data)
liststg.set_sort_column_id(1, gtk.SORT_ASCENDING)
host = self.selected_host
# Fill the list of storage
if host:
self.xc_servers[host].fill_local_storage(self.selected_ref, \
liststg)
elif tab_label == "Maps":
self.update_maps()
def compare_data(self, model, iter1, iter2):
data1 = model.get_value(iter1,1)
data2 = model.get_value(iter2,1)
return cmp(data1, data2)
def update_maps(self):
dotcode = """
digraph G {
overlap=false;
bgcolor=white;
node [shape=polygon, sides=6, fontname="Verdana", fontsize="8"];
edge [color=deepskyblue3, fontname="Verdana", fontsize="5"];
"""
if self.selected_host:
show_halted_vms = self.builder.get_object("check_show_halted_vms").get_active()
if self.builder.get_object("check_show_network").get_active():
relation = self.xc_servers[self.selected_host].get_network_relation(self.selected_ref, show_halted_vms)
for network in relation:
uuid, name = network.split("_", 1)
safename = name.replace("&","&").replace("<", "<").replace("\"", """)
if self.builder.get_object("check_unused_network").get_active() or relation[network]:
dotcode += '"%s"[shape=plaintext, label=< |
|
%s |
> tooltip="%s"];' % (uuid, safename, name)
dotcode += "\n"
for vm in relation[network]:
uuid2, name2 = vm.split("_", 1)
dotcode += '"%s"[shape=plaintext, label=< |
|
%s |
>URL="%s" tooltip="%s"];' % (uuid2, name2, uuid2, name2)
dotcode += "\n"
dotcode += '"%s" -> "%s"' % (uuid, uuid2)
dotcode += "\n"
if self.builder.get_object("check_show_storage").get_active():
dotcode += 'edge [color=forestgreen, fontname="Verdana", fontsize="5"];'
relation = self.xc_servers[self.selected_host].get_storage_relation(self.selected_ref, show_halted_vms)
for storage in relation:
uuid, name = storage.split("_", 1)
safename = name.replace("&","&").replace("<", "<").replace("\"", """)
if self.builder.get_object("check_unused_storage").get_active() or relation[storage]:
dotcode += '"%s"[shape=plaintext, label=< |
|
%s |
>URL="%s" tooltip="%s"];' % (uuid, safename, uuid, name)
dotcode += "\n"
for vm in relation[storage]:
uuid2, name2 = vm.split("_", 1)
safename2 = name2.replace("&","&").replace("<", "<").replace("\"", """)
dotcode += '"%s"[shape=plaintext, label=< |
|
%s |
>URL="%s" tooltip="%s"];' % (uuid2, safename2, uuid2, name2)
dotcode += "\n"
dotcode += '"%s" -> "%s"' % (uuid2, uuid)
dotcode += "\n"
dotcode += "}"
self.windowmap.set_dotcode(dotcode)
self.builder.get_object("viewportmap").show_all()
def on_btopenfile_activate(self, widget, data=None):
"""
Obsoleted function
"""
filechooser = self.fileopen.get_children()[0].get_children()[0]
if filechooser.get_filename():
self.xc_servers[self.selected_host].import_vm(self.selected_ref, filechooser.get_filename())
self.fileopen.hide()
else:
self.show_error_dlg("Select a file")
def on_btsavefile_activate(self, widget, data=None):
"""
Function called when you press "Export VM"
"""
filechooser = self.filesave.get_children()[0].get_children()[0]
if filechooser.get_filename():
# Call to export_vm function with vm renf and filename choosed
if self.export_snap:
print "Export snap.."
self.xc_servers[self.selected_host].export_vm(self.selected_snap_ref, filechooser.get_filename(), self.selected_ref)
self.export_snap = False
elif self.export_snap_vm:
print "Export snap as VM.."
self.xc_servers[self.selected_host].export_vm(self.selected_snap_ref, filechooser.get_filename(), self.selected_ref, as_vm = True)
self.export_snap_vm = False
else:
self.xc_servers[self.selected_host].export_vm(self.selected_ref, filechooser.get_filename())
self.filesave.hide()
self.builder.get_object("tabbox").set_current_page(17)
else:
self.show_error_dlg("Select a file")
def on_filesave_confirm_overwrite(self, widget, data=None):
"""
Not used function
"""
print widget
print data
def on_btcancelsavefile_activate(self, widget, data=None):
"""
If you press cancel on "Export VM" dialog, then close the dialog
"""
self.export_snap = False
self.filesave.hide()
def on_btcancelopenfile_activate(self, widget, data=None):
"""
Not used function
"""
self.fileopen.hide()
def on_treevm_button_press_event(self, widget, event):
"""
Function is called when you do click (or double click) on left tree
"""
x = int(event.x)
y = int(event.y)
time = event.time
if x == -10 and y == -10:
pthinfo = [self.modelfilter.get_path(self.treeview.get_selection().get_selected()[1]), None, 0, 0]
else:
pthinfo = widget.get_path_at_pos(x, y)
if event.type == gtk.gdk._2BUTTON_PRESS:
# On double click, if server is disconnected then connect to it
if self.selected_state == "Disconnected":
self.on_m_connect_activate(widget, None)
elif pthinfo is not None:
# On single click
path, col, cellx, celly = pthinfo
widget.grab_focus()
widget.set_cursor( path, col, 0)
path = self.modelfilter.convert_path_to_child_path(path)
iter_ref= self.treestore.get_iter(path)
# Define selected variables
self.selected_iter = iter_ref
self.selected_name = self.treestore.get_value(iter_ref, 1)
self.selected_uuid = self.treestore.get_value(iter_ref, 2)
self.selected_type = self.treestore.get_value(iter_ref, 3)
self.selected_state = self.treestore.get_value(iter_ref, 4)
self.selected_host = self.treestore.get_value(iter_ref, 5)
self.selected_ip = self.treestore.get_value(iter_ref, 8)
# Used to prevent not manual changes
previous_ref = self.selected_ref
self.selected_ref = self.treestore.get_value(iter_ref, 6)
# Define the possible actions for VM/host/storage..
if self.selected_type == "vm":
self.selected_actions = self.xc_servers[self.selected_host].get_actions(self.selected_ref)
else:
self.selected_actions = self.treestore.get_value(iter_ref, 7)
#if type(self.selected_actions) == type(""):
# self.selected_actions = eval(self.selected_actions)
# Update menubar and tabs with new selection
self.update_menubar()
self.update_tabs()
if self.selected_ref != previous_ref:
# If you selected a different element than previous
# then select the correct tab for selected type
if self.selected_type == "vm":
self.builder.get_object("tabbox").set_current_page(5)
else:
self.builder.get_object("tabbox").set_current_page(3)
if self.selected_type == "pool":
self.builder.get_object("tabbox").set_current_page(0)
elif self.selected_type == "host":
self.builder.get_object("tabbox").set_current_page(1)
self.builder.get_object("tabbox").set_current_page(4)
elif self.selected_type == "server":
self.builder.get_object("tabbox").set_current_page(2)
elif self.selected_type == "template":
self.builder.get_object("tabbox").set_current_page(2)
elif self.selected_type == "custom_template":
self.builder.get_object("tabbox").set_current_page(2)
elif self.selected_type == "storage":
self.builder.get_object("tabbox").set_current_page(1)
if event.button == 3:
# On right click..
# Show the menu
menu_vm = self.builder.get_object("menu_vm")
collapsed = False
expanded = False
can_expand_or_collapse = False
for child in range(0,self.treestore.iter_n_children(self.selected_iter)):
iter_ref= self.treestore.iter_nth_child(self.selected_iter, child)
if self.treestore.iter_n_children(iter_ref):
can_expand_or_collapse = True
path = self.treestore.get_path(iter_ref)
if self.treeview.row_expanded(path):
expanded = True
else:
collapsed = True
if can_expand_or_collapse:
if collapsed:
self.builder.get_object("expandall").show()
else:
self.builder.get_object("expandall").hide()
if expanded:
self.builder.get_object("collapsechildren").show()
else:
self.builder.get_object("collapsechildren").hide()
else:
self.builder.get_object("expandall").hide()
self.builder.get_object("collapsechildren").hide()
for child in menu_vm.get_children():
# Menuitems are with name "m_action"
# Checks if "action" is on selected_actions"
typestg = None
pbdstg = 1
broken = False
if self.selected_type == "storage":
typestg = self.xc_servers[self.selected_host].all_storage[self.selected_ref]["type"]
pbdstg = len(self.xc_servers[self.selected_host].all_storage[self.selected_ref]["PBDs"])
if gtk.Buildable.get_name(child)[0:2] == "m_":
if not self.selected_actions or \
self.selected_actions.count(gtk.Buildable.get_name(child)[2:]) \
== 0:
child.hide()
else:
# If selected_type is storage and typestg is not "lvm" or "udev"
if typestg != "lvm" and typestg != "udev":
# If has not pbds.. then enable only "Reattach" and "Forget"
if pbdstg == 0 and (gtk.Buildable.get_name(child) == "m_plug" or gtk.Buildable.get_name(child) == "m_forget"):
child.show()
else:
# Disable else
if pbdstg == 0:
child.hide()
else:
# If has pbds.. disable "Reattach"
if gtk.Buildable.get_name(child) != "m_plug":
child.show()
else:
child.hide()
else:
child.hide()
# Properties will be showed always else on home and disconnected servers
if gtk.Buildable.get_name(child) == "properties":
if self.selected_type == "home":
child.hide()
elif self.selected_type == "server" and not self.selected_ref:
child.hide()
else:
child.show()
# Delete will be showed only on pool
elif gtk.Buildable.get_name(child) == "delete":
if self.selected_type == "pool":
child.show()
else:
child.hide()
# Install XenServer Tools only on
elif gtk.Buildable.get_name(child) == "installxenservertools":
if self.selected_type == "vm" and self.selected_state == "Running":
self.builder.get_object("separator1").show()
self.builder.get_object("separator2").show()
child.show()
else:
self.builder.get_object("separator1").hide()
self.builder.get_object("separator2").hide()
child.hide()
# Repair storage, only on broken storage
elif gtk.Buildable.get_name(child) == "m_repair_storage":
if self.selected_type == "storage":
broken = self.xc_servers[self.selected_host].is_storage_broken(self.selected_ref)
if broken:
child.show()
else:
child.hide()
# Add to pool, only for servers without pools
elif gtk.Buildable.get_name(child) == "m_add_to_pool":
if self.selected_type == "host":
pool_ref = self.xc_servers[self.selected_host].all_pools.keys()[0]
if self.xc_servers[self.selected_host].all_pools[pool_ref]["name_label"] == "":
child.show()
else:
child.hide()
else:
child.hide()
# Add server to pool from pool menu
elif gtk.Buildable.get_name(child) == "m_pool_add_server":
if self.selected_type == "pool":
child.show()
else:
child.hide()
menu_vm.popup( None, None, None, event.button, time)
# Update toolbar and set label/image on top right pane
self.update_toolbar()
self.headlabel.set_label(self.selected_name)
self.headimage.set_from_pixbuf(self.treestore.get_value(iter_ref, 0))
def vnc_disconnected(self, info):
print "VNC disconnected..", info
def on_txttreefilter_changed(self, widget, data=None):
"""
Function called when on left top entry you write text to filter
"""
self.modelfilter.refilter()
self.treeview.expand_all()
def show_error_dlg(self, error_string, error_title="Error"):
"""This Function is used to show an error dialog when
an error occurs.
error_string - The error string that will be displayed
on the dialog.
http://www.pygtk.org/articles/extending-our-pygtk-application/extending-our-pygtk-application.htm
"""
self.builder.get_object("walert").set_title(error_title)
self.builder.get_object("walerttext").set_text(error_string)
self.builder.get_object("walert").show()
def on_closewalert_clicked(self, widget, data=None):
self.builder.get_object("walert").hide()
def push_alert(self, alert):
"""
Function to set in statusbar an alert
"""
self.statusbar.get_children()[0].get_children()[0].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#000000'))
self.statusbar.push(1, alert)
def push_error_alert(self, alert):
"""
Function to set in statusbar an error alert
"""
self.statusbar.get_children()[0].get_children()[0].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#FF0000'))
self.statusbar.push(1, alert)
def not_implemented_yet(self, widget, data=None):
"""
Some functions are not implemented yet, show the dialog
"""
self.show_error_dlg("Not implemented yet")
def dump(self, obj):
"""
Internal use only
"""
for attr in dir(obj):
print "obj.%s = %s" % (attr, getattr(obj, attr))
def signal_handler(self):
"""
Function called when oxc gets a signal
"""
print "Exiting..."
for sh in self.xc_servers:
self.xc_servers[sh].halt = True
self.xc_servers[sh].halt_search = True
self.xc_servers[sh].halt_performance = True
self.xc_servers[sh].logout()
self.config.write()
if self.hWnd != 0:
win32gui.PostMessage(self.hWnd, win32con.WM_QUIT, 0, 0)
self.hWnd = 0
def on_delete_event(self, widget, event):
"""
Returning True, the window will not be destroyed
"""
widget.hide()
return True
def convert_bytes(self, bytes):
"""
Convert bytes to string
http://www.5dollarwhitebox.org/drupal/node/84
"""
bytes = float(bytes)
if bytes >= 1099511627776:
terabytes = bytes / 1099511627776
size = '%.1fT' % terabytes
elif bytes >= 1073741824:
gigabytes = bytes / 1073741824
size = '%.1fG' % gigabytes
elif bytes >= 1048576:
megabytes = bytes / 1048576
size = '%.1fM' % megabytes
elif bytes >= 1024:
kilobytes = bytes / 1024
size = '%.1fK' % kilobytes
else:
size = '%.1fb' % bytes
return size
def convert_bytes_mb(self, n):
"""
Convert byes to mb string
"""
n = float(n)
K, M = 1 << 10, 1 << 20
if n >= M:
return '%d' % (float(n) / M)
elif n >= K:
return '%d' % (float(n) / K)
else:
return '%d' % n
if __name__ == "__main__":
# Main function
gobject.threads_init()
gtk.gdk.threads_init()
wine = oxcWindow()
gtk.main()
openxenmanager/oxcSERVER.py 0000644 0001750 0001750 00000410077 11636446664 014406 0 ustar rrs rrs # -----------------------------------------------------------------------
# OpenXenManager
#
# Copyright (C) 2009 Alberto Gonzalez Rodriguez alberto@pesadilla.org
# Copyright (C) 2011 Cheng Sun
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------
import xmlrpclib, urllib
import asyncore, socket
import select
import gtk
import os
import platform
import sys, shutil
import datetime
import xml.dom.minidom
import pdb
import rrdinfo
import time
import put
import gobject
from rrd import RRD, XPORT
import xml.sax.saxutils as saxutils
import traceback
from threading import Thread
from configobj import ConfigObj
from operator import itemgetter
from pygtk_chart import line_chart
from messages import messages, messages_header
from oxcSERVER_vm import *
from oxcSERVER_host import *
from oxcSERVER_properties import *
from oxcSERVER_storage import *
from oxcSERVER_alerts import *
from oxcSERVER_addserver import *
from oxcSERVER_newvm import *
from oxcSERVER_menuitem import *
from capabilities import capabilities_text
class oxcSERVER(oxcSERVERvm,oxcSERVERhost,oxcSERVERproperties,oxcSERVERstorage,oxcSERVERalerts,oxcSERVERaddserver,oxcSERVERnewvm,oxcSERVERmenuitem):
session_uuid = None
is_connected = False
host_vm = {}
set_descriptions = {}
halt = False
halt_search = False
halt_import = False
track_tasks = {}
tasks = {}
vboxchildcancel = {}
vboxchildprogressbar = {}
vboxchildprogress = {}
autostart = {}
vif_plug = []
flag_vif_plug = False
found_iter = ""
import_ref = None
import_start = False
import_make_into_template = False
poolroot = None
hostroot = {}
last_storage_iter = None
pbdcreate = []
def __init__(self, host, user, password, wine, ssl = False, port = 80):
super(oxcSERVER, self).__init__()
self.host = host
self.hostname = host
self.wine = wine
self.user = user
self.password = password
self.ssl = ssl
self.port = port
def logout(self):
self.halt_search = True
self.halt = True
if self.is_connected:
self.connection.event.unregister(self.session_uuid, ["*"])
self.connection.session.logout(self.session_uuid)
self.is_connected = False
def get_network_relation(self, ref, show_halted_vms):
# Get network -> VM relation
relation = {}
for network in self.all_network:
network_name = self.all_network[network]['name_label'].replace('Pool-wide network associated with eth','Network ')
vms = []
for vif in self.all_network[network]['VIFs']:
vm = self.all_vif[vif]['VM']
if not vms.count(vm + "_" + self.all_vms[vm]['name_label']):
if show_halted_vms or self.all_vms[vm]['power_state'] == "Running":
vms.append(vm + "_" + self.all_vms[vm]['name_label'])
relation[network + "_" + network_name] = vms
return relation
def get_storage_relation(self, ref, show_halted_vms):
# Get network -> VM relation
relation = {}
for storage in self.all_storage:
storage_name = self.all_storage[storage]['name_label']
vms = []
for vdi in self.all_storage[storage]['VDIs']:
vbds = self.all_vdi[vdi]['VBDs']
for vbd in vbds:
vm = self.all_vbd[vbd]['VM']
if not vms.count(vm + "_" + self.all_vms[vm]['name_label']):
if show_halted_vms or self.all_vms[vm]['power_state'] == "Running":
vms.append(vm + "_" + self.all_vms[vm]['name_label'])
relation[storage+ "_" + storage_name] = vms
return relation
def prueba(self):
print self.session_uuid
task_uuid = self.connection.task.create(self.session_uuid, "Restore2", "Restoring2 ")
print task_uuid
time.sleep(300)
print task_uuid
return
networks = self.connection.network.get_all_records(self.session_uuid)['Value']
for network in networks:
print networks[network]['name_label']
vms = []
for vif in networks[network]['VIFs']:
vms.append(self.connection.VIF.get_record(self.session_uuid, vif)['Value']['VM'])
# Remove duplicates
set = {}
map(set.__setitem__, vms, [])
for vm in set.keys():
print "\t" + self.connection.VM.get_record(self.session_uuid, vm)['Value']['name_label']
storages = self.connection.SR.get_all_records(self.session_uuid)['Value']
for storage in storages:
vms = []
print storages[storage]['name_label']
for vdi in storages[storage]['VDIs']:
vbds = self.connection.VDI.get_record(self.session_uuid, vdi)['Value']['VBDs']
for vbd in vbds:
vms.append(self.connection.VBD.get_record(self.session_uuid, vbd)['Value']['VM'])
set = {}
map(set.__setitem__, vms, [])
for vm in set.keys():
print "\t" + self.connection.VM.get_record(self.session_uuid, vm)['Value']['name_label']
"""
print self.connection.Async.pool_patch.apply(self.session_uuid, "OpaqueRef:772a39ac-e9be-1b14-2b20-ded03b95b20b", "OpaqueRef:be650e6f-8e2f-d937-c525-15fd57568bac")
result = self.connection.host.get_system_status_capabilities(self.session_uuid, "OpaqueRef:480dede4-930b-1b5c-54a8-73d38fa56d3a")['Value']
privacy = {"yes": "1", "maybe": "2", "if_customized": "3", "no": "4"}
dom = xml.dom.minidom.parseString(result)
nodes = dom.getElementsByTagName("capability")
capabilities = {}
for node in nodes:
attr = node.attributes
key, checked, pii, minsize, maxsize, mintime, maxtime = [attr.getNamedItem(k).value for k \
in ["key", "default-checked", "pii", "min-size", "max-size", "min-time", "max-time"]]
capabilities[privacy[pii] + "_" + key] = [checked, minsize, maxsize, mintime, maxtime]
totalsize = 0
totaltime = 0
for key in sorted(capabilities.keys()):
if key.split("_",2)[1] in capabilities_text:
print capabilities_text[key.split("_",2)[1]]
checked, minsize, maxsize, mintime, maxtime = [value for value in capabilities[key]]
if minsize == maxsize:
if maxsize != "-1":
totalsize += int(maxsize)
size = self.convert_bytes(maxsize)
elif minsize == "-1":
totalsize += int(maxsize)
size = "< %s" % self.convert_bytes(maxsize)
else:
totalsize += int(maxsize)
size = "%s-%s" % (self.convert_bytes(minsize), self.convert_bytes(maxsize))
if mintime == maxtime:
if maxtime == "-1":
time = "Negligible"
else:
totaltime += int(maxtime)
time = maxtime
elif mintime == "-1":
totaltime += int(maxtime)
time= "< %s" % maxtime
else:
totaltime += int(maxtime)
time= "%s-%s" % (mintime, maxtime)
print "\tChecked: %s\n\tSize: %s\n\tTime: %s seconds\n" % (checked, size, time)
print "Total Size: < %s Total Time: < %d minutes\n" % (self.convert_bytes(totalsize), totaltime/60)
print self.connection.VM.get_record(self.session_uuid, "OpaqueRef:dfd4eb56-d44b-8895-328e-83a36a0807ee")
print self.connection.VM.set_PV_kernel(self.session_uuid, "OpaqueRef:dfd4eb56-d44b-8895-328e-83a36a0807ee", "asdfasdf")
print "https://%s/vncsnapshot?session_id=%s&ref=%s" % (self.host, self.session_uuid, "OpaqueRef:be4332e6-a8c2-eb35-6b4d-58384e1f8463")
time.sleep(30)
task_uuid = self.connection.task.create(self.session_uuid, "Backup database pool", "Backup database pool")
url = "http://" + self.host + '/pool/xmldbdump?session_id=%s&task_id=%s' % (self.session_uuid, task_uuid['Value'])
urllib.urlretrieve(url, "/tmp/backup.xml")
import httplib, os
filename = "/root/openxencenter/prueba.xml"
task_uuid = self.connection.task.create(self.session_uuid, "Restore Pool database", "Restoring database pool " + filename)
self.track_tasks[task_uuid['Value']] = "Restore.Pool"
size=os.path.getsize(filename)
conn = httplib.HTTPConnection("192.168.100.2", 80)
conn.putrequest('PUT', '/pool/xmldbdump?session_id=%s&task_id=%s&dry_run=true' % (self.session_uuid, task_uuid['Value']), True, True)
conn.putheader("Content-length:", str(size));
conn.endheaders()
fp=open(filename, 'r')
total = 0
while True:
leido = fp.read(16384)
total += len(leido)
if leido:
time.sleep(0.1)
conn.send(leido)
else:
break
conn.close()
fp.close()
value = task_uuid["Value"]
task = self.connection.task.get_record(self.session_uuid, value)['Value']
while task["status"] == "pending":
task = self.connection.task.get_record(self.session_uuid, value)['Value']
print self.connection.host.get_all_records(self.session_uuid)
print self.connection.host.dmesg(self.session_uuid, "OpaqueRef:480dede4-930b-1b5c-54a8-73d38fa56d3a")
res = self.connection.SR.create(self.session_uuid,"OpaqueRef:5c0a69d1-7719-946b-7f3c-683a7058338d", {"SCSIid" : "3600a0b8000294d50000043454990e472" }, "0", ">Hardware HBA virtual disk storage", "Hardware HBA SR [IBM - /dev/sde]","lvmohba", "", False,{})
if len(res['ErrorDescription']) > 2:
print res['ErrorDescription'][2]
#Async.SR.probeOpaqueRef:021466a4-68d1-8e4b-c8ee-4d40e7be1d19OpaqueRef:5c0a69d1-7719-946b-7f3c-683a7058338dSCSIid3600a0b8000294d50000045784b85e36flvmohba
all_storage = self.connection.SR.get_all_records(self.session_uuid)['Value']
all_pbd = self.connection.PBD.get_all_records(self.session_uuid)['Value']
result = self.connection.SR.probe(self.session_uuid, "OpaqueRef:5c0a69d1-7719-946b-7f3c-683a7058338d", {"SCSIid" : "3600a0b8000294d50000045784b85e36f" }, "lvmohba", {})['Value']
dom = xml.dom.minidom.parseString(result)
nodes = dom.getElementsByTagName("UUID")
if len(nodes):
reattach = True
uuid = nodes[0].childNodes[0].data.strip()
for storage in all_storage.values():
if storage["uuid"] == uuid:
print storage
if len(storage['PBDs']):
print all_pbd[storage['PBDs'][0]]
reattach = False
if reattach:
return 0
print "Do you want reattach...."
else:
print "Please first detach...."
else:
print "Do you want format.."
pass
res = self.connection.SR.probe(self.session_uuid, "OpaqueRef:5c0a69d1-7719-946b-7f3c-683a7058338d", {}, "lvmohba", {})
if len(res['ErrorDescription']) > 2:
result = res['ErrorDescription'][3]
dom = xml.dom.minidom.parseString(result)
nodes = dom.getElementsByTagName("BlockDevice")
disks = {}
for node in nodes:
size = self.convert_bytes(node.getElementsByTagName("size")[0].childNodes[0].data.strip())
serial = node.getElementsByTagName("serial")[0].childNodes[0].data.strip()
scsiid = node.getElementsByTagName("SCSIid")[0].childNodes[0].data.strip()
adapter = node.getElementsByTagName("adapter")[0].childNodes[0].data.strip()
channel = node.getElementsByTagName("channel")[0].childNodes[0].data.strip()
id = node.getElementsByTagName("id")[0].childNodes[0].data.strip()
lun = node.getElementsByTagName("lun")[0].childNodes[0].data.strip()
vendor = node.getElementsByTagName("vendor")[0].childNodes[0].data.strip()
if vendor not in disks:
disks[vendor] = []
disks[vendor].append("%s %s %s %s:%s:%s:%s" % (size, serial, scsiid, adapter, channel, id, lun))
print disks
else:
print "No LUNS found"
"""
#Async.SR.probe
#
#OpaqueRef:047a0487-db6d-d273-09a3-d2ac68cb0a7c
#OpaqueRef:480dede4-930b-1b5c-54a8-73d38fa56d3a
#
# serverpath/home
# server192.168.100.4
# options
#
#nfs
#
"""
all_vms = self.connection.VM.get_all_records(self.session_uuid)['Value']
all_vdi = self.connection.VDI.get_all_records(self.session_uuid)['Value']
all_vbd = self.connection.VBD.get_all_records(self.session_uuid)['Value']
vm = "OpaqueRef:0bbb21d5-4810-2cdc-9b75-c02415de78bb"
vm_vbd = ""
vm_vdi = ""
for vbd in all_vbd.keys():
if all_vbd[vbd]["VM"] == vm and \
all_vbd[vbd]['type'] == "CD":
vm_vbd = vbd
for vdi in all_vdi:
if all_vdi[vdi]['location'] == "XenCenter.iso":
vm_vdi = vdi
print self.connection.Async.VBD.eject(self.session_uuid, vm_vbd)
print self.connection.VBD.insert(self.session_uuid, vm_vbd, vm_vdi)
sr = {
"serverpath" : "/home",
"server" : "192.168.100.4",
"options" : ""
}
value = self.connection.Async.SR.probe(self.session_uuid, "OpaqueRef:480dede4-930b-1b5c-54a8-73d38fa56d3a", sr, "nfs", {})['Value']
task = self.connection.task.get_record(self.session_uuid, value)['Value']
while task["status"] == "pending":
task = self.connection.task.get_record(self.session_uuid, value)['Value']
result = saxutils.unescape(task['result']).replace("","").replace("","").replace(""", '"')
print result
dom = xml.dom.minidom.parseString(result)
nodes = dom.getElementsByTagName("SRlist")
if len(nodes[0].childNodes):
for i in range(1,len(nodes[0].childNodes),2):
print nodes[0].childNodes[i].childNodes[1].childNodes[0].data.strip()
self.connection.task.destroy(self.session_uuid, value)
sr = {
"port" : "3260",
"target" : "192.168.100.4",
"SCSIid" : "14945540000000000000000000100000002a00a002100a00c",
"targetIQN" : "iqn.2001-04.com.example:storage.disk2.sys1.xyz",
}
value = self.connection.Async.SR.probe(self.session_uuid, "OpaqueRef:480dede4-930b-1b5c-54a8-73d38fa56d3a", sr, "lvmoiscsi",{})['Value']
task = self.connection.task.get_record(self.session_uuid, value)['Value']
while task["status"] == "pending":
task = self.connection.task.get_record(self.session_uuid, value)['Value']
print task
self.connection.task.destroy(self.session_uuid, value)
sr = {
"port" : "3260",
"target": "192.168.100.4",
}
# chapuser
# chappassword
value = self.connection.Async.SR.create(self.session_uuid, "OpaqueRef:480dede4-930b-1b5c-54a8-73d38fa56d3a", sr, "0", "__gui__", "SHOULD NEVER BE CREATED","lvmoiscsi","user", True, {})['Value']
task = self.connection.task.get_record(self.session_uuid, value)['Value']
while task["status"] == "pending":
task = self.connection.task.get_record(self.session_uuid, value)['Value']
if task["error_info"][3]:
dom = xml.dom.minidom.parseString(task["error_info"][3])
nodes = dom.getElementsByTagName("TGT")
index = nodes[0].childNodes[1].childNodes[0].data.strip()
ip = nodes[0].childNodes[3].childNodes[0].data.strip()
target = nodes[0].childNodes[5].childNodes[0].data.strip()
print "%s (%s)" % (target, ip)
else:
print task["error_info"][2]
self.connection.task.destroy(self.session_uuid, value)
sr["targetIQN"] = target
value = self.connection.Async.SR.create(self.session_uuid, "OpaqueRef:480dede4-930b-1b5c-54a8-73d38fa56d3a", sr, "0", "__gui__", "SHOULD NEVER BE CREATED","lvmoiscsi","user", True, {})['Value']
task = self.connection.task.get_record(self.session_uuid, value)['Value']
while task["status"] == "pending":
task = self.connection.task.get_record(self.session_uuid, value)['Value']
print task["error_info"][3]
if task["error_info"][3]:
dom = xml.dom.minidom.parseString(task["error_info"][3])
nodes = dom.getElementsByTagName("LUN")
vendor = nodes[0].childNodes[1].childNodes[0].data.strip()
lunid = nodes[0].childNodes[3].childNodes[0].data.strip()
size = nodes[0].childNodes[5].childNodes[0].data.strip()
scsiid = nodes[0].childNodes[7].childNodes[0].data.strip()
print "LUN %s: %s (%s)" % (lunid, self.convert_bytes(size), vendor)
else:
print task["error_info"][2]
self.connection.task.destroy(self.session_uuid, value)
"""
def export_vm(self, uuid):
vm_uuid = self.connection.VM.get_by_uuid(self.session_uuid, uuid)['Value']
print "GET /export?ref=%s&session_id=%s HTTP/1.1\r\n\r\n" % (vm_uuid,self.session_uuid)
def get_seconds(self, toconvert):
converted = datetime.datetime.strptime(str(toconvert), "%Y%m%dT%H:%M:%SZ")
totime = time.mktime(converted.timetuple())
#FIXME
return totime
def format_date(self, toconvert):
converted = datetime.datetime.strptime(str(toconvert), "%Y%m%dT%H:%M:%SZ")
#totime = time.mktime(converted.timetuple())
return str(converted)
#FIXME
def get_seconds_difference_reverse(self, toconvert):
converted = datetime.datetime.strptime(str(toconvert), "%Y%m%dT%H:%M:%SZ")
totime = time.mktime(converted.timetuple())
#FIXME
return totime-time.time()-3600
def get_seconds_difference(self, toconvert):
converted = datetime.datetime.strptime(str(toconvert), "%Y%m%dT%H:%M:%SZ")
totime = time.mktime(converted.timetuple())
#FIXME
return time.time()-totime-3600
def get_dmesg(self, ref):
return self.connection.host.dmesg(self.session_uuid, ref)["Value"]
def restore_server(self, ref, file, name):
import httplib
#task.createOpaqueRef:149c1416-9934-3955-515a-d644aaddc38fuploadTaskhttp://83.165.161.223/host_restore?session_id=OpaqueRef:149c1416-9934-3955-515a-d644aaddc38f
task_uuid = self.connection.task.create(self.session_uuid, "Restoring Server", "Restoring Server %s from %s " % (name,file))
self.track_tasks[task_uuid['Value']] = "Restore.Server"
#size=os.stat(file)[6]
fp=open(file, 'rb')
url = self.wine.selected_ip
put.putfile(fp, 'http://' + url + '/host_restore?session_id=%s&task_id=%s&dry_run=true' % (self.session_uuid, task_uuid['Value']))
return
conn = httplib.HTTP(url)
conn.putrequest('PUT', '/host_restore?session_id=%s&task_id=%s&dry_run=true' % (self.session_uuid, task_uuid['Value']))
conn.putheader('Content-Type', 'text/plain')
conn.endheaders()
blocknum=0
uploaded=0
blocksize=4096
while not self.halt_import:
bodypart=fp.read(blocksize)
blocknum+=1
if blocknum % 10 == 0:
uploaded+=len(bodypart)
if not bodypart: break
conn.send(bodypart)
fp.close()
def save_screenshot(self, ref, filename):
url = "http://" + self.wine.selected_ip + '/vncsnapshot?session_id=%s&ref=%s' % (self.session_uuid, ref)
urllib.urlretrieve(url, filename)
def pool_backup_database(self, ref, filename, name):
task_uuid = self.connection.task.create(self.session_uuid, "Backup Pool database", "Backing up database pool " + name)
self.track_tasks[task_uuid['Value']] = "Backup.Pool"
url = "http://" + self.wine.selected_ip+ '/pool/xmldbdump?session_id=%s&task_id=%s' % (self.session_uuid, task_uuid['Value'])
urllib.urlretrieve(url, filename)
def pool_restore_database(self, ref, filename, name, dry_run="true"):
import httplib
task_uuid = self.connection.task.create(self.session_uuid, "Restore Pool database", "Restoring database pool " + filename)
self.track_tasks[task_uuid['Value']] = "Restore.Pool"
size=os.path.getsize(filename)
url = self.wine.selected_ip
fp=open(filename, 'r')
put.putfile(fp, 'http://' + url + '/pool/xmldbdump?session_id=%s&task_id=%s&dry_run=%s' % (self.session_uuid, task_uuid['Value'], dry_run))
return
conn = httplib.HTTP(url)
conn.putrequest('PUT', '/pool/xmldbdump?session_id=%s&task_id=%s&dry_run=%s' % (self.session_uuid, task_uuid['Value'], dry_run))
conn.putheader('Content-Length', str(size))
conn.endheaders()
total = 0
while True:
leido = fp.read(16384)
if leido:
total += len(leido)
time.sleep(0.1)
conn.send(leido)
else:
break
fp.close()
def host_download_logs(self, ref, filename, name):
task_uuid = self.connection.task.create(self.session_uuid, "Downloading host logs", "Downloading logs from host " + name)
self.track_tasks[task_uuid['Value']] = "Download.Logs"
url = "http://" + self.wine.selected_ip + '/host_logs_download?session_id=%s&sr_id=%s&task_id=%s' % (self.session_uuid, ref, task_uuid['Value'])
urllib.urlretrieve(url, filename)
def host_download_status_report(self, ref, refs, filename, name):
task_uuid = self.connection.task.create(self.session_uuid, "Downloading status report", "Downloading status report from host " + name)
self.track_tasks[task_uuid['Value']] = self.host_vm[ref][0]
url = "https://" + self.wine.selected_ip + '/system-status?session_id=%s&entries=%s&task_id=%s&output=tar' % (self.session_uuid, refs, task_uuid['Value'])
urllib.urlretrieve(url, filename)
def backup_server(self, ref, filename, name):
task_uuid = self.connection.task.create(self.session_uuid, "Backup Server", "Backing up server " + name)
self.track_tasks[task_uuid['Value']] = "Backup.Server"
url = "http://" + self.wine.selected_ip + '/host_backup?session_id=%s&sr_id=%s&task_id=%s' % (self.session_uuid, ref, task_uuid['Value'])
urllib.urlretrieve(url, filename)
def import_vm(self, ref, filename):
#file = "pruebadebian.xva"
import httplib
task_uuid = self.connection.task.create(self.session_uuid, "Importing VM", "Importing VM " + filename)
self.track_tasks[task_uuid['Value']] = "Import.VM"
size=os.stat(filename)[6]
url = self.wine.selected_ip
fp=open(filename, 'r')
put.putfile(fp, 'http://' + url + '/import?session_id=%s&sr_id=%s&task_id=%s' % (self.session_uuid, ref, task_uuid['Value']))
return
conn = httplib.HTTP(url)
conn.putrequest('PUT', '/import?session_id=%s&sr_id=%s&task_id=%s' % (self.session_uuid, ref, task_uuid['Value']))
conn.putheader('Content-Type', 'text/plain')
conn.putheader('Content-Length', str(size))
conn.endheaders()
fp=open(file, 'rb')
blocknum=0
uploaded=0
blocksize=4096
while not self.halt_import:
bodypart=fp.read(blocksize)
blocknum+=1
if blocknum % 10 == 0:
uploaded+=len(bodypart)
if blocknum % 1000 == 0:
time.sleep(0.1)
if not bodypart: break
conn.send(bodypart)
fp.close()
def add_alert(self, message, ref, list):
if message['cls'] == "Host":
if message['name'] in messages:
parent = list.prepend(None, [gtk.gdk.pixbuf_new_from_file("images/info.gif"),
self.hostname, messages_header[message['name']], self.format_date(str(message['timestamp'])),
ref, self.host])
list.prepend(parent, [None, "", messages[message['name']] % (self.hostname), "",
ref, self.host])
else:
parent = list.prepend(None, [gtk.gdk.pixbuf_new_from_file("images/info.gif"),
self.hostname, message['name'], self.format_date(str(message['timestamp'])),
ref, self.host])
list.prepend(parent, [None, "", message['name'], "",
ref, self.host])
elif message['name'] == "ALARM":
self.filter_uuid = message['obj_uuid']
if self.vm_filter_uuid() not in self.all_vms:
return None
if not self.all_vms[self.vm_filter_uuid()]['is_control_domain']:
value = message['body'].split("\n")[0].split(" ")[1]
dom = xml.dom.minidom.parseString(message['body'].split("config:")[1][1:])
nodes = dom.getElementsByTagName("name")
#alert = message['body'].split('value="')[1].split('"')[0]
alert = nodes[0].attributes.getNamedItem("value").value
nodes = dom.getElementsByTagName("alarm_trigger_level")
level = nodes[0].attributes.getNamedItem("value").value
nodes = dom.getElementsByTagName("alarm_trigger_period")
period = nodes[0].attributes.getNamedItem("value").value
if "alert_" + alert in messages:
parent = list.prepend(None, [gtk.gdk.pixbuf_new_from_file("images/warn.gif"),
self.hostname, messages_header["alert_" + alert],
self.format_date(str(message['timestamp'])), ref, self.host])
list.prepend(parent, [None, "", messages["alert_" + alert] % \
(self.all_vms[self.vm_filter_uuid()]['name_label'], float(value)*100, int(period), float(level)*100), "",
ref, self.host])
else:
print message['name']
print message['body']
else:
value = message['body'].split("\n")[0].split(" ")[1]
alert = message['body'].split('value="')[1].split('"')[0]
if "host_alert_" + alert in messages:
parent = list.prepend(None, [gtk.gdk.pixbuf_new_from_file("images/warn.gif"),
self.hostname, messages_header["host_alert_" + alert] % ("Control Domain"),
self.format_date(str(message['timestamp'])), ref, self.host])
list.prepend(parent, [None, "", messages["host_alert_" + alert] % \
("Control Domain", self.hostname, float(value)), "",
ref, self.host])
else:
print message['name']
print message['body']
def add_vm_to_tree(self, vm):
if self.all_vms[vm]['resident_on'] != "OpaqueRef:NULL" and self.all_vms[vm]['resident_on'] in self.hostroot:
resident = self.all_vms[vm]['resident_on']
self.treestore.prepend(self.hostroot[self.all_vms[vm]['resident_on']], [\
gtk.gdk.pixbuf_new_from_file("images/tree_%s_16.png"\
% self.all_vms[vm]['power_state'].lower()),\
self.all_vms[vm]['name_label'], self.all_vms[vm]['uuid'],\
"vm", self.all_vms[vm]['power_state'], self.host,
vm, self.all_vms[vm]['allowed_operations'], self.all_hosts[resident]['address']])
elif self.all_vms[vm]['affinity'] != "OpaqueRef:NULL" and self.all_vms[vm]['affinity'] in self.hostroot:
affinity = self.all_vms[vm]['affinity']
self.treestore.prepend(self.hostroot[self.all_vms[vm]['affinity']], [\
gtk.gdk.pixbuf_new_from_file("images/tree_%s_16.png"\
% self.all_vms[vm]['power_state'].lower()),\
self.all_vms[vm]['name_label'], self.all_vms[vm]['uuid'],\
"vm", self.all_vms[vm]['power_state'], self.host,
vm, self.all_vms[vm]['allowed_operations'], self.all_hosts[affinity]['address']])
else:
if self.poolroot:
self.treestore.prepend(self.poolroot, [\
gtk.gdk.pixbuf_new_from_file("images/tree_%s_16.png"\
% self.all_vms[vm]['power_state'].lower()),\
self.all_vms[vm]['name_label'], self.all_vms[vm]['uuid'],\
"vm", self.all_vms[vm]['power_state'], self.host,
vm, self.all_vms[vm]['allowed_operations'], self.host])
else:
self.treestore.prepend(self.hostroot[self.all_hosts.keys()[0]], [\
gtk.gdk.pixbuf_new_from_file("images/tree_%s_16.png"\
% self.all_vms[vm]['power_state'].lower()),\
self.all_vms[vm]['name_label'], self.all_vms[vm]['uuid'],\
"vm", self.all_vms[vm]['power_state'], self.host,
vm, self.all_vms[vm]['allowed_operations'], self.host])
def fill_allowed_operations(self, ref):
actions = self.connection.VM.get_allowed_operations(self.session_uuid, ref)['Value']
self.all_vms[ref]['allowed_operations'] = actions
return actions
def fill_vm_network(self, ref, tree, list):
#self.filter_ref = ref
#vm_vifs = filter(self.filter_vif_ref, self.all_vif.values())
list.clear()
if ref in self.all_vms:
guest_metrics = self.all_vms[ref]['guest_metrics']
for vif_ref in self.all_vms[ref]['VIFs']:
vif = self.all_vif[vif_ref]
if "kbps" in vif['qos_algorithm_params']:
limit = vif['qos_algorithm_params']['kbps']
else:
limit = ""
ip = ""
if guest_metrics in self.all_vm_guest_metrics and vif['device'] + "/ip" in self.all_vm_guest_metrics[guest_metrics]['networks']:
ip = self.all_vm_guest_metrics[guest_metrics]['networks'][vif['device'] + "/ip"]
else:
ip = ""
#FIXME
if vif['network'] in self.all_network:
network = self.all_network[vif['network']]['name_label'].replace('Pool-wide network associated with eth','Network ')
else:
network = ""
list.append((vif['device'], \
vif['MAC'], \
limit, \
network, \
ip, \
str(vif['currently_attached']), vif_ref))
else:
print "VM not found %s" % ref
def set_vif_limit(self, ref, limit, vm_ref):
qos_algorithm_params = {
'kbps': str(limit)
}
res = self.connection.VIF.set_qos_algorithm_params(self.session_uuid, ref, qos_algorithm_params)
if "Value" in res:
self.track_tasks[res['Value']] = vm_ref
else:
print res
def set_vif_to_manual(self, ref, vm_ref):
res = self.connection.VIF.set_MAC_autogenerated(self.session_uuid, ref, False)
if "Value" in res:
self.track_tasks[res['Value']] = vm_ref
else:
print res
def fill_vm_snapshots(self, uuid, tree=None, list=None):
list.clear()
if uuid in self.all_vms:
all_snapshots = self.all_vms[uuid]['snapshots']
for snapshot_uuid in all_snapshots:
snapshot_name = self.all_vms[snapshot_uuid]['name_label']
snapshot_time = self.all_vms[snapshot_uuid]['snapshot_time']
snapshot_of = self.all_vms[snapshot_uuid]['snapshot_of']
snapshot_size = 0
for vbd in self.all_vms[snapshot_uuid]['VBDs']:
vbd_data = self.all_vbd[vbd]
if vbd_data['type'] == 'Disk':
snapshot_size += int(self.connection.VDI.get_record(self.session_uuid,vbd_data['VDI'])['Value']['physical_utilisation'])
list.append([snapshot_uuid, "" + snapshot_name + "\n\nTaken on: " + str(snapshot_time) + "\n\nSize: " + \
self.convert_bytes(snapshot_size) + "\n\n" + "Used by: " + self.wine.selected_name + "\n"])
def update_performance(self, uuid, ref, ip, host=False, period=5):
# Default three hours of period
self.halt_performance = False
for widget in ["scrolledwindow47", "scrolledwindow48", "scrolledwindow49", "scrolledwindow50"]:
if self.wine.builder.get_object(widget).get_children()[0].get_children():
#gobject.idle_add(lambda: self.wine.builder.get_object(widget).get_children()[0].remove(self.wine.builder.get_object(widget).get_children()[0].get_children()[0]) and False)
gtk.gdk.threads_enter()
self.wine.builder.get_object(widget).get_children()[0].remove(self.wine.builder.get_object(widget).get_children()[0].get_children()[0])
gtk.gdk.threads_leave()
if host:
data_sources = self.connection.host.get_data_sources(self.session_uuid, ref)
else:
data_sources = self.connection.VM.get_data_sources(self.session_uuid, ref)
if not "Value" in data_sources:
return
data_sources = data_sources['Value']
ds = {}
for data_source in data_sources:
if data_source['enabled']:
name = data_source['name_label']
desc = data_source['name_description']
if not name[:3] in ds.keys():
ds[name[:3]] = []
if ds[name[:3]].count([name, desc]) == 0:
if name not in ("memory_internal_free", "xapi_free_memory_kib", "xapi_memory_usage_kib", "xapi_live_memory_kib") \
and name[:6] != "pif___":
ds[name[:3]].append([name, desc])
if host:
if os.path.exists(os.path.join(self.wine.pathconfig, "host_rrds.rrd")):
os.unlink(os.path.join(self.wine.pathconfig, "host_rrds.rrd"))
urllib.urlretrieve("http://%s/host_rrds?session_id=%s" % (ip, self.session_uuid), os.path.join(self.wine.pathconfig, "host_rrds.rrd"))
rrd = RRD(os.path.join(self.wine.pathconfig, "host_rrds.rrd"))
else:
if os.path.exists(os.path.join(self.wine.pathconfig, "vm_rrds.rrd")):
os.unlink(os.path.join(self.wine.pathconfig, "vm_rrds.rrd"))
urllib.urlretrieve("http://%s/vm_rrds?session_id=%s&uuid=%s" % (ip, self.session_uuid, uuid), os.path.join(self.wine.pathconfig, "vm_rrds.rrd"))
rrd = RRD(os.path.join(self.wine.pathconfig, "vm_rrds.rrd"))
rrdinfo = rrd.get_data(period)
def show_tic(value):
if time.strftime("%S", time.localtime(value)) == "00":
return time.strftime("%H:%M", time.localtime(value))
else:
return ""
def hovered(chart, graph, (x, y)):
#print chart.get_title()
self.wine.builder.get_object("lblperf" + graph.get_title()[:3].lower()).set_label(
"%s - %s = %0.2f" % (time.strftime("%d/%m %H:%M:%S", time.localtime(x)), graph.get_title(), y))
# Chart
chart = {}
graph = {}
for name in ["cpu", "vbd", "vif", "mem"]:
chart[name] = line_chart.LineChart()
chart[name].xaxis.set_show_tics(True)
chart[name].xaxis.set_tic_format_function(show_tic)
chart[name].yaxis.set_position(7)
chart[name].connect("datapoint-hovered", hovered)
chart[name].legend.set_visible(True)
chart[name].legend.set_position(line_chart.POSITION_BOTTOM_RIGHT)
chart[name].set_padding(100)
chart[name].yaxis.set_label("kBps")
chart["cpu"].yaxis.set_label("%")
chart["mem"].yaxis.set_label("MB")
# CPU Graph
chart["cpu"].set_yrange((0, 100))
for key in rrdinfo.keys():
if key[:3] == "cpu":
data = rrdinfo[key]["values"]
for i in range(len(data)):
data[i][1] = data[i][1]*100
graph[key] = line_chart.Graph(key, key, data)
graph[key].set_show_title(False)
chart["cpu"].add_graph(graph[key])
chart["cpu"].set_size_request(len(data)*20, 250)
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow47").add_with_viewport(chart["cpu"]) and False)
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow47").show_all() and False)
# Memory
if "memory_internal_free" in rrdinfo and "memory" in rrdinfo:
chart["mem"].set_yrange((0, int(rrdinfo["memory"]["max_value"])/1024/1024))
data = rrdinfo["memory"]["values"]
data2 = rrdinfo["memory_internal_free"]["values"]
for i in range(len(data2)):
data[i][1] = (data[i][1] - data2[i][1]*1024)/1024/1024
graph["mem"] = line_chart.Graph("Memory used", "Memory used", data)
graph["mem"].set_show_title(False)
chart["mem"].add_graph(graph["mem"])
chart["mem"].set_size_request(len(data)*20, 250)
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow48").add_with_viewport(chart["mem"]) and False)
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow48").show_all() and False)
elif "memory_total_kib" in rrdinfo and "xapi_free_memory_kib" in rrdinfo:
chart["mem"].set_yrange((0, int(rrdinfo["memory_total_kib"]["max_value"])/1024/1024))
data = rrdinfo["memory_total_kib"]["values"]
data2 = rrdinfo["xapi_free_memory_kib"]["values"]
for i in range(len(data2)):
data[i][1] = (data[i][1] - data2[i][1]*1024)/1024/1024
graph["mem"] = line_chart.Graph("Memory used", "Memory used", data)
graph["mem"].set_show_title(False)
chart["mem"].add_graph(graph["mem"])
chart["mem"].set_size_request(len(data)*20, 250)
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow48").add_with_viewport(chart["mem"]) and False)
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow48").show_all() and False)
else:
label = gtk.Label()
label.set_markup("No data availaible")
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow48").add_with_viewport(label) and False)
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow48").show_all() and False)
# Network
max_value = 0
data = None
for key in rrdinfo.keys():
if key[:3] == "vif" or key[:3] == "pif":
data = rrdinfo[key]["values"]
for i in range(len(data)):
data[i][1] = data[i][1]/1024
if data[i][1] > max_value:
max_value = data[i][1]
graph[key] = line_chart.Graph(key, key, data)
graph[key].set_show_title(False)
chart["vif"].add_graph(graph[key])
if data:
chart["vif"].set_yrange((0, max_value))
chart["vif"].set_size_request(len(data)*20, 250)
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow49").add_with_viewport(chart["vif"]) and False)
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow49").show_all() and False)
else:
label = gtk.Label()
label.set_markup("No data availaible")
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow49").add_with_viewport(label) and False)
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow49").show_all() and False)
# Disk
if not host:
max_value = 0
data = None
for key in rrdinfo.keys():
if key[:3] == "vbd":
data = rrdinfo[key]["values"]
for i in range(len(data)):
data[i][1] = data[i][1]/1024
graph[key] = line_chart.Graph(key, key, data)
graph[key].set_show_title(False)
chart["vbd"].add_graph(graph[key])
if rrdinfo[key]['max_value']/1024 > max_value:
max_value = rrdinfo[key]['max_value']/1024
chart["vbd"].set_yrange((0, max_value))
chart["vbd"].set_size_request(len(data)*20, 250)
if data:
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow50").add_with_viewport(chart["vbd"]) and False)
gobject.idle_add(lambda: self.wine.builder.get_object("scrolledwindow50").show_all() and False)
if max_value == 0: max_value = 1
gobject.idle_add(lambda: self.wine.adjust_scrollbar_performance() and False)
time.sleep(5)
while not self.halt_performance:
if os.path.exists(os.path.join(self.wine.pathconfig, "update.rrd")):
os.unlink(os.path.join(self.wine.pathconfig, "update.rrd"))
urllib.urlretrieve("http://%s/rrd_updates?session_id=%s&start=%s&cf=AVERAGE&interval=5&vm_uuid=%s" % (ip, self.session_uuid, int(time.time())-10, uuid), os.path.join(self.wine.pathconfig, "update.rrd"))
rrd = XPORT(os.path.join(self.wine.pathconfig, "update.rrd"))
rrdinfo = rrd.get_data()
for key in rrdinfo:
if key in graph:
if rrdinfo[key]['values']:
if key[:3] == "cpu":
data = rrdinfo[key]["values"]
for i in range(len(data)):
data[i][1] = data[i][1]*100
graph[key].add_data(data)
chart[key[:3]].queue_draw()
elif key[:3] == "vif":
data = rrdinfo[key]["values"]
for i in range(len(data)):
data[i][1] = data[i][1]/1024
graph[key].add_data(data)
chart[key[:3]].queue_draw()
elif key[:3] == "vbd":
data = rrdinfo[key]["values"]
for i in range(len(data)):
data[i][1] = data[i][1]/1024
graph[key].add_data(data)
chart[key[:3]].queue_draw()
if "memory_internal_free" in rrdinfo:
data = rrdinfo["memory"]["values"]
data2 = rrdinfo["memory_internal_free"]["values"]
for i in range(len(data2)):
data[i][1] = (data[i][1] - data2[i][1]*1024)/1024/1024
graph["mem"].add_data(data)
chart["mem"].queue_draw()
for i in range(5):
if not self.halt_performance:
time.sleep(1)
def fill_vm_log(self, uuid, tree=None, list=None, thread=False):
self.filter_uuid = uuid
self.filter_ref = self.wine.selected_ref
i = 0
for ch in self.wine.builder.get_object("vmtablelog").get_children():
gobject.idle_add(lambda: self.wine.builder.get_object("vmtablelog").remove(ch) and False)
for task_ref in filter(self.task_filter_uuid, self.tasks):
task = self.all_tasks[task_ref]
if "snapshot" in task:
self.add_box_log(task['snapshot']['name_label'], str(task['snapshot']['created']), "%s %s" % (task["snapshot"]["name_label"], self.all_vms[self.track_tasks[task["ref"]]]["name_label"]), str(task['snapshot']['created']), task['ref'], task, float(task['snapshot']['progress']),i%2)
else:
if "ref" in task:
self.add_box_log(task['name_label'], str(task['created']), "%s %s" % (task["name_label"], self.all_vms[self.track_tasks[task["ref"]]]["name_label"]), str(task['created']), self.get_task_ref_by_uuid(task['uuid']), task, float(task['progress']),i%2)
else:
self.add_box_log(task['name_label'], str(task['created']), "%s %s" % (task["name_label"], task["name_description"]), str(task['created']), task_ref, task, float(task['progress']),i%2)
i = i + 1
for log in sorted(filter(self.log_filter_uuid, self.all_messages.values()), key=itemgetter("timestamp"), reverse=True):
timestamp = str(log['timestamp'])
if thread:
gobject.idle_add(lambda: self.add_box_log(log['name'], timestamp, log['body'], str(log['timestamp']),alt=i%2) and False)
else:
self.add_box_log(log['name'], timestamp, log['body'], str(log['timestamp']),alt=i%2)
i = i + 1
def add_box_log(self, title, date, description, time, id=None, task=None, progress=0, alt=0):
date = self.format_date(date)
vboxframe = gtk.Frame()
vboxframe.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#d5e5f7"))
if task:
vboxframe.set_size_request(700,100)
else:
vboxframe.set_size_request(700,80)
vboxchild = gtk.Fixed()
vboxevent = gtk.EventBox()
vboxevent.add(vboxchild)
vboxframe.add(vboxevent)
vboxchildlabel1 = gtk.Label()
vboxchildlabel1.set_selectable(True)
vboxchildlabel2 = gtk.Label()
vboxchildlabel2.set_selectable(True)
vboxchildlabel3 = gtk.Label()
vboxchildlabel3.set_selectable(True)
vboxchildlabel3.set_size_request(600,-1)
vboxchildlabel3.set_line_wrap(True)
vboxchildlabel4 = gtk.Label()
vboxchildlabel4.set_selectable(True)
#FIXME
#vboxchildprogressbar.set_style(1)
vboxchildlabel2.set_label(date)
if title in messages_header:
vboxchildlabel1.set_label(messages_header[title])
else:
vboxchildlabel1.set_label(title)
if title in messages:
vboxchildlabel3.set_label(messages[title] % (self.wine.selected_name))
else:
vboxchildlabel3.set_label(description)
vboxchildlabel1.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("blue"))
#vboxchildlabel4.set_label(time)
vboxchild.put(vboxchildlabel1, 25, 12)
vboxchild.put(vboxchildlabel2, 500, 12)
vboxchild.put(vboxchildlabel3, 25, 32)
vboxchild.put(vboxchildlabel4, 25, 52)
# Active task
if task:
self.vboxchildcancel[id] = gtk.Button()
self.vboxchildcancel[id].connect("clicked", self.cancel_task)
self.vboxchildcancel[id].set_name(id)
self.vboxchildprogressbar[id] = gtk.ProgressBar()
self.vboxchildprogress[id] = gtk.Label()
self.vboxchildprogress[id].set_selectable(True)
self.vboxchildprogressbar[id].set_size_request(500,20)
self.vboxchildprogressbar[id].set_fraction(progress)
if ("snapshot" in task and (task["snapshot"]["status"] != "failure" and task["snapshot"]["status"] != "success")) or \
(task["status"] != "failure" and task["status"] != "success"):
vboxchild.put(self.vboxchildcancel[id], 500, 32)
self.vboxchildcancel[id].set_label("Cancel")
self.vboxchildprogress[id].set_label("Progress: ")
vboxchild.put(self.vboxchildprogressbar[id], 100, 72)
elif ("snapshot" in task and task["snapshot"]["status"] == "failure") or task["status"] == "failure":
self.vboxchildcancel[id].hide()
self.vboxchildprogressbar[id].hide()
self.vboxchildprogress[id].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#FF0000'))
if "snapshot" in task:
self.vboxchildprogress[id].set_label("Error: %s" % task["snapshot"]["error_info"])
else:
self.vboxchildprogress[id].set_label("Error: %s" % task["error_info"])
else:
if ("snapshot" in task and task["snapshot"]["finished"]) or task["finished"]:
vboxchildlabel4.set_label("Finished: %s" % self.format_date(str(task["finished"])))
vboxchild.put(self.vboxchildprogress[id], 25, 72)
if ("snapshot" in task and task["snapshot"]["status"] == "success"):
self.vboxchildcancel[id].hide()
self.vboxchildprogressbar[id].hide()
if task["status"] == "success":
self.vboxchildcancel[id].hide()
self.vboxchildprogressbar[id].hide()
if alt:
vboxevent.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#d5e5f7"))
else:
vboxevent.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#BAE5D3"))
self.wine.builder.get_object("vmtablelog").add(vboxframe)
self.wine.builder.get_object("vmtablelog").show_all()
def cancel_task(self, widget, data=None):
self.connection.task.cancel(self.session_uuid, gtk.Buildable.get_name(widget))
widget.hide()
self.vboxchildprogress[gtk.Buildable.get_name(widget)].set_label("Cancelled")
self.vboxchildprogressbar[gtk.Buildable.get_name(widget)].hide()
self.wine.push_alert("Task cancelled")
def fill_host_storage(self, ref, list):
list.clear()
for storage in self.all_storage.values():
on_host = False
for pbd in storage['PBDs']:
if self.all_pbd[pbd]['host'] == ref:
on_host = True
#if storage['type'] != "iso":
if on_host:
if "physical_size" in storage:
if int(storage['physical_size']) > 0:
usage = "%d%% (%s used)" % \
(((float(storage['physical_utilisation'])/1073741824) / \
(float(storage['physical_size'])/1073741824) * 100), \
self.convert_bytes(storage['physical_utilisation']))
else:
usage = "0% (0B Used)"
if storage['name_label'] != "XenServer Tools":
list.append((storage['name_label'],
storage['name_description'],
storage['type'],
str(storage['shared']),
usage,
self.convert_bytes(storage['physical_size']),
self.convert_bytes(storage['virtual_allocation'])))
def fill_host_search(self, ref, list):
while not self.halt_search:
gobject.idle_add(lambda: list.clear() and False)
position = 0
hosts = {}
#FIXME: what happen when a pool exists?
for host in self.all_hosts.keys():
metrics = self.all_hosts[host]['metrics']
memory_free = int(self.all_host_metrics[metrics]['memory_free'])
memory_total = int(self.all_host_metrics[metrics]['memory_total'])
if memory_total == 0:
memory = ""
memory_img = 0
else:
memory = str(((memory_total-memory_free)*100)/memory_total) + "% used of " + self.convert_bytes(memory_total)
memory_img = int((((memory_total-memory_free)*100)/memory_total)/10)
start_time = self.all_hosts[host]['other_config']['boot_time'][:-1]
uptime = self.humanize_time(time.time() - int(start_time))
hosts[host] = position
gobject.idle_add(lambda item: list.append(None, item) and False, ([gtk.gdk.pixbuf_new_from_file("images/tree_connected_16.png"), "" + self.all_hosts[host]['name_label'] + "\n" + self.all_hosts[host]['name_description'] + "", gtk.gdk.pixbuf_new_from_file("images/usagebar_5.png"), "",gtk.gdk.pixbuf_new_from_file("images/usagebar_%s.png" % str(memory_img)),memory,"-","",self.all_hosts[host]['address'],uptime, None]))
position = position + 1
for host in self.all_hosts.keys():
Thread(target=self.fill_vm_search, args=(host,list,hosts)).start()
for i in range(0,60):
if not self.halt_search:
time.sleep(1)
def fill_vm_search(self, host,list, hosts):
rrd_updates = rrdinfo.RRDUpdates("http://%s/rrd_updates?session_id=%s&start=%d&cf=AVERAGE&interval=5&host=true" % (self.all_hosts[host]["address"], self.session_uuid, time.time()-600))
rrd_updates.refresh()
for uuid in rrd_updates.get_vm_list():
for vm in self.all_vms:
if self.all_vms[vm]["uuid"] == uuid:
break
guest_metrics = self.all_vms[vm]['guest_metrics']
ips = []
with_tools = True
if guest_metrics != "OpaqueRef:NULL":
for vif in self.all_vms[vm]['VIFs']:
if "networks" in self.all_vm_guest_metrics[guest_metrics]:
if self.all_vif[vif]['device'] + "/ip" in self.all_vm_guest_metrics[guest_metrics]['networks']:
if self.all_vm_guest_metrics[guest_metrics]['networks'][self.all_vif[vif]['device'] + "/ip"]:
ips.append(self.all_vm_guest_metrics[guest_metrics]['networks'][self.all_vif[vif]['device'] + "/ip"])
else:
with_tools = False
cpu = 0
cpu_pct = 0
vbd_write_avg = 0
vbd_write_max = 0
vbd_read_avg = 0
vbd_read_max = 0
vif_write_avg = 0
vif_write_max = 0
vif_read_avg = 0
vif_read_max = 0
memory = 0
memory_total = 0
for param in rrd_updates.get_vm_param_list(uuid):
data=[0]
media=0.0
i = 0
row = None
for row in range(rrd_updates.get_nrows()):
value1 = rrd_updates.get_vm_data(uuid,param,row)
if value1 != "NaN":
data.append(value1)
media += value1
i += 1
if i == 0: i=1
if row:
if param.count("cpu") > 0:
cpu = cpu + 1
cpu_pct = cpu_pct + int(rrd_updates.get_vm_data(uuid,param,row)*100)
elif param.count("vbd") > 0 and param.count("write"):
try:
vbd_write_avg += int((media/i)/1024)
vbd_write_max += int(max(data)/1024)
except:
vbd_write_avg += 0
vbd_write_max += 0
elif param.count("vbd") > 0 and param.count("read"):
try:
vbd_read_avg += int((media/i)/1024)
vbd_read_max += int(max(data)/1024)
except:
vbd_read_avg += 0
vbd_read_max += 0
elif param.count("vif") > 0 and param.count("tx"):
try:
vif_write_avg += int((media/i)/1024)
vif_write_max += int(max(data)/1024)
except:
vif_write_avg += 0
vif_write_max += 0
elif param.count("vif") > 0 and param.count("rx"):
try:
vif_read_avg += int((media/i)/1024)
vif_read_max += int(max(data)/1024)
except:
vif_read_avg += 0
vif_read_max += 0
elif param.count("memory_internal_free") > 0:
memory = int(rrd_updates.get_vm_data(uuid,param,row))*1024
memory_total = int(self.all_vms[vm]['memory_dynamic_max'])
else:
#print str(media/i) + "/" + str(max(data))
#print "last: " + str(rrd_updates.get_vm_data(uuid,param,row))
pass
if cpu:
load = str(cpu_pct/cpu)
load_img = str(int((cpu_pct/cpu)/10))
else:
load = "0"
load_img = "0"
if memory:
memory_used = str(((memory_total-memory)*100)/memory_total)
memory_img = str(int(((memory_total-memory)*100)/memory_total)/10)
else:
memory_used = "0"
memory_img = "0"
if row:
parent = self.all_vms[vm]['resident_on']
if parent == "OpaqueRef:NULL":
parent = self.all_vms[vm]['affinity']
if not self.all_vms[vm]['is_control_domain']:
if self.all_vms[vm]['metrics'] not in self.all_vm_metrics:
self.all_vm_metrics[self.all_vms[vm]['metrics']] = self.connection.VM_metrics.get_record(self.session_uuid, self.all_vms[vm]['metrics'])['Value']
start_time = self.all_vm_metrics[self.all_vms[vm]['metrics']]['start_time']
uptime = self.humanize_time(self.get_seconds_difference(start_time))
if parent != "OpaqueRef:NULL":
if int(load_img) > 10:
load_img = "10"
elif int(load_img) < 0:
load_img = "0"
if int(memory_img) > 10:
memory_img = "10"
elif int(memory_img) < 0:
memory_img = "0"
if with_tools:
gobject.idle_add(lambda parent_path, item: list.append(list.get_iter(parent_path), item) and False,
hosts[parent],
([gtk.gdk.pixbuf_new_from_file("images/tree_running_16.png"),
self.all_vms[vm]['name_label'] + "\n" + self.all_vms[vm]['name_description'] + "",
gtk.gdk.pixbuf_new_from_file("images/usagebar_%s.png" % load_img),
load + "% of " + str(cpu) + " cpus",
gtk.gdk.pixbuf_new_from_file("images/usagebar_%s.png" % abs(int(memory_img))),
memory_used + "% of " + self.convert_bytes(memory_total),
str(vbd_write_avg) + "/" + str(vbd_write_max) + " | " + str(vbd_read_avg) + "/" + str(vbd_read_max),
str(vif_write_avg) + "/" + str(vif_write_max) + " | " + str(vif_read_avg) + "/" + str(vif_read_max),
"\n".join(ips),
uptime,
None
]))
else:
gobject.idle_add(lambda parent_path, item: list.append(list.get_iter(parent_path), item) and False,
hosts[parent],
([gtk.gdk.pixbuf_new_from_file("images/tree_running_16.png"),
self.all_vms[vm]['name_label'] + "\n" + self.all_vms[vm]['name_description'] + "",
gtk.gdk.pixbuf_new_from_file("images/usagebar_%s.png" % load_img),
load + "% of " + str(cpu) + " cpus",
gtk.gdk.pixbuf_new_from_file("images/usagebar_0.png"),
"",
"XenServer tools",
"not installed",
"-",
uptime,
None
]))
else:
pass
"""
list.append(None,
([gtk.gdk.pixbuf_new_from_file("images/tree_running_16.png"),
self.all_vms[vm]['name_label'] + "\n" + self.all_vms[vm]['name_description'] + "",
gtk.gdk.pixbuf_new_from_file("images/usagebar_%s.png" % load_img),
load + "% of " + str(cpu) + " cpus",
gtk.gdk.pixbuf_new_from_file("images/usagebar_0.png"),
"",
"XenServer tools",
"not installed",
"-",
uptime,
None
]))
"""
#print self.all_vms[vm]
else:
gobject.idle_add(lambda: list.set(list.get_iter(hosts[parent]), 2, gtk.gdk.pixbuf_new_from_file("images/usagebar_%s.png" % load_img),
3, load + "% of " + str(cpu) + " cpus",
7, str(vif_write_avg) + "/" + str(vif_write_max) + " | " + str(vif_read_avg) + "/" + str(vif_read_max)) and False)
gobject.idle_add(lambda: self.wine.treesearch.expand_all() and False)
def fill_local_storage(self, ref, list):
list.clear()
"""
for pbd in self.all_storage[ref]['PBDs']:
print self.all_pbd[pbd]
print "*************"
"""
if ref in self.all_storage:
for vdi in self.all_storage[ref]['VDIs']:
pct = (int(self.all_vdi[vdi]['physical_utilisation'])/int(self.all_vdi[vdi]['virtual_size']))*100
if self.all_vdi[vdi]['VBDs']:
vbd = self.all_vbd[self.all_vdi[vdi]['VBDs'][0]]
vm = self.all_vms[vbd['VM']]['name_label']
else:
vm = ""
if self.all_vdi[vdi]['is_a_snapshot']:
vm += " (snapshot)"
#FIXME
if self.all_vdi[vdi]['name_label'] != "base copy":
list.append([vdi, self.all_vdi[vdi]['name_label'], self.all_vdi[vdi]['name_description'], \
self.convert_bytes(self.all_vdi[vdi]['virtual_size']) + " (" + str(pct) + "% on disk)", vm])
def fill_vm_storage(self, ref, list):
self.filter_ref = ref
all_vbds = filter(self.filter_vbd_ref, self.all_vbd.values())
list.clear()
if ref not in self.all_vms:
return
for vbd_ref in self.all_vms[ref]['VBDs']:
vbd = self.all_vbd[vbd_ref]
if vbd['VDI'] != "OpaqueRef:NULL" and vbd['type'] != "CD":
if vbd['mode'] == "RW":
ro = "False"
else:
ro = "True"
if vbd['VDI']:
self.filter_vdi = vbd['VDI']
vdi = self.all_vdi[self.filter_vdi_ref()]
vdi_name_label = vdi['name_label']
vdi_name_description = vdi['name_description']
vdi_virtual_size = vdi['virtual_size']
vdi_sr = vdi['SR']
sr_name = self.all_storage[vdi_sr]['name_label']
list.append((vdi_name_label, \
vdi_name_description, \
sr_name, \
vbd['userdevice'], \
self.convert_bytes(vdi_virtual_size), \
ro, \
"0 (Highest) ", \
str(vbd['currently_attached']), \
"/dev/" + vbd['device'], vbd['VDI'], vbd_ref, vbd['bootable']))
def fill_vm_storage_dvd(self, ref, list):
i = 0
active = 0
self.filter_ref = ref
all_vbds = filter(self.filter_vbd_ref, self.all_vbd.values())
vmvdi = ""
for vbd in all_vbds:
if vbd['type'] == "CD":
vmvdi = vbd['VDI']
list.clear()
list.append(["", "empty", True, True])
list.append(["DVD drives", "", False, True])
for sr in self.all_storage:
if self.all_storage[sr]['type'] == "udev" and self.all_storage[sr]['sm_config']["type"] == "cd":
if len(self.all_storage[sr]['VDIs']):
i = i + 1
if self.all_storage[sr]['VDIs'][0] == vmvdi:
active = i
if self.all_storage[sr]['VDIs'][0] in self.all_vdi:
info = self.all_vdi[self.all_storage[sr]['VDIs'][0]]
list.append(["\tDVD Drive " + info['location'][-1:], self.all_storage[sr]['VDIs'][0], True, False])
else:
list.append(["\tDVD Drive", self.all_storage[sr]['VDIs'][0], True, False])
for sr in self.all_storage:
if self.all_storage[sr]['type'] == "iso":
list.append([self.all_storage[sr]['name_label'], sr, False, True])
i = i + 1
isos = {}
for vdi in self.all_storage[sr]['VDIs']:
isos[str(self.all_vdi[vdi]['name_label'])] = vdi
for vdi_ref in sorted(isos):
vdi = isos[vdi_ref]
list.append(["\t" + self.all_vdi[vdi]['name_label'], vdi, True, False])
i = i + 1
if vdi == vmvdi:
active = i
if active == 0:
return active
else:
return active+1
def update_tab_storage(self, ref, builder):
labels = {}
labels['lblstgname'] = self.all_storage[ref]['name_label']
labels['lblstgdescription'] = self.all_storage[ref]['name_description']
labels['lblstgtags'] = ", ".join(self.all_storage[ref]['tags'])
stg_other_config = self.all_storage[ref]['other_config']
if "folder" in stg_other_config:
labels['lblstgfolder'] = stg_other_config['folder']
else:
labels['lblstgfolder'] = ""
labels['lblstgtype'] = self.all_storage[ref]['type'].upper()
labels['lblstgsize'] = "%s used of %s total (%s allocated)" % \
(self.convert_bytes(self.all_storage[ref]['physical_utilisation']),
self.convert_bytes(self.all_storage[ref]['physical_size']),
self.convert_bytes(self.all_storage[ref]['virtual_allocation'])
)
if "devserial" in self.all_storage[ref]['sm_config']:
devserial = self.all_storage[ref]['sm_config']['devserial'].split("-",2)
labels['lblstgserial'] = devserial[0].upper() + " ID:"
if len(devserial) > 1:
labels['lblstgscsi'] = devserial[1]
else:
labels['lblstgscsi'] = devserial[0]
else:
labels['lblstgscsi'] = ""
broken = False
# Fix using PBD and "currently_attached"
if len(self.all_storage[ref]['PBDs']) == 0:
broken = True
labels['lblstgstate'] = "Detached"
labels['lblstghostcon'] = "Connection Missing"
else:
broken = False
for pbd_ref in self.all_storage[ref]['PBDs']:
if not self.all_pbd[pbd_ref]['currently_attached']:
labels['lblstgstate'] = "Broken"
labels['lblstghostcon'] = "Unplugged"
broken = True
if not broken:
if len(self.all_storage[ref]['PBDs']) > 0:
labels['lblstgstate'] = "OK"
labels['lblstghostcon'] = "Connected"
"""
elif len(self.all_storage[ref]['PBDs']) > 0:
labels['lblstgstate'] = "Dettached"
labels['lblstghostcon'] = "Connection Missing"
"""
labels['lblstghost'] = self.wine.selected_host
if len(self.all_storage[ref]['PBDs']) == 0:
labels['lblstgmultipath'] = "No"
else:
pbd = self.all_pbd[self.all_storage[ref]['PBDs'][0]]
if "multipathed" in pbd['other_config'] and pbd['other_config']["multipathed"] == "true":
if "SCSIid" in pbd['device_config']:
#{'uuid': '232b7d15-d8cb-e183-3838-dfd33f6bd597', 'SR': 'OpaqueRef:1832f6e1-73fa-b43d-fcd2-bac969abf867', 'other_config': {'mpath-3600a0b8000294d50000045784b85e36f': '[1, 1, -1, -1]', 'multipathed': 'true'}, 'host': 'OpaqueRef:5c0a69d1-7719-946b-7f3c-683a7058338d', 'currently_attached': True, 'device_config': {'SCSIid': '3600a0b8000294d50000045784b85e36f'}}
scsiid = pbd['device_config']["SCSIid"]
paths = eval(pbd["other_config"]["mpath-" + scsiid])
if paths[0] == paths[1]:
labels['lblstgmultipath'] = "%s of %s paths active" % (paths[0], paths[1])
else:
labels['lblstgmultipath'] = "%s of %s paths active" % (paths[0], paths[1])
else:
labels['lblstgmultipath'] = "Yes"
else:
labels['lblstgmultipath'] = "No"
for label in labels.keys():
builder.get_object(label).set_label(labels[label])
def is_storage_broken(self, ref):
for pbd_ref in self.all_storage[ref]['PBDs']:
if not self.all_pbd[pbd_ref]['currently_attached']:
return True
return False
def update_tab_template(self, ref, builder):
labels = {}
labels['lbltplname'] = self.all_vms[ref]['name_label']
labels['lbltpldescription'] = self.all_vms[ref]['name_description']
if not self.all_vms[ref]['HVM_boot_policy']:
labels['lbltplboot'] = "Boot order:"
labels["lbltplparameters"] = self.all_vms[ref]['PV_args']
else:
labels['lbltplboot'] = "OS boot parameters:"
labels['lbltplparameters'] = ""
for param in list(self.all_vms[ref]['HVM_boot_params']['order']):
if param == 'c':
labels['lbltplparameters'] += "Hard Disk\n"
elif param == 'd':
labels['lbltplparameters'] += "DVD-Drive\n"
elif param == 'n':
labels['lbltplparameters'] += "Network\n"
other_config = self.all_vms[ref]['other_config']
if "folder" in other_config:
labels['lbltplfolder'] = other_config['folder']
else:
labels['lbltplfolder'] = ""
labels["lbltplmemory"] = self.convert_bytes(self.all_vms[ref]['memory_dynamic_max'])
if self.all_vms[ref]['tags']:
labels["lbltpltags"] = ", ".join(self.all_vms[ref]['tags'])
else:
labels["lbltpltags"] = ""
labels["lbltplcpu"] = self.all_vms[ref]['VCPUs_at_startup']
if "auto_poweron" in other_config and other_config["auto_poweron"] == "true":
labels["lbltplautoboot"] = "Yes"
else:
labels["lbltplautoboot"] = "No"
priority = self.all_vms[ref]["VCPUs_params"]
if "weight" in priority:
#labels["lbltplpriority"] = priority['weight']
weight = priority['weight']
if weight == 1:
labels["lbltplpriority"] = "Lowest"
elif weight <= 4:
labels["lbltplpriority"] = "Very Low"
elif weight <= 32:
labels["lbltplpriority"] = "Low"
elif weight <= 129:
labels["lbltplpriority"] = "Below Normal"
elif weight <= 512:
labels["lbltplpriority"] = "Normal"
elif weight <= 2048:
labels["lbltplpriority"] = "Above Normal"
elif weight <= 4096:
labels["lbltplpriority"] = "High"
elif weight <= 16384:
labels["lbltplpriority"] = "Very High"
else:
labels["lbltplpriority"] = "Highest"
else:
labels["lbltplpriority"] = "Normal"
#FIXME
#labels["lblvmstartup"] = str(self.connection.VM_metrics.get_start_time(self.session_uuid,metric)['Value'])
metric = self.all_vms[ref]['metrics']
if metric not in self.all_vm_metrics:
res = self.connection.VM_metrics.get_record(self.session_uuid, ref)
if "Value" in res:
self.all_vm_metrics[ref] = res["Value"]
for label in labels.keys():
builder.get_object(label).set_label(labels[label])
pass
def update_tab_host_general(self, ref, builder):
labels = {}
software_version = self.all_hosts[ref]['software_version']
license_params = self.all_hosts[ref]['license_params']
labels['lblhostname'] = self.all_hosts[ref]['name_label']
labels['lblhostdescription'] = self.all_hosts[ref]['name_description']
labels['lblhosttags'] = ", ".join(self.all_hosts[ref]['tags'])
host_other_config = self.all_hosts[ref]['other_config']
if "folder" in host_other_config:
labels['lblhostfolder'] = host_other_config['folder']
else:
labels['lblhostfolder'] = ""
# FIXME
if "iscsi_iqn" in host_other_config:
labels['lblhostiscsi'] = host_other_config['iscsi_iqn']
else:
labels['lblhostiscsi'] = ""
#FIXME
labels['lblhostpool'] = ""
#str(self.connection.session.get_pool(
# self.session_uuid, self.session['Value'])['Value'])
logging = self.all_hosts[ref]['logging']
if "syslog_destination" in logging:
labels['lblhostlog'] = logging['syslog_destination']
else:
labels['lblhostlog'] = "Local"
boot_time = self.humanize_time(time.time() - int(host_other_config['boot_time'][:-1]))
tool_boot_time = self.humanize_time(time.time() - int(host_other_config['agent_start_time'][:-1]))
labels['lblhostuptime'] = boot_time
labels['lblhosttooluptime'] = tool_boot_time
labels['lblhostdns'] = self.all_hosts[ref]['hostname']
labels['lblhostprimary'] = self.all_hosts[ref]['address']
resident_vms = self.all_hosts[ref]['resident_VMs']
host_vms_memory = ""
for resident_vm_uuid in resident_vms:
if self.all_vms[resident_vm_uuid]['is_control_domain']:
host_memory = self.all_vms[resident_vm_uuid]['memory_target']
else:
host_vms_memory += self.all_vms[resident_vm_uuid]['name_label'] \
+ ": using " + \
self.convert_bytes(self.all_vms[resident_vm_uuid]['memory_dynamic_max']) + "\n"
host_metrics_uuid = self.all_hosts[ref]['metrics']
host_metrics = self.all_host_metrics[host_metrics_uuid]
labels['lblhostmemserver'] = "%s free of %s available (%s total)" % \
(self.convert_bytes(host_metrics['memory_free']), \
self.convert_bytes(int(host_metrics['memory_total']) - int(host_memory)), \
self.convert_bytes(host_metrics['memory_total']))
labels['lblhostmemoryvms'] = host_vms_memory
labels['lblhostmemory'] = self.convert_bytes(host_memory)
labels['lblhostversiondate'] = software_version['date']
labels['lblhostversionbuildnumber'] = software_version['build_number']
labels['lblhostversionbuildversion'] = software_version['product_version']
expiry = self.humanize_time(self.get_seconds_difference_reverse(license_params['expiry']))
labels['lblhostlicexpire'] = expiry
labels['lblhostlicserver'] = license_params['sku_marketing_name']
labels['lblhostliccode'] = license_params['productcode']
labels['lblhostlicserial'] = license_params['serialnumber']
host_cpus = self.all_hosts[ref]['host_CPUs']
cpus = ""
for host_cpu_uuid in host_cpus:
cpus += "Vendor: %s\nModel: %s\nSpeed: %s\n" % \
(self.all_host_cpu[host_cpu_uuid]['vendor'],
self.all_host_cpu[host_cpu_uuid]['modelname'],
self.all_host_cpu[host_cpu_uuid]['speed'])
labels['lblhostcpus'] = cpus
host_patchs = self.all_hosts[ref]['patches']
patchs = ""
for host_cpu_patch in host_patchs:
pool_patch = self.all_host_patch[host_cpu_patch]['pool_patch']
patchs += self.all_pool_patch[pool_patch]['name_label'] + "\n"
labels['lblhostpatchs'] = patchs
# TODO: list hotfix applied
for label in labels.keys():
builder.get_object(label).set_label(labels[label])
def update_tab_pool_general(self, ref, builder):
labels = {}
if ref not in self.all_pools:
return
labels["lblpoolname"] = self.all_pools[ref]['name_label']
labels["lblpooldescription"] = self.all_pools[ref]['name_description']
other_config = self.all_pools[ref]['other_config']
if self.all_pools[ref]['tags']:
labels["lblpooltags"] = ", ".join(self.all_pools[ref]['tags'])
else:
labels["lblpooltags"] = ""
if "folder" in other_config:
labels["lblpoolfolder"] = other_config['folder']
else:
labels["lblpoolfolder"] = ""
fullpatchs = ""
partialpatchs = ""
for patch in self.all_pool_patch:
hosts = {}
for host_patch in self.all_pool_patch[patch]["host_patches"]:
host = self.all_host_patch[host_patch]["host"]
if host not in hosts:
hosts[host] = []
hosts[host] += self.all_pool_patch[patch]["host_patches"]
if hosts.keys() == self.all_hosts.keys():
fullpatchs += self.all_pool_patch[patch]["name_label"] + "\n"
else:
partialpatchs += self.all_pool_patch[patch]["name_label"] + "\n"
labels["lblpoolfullpatchs"] = fullpatchs
labels["lblpoolpartialpatchs"] = partialpatchs
for label in labels.keys():
builder.get_object(label).set_label(labels[label])
if partialpatchs == "":
builder.get_object("label365").hide()
builder.get_object("lblpoolpartialpatchs").hide()
if fullpatchs == "":
builder.get_object("label363").hide()
builder.get_object("lblpoolfullpatchs").hide()
def update_tab_vm_general(self, ref, builder):
self.builder = builder
labels = {}
if ref in self.all_vms:
metric = self.all_vms[ref]['metrics']
metric_guest = self.all_vms[ref]['guest_metrics']
labels["lblvmname"] = self.all_vms[ref]['name_label']
labels["lblvmdescription"] = self.all_vms[ref]['name_description']
labels["lblvmuuid"] = self.all_vms[ref]['uuid']
labels["lblvmmemory"] = self.convert_bytes(self.all_vms[ref]['memory_dynamic_max'])
if self.all_vms[ref]['tags']:
labels["lblvmtags"] = ", ".join(self.all_vms[ref]['tags'])
else:
labels["lblvmtags"] = ""
labels["lblvmcpu"] = self.all_vms[ref]['VCPUs_at_startup']
other_config = self.all_vms[ref]['other_config']
if "auto_poweron" in other_config and other_config["auto_poweron"] == "true":
labels["lblvmautoboot"] = "Yes"
else:
labels["lblvmautoboot"] = "No"
if not self.all_vms[ref]['HVM_boot_policy']:
labels['lblvmboot'] = "Boot order:"
labels["lblvmparameters"] = self.all_vms[ref]['PV_args']
else:
labels['lblvmboot'] = "OS boot parameters:"
labels['lblvmparameters'] = ""
for param in list(self.all_vms[ref]['HVM_boot_params']['order']):
if param == 'c':
labels['lblvmparameters'] += "Hard Disk\n"
elif param == 'd':
labels['lblvmparameters'] += "DVD-Drive\n"
elif param == 'n':
labels['lblvmparameters'] += "Network\n"
priority = self.all_vms[ref]["VCPUs_params"]
if "weight" in priority:
weight = int(priority['weight'])
if weight == 1:
labels["lblvmpriority"] = "Lowest"
elif weight <= 4:
labels["lblvmpriority"] = "Very Low"
elif weight <= 32:
labels["lblvmpriority"] = "Low"
elif weight <= 129:
labels["lblvmpriority"] = "Below Normal"
elif weight <= 512:
labels["lblvmpriority"] = "Normal"
elif weight <= 2048:
labels["lblvmpriority"] = "Above Normal"
elif weight <= 4096:
labels["lblvmpriority"] = "High"
elif weight <= 16384:
labels["lblvmpriority"] = "Very High"
else:
labels["lblvmpriority"] = "Highest"
else:
labels["lblvmpriority"] = "Normal"
#FIXME
#labels["lblvmstartup"] = str(self.connection.VM_metrics.get_start_time(self.session_uuid,metric)['Value'])
metric = self.all_vms[ref]['metrics']
if metric not in self.all_vm_metrics:
res = self.connection.VM_metrics.get_record(self.session_uuid, ref)
if "Value" in res:
self.all_vm_metrics[ref] = res["Value"]
if metric in self.all_vm_metrics:
if self.all_vm_metrics[metric]['start_time'] != "19700101T00:00:00Z":
startup = self.humanize_time(self.get_seconds_difference(self.all_vm_metrics[metric]['start_time']))
labels["lblvmstartup"] = startup
else:
labels["lblvmstartup"] = "never started up"
else:
labels["lblvmstartup"] = ""
labels['lblvmdistro'] = ""
if metric_guest != "OpaqueRef:NULL" and metric_guest in self.all_vm_guest_metrics:
guest_metrics = self.all_vm_guest_metrics[metric_guest]
if "PV_drivers_up_to_date" in guest_metrics and guest_metrics['PV_drivers_up_to_date']:
state = "Optimized"
else:
state = "Not optimized"
if "PV_drivers_up_to_date" in guest_metrics and "major" in guest_metrics["PV_drivers_version"]:
if "build" in guest_metrics['PV_drivers_version']:
state = state + " (version " + guest_metrics['PV_drivers_version']['major'] + "."\
+ guest_metrics['PV_drivers_version']['minor'] + " build "\
+ guest_metrics['PV_drivers_version']['build'] + ")"
else:
state = state + " (version " + guest_metrics['PV_drivers_version']['major'] + "."\
+ guest_metrics['PV_drivers_version']['minor'] + " build )"
else:
state = "Tools not installed"
labels["lblvmvirtstate"] = state
if "name" in guest_metrics["os_version"]:
labels["lblvmdistro"] = guest_metrics["os_version"]["name"]
else:
state = "Tools not installed"
labels["lblvmvirtstate"] = state
if "folder" in other_config:
labels["lblvmfolder"] = other_config['folder']
else:
labels["lblvmfolder"] = ""
for label in labels.keys():
builder.get_object(label).set_label(labels[label])
def export_vm(self, ref, destination, ref2=None, as_vm = False):
if ref2:
task_uuid = self.connection.task.create(self.session_uuid, "Exporting snapshot", "Exporting snapshot " + destination)
else:
task_uuid = self.connection.task.create(self.session_uuid, "Exporting VM", "Exporting VM " + destination)
self.track_tasks[task_uuid['Value']] = ref2 if ref2 else ref
url = "http://%s/export?ref=%s&session_id=%s&task_id=%s" % (self.wine.selected_host,
ref, self.session_uuid, task_uuid['Value'])
Thread(target=self.download_export, args=(url,destination, ref, as_vm)).start()
def download_export(self, url, destination, ref, as_vm):
#print "Saving %s to %s" % (url, destination)
if as_vm:
self.connection.VM.set_is_a_template(self.session_uuid, ref, False)
urllib.urlretrieve(url, destination)
if as_vm:
self.connection.VM.set_is_a_template(self.session_uuid, ref, True)
def get_actions(self, ref):
return self.all_vms[ref]['allowed_operations']
def get_connect_string(self, ref):
#FIXME
"""
vm_uuid = self.connection.VM.get_by_uuid(self.session_uuid,uuid)
consoles = self.connection.VM.get_consoles(self.session_uuid, vm_uuid['Value'])
console = self.connection.console.get_record(self.session_uuid,consoles['Value'][0])
"""
return "CONNECT /console?ref=%s&session_id=%s HTTP/1.1\r\n\r\n" % (ref,self.session_uuid)
def get_connect_parameters(self, ref, host):
"""
vm_uuid = self.connection.VM.get_by_uuid(self.session_uuid,uuid)
consoles = self.connection.VM.get_consoles(self.session_uuid, vm_uuid['Value'])
console = self.connection.console.get_record(self.session_uuid,consoles['Value'][0])
"""
return "%s %s %s" % (host, ref, self.session_uuid)
# TODO: these should *not* be here
# {
def dump(self, obj):
for attr in dir(obj):
print "obj.%s = %s" % (attr, getattr(obj, attr))
def humanize_time(self, secs):
string = ""
mins, secs = divmod(secs, 60)
hours, mins = divmod(mins, 60)
days, hours = divmod(hours, 24)
if days:
string += "%02d days " % (days)
if hours:
string += "%02d hours " % (hours)
if mins:
string += "%02d minutes " % (mins)
if secs:
string += "%02d seconds " % (secs)
return string
def convert_bytes(self, n):
"""
http://www.5dollarwhitebox.org/drupal/node/84
"""
n = float(n)
K, M, G, T = 1 << 10, 1 << 20, 1 << 30, 1 << 40
if n >= T:
return '%.2fT' % (float(n) / T)
elif n >= G:
return '%.2fG' % (float(n) / G)
elif n >= M:
return '%.2fM' % (float(n) / M)
elif n >= K:
return '%.2fK' % (float(n) / K)
else:
return '%d' % n
# }
def thread_host_search(self, ref, list):
Thread(target=self.fill_host_search, args=(ref, list)).start()
return True
def search_ref(self, model, path, iter_ref, user_data):
if self.treestore.get_value(iter_ref, 6) == user_data:
self.found_iter = iter_ref
def event_next(self):
print "Entering event loop"
while not self.halt:
try:
eventn = self.connection_events.event.next(self.session_events_uuid)
if "Value" in eventn:
for event in eventn["Value"]:
if event['class'] == "vm":
if event['operation'] == "add":
self.all_vms[event["ref"]] = event['snapshot']
if not self.all_vms[event["ref"]]["is_a_snapshot"]:
gobject.idle_add(lambda: self.add_vm_to_tree(event["ref"]) and False)
else:
gobject.idle_add(lambda: self.fill_vm_snapshots(self.wine.selected_ref, \
self.wine.builder.get_object("treevmsnapshots"), \
self.wine.builder.get_object("listvmsnapshots")) and False)
gobject.idle_add(lambda: self.wine.modelfilter.clear_cache() and False)
gobject.idle_add(lambda: self.wine.modelfilter.refilter() and False)
for track in self.track_tasks:
if self.track_tasks[track] == "Import.VM":
self.track_tasks[track] = event["ref"]
if self.track_tasks[track] == "Backup.Server":
self.track_tasks[track] = event["ref"]
if self.track_tasks[track] == "Restore.Server":
self.track_tasks[track] = event["ref"]
if self.track_tasks[track] == "Backup.Pool":
self.track_tasks[track] = event["ref"]
if self.track_tasks[track] == "Restore.Pool":
self.track_tasks[track] = event["ref"]
if self.track_tasks[track] == "Upload.Patch":
self.track_tasks[track] = event["ref"]
self.wine.builder.get_object("wprogressimportvm").hide()
# Perfect -> set now import_ref to event["ref"]
self.import_ref = event["ref"]
elif event['operation'] == "del":
if not self.all_vms[event["ref"]]["is_a_snapshot"]:
self.found_iter = None
self.treestore.foreach(self.search_ref, event["ref"])
if self.found_iter:
gobject.idle_add(lambda: self.treestore.remove(self.found_iter) and False)
del self.all_vms[event["ref"]]
else:
gobject.idle_add(lambda: self.fill_vm_snapshots(self.wine.selected_ref, \
self.wine.builder.get_object("treevmsnapshots"), \
self.wine.builder.get_object("listvmsnapshots")) and False)
del self.all_vms[event["ref"]]
else:
self.filter_uuid = event['snapshot']['uuid']
if self.vm_filter_uuid():
#make into a template
if event['snapshot']['is_a_template'] != self.all_vms[self.vm_filter_uuid()]['is_a_template']:
self.all_vms[self.vm_filter_uuid()] = event['snapshot']
self.found_iter = None
self.treestore.foreach(self.search_ref, event["ref"])
if self.found_iter and event['snapshot']['is_a_template']:
gobject.idle_add(lambda: self.treestore.set(self.found_iter, 0, gtk.gdk.pixbuf_new_from_file("images/user_template_16.png"), 3, "custom_template") and False)
gobject.idle_add(lambda: self.wine.update_tabs() and False)
else:
if event['snapshot']['resident_on'] != self.all_vms[self.vm_filter_uuid()]['resident_on']:
self.found_iter = None
gobject.idle_add(lambda: self.treestore.foreach(self.search_ref, event["ref"]) and False)
if self.found_iter:
gobject.idle_add(lambda: self.treestore.remove(self.found_iter) and False)
self.all_vms[self.vm_filter_uuid()] = event['snapshot']
gobject.idle_add(lambda: self.add_vm_to_tree(event["ref"] and False))
if event['snapshot']['affinity'] != self.all_vms[self.vm_filter_uuid()]['affinity']:
print "migrate or start on or resume on2"
self.all_vms[self.vm_filter_uuid()] = event['snapshot']
else:
if event["ref"] in self.track_tasks:
self.all_vms[self.track_tasks[event["ref"]]] = event['snapshot']
else:
self.all_vms[event["ref"]] = event['snapshot']
self.all_vms[event["ref"]] = event['snapshot']
self.treestore.foreach(self.update_vm_status, "")
gobject.idle_add(lambda: self.wine.update_memory_tab() and False)
elif event['class'] == "vm_guest_metrics":
self.all_vm_guest_metrics[event['ref']] = self.connection.VM_guest_metrics.get_record(self.session_uuid, event['ref'])
elif event['class'] == "task":
#print ">>>" + event["snapshot"]["name_label"] + " " + event["snapshot"]["status"] + " " + str(event["snapshot"]["progress"]) + ":\t", event
self.all_tasks[event["ref"]] = event["snapshot"]
if event["ref"] not in self.track_tasks:
#print event
#print event["snapshot"]["name_label"] + " " + event["snapshot"]["status"] + " " + str(event["snapshot"]["progress"]) + ":\t", event
pass
if event["snapshot"]["status"] == "success":
if event["ref"] in self.vboxchildprogressbar:
self.vboxchildprogress[event["ref"]].hide()
self.vboxchildprogressbar[event["ref"]].hide()
self.vboxchildcancel[event["ref"]].hide()
if event["snapshot"]["error_info"]:
if event["ref"] in self.track_tasks:
if self.track_tasks[event["ref"]] in self.all_vms:
gobject.idle_add(lambda: self.wine.push_error_alert("%s %s %s" % (event["snapshot"]["name_label"], self.all_vms[self.track_tasks[event["ref"]]]["name_label"], event["snapshot"]["error_info"])) and False)
eref = event["ref"]
if eref in self.vboxchildcancel:
self.vboxchildcancel[eref].hide()
self.vboxchildprogressbar[eref].hide()
self.vboxchildprogress[eref].set_label(str(event["snapshot"]["error_info"]))
self.vboxchildprogress[eref].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#FF0000'))
else:
self.wine.builder.get_object("wprogressimportvm").hide()
self.wine.builder.get_object("tabboximport").set_current_page(2)
gobject.idle_add(lambda: self.wine.push_error_alert("%s: %s" % (event["snapshot"]["name_description"], event["snapshot"]["error_info"])) and False)
else:
if event["ref"] in self.track_tasks:
if self.track_tasks[event["ref"]] in self.all_vms:
if event["snapshot"]["status"] == "success":
gobject.idle_add(lambda: self.wine.push_alert("%s %s completed" % (event["snapshot"]["name_label"], self.all_vms[self.track_tasks[event["ref"]]]["name_label"])) and False)
else:
gobject.idle_add(lambda: self.wine.push_alert("%s %s %s" % (event["snapshot"]["name_label"], self.all_vms[self.track_tasks[event["ref"]]]["name_label"], (" %.2f%%" % (float(event["snapshot"]["progress"])*100)))) and False)
else:
vm = self.connection.VM.get_record(self.session_uuid, self.track_tasks[event["ref"]])
if "Value" in vm:
self.all_vms[self.track_tasks[event["ref"]]] = vm['Value']
#self.add_vm_to_tree(self.track_tasks[event["ref"]])
gobject.idle_add(lambda: self.wine.modelfilter.clear_cache() and False)
gobject.idle_add(lambda: self.wine.modelfilter.refilter() and False)
gobject.idle_add(lambda: self.wine.push_alert("%s %s %s" % (event["snapshot"]["name_label"], self.all_vms[self.track_tasks[event["ref"]]]["name_label"], (" %.2f%%" % (float(event["snapshot"]["progress"])*100)))) and False)
else:
gobject.idle_add(lambda: self.wine.push_alert("%s: %s %s" % (event["snapshot"]["name_label"], event["snapshot"]["name_description"], (" %.2f%%" % (float(event["snapshot"]["progress"])*100)))) and False)
else:
pass #FIXME?
#self.wine.push_alert(event["snapshot"]["name_label"] + (" %.2f%%" % (float(event["snapshot"]["progress"])*100)))
if event["snapshot"]["status"] == "success":
if event["snapshot"]["name_label"] == "Async.VIF.create":
dom = xml.dom.minidom.parseString(event['snapshot']['result'])
nodes = dom.getElementsByTagName("value")
vif_ref = nodes[0].childNodes[0].data
self.connection.VIF.plug(self.session_uuid, vif_ref)
if self.wine.selected_tab == "VM_Network":
gobject.idle_add(lambda: self.fill_vm_network(self.wine.selected_ref,
self.wine.builder.get_object("treevmnetwork"),
self.wine.builder.get_object("listvmnetwork")) and False)
if event["snapshot"]["name_label"] == "Async.VM.revert":
self.start_vm(self.track_tasks[event["ref"]])
if event["snapshot"]["name_label"] in ("Async.VM.clone", "Async.VM.copy"):
dom = xml.dom.minidom.parseString(event['snapshot']['result'])
nodes = dom.getElementsByTagName("value")
vm_ref = nodes[0].childNodes[0].data
#self.add_vm_to_tree(vm_ref)
if event["ref"] in self.set_descriptions:
self.connection.VM.set_name_description(self.session_uuid, vm_ref, self.set_descriptions[event["ref"]])
if event["snapshot"]["name_label"] in ("Async.VM.provision", "Async.VM.clone", "Async.VM.copy"):
self.filter_uuid = event['snapshot']['uuid']
# TODO
# Detect VM with event["ref"]
if event["ref"] in self.track_tasks and self.track_tasks[event["ref"]] in self.all_vms:
for vbd in self.all_vms[self.track_tasks[event["ref"]]]['VBDs']:
self.all_storage[vbd] = self.connection.VBD.get_record(self.session_uuid, vbd)['Value']
for vif in self.all_vms[self.track_tasks[event["ref"]]]['VIFs']:
self.all_vif[vif] = self.connection.VIF.get_record(self.session_uuid, vif)['Value']
if self.vm_filter_uuid() != None:
self.all_vms[self.vm_filter_uuid()]['allowed_operations'] = \
self.connection.VM.get_allowed_operations(self.session_uuid, self.vm_filter_uuid())['Value']
else:
if event["ref"] in self.track_tasks:
self.all_vms[self.track_tasks[event["ref"]]]['allowed_operations'] = \
self.connection.VM.get_allowed_operations(self.session_uuid, self.track_tasks[event["ref"]])['Value']
if self.all_vms[self.track_tasks[event["ref"]]]['allowed_operations'].count("start"):
if self.track_tasks[event["ref"]] in self.autostart:
host_start = self.autostart[self.track_tasks[event["ref"]]]
res = self.connection.Async.VM.start_on(self.session_uuid, self.track_tasks[event["ref"]], host_start, False, False)
if "Value" in res:
self.track_tasks[res['Value']] = self.track_tasks[event["ref"]]
else:
print res
if event["snapshot"]["name_label"] == "Async.VM.snapshot":
self.filter_uuid = event['snapshot']['uuid']
if self.track_tasks[event["ref"]] in self.all_vms:
vm_uuid = self.track_tasks[event["ref"]]
dom = xml.dom.minidom.parseString(event['snapshot']['result'])
nodes = dom.getElementsByTagName("value")
snapshot_ref = nodes[0].childNodes[0].data
#self.all_vms[vm_uuid]['snapshots'].append(snapshot_ref)
self.all_vms[snapshot_ref] = self.connection.VM.get_record(self.session_uuid, snapshot_ref)['Value']
for vbd in self.all_vms[snapshot_ref]['VBDs']:
#FIXME
self.all_vbd[vbd] = self.connection.VBD.get_record(self.session_uuid, vbd)['Value']
if self.track_tasks[event["ref"]] == self.wine.selected_ref and \
self.wine.selected_tab == "VM_Snapshots":
gobject.idle_add(lambda: self.fill_vm_snapshots(self.wine.selected_ref, \
self.wine.builder.get_object("treevmsnapshots"), \
self.wine.builder.get_object("listvmsnapshots")) and False)
if event["snapshot"]["name_label"] == "VM.Async.snapshot":
if self.track_tasks[event["ref"]] == self.wine.selected_ref and \
self.wine.selected_tab == "VM_Snapshots":
gobject.idle_add(lambda: self.fill_vm_snapshots(self.wine.selected_ref, \
self.wine.builder.get_object("treevmsnapshots"), \
self.wine.builder.get_object("listvmsnapshots")) and False)
if event["snapshot"]["name_label"] == "Importing VM":
if self.import_start:
self.start_vm(self.track_tasks[event["ref"]])
if self.import_make_into_template:
self.make_into_template(self.track_tasks[event["ref"]])
if event["snapshot"]["name_label"] == "VM.destroy":
if self.wine.selected_tab == "VM_Snapshots":
gobject.idle_add(lambda: self.fill_vm_snapshots(self.wine.selected_ref, \
self.wine.builder.get_object("treevmsnapshots"), \
self.wine.builder.get_object("listvmsnapshots")) and False)
if event["snapshot"]["name_label"] == "VIF.destroy":
if self.wine.selected_tab == "VM_Network":
gobject.idle_add(lambda: self.fill_vm_network(self.wine.selected_ref, \
self.wine.builder.get_object("treevmnetwork"), \
self.wine.builder.get_object("listvmnetwork")) and False)
if event["snapshot"]["name_label"] == "VIF.plug":
if self.wine.selected_tab == "VM_Network":
gobject.idle_add(lambda: self.fill_vm_network(self.wine.selected_ref, \
self.wine.builder.get_object("treevmnetwork"), \
self.wine.builder.get_object("listvmnetwork")) and False)
if event["snapshot"]["name_label"] in ("VBD.create", "VBD.destroy"):
if self.wine.selected_tab == "VM_Storage":
#print "fill_vm_storage start"
gobject.idle_add(lambda: self.fill_vm_storage(self.wine.selected_ref, \
self.wine.builder.get_object("listvmstorage")) and False)
#print pdb.set_trace()
#print "fill_vm_storage end"
if event["snapshot"]["name_label"] in ("VDI.create", "VDI.destroy"):
if self.wine.selected_tab == "Local_Storage":
gobject.idle_add(lambda: self.fill_local_storage(self.wine.selected_ref, \
self.wine.builder.get_object("liststg")) and False)
if event["snapshot"]["name_label"] in ("network.create", "network.destroy"):
if self.wine.selected_tab == "HOST_Network":
gobject.idle_add(lambda: self.wine.update_tab_host_network() and False)
if event["snapshot"]["name_label"] in ("Async.Bond.create", "Bond.create",
"Async.Bond.destroy", "Bond.destroy"):
if self.wine.selected_tab == "HOST_Nics":
gobject.idle_add(lambda: self.wine.update_tab_host_nics() and False)
if event["ref"] in self.track_tasks:
self.tasks[event["ref"]] = event
if event["ref"] in self.vboxchildprogressbar:
self.vboxchildprogressbar[event["ref"]].set_fraction(float(event["snapshot"]["progress"]))
else:
if event["ref"] in self.track_tasks:
self.tasks[event["ref"]] = event
if self.track_tasks[event["ref"]] == self.wine.selected_ref and \
self.wine.selected_tab == "VM_Logs":
if event["ref"] in self.track_tasks and event["ref"] not in self.vboxchildprogressbar:
gobject.idle_add(lambda: self.fill_vm_log(self.wine.selected_uuid, thread=True) and False)
else:
if event["snapshot"]["name_label"] == "Exporting VM" and event["ref"] not in self.vboxchildprogressbar:
self.track_tasks[event["ref"]] = self.wine.selected_ref
self.tasks[event["ref"]] = event
gobject.idle_add(lambda: self.fill_vm_log(self.wine.selected_uuid, thread=True) and False)
else:
#print event
pass
elif event["class"] == "vdi":
self.all_vdi[event["ref"]] = event["snapshot"]
if self.wine.selected_tab == "Local_Storage":
liststg = self.wine.builder.get_object("liststg")
gobject.idle_add(lambda: self.fill_local_storage(self.wine.selected_ref,liststg) and False)
if self.wine.selected_tab == "VM_Storage":
gobject.idle_add(lambda: self.fill_vm_storage(self.wine.selected_ref, \
self.wine.builder.get_object("listvmstorage")) and False)
elif event["class"] == "vbd":
self.all_vbd[event["ref"]] = event["snapshot"]
"""
if event["snapshot"]["allowed_operations"].count("attach") == 1:
self.last_vbd = event["ref"]
"""
elif event["class"] == "pif":
self.all_pif[event["ref"]] = event["snapshot"]
if self.wine.selected_tab == "HOST_Nics":
gobject.idle_add(lambda: self.wine.update_tab_host_nics() and False)
elif event["class"] == "bond":
if event["operation"] == "del":
del self.all_bond[event["ref"]]
else:
self.all_bond[event["ref"]] = event["snapshot"]
if self.wine.selected_tab == "HOST_Nics":
gobject.idle_add(lambda: self.wine.update_tab_host_nics() and False)
elif event["class"] == "vif":
if event["operation"] == "del":
del self.all_vif[event["ref"]]
else:
if event["operation"] == "add":
self.connection.VIF.plug(self.session_uuid, event["ref"])
self.all_vif[event["ref"]] = event["snapshot"]
elif event["class"] == "sr":
self.filter_uuid = event['snapshot']['uuid']
self.all_storage[event["ref"]] = event["snapshot"]
self.treestore.foreach(self.update_storage_status, "")
if event["operation"] == "del":
self.filter_uuid = event['snapshot']['uuid']
gobject.idle_add(lambda: self.treestore.foreach(self.delete_storage, "") and False)
if event["operation"] == "add":
sr = event["ref"]
# FIXME
host = self.all_hosts.keys()[0]
if self.poolroot:
#iter_ref = self.treestore.append(self.poolroot, [\
gobject.idle_add(lambda: self.treestore.append(self.poolroot, [\
gtk.gdk.pixbuf_new_from_file("images/storage_shaped_16.png"),\
self.all_storage[sr]['name_label'], self.all_storage[sr]['uuid'],\
"storage", None, self.host, sr, self.all_storage[sr]['allowed_operations'], None]) and False)
else:
#iter_ref = self.treestore.append(self.hostroot[host], [\
gobject.idle_add(lambda: self.treestore.append(self.hostroot[host], [\
gtk.gdk.pixbuf_new_from_file("images/storage_shaped_16.png"),\
self.all_storage[sr]['name_label'], self.all_storage[sr]['uuid'],\
"storage", None, self.host, sr, self.all_storage[sr]['allowed_operations'], None]) and False)
elif event["class"] == "pool":
if self.all_pools[event["ref"]]['name_label'] != event["snapshot"]["name_label"]:
if self.poolroot:
gobject.idle_add(lambda: self.wine.treestore.remove(self.poolroot) and False)
else:
for host_ref in self.hostroot.keys():
gobject.idle_add(lambda: self.wine.treestore.remove(self.hostroot[host_ref]) and False)
self.sync()
if self.all_pools[event["ref"]]['default_SR'] != event["snapshot"]["default_SR"]:
self.treestore.foreach(self.update_default_sr, \
[self.all_pools[event["ref"]]['default_SR'], event["snapshot"]["default_SR"]])
self.all_pools[event["ref"]] = event["snapshot"]
if self.wine.selected_type == "pool":
self.update_tab_pool_general(self.wine.selected_ref, self.wine.builder)
elif event["class"] == "message":
if event["operation"] == "del":
del self.all_messages[event["ref"]]
elif event["operation"] == "add":
self.all_messages[event["ref"]] = event["snapshot"]
self.add_alert(event["snapshot"], event["ref"],
self.wine.listalerts)
self.wine.update_n_alerts()
else:
print event
elif event["class"] == "vm_guest_metrics":
self.all_vm_guest_metrics[event["ref"]] = event["snapshot"]
elif event["class"] == "network":
if event["operation"] == "del":
del self.all_network[event["ref"]]
else:
self.all_network[event["ref"]] = event["snapshot"]
if self.wine.selected_tab == "HOST_Network":
gobject.idle_add(lambda: self.wine.update_tab_host_network() and False)
elif event["class"] == "vlan":
if event["operation"] == "del":
if event["ref"] in self.all_vlan:
del self.all_vlan[event["ref"]]
self.all_vlan[event["ref"]] = event["snapshot"]
elif event["class"] == "host":
if event["operation"] == "del":
self.filter_uuid = event['snapshot']['uuid']
self.treestore.foreach(self.delete_host, "")
del self.all_hosts[event["ref"]]
elif event["operation"] == "add":
self.all_hosts[event["ref"]] = event["snapshot"]
self.wine.show_error_dlg("Host added, please reconnect for sync all info")
else:
self.filter_uuid = event['snapshot']['uuid']
self.all_hosts[event["ref"]] = event["snapshot"]
self.treestore.foreach(self.update_host_status, "")
elif event["class"] == "pif_metrics":
self.all_pif_metrics[event["ref"]] = event["snapshot"]
elif event["class"] == "host_metrics":
self.all_host_metrics[event["ref"]] = event["snapshot"]
elif event["class"] == "vbd_metrics":
self.all_vbd_metrics[event["ref"]] = event["snapshot"]
elif event["class"] == "vif_metrics":
self.all_vif_metrics[event["ref"]] = event["snapshot"]
elif event["class"] == "vm_metrics":
self.all_vm_metrics[event["ref"]] = event["snapshot"]
elif event["class"] == "console":
self.all_console[event["ref"]] = event["snapshot"]
elif event["class"] == "host_patch":
if event["operation"] == "del":
del self.all_host_patch[event["ref"]]
else:
self.all_host_patch[event["ref"]] = event["snapshot"]
elif event["class"] == "pool_patch":
if event["operation"] == "del":
del self.all_pool_patch[event["ref"]]
else:
self.all_pool_patch[event["ref"]] = event["snapshot"]
elif event["class"] == "pbd":
self.all_pbd[event["ref"]] = event["snapshot"]
if event["operation"] == "add":
sr = event["snapshot"]["SR"]
host = event["snapshot"]["host"]
gobject.idle_add(lambda: self.treestore.insert_after(self.hostroot[host], self.last_storage_iter, [\
gtk.gdk.pixbuf_new_from_file("images/storage_shaped_16.png"),\
self.all_storage[sr]['name_label'], self.all_storage[sr]['uuid'],\
"storage", None, self.host, sr, self.all_storage[sr]['allowed_operations'], None]) and False)
elif event["class"] == "host_cpu":
self.all_host_cpu[event["ref"]] = event["snapshot"]
else:
print event["class"] + " => ",event
except socket, msg:
self.halt = True
# FIXME TODO
# Disconnect
except httplib.CannotSendRequest:
# TODO: csun: this is a common error/complaint. Find out why this is happening and fix this?
print "Event loop received CannotSendRequest exception, retrying..."
time.sleep(0.1)
except:
print "Event loop -- unexpected error:"
print traceback.print_exc()
print "Exiting event loop"
def update_default_sr(self, model, path, iter_ref, user_data):
"""
user_data contains:
[0] -> old default sr
[1] -> new default sr
"""
sr = self.treestore.get_value(iter_ref, 6)
if sr == user_data[0]:
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, gtk.gdk.pixbuf_new_from_file("images/storage_shaped_16.png")) and False)
if sr == user_data[1]:
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, gtk.gdk.pixbuf_new_from_file("images/storage_default_16.png")) and False)
self.default_sr = sr
if sr == user_data[0] or sr == user_data[1]:
if len(self.all_storage[sr]['PBDs']) == 0:
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, gtk.gdk.pixbuf_new_from_file("images/storage_detached_16.png")) and False)
broken = False
for pbd_ref in self.all_storage[sr]['PBDs']:
if not self.all_pbd[pbd_ref]['currently_attached']:
broken = True
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, gtk.gdk.pixbuf_new_from_file("images/storage_broken_16.png")) and False)
if not broken:
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, gtk.gdk.pixbuf_new_from_file("images/storage_shaped_16.png")) and False)
def update_vm_status(self, model, path, iter_ref, user_data):
if self.treestore.get_value(iter_ref, 2) == self.filter_uuid:
vm = self.all_vms[self.vm_filter_uuid()]
if not self.all_vms[self.vm_filter_uuid()]["is_a_template"]:
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 1, \
vm['name_label']) and False)
if len(self.all_vms[self.vm_filter_uuid()]["current_operations"]):
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, \
gtk.gdk.pixbuf_new_from_file("images/tree_starting_16.png")) and False)
else:
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, \
gtk.gdk.pixbuf_new_from_file("images/tree_%s_16.png" % \
vm['power_state'].lower())) and False)
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 4, \
vm['power_state']) and False)
self.wine.selected_state = vm['power_state']
self.wine.selected_actions = vm['allowed_operations']
else:
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 1, \
vm['name_label']) and False)
if self.wine.selected_ref == self.treestore.get_value(iter_ref, 6):
gobject.idle_add(lambda: self.wine.update_tabs() and False)
gobject.idle_add(lambda: self.wine.builder.get_object("headimage").set_from_pixbuf(self.treestore.get_value(iter_ref, 0)) and False)
gobject.idle_add(lambda: self.wine.builder.get_object("headlabel").set_label(self.treestore.get_value(iter_ref, 1)) and False)
def update_storage_status(self, model, path, iter_ref, user_data):
if self.treestore.get_value(iter_ref, 2) == self.filter_uuid:
storage = self.all_storage[self.storage_filter_uuid()]
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 1, \
storage['name_label']
) and False)
if self.wine.selected_ref == self.treestore.get_value(iter_ref, 6):
gobject.idle_add(lambda: self.wine.update_tabs() and False)
gobject.idle_add(lambda: self.wine.builder.get_object("headimage").set_from_pixbuf(self.treestore.get_value(iter_ref, 0)) and False)
gobject.idle_add(lambda: self.wine.builder.get_object("headlabel").set_label(self.treestore.get_value(iter_ref, 1)) and False)
sr = self.treestore.get_value(iter_ref, 6)
if len(self.all_storage[sr]['PBDs']) == 0:
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, gtk.gdk.pixbuf_new_from_file("images/storage_detached_16.png")) and False)
broken = False
for pbd_ref in self.all_storage[sr]['PBDs']:
if not self.all_pbd[pbd_ref]['currently_attached']:
broken = True
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, gtk.gdk.pixbuf_new_from_file("images/storage_broken_16.png")) and False)
if not broken:
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, gtk.gdk.pixbuf_new_from_file("images/storage_shaped_16.png")) and False)
def delete_storage(self, model, path, iter_ref, user_data):
if self.treestore.get_value(iter_ref, 2) == self.filter_uuid:
self.treestore.remove(iter_ref)
def update_host_status(self, model, path, iter_ref, user_data):
if self.treestore.get_value(iter_ref, 2) == self.filter_uuid:
if self.treestore.get_value(iter_ref, 1):
host = self.all_hosts[self.host_filter_uuid()]
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 1, \
host['name_label']
) and False)
if host["enabled"]:
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, gtk.gdk.pixbuf_new_from_file("images/tree_connected_16.png")) and False)
else:
gobject.idle_add(lambda: self.treestore.set_value(iter_ref, 0, gtk.gdk.pixbuf_new_from_file("images/tree_disabled_16.png")) and False)
gobject.idle_add(lambda: self.wine.update_tabs() and False)
gobject.idle_add(lambda: self.wine.update_toolbar() and False)
gobject.idle_add(lambda: self.wine.update_menubar() and False)
gobject.idle_add(lambda: self.wine.builder.get_object("headimage").set_from_pixbuf(self.treestore.get_value(iter_ref, 0)) and False)
gobject.idle_add(lambda: self.wine.builder.get_object("headlabel").set_label(self.treestore.get_value(iter_ref, 1)) and False)
def delete_host(self, model, path, iter_ref, user_data):
if self.treestore.get_value(iter_ref, 2) == self.filter_uuid:
gobject.idle_add(lambda: self.treestore.remove(iter_ref) and False)
gobject.idle_add(lambda: self.wine.update_tabs() and False)
def log_filter_uuid(self, item):
return item["obj_uuid"] == self.filter_uuid
def task_filter_uuid(self, item_ref):
if item_ref in self.all_tasks:
item = self.all_tasks[item_ref]
if item_ref in self.track_tasks:
if self.track_tasks[item_ref] in self.all_vms:
return self.all_vms[self.track_tasks[item_ref]]["uuid"] == self.filter_uuid
#return True
if "ref" in item and item["ref"] in self.track_tasks and self.track_tasks[item["ref"]] in self.all_vms:
return self.all_vms[self.track_tasks[item["ref"]]]["uuid"] == self.filter_uuid
else:
if "resident_on" in item:
return item["resident_on"] == self.filter_ref
if "uuid" in item:
self.get_task_ref_by_uuid(item["uuid"])
return False
def get_task_ref_by_uuid(self, uuid):
for task in self.tasks.keys():
if "uuid" in self.tasks[task]:
if uuid == self.tasks[task]["uuid"]:
return task
else:
print self.tasks[task]
def filter_vif_ref(self, item):
return item["VM"] == self.filter_ref
def filter_vbd_ref(self, item):
return item["VM"] == self.filter_ref
def filter_vbd_uuid(self, uuid):
for vbd in self.all_vbd:
if self.all_vbd[vbd]["uuid"] == uuid:
return vbd
return None
def filter_vm_uuid(self, item):
return item["uuid"] == self.filter_uuid
def vm_filter_uuid(self):
for vm in self.all_vms:
if self.all_vms[vm]["uuid"] == self.filter_uuid:
return vm
return None
def storage_filter_uuid(self):
for stg in self.all_storage:
if self.all_storage[stg]["uuid"] == self.filter_uuid:
return stg
return None
def host_filter_uuid(self):
for host in self.all_hosts:
if self.all_hosts[host]["uuid"] == self.filter_uuid:
return host
return None
def filter_custom_template(self, item):
if not item["is_a_template"]:
return False
if item["name_label"][:7] == "__gui__":
return False
if item["last_booted_record"] != "":
return True
return False
def filter_normal_template(self, item):
if not item["is_a_template"]:
return False
elif item["name_label"][:7] == "__gui__":
return False
elif item["last_booted_record"] == "":
return True
return False
def filter_vdi_ref(self):
for vdi in self.all_vdi.keys():
if vdi == self.filter_vdi:
return vdi
def search_in_liststore(self, list, ref, field):
"""
Function retrns iter of element found or None
"""
print list.__len__()
for i in range(0, list.__len__()):
iter_ref = list.get_iter((i,))
print list.get_value(iter_ref, field)
if ref == list.get_value(iter_ref, field):
return iter_ref
return None
openxenmanager/window_host.py 0000644 0001750 0001750 00000064766 11636446664 015244 0 ustar rrs rrs # -----------------------------------------------------------------------
# OpenXenManager
#
# Copyright (C) 2009 Alberto Gonzalez Rodriguez alberto@pesadilla.org
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------
#!/usr/bin/env python
from window_host_nics import *
from window_host_network import *
from capabilities import capabilities_conf_text
from threading import Thread
from messages import messages_header
import gtk
class oxcWindowHost(oxcWindowHostNics, oxcWindowHostNetwork):
"""
Class to manage host tabs, host properties and host functions
"""
def on_btleavedomain_clicked(self, widget, data=None):
"""
Press "Leave Domain" on Users tab
"""
pass
def on_btjoindomain_clicked(self, widget, data=None):
"""
Press "Join Domain" on Users tab
"""
pass
def on_btadduser_clicked(self, widget, data=None):
"""
Press "Add user" on Users tab
"""
pass
def on_btremoveuser_clicked(self, widget, data=None):
"""
Press "Remove user" on Users tab
"""
pass
def on_btlogoutuser_clicked(self, widget, data=None):
"""
Press "Logout User" on Users tab
"""
pass
def on_treeusers_cursor_changed(self, widget, data=None):
"""
Selected row in treeusers treeview
"""
pass
def on_btchangerole_clicked(self, widget, data=None):
"""
Press "Join Domain" on Users tab
"""
pass
def on_cancelfileexportmap_clicked(self, widget, data=None):
"""
Cancel dialog file export map to png
"""
self.builder.get_object("fileexportmap").hide()
def on_acceptfileexportmap_clicked(self, widget, data=None):
"""
Accept dialog file export map to png
"""
filename = self.builder.get_object("fileexportmap").get_filename()
pixbuf = gtk.gdk.Pixbuf( gtk.gdk.COLORSPACE_RGB, False, 8, 640, 480)
pixmap = self.windowmap.widget.get_snapshot()
pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, -1, -1)
pixbuf.save(filename, 'png')
self.builder.get_object("fileexportmap").hide()
def on_btexportmap_clicked(self, widget, data=None):
"""
Function to export current map to PNG file
"""
self.builder.get_object("fileexportmap").set_current_name(self.selected_name + ".png")
self.builder.get_object("fileexportmap").show()
def on_check_map_options(self, widget, data=None):
"""
Function called when you check or uncheck a map option
"""
if not "maps" in self.config:
self.config["maps"] = {}
self.config["maps"][gtk.Buildable.get_name(widget)] = str(widget.get_active())
self.config.write()
self.update_maps()
def on_acceptfilenewupdate_clicked(self, widget, data=None):
# When you press accept "new update" file chooser
filename = self.builder.get_object("filenewupdate").get_filename()
Thread(target=self.xc_servers[self.selected_host].upload_patch, \
args=(self.selected_ref, filename)).start()
self.builder.get_object("updatemanager").hide()
self.builder.get_object("filenewupdate").hide()
def on_cancelfilenewupdate_clicked(self, widget, data=None):
# When you press cancel "new update" file chooser
self.builder.get_object("filenewupdate").hide()
def on_btuploadnewupdate_clicked(self, widget, data=None):
# When you press "Upload new update" (patch)
self.builder.get_object("filterfilenewupdate").add_pattern("*.xsupdate")
self.builder.get_object("filenewupdate").show()
def on_btremoveupdate_clicked(self, wiget, data=None):
# When you press "remove" (patch)
treeupdates = self.builder.get_object("treeupdates")
iter = treeupdates.get_selection().get_selected()[1]
if iter:
listupdates = self.builder.get_object("listupdates")
patch_ref = listupdates.get_value(iter, 0)
self.xc_servers[self.selected_host].remove_patch(self.selected_ref, patch_ref)
self.builder.get_object("updatemanager").hide()
def on_btapplypatch_clicked(self, widget, data=None):
# When you press "apply patch"
treeupdates = self.builder.get_object("treeupdates")
treeupdatestatus = self.builder.get_object("treeupdatestatus")
iter = treeupdates.get_selection().get_selected()[1]
if iter:
listupdates = self.builder.get_object("listupdates")
patch_ref = listupdates.get_value(iter, 0)
iter = treeupdatestatus.get_selection().get_selected()[1]
if iter:
listupdatestatus = self.builder.get_object("listupdatestatus")
host_ref = listupdatestatus.get_value(iter, 0)
self.xc_servers[self.selected_host].apply_patch(host_ref, patch_ref)
self.builder.get_object("updatemanager").hide()
def on_treeupdatestatus_cursor_changed(self, widget, data=None):
# When you select a host in update manager
iter = widget.get_selection().get_selected()[1]
if iter:
listupdatestatus = self.builder.get_object("listupdatestatus")
self.builder.get_object("btapplypatch").set_sensitive(listupdatestatus.get_value(iter, 2))
def on_treeupdates_cursor_changed(self, widget, data=None):
# When you select a patch
iter = widget.get_selection().get_selected()[1]
if iter:
listupdates = self.builder.get_object("listupdates")
ref = listupdates.get_value(iter, 0)
name = self.xc_servers[self.selected_host].all_pool_patch[ref]['name_label']
desc = self.xc_servers[self.selected_host].all_pool_patch[ref]['name_description']
version = self.xc_servers[self.selected_host].all_pool_patch[ref]['version']
guidance = self.xc_servers[self.selected_host].all_pool_patch[ref]['after_apply_guidance']
self.builder.get_object("lblupdatename").set_label(name)
self.builder.get_object("lblupdatedesc").set_label(desc)
self.builder.get_object("lblupdateversion").set_label(version)
guidance_text = ""
for guid in guidance:
if guid in messages_header:
guidance_text += messages_header[guid] + "\n"
else:
guidance_text += guid
self.builder.get_object("lblupdateguidance").set_label(guidance_text)
host_patches = self.xc_servers[self.selected_host].all_pool_patch[ref]["host_patches"]
self.builder.get_object("btremoveupdate").set_sensitive(len(host_patches) == 0)
listupdatestatus = self.builder.get_object("listupdatestatus")
listupdatestatus.clear()
for host in self.xc_servers[self.selected_host].all_hosts.keys():
name = self.xc_servers[self.selected_host].all_hosts[host]['name_label']
found = False
for host_patch in host_patches:
host2 = self.xc_servers[self.selected_host].all_host_patch[host_patch]['host']
if host == host2:
found = True
timestamp = self.xc_servers[self.selected_host].all_host_patch[host_patch]['timestamp_applied']
patch_text = "%s - applied (%s)" % (name, \
self.xc_servers[self.selected_host].format_date(timestamp))
listupdatestatus.append([host, patch_text, False])
if not found:
patch_text = "%s - not applied" % (name)
listupdatestatus.append([host, patch_text, True])
def on_closeupdatemanager_clicked(self, widget, data=None):
"""
Function called when you close "update manager" window
"""
self.builder.get_object("updatemanager").hide()
def on_txttemplatesearch_changed(self, widget, data=None):
"""
Function called when you type something on search template list (newvm)
"""
self.modelfiltertpl.refilter()
def update_report_total_size_time(self):
"""
Update the total size and the total time on report status window
"""
treereport = self.builder.get_object("treereport")
listreport = self.builder.get_object("listreport")
totalsize, totaltime = 0, 0
for i in range(0, listreport.__len__()):
iter = listreport.get_iter((i,))
if listreport.get_value(iter, 1):
totalsize += listreport.get_value(iter, 7)
totaltime += listreport.get_value(iter, 8)
self.builder.get_object("lblreportotalsize").set_label("< %s" % (self.convert_bytes(totalsize)))
self.builder.get_object("lblreportotaltime").set_label("< %d minutes" % (int(totaltime)/60))
def on_cellrenderertoggle1_toggled(self, widget, data=None):
"""
Function called when you change the state of checkbox on report tree
"""
treereport = self.builder.get_object("treereport")
listreport = self.builder.get_object("listreport")
iter = treereport.get_selection().get_selected()[1]
if iter:
listreport.set_value(iter, 1, not widget.get_active())
self.update_report_total_size_time()
def on_treereport_cursor_changed(self, widget, data=None):
"""
Function called when you select a item on report
"""
treereport = self.builder.get_object("treereport")
listreport = self.builder.get_object("listreport")
iter = treereport.get_selection().get_selected()[1]
if iter:
self.builder.get_object("lblreportdesc").set_label(listreport.get_value(iter, 4))
self.builder.get_object("lblreportsize").set_label(listreport.get_value(iter, 5))
self.builder.get_object("lblreporttime").set_label(listreport.get_value(iter, 6) + " seconds")
conf = listreport.get_value(iter, 9)
self.builder.get_object("lblreportconf").set_label(capabilities_conf_text[conf-1])
def on_acceptstatusreport_clicked(self, widget, data=None):
"""
Function called when you accept status report dialog
"""
from time import strftime
self.builder.get_object("filesavereport").set_current_name(strftime("status-report-%Y-%m-%d-%H-%M-%S.tar"))
self.builder.get_object("filesavereport").show()
self.builder.get_object("statusreport").hide()
def on_acceptfilereport_clicked(self, widget, data=None):
"""
Function called when you accept save report file chooser dialog
"""
treereport = self.builder.get_object("treereport")
listreport = self.builder.get_object("listreport")
totalsize, totaltime = 0, 0
refs = []
for i in range(0, listreport.__len__()):
iter = listreport.get_iter((i,))
if listreport.get_value(iter, 1):
refs.append(listreport.get_value(iter, 0))
destination = self.builder.get_object("filesavereport").get_filename()
Thread(target=self.xc_servers[self.selected_host].host_download_status_report, \
args=(self.selected_ref, ",".join(refs), destination, self.selected_name)).start()
self.builder.get_object("filesavereport").hide()
def on_cancelfilereport_clicked(self, widget, data=None):
"""
Function called when you cancel save report file chooser dialog
"""
self.builder.get_object("filesavereport").hide()
def on_cancelstatusreport_clicked(self, widget, data=None):
"""
Function called when you cancel status report dialog
"""
self.builder.get_object("statusreport").hide()
def on_clearallstatusreport_clicked(self, widget, data=None):
"""
Uncheck all checkbox for each status report
"""
treereport = self.builder.get_object("treereport")
listreport = self.builder.get_object("listreport")
for i in range(0, listreport.__len__()):
iter = listreport.get_iter((i,))
listreport.set_value(iter, 1, False)
self.update_report_total_size_time()
def on_selectallstatusreport_clicked(self, widget, data=None):
"""
Check all checkbox for each status report
"""
treereport = self.builder.get_object("treereport")
listreport = self.builder.get_object("listreport")
for i in range(0, listreport.__len__()):
iter = listreport.get_iter((i,))
listreport.set_value(iter, 1, True)
self.update_report_total_size_time()
def on_txtcurrentpw_changed(self, widget, data=None):
"""
Function called when you change text on "current password", "type new password" or "re-enter new password"
On change server password window
"""
# If some textfield is empty, then disable button
if len(self.builder.get_object("txtcurrentpw").get_text()) and \
len(self.builder.get_object("txtnewpw").get_text()) and \
len(self.builder.get_object("txtrenewpw").get_text()) and \
(self.builder.get_object("txtnewpw").get_text() == self.builder.get_object("txtrenewpw").get_text()):
self.builder.get_object("acceptchangepassword").set_sensitive(True)
else:
self.builder.get_object("acceptchangepassword").set_sensitive(False)
def on_cancelchangepassword_clicked(self, widget, data=None):
"""
Function called when you press "Cancel" button on "Change Server Password" window
"""
self.builder.get_object("changepassword").hide()
def on_acceptchangepassword_clicked(self, widget, data=None):
"""
Function called when you press "OK" button on "Change Server Password" window
"""
old = self.xc_servers[self.selected_host].password
typed = self.builder.get_object("txtcurrentpw").get_text()
if typed != old:
self.builder.get_object("lblwrongpw").show()
else:
new = self.builder.get_object("txtnewpw").get_text()
self.xc_servers[self.selected_host].change_server_password(old, new)
self.builder.get_object("changepassword").hide()
def update_tab_host_nics(self):
"""
Function called to fill host nics
"""
if self.treeview.get_cursor()[1]:
listhostnics = self.builder.get_object("listhostnics")
host = self.selected_host
# Fill list "listhostnics"
self.xc_servers[host].fill_host_nics(self.selected_ref, \
listhostnics)
treehostnics = self.builder.get_object("treehostnics")
# Select the first as default
treehostnics.set_cursor((0,), treehostnics.get_column(0))
treehostnics.get_selection().select_path((0, ))
iter = listhostnics.get_iter((0, ))
# Get the reference of first selected
ref = self.builder.get_object("listhostnics").get_value(iter, 8)
nic_bond_master_of = self.xc_servers[self.selected_host].all_pif[ref]['bond_master_of']
# If is already on a bond
if len(nic_bond_master_of):
# Enable remove bond button
self.builder.get_object("bthostnicremove").set_sensitive(True)
else:
# Disable remove bond button
self.builder.get_object("bthostnicremove").set_sensitive(False)
def update_tab_host_network(self):
"""
Function called to fill host networks
"""
if self.treeview.get_cursor()[1]:
listhostnetwork= self.builder.get_object("listhostnetwork")
host = self.selected_host
# Fill list "listhostnetwork"
self.xc_servers[host].fill_host_network(self.selected_ref, \
listhostnetwork)
treehostnetwork = self.builder.get_object("treehostnetwork")
# Select the first as default
treehostnetwork.set_cursor((0,), treehostnetwork.get_column(0))
treehostnetwork.get_selection().select_path((0, 0))
iter = listhostnetwork.get_iter((0,0))
# Get the reference of first selected
ref = self.builder.get_object("listhostnetwork").get_value(iter, 7)
# Get the pifs from selected network
network_pifs = self.xc_servers[self.selected_host].all_network[ref]['PIFs']
# Enable "remove network" by default
self.builder.get_object("bthostnetworkremove").set_sensitive(True)
for pif in network_pifs:
# If is physical then disable it
if self.xc_servers[self.selected_host].all_pif[pif]['physical'] == True:
self.builder.get_object("bthostnetworkremove").set_sensitive(False)
break
def on_radiomgmtipmanual_toggled(self, widget, data=None):
"""
On "management interface" radio "manual ip" selected
"""
self.builder.get_object("txtmgmtip").set_sensitive(widget.get_active())
self.builder.get_object("txtmgmtmask").set_sensitive(widget.get_active())
self.builder.get_object("txtmgmtgw").set_sensitive(widget.get_active())
def on_radiomgmtdnsmanual_toggled(self, widget, data=None):
"""
On "management interface" radio "manual dns" selected
"""
self.builder.get_object("txtmgmtdns1").set_sensitive(widget.get_active())
self.builder.get_object("txtmgmtdns2").set_sensitive(widget.get_active())
def on_cancelmgmtinterface_clicked(self, widget, data=None):
"""
On "cancel" button pressed on "management interface"
"""
self.builder.get_object("mgmtinterface").hide()
def on_checkpoolserver_toggled(self, widget, data=None):
"""
Function called on "new pool" window, when you check a server to join to pool
"""
listpoolvms = self.builder.get_object("listpoolvms")
iter = listpoolvms.get_iter((int(data),))
# Field 4 (beginning on 0) contains if check could be modified
if listpoolvms.get_value(iter, 4):
# widget.get_active() contains last state: enabled o disabled
listpoolvms.set(iter, 2, not widget.get_active())
def on_cancelnewpool_clicked(self, widget, data=None):
"""
On "cancel" button pressed on "new pool"
"""
self.builder.get_object("newpool").hide()
def on_acceptnewpool_clicked(self, widget, data=None):
"""
On "accept" button pressed on "new pool"
"""
listpoolvms = self.builder.get_object("listpoolvms")
listpoolmaster = self.builder.get_object("listpoolmaster")
combopoolmaster = self.builder.get_object("combopoolmaster")
# If a master pool is selected..
if combopoolmaster.get_active_iter():
name = self.builder.get_object("txtpoolname").get_text()
desc = self.builder.get_object("txtpooldesc").get_text()
# Get the reference the selected iter
ref = listpoolmaster.get_value(combopoolmaster.get_active_iter(), 0)
# Create a pool
self.xc_servers[ref].create_pool(name, desc)
# For each server on treeview
for i in range(0, listpoolvms.__len__()):
iter = listpoolvms.get_iter((int(i),))
# If is checked
if listpoolvms.get_value(iter, 2):
host = listpoolvms.get_value(iter, 0)
# And is not "Master"
if listpoolvms.get_value(iter, 3) == "":
# Join to pool
self.xc_servers[host].join_pool(self.xc_servers[ref].host, self.xc_servers[ref].user, self.xc_servers[ref].password)
self.builder.get_object("newpool").hide()
def on_combopoolmaster_changed(self, widget, data=None):
# FIXME: active the selected on treeview and set as "Master"
listpoolvms = self.builder.get_object("listpoolvms")
listpoolmaster = self.builder.get_object("listpoolmaster")
combopoolmaster = self.builder.get_object("combopoolmaster")
if widget.get_active_iter():
ref = listpoolmaster.get_value(widget.get_active_iter(),0)
for i in range(0, listpoolvms.__len__()):
iter = listpoolvms.get_iter((int(i),))
if listpoolvms.get_value(iter, 3) == "Master":
listpoolvms.set(iter, 3, "", 2, False, 4, True)
if listpoolvms.get_value(iter, 0) == ref:
listpoolvms.set(iter, 3, "Master", 2, True, 4, False)
def on_canceldialogreconfigure_clicked(self, widget, data=None):
"""
On "cancel" button pressed on confirmation of "management interface"
"""
self.builder.get_object("dialogreconfigure").hide()
def on_closewarninglicense_clicked(self, widget, data=None):
"""
On "close" button pressed on warning alert
"""
self.builder.get_object("warninglicense").hide()
def on_accepthostdmesg_clicked(self, widget, data=None):
"""
On "accept" button pressed on dmesg dialog
"""
self.builder.get_object("hostdmesg").hide()
def on_acceptdialogreconfigure_clicked(self, widget, data=None):
"""
On "accept" button pressed on confirmation dialog to reconfigure interface
"""
listmgmtinterfaces = self.builder.get_object("listmgmtinterfaces")
treemgmtinterfaces = self.builder.get_object("treemgmtinterfaces")
selection = treemgmtinterfaces.get_selection()
pif_ref = listmgmtinterfaces.get_value(selection.get_selected()[1],0)
combomgmtnetworks = self.builder.get_object("combomgmtnetworks")
listmgmtnetworks = self.builder.get_object("listmgmtnetworks")
iter = combomgmtnetworks.get_active_iter()
# Get selected network and rest of elements
network_ref = listmgmtnetworks.get_value(iter, 0)
ip = self.builder.get_object("txtmgmtip").get_text()
mask = self.builder.get_object("txtmgmtmask").get_text()
gw = self.builder.get_object("txtmgmtgw").get_text()
dns1 = self.builder.get_object("txtmgmtdns1").get_text()
dns2 = self.builder.get_object("txtmgmtdns2").get_text()
radiomgmtipdhcp = self.builder.get_object("radiomgmtipdhcp")
radiomgmtdnsdhcp = self.builder.get_object("radiomgmtdnsdhcp")
if radiomgmtdnsdhcp.get_active():
dns = ""
else:
dns = dns1 + "," + dns2
if radiomgmtipdhcp.get_active():
configuration_mode = "DHCP"
else:
configuration_mode = "Static"
# Call to reconfigure interface with specified configuration
self.xc_servers[self.selected_host].reconfigure_pif(pif_ref, configuration_mode, ip, mask, gw, dns, self.selected_ref)
# Hide both windows: management window and confirmation
self.builder.get_object("dialogreconfigure").hide()
self.builder.get_object("mgmtinterface").hide()
def on_acceptmgmtinterface_clicked(self, widget, data=None):
"""
On "accept" button pressed on confirmation dialog to reconfigure interface
change is a variable, if is False doesn't change anything, if is True show reconfigure window confirmation
"""
listmgmtinterfaces = self.builder.get_object("listmgmtinterfaces")
treemgmtinterfaces = self.builder.get_object("treemgmtinterfaces")
# Get selected pif
selection = treemgmtinterfaces.get_selection()
pif_ref = listmgmtinterfaces.get_value(selection.get_selected()[1],0)
combomgmtnetworks = self.builder.get_object("combomgmtnetworks")
listmgmtnetworks = self.builder.get_object("listmgmtnetworks")
# Get selected pif info
pif = self.xc_servers[self.selected_host].all_pif[pif_ref]
iter = combomgmtnetworks.get_active_iter()
# Get selected network_ref
pif = self.xc_servers[self.selected_host].all_pif[pif_ref]
network_ref = listmgmtnetworks.get_value(iter, 0)
if pif['network'] != network_ref:
change = True
radiomgmtipmanual = self.builder.get_object("radiomgmtipmanual")
radiomgmtipdhcp = self.builder.get_object("radiomgmtipdhcp")
radiomgmtdnsmanual = self.builder.get_object("radiomgmtdnsmanual")
radiomgmtdnsdhcp = self.builder.get_object("radiomgmtdnsdhcp")
ip = self.builder.get_object("txtmgmtip").get_text()
mask = self.builder.get_object("txtmgmtmask").get_text()
gw = self.builder.get_object("txtmgmtgw").get_text()
dns1 = self.builder.get_object("txtmgmtdns1").get_text()
dns2 = self.builder.get_object("txtmgmtdns2").get_text()
change = False
if pif['ip_configuration_mode'] == "DHCP" and radiomgmtipmanual.get_active():
change = True
if pif['ip_configuration_mode'] != "DHCP" and radiomgmtipdhcp.get_active():
change = True
if ip != pif['IP'] or mask != pif['netmask'] or gw != pif['gateway']:
change = True
if pif['DNS'] == "" and radiomgmtdnsmanual.get_active():
change = True
if pif['DNS'] != "" and radiomgmtdnsdhcp.get_active():
change = True
if dns1 + "," + dns2 != pif['DNS']:
change = True
# If some parameter was changed, show confirmation dialog, if not hide magement interface window
if change:
self.builder.get_object("dialogreconfigure").show()
else:
self.builder.get_object("mgmtinterface").hide()
openxenmanager/plugins/ 0000755 0001750 0001750 00000000000 11636446664 013764 5 ustar rrs rrs openxenmanager/plugins/GlpiWebUI.xcplugin.xml 0000644 0001750 0001750 00000001202 11636446664 020120 0 ustar rrs rrs
openxenmanager/plugins/OpenFilerWebUI.xcplugin.xml 0000644 0001750 0001750 00000001243 11636446664 021115 0 ustar rrs rrs
openxenmanager/plugins/NagiosWebUI.xcplugin.xml 0000644 0001750 0001750 00000001227 11636446664 020454 0 ustar rrs rrs
openxenmanager/rrdinfo.py 0000755 0001750 0001750 00000016003 11636446664 014323 0 ustar rrs rrs #!/usr/bin/python
#
#Copyright (C) 2011 by Citrix Systems
#
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#
#
#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
#
# Example code for reading RRDs
# Contact: Jon Ludlam (jonathan.ludlam@eu.citrix.com)
#
# Mostly this script is taken from perfmon, by Alex Zeffert
#
import urllib
from xml.dom import minidom
from xml.parsers.expat import ExpatError
import time
# Per VM dictionary (used by RRDUpdates to look up column numbers by variable names)
class VMReport(dict):
"""Used internally by RRDUpdates"""
def __init__(self, uuid):
self.uuid = uuid
# Per Host dictionary (used by RRDUpdates to look up column numbers by variable names)
class HostReport(dict):
"""Used internally by RRDUpdates"""
def __init__(self, uuid):
self.uuid = uuid
class RRDUpdates:
""" Object used to get and parse the output the http://localhost/rrd_udpates?...
"""
def __init__(self, url):
self.url = url
def get_nrows(self):
return self.rows
def get_vm_list(self):
return self.vm_reports.keys()
def get_vm_param_list(self, uuid):
report = self.vm_reports[uuid]
if not report:
return []
return report.keys()
def get_vm_data(self, uuid, param, row):
report = self.vm_reports[uuid]
col = report[param]
return self.__lookup_data(col, row)
def get_host_uuid(self):
report = self.host_report
if not report:
return None
return report.uuid
def get_host_param_list(self):
report = self.host_report
if not report:
return []
return report.keys()
def get_host_data(self, param, row):
report = self.host_report
col = report[param]
return self.__lookup_data(col, row)
def get_row_time(self,row):
return self.__lookup_timestamp(row)
# extract float from value () node by col,row
def __lookup_data(self, col, row):
# Note: the nodes are in reverse chronological order, and comprise
# a timestamp node, followed by self.columns data nodes
if len(self.data_node.childNodes) >= (self.rows - 1 - row) and \
len(self.data_node.childNodes[self.rows - 1 - row].childNodes) > (col+1):
node = self.data_node.childNodes[self.rows - 1 - row].childNodes[col+1]
return float(node.firstChild.toxml()) # node.firstChild should have nodeType TEXT_NODE
return float(0)
# extract int from value () node by row
def __lookup_timestamp(self, row):
# Note: the nodes are in reverse chronological order, and comprise
# a timestamp node, followed by self.columns data nodes
node = self.data_node.childNodes[self.rows - 1 - row].childNodes[0]
return int(node.firstChild.toxml()) # node.firstChild should have nodeType TEXT_NODE
def refresh(self):
sock = urllib.URLopener().open(self.url)
xmlsource = sock.read()
#sock.close()
xmldoc = minidom.parseString(xmlsource)
self.__parse_xmldoc(xmldoc)
# Update the time used on the next run
def __parse_xmldoc(self, xmldoc):
# The 1st node contains meta data (description of the data)
# The 2nd node contains the data
self.meta_node = xmldoc.firstChild.childNodes[0]
self.data_node = xmldoc.firstChild.childNodes[1]
def lookup_metadata_bytag(name):
return int (self.meta_node.getElementsByTagName(name)[0].firstChild.toxml())
# rows = number of samples per variable
# columns = number of variables
self.rows = lookup_metadata_bytag('rows')
self.columns = lookup_metadata_bytag('columns')
# These indicate the period covered by the data
self.start_time = lookup_metadata_bytag('start')
self.step_time = lookup_metadata_bytag('step')
self.end_time = lookup_metadata_bytag('end')
# the