2017-01-16 20:59:50 +01:00
|
|
|
|
/* Copyright (c) Citrix Systems, Inc.
|
2015-02-11 10:32:34 +01:00
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Redistribution and use in source and binary forms,
|
|
|
|
|
* with or without modification, are permitted provided
|
|
|
|
|
* that the following conditions are met:
|
|
|
|
|
*
|
|
|
|
|
* * Redistributions of source code must retain the above
|
|
|
|
|
* copyright notice, this list of conditions and the
|
|
|
|
|
* following disclaimer.
|
|
|
|
|
* * Redistributions in binary form must reproduce the above
|
|
|
|
|
* copyright notice, this list of conditions and the
|
|
|
|
|
* following disclaimer in the documentation and/or other
|
|
|
|
|
* materials provided with the distribution.
|
|
|
|
|
*
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
|
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS 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 THE COPYRIGHT HOLDER OR
|
|
|
|
|
* CONTRIBUTORS 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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using XenAPI;
|
|
|
|
|
|
|
|
|
|
using XenAdmin.Actions;
|
|
|
|
|
using XenAdmin.Core;
|
|
|
|
|
using XenAdmin.Network;
|
|
|
|
|
using System.Xml;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace XenAdmin.Model
|
|
|
|
|
{
|
|
|
|
|
public class DockerContainers
|
|
|
|
|
{
|
|
|
|
|
public static void InitDockerContainers()
|
|
|
|
|
{
|
|
|
|
|
Trace.Assert(InvokeHelper.Synchronizer != null);
|
|
|
|
|
CollectionChangedWithInvoke = InvokeHelper.InvokeHandler(CollectionChanged);
|
|
|
|
|
|
|
|
|
|
ConnectionsManager.XenConnections.CollectionChanged += XenConnections_CollectionChanged;
|
|
|
|
|
|
|
|
|
|
foreach (IXenConnection connection in ConnectionsManager.XenConnectionsCopy)
|
|
|
|
|
AddConnection(connection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void XenConnections_CollectionChanged(object sender, CollectionChangeEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
InvokeHelper.BeginInvoke(() =>
|
2017-07-14 19:08:54 +02:00
|
|
|
|
{
|
|
|
|
|
IXenConnection connection = e.Element as IXenConnection;
|
|
|
|
|
|
|
|
|
|
switch (e.Action)
|
|
|
|
|
{
|
|
|
|
|
case CollectionChangeAction.Add:
|
|
|
|
|
if (connection != null)
|
|
|
|
|
AddConnection(connection);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CollectionChangeAction.Remove:
|
|
|
|
|
if (connection != null)
|
|
|
|
|
{
|
|
|
|
|
RemoveConnection(connection);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var range = e.Element as List<IXenConnection>;
|
|
|
|
|
if (range != null)
|
|
|
|
|
foreach (var con in range)
|
|
|
|
|
RemoveConnection(con);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
});
|
2015-02-11 10:32:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static CollectionChangeEventHandler CollectionChangedWithInvoke;
|
|
|
|
|
private static void AddConnection(IXenConnection connection)
|
|
|
|
|
{
|
|
|
|
|
connection.Cache.RegisterCollectionChanged<VM>(CollectionChangedWithInvoke);
|
|
|
|
|
|
|
|
|
|
connection.XenObjectsUpdated += connection_XenObjectsUpdated;
|
|
|
|
|
|
|
|
|
|
InvokeHelper.Invoke(delegate()
|
|
|
|
|
{
|
|
|
|
|
UpdateAll(connection.Cache.VMs);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void RemoveConnection(IXenConnection connection)
|
|
|
|
|
{
|
|
|
|
|
connection.Cache.DeregisterCollectionChanged<VM>(CollectionChangedWithInvoke);
|
|
|
|
|
|
|
|
|
|
connection.XenObjectsUpdated -= connection_XenObjectsUpdated;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void CollectionChanged(Object sender, CollectionChangeEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
InvokeHelper.AssertOnEventThread();
|
|
|
|
|
|
2015-02-24 14:20:11 +01:00
|
|
|
|
var vm = e.Element as VM;
|
2017-07-14 19:08:54 +02:00
|
|
|
|
Trace.Assert(vm != null, "The item changed is not a VM");
|
2015-02-11 10:32:34 +01:00
|
|
|
|
|
|
|
|
|
switch (e.Action)
|
|
|
|
|
{
|
|
|
|
|
case CollectionChangeAction.Add:
|
2015-02-23 18:02:06 +01:00
|
|
|
|
vm.PropertyChanged += ServerXenObject_PropertyChanged;
|
|
|
|
|
UpdateDockerContainer(vm);
|
2015-02-11 10:32:34 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CollectionChangeAction.Remove:
|
2015-02-23 18:02:06 +01:00
|
|
|
|
vm.PropertyChanged -= ServerXenObject_PropertyChanged;
|
|
|
|
|
RemoveObject(vm);
|
2015-02-11 10:32:34 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
System.Diagnostics.Trace.Assert(false);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void connection_XenObjectsUpdated(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
IXenConnection connection = sender as IXenConnection;
|
|
|
|
|
if (connection == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
connection.Cache.CheckDockerContainersBatchChange();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void ServerXenObject_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
|
|
|
{
|
2015-02-24 14:20:11 +01:00
|
|
|
|
Trace.Assert(sender is VM);
|
2015-02-23 18:02:06 +01:00
|
|
|
|
|
2015-02-24 14:20:11 +01:00
|
|
|
|
VM vm = sender as VM;
|
2015-02-23 18:02:06 +01:00
|
|
|
|
|
2015-02-11 10:32:34 +01:00
|
|
|
|
if (e.PropertyName == "other_config")
|
|
|
|
|
{
|
2015-02-23 18:02:06 +01:00
|
|
|
|
UpdateDockerContainer(vm);
|
2015-02-11 10:32:34 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-24 14:20:11 +01:00
|
|
|
|
private static void RemoveObject(VM vm)
|
2015-02-11 10:32:34 +01:00
|
|
|
|
{
|
|
|
|
|
InvokeHelper.AssertOnEventThread();
|
|
|
|
|
|
2015-02-24 14:20:11 +01:00
|
|
|
|
IXenConnection connection = vm.Connection;
|
|
|
|
|
connection.Cache.UpdateDockerContainersForVM(new List<DockerContainer>(), vm);
|
2015-02-11 10:32:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 18:02:06 +01:00
|
|
|
|
private static void UpdateAll(VM[] vms)
|
2015-02-11 10:32:34 +01:00
|
|
|
|
{
|
2015-02-23 18:02:06 +01:00
|
|
|
|
foreach (VM vm in vms)
|
2015-02-11 10:32:34 +01:00
|
|
|
|
{
|
2015-02-23 18:02:06 +01:00
|
|
|
|
vm.PropertyChanged -= ServerXenObject_PropertyChanged;
|
|
|
|
|
vm.PropertyChanged += ServerXenObject_PropertyChanged;
|
|
|
|
|
UpdateDockerContainer(vm);
|
2015-02-11 10:32:34 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 18:02:06 +01:00
|
|
|
|
private static void UpdateDockerContainer(VM vm)
|
2015-02-11 10:32:34 +01:00
|
|
|
|
{
|
|
|
|
|
InvokeHelper.AssertOnEventThread();
|
|
|
|
|
|
2015-02-23 18:02:06 +01:00
|
|
|
|
if (vm == null)
|
2015-02-11 10:32:34 +01:00
|
|
|
|
return;
|
|
|
|
|
|
2015-02-23 18:02:06 +01:00
|
|
|
|
IXenConnection connection = vm.Connection;
|
2015-02-11 10:32:34 +01:00
|
|
|
|
|
2015-02-23 18:02:06 +01:00
|
|
|
|
var dockerVMs = GetDockerVMs(vm);
|
|
|
|
|
connection.Cache.UpdateDockerContainersForVM(dockerVMs, vm);
|
2015-02-11 10:32:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static List<DockerContainer> GetContainersFromOtherConfig(VM vm)
|
|
|
|
|
{
|
|
|
|
|
var containers = new List<DockerContainer>();
|
|
|
|
|
var other_config = vm.other_config;
|
|
|
|
|
if (other_config.ContainsKey("docker_ps"))
|
|
|
|
|
{
|
|
|
|
|
XmlDocument doc = new XmlDocument();
|
|
|
|
|
doc.LoadXml(other_config["docker_ps"]);
|
|
|
|
|
|
|
|
|
|
foreach (XmlNode entry in doc.GetElementsByTagName("entry"))
|
|
|
|
|
{
|
|
|
|
|
//uuid
|
|
|
|
|
string id = "";
|
|
|
|
|
var propertyNode = entry.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.Name == "id");
|
|
|
|
|
if (propertyNode != null)
|
|
|
|
|
id = propertyNode.InnerText;
|
|
|
|
|
|
|
|
|
|
string name = "";
|
|
|
|
|
propertyNode = entry.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.Name == "names");
|
|
|
|
|
if (propertyNode != null)
|
|
|
|
|
name = propertyNode.InnerText;
|
|
|
|
|
|
|
|
|
|
string status = "";
|
|
|
|
|
propertyNode = entry.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.Name == "status");
|
|
|
|
|
if (propertyNode != null)
|
|
|
|
|
status = propertyNode.InnerText;
|
|
|
|
|
|
|
|
|
|
string container = "";
|
|
|
|
|
propertyNode = entry.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.Name == "container");
|
|
|
|
|
if (propertyNode != null)
|
|
|
|
|
container = propertyNode.InnerText;
|
|
|
|
|
|
|
|
|
|
string created = "";
|
|
|
|
|
propertyNode = entry.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.Name == "created");
|
|
|
|
|
if (propertyNode != null)
|
|
|
|
|
created = propertyNode.InnerText;
|
|
|
|
|
|
|
|
|
|
string image = "";
|
|
|
|
|
propertyNode = entry.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.Name == "image");
|
|
|
|
|
if (propertyNode != null)
|
2015-02-10 04:03:53 +01:00
|
|
|
|
image = propertyNode.InnerText;
|
|
|
|
|
|
|
|
|
|
string command = "";
|
|
|
|
|
propertyNode = entry.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.Name == "command");
|
|
|
|
|
if (propertyNode != null)
|
|
|
|
|
command = propertyNode.InnerText;
|
|
|
|
|
|
|
|
|
|
string ports = "";
|
|
|
|
|
propertyNode = entry.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.Name == "ports");
|
|
|
|
|
if (propertyNode != null)
|
2015-03-06 12:43:47 +01:00
|
|
|
|
ports = propertyNode.InnerXml;
|
2015-02-10 04:03:53 +01:00
|
|
|
|
|
2015-02-11 11:21:48 +01:00
|
|
|
|
DockerContainer newContainer = new DockerContainer(vm, id, name, string.Empty, status, container, created, image, command, ports);
|
2015-02-11 10:32:34 +01:00
|
|
|
|
|
|
|
|
|
// update existing container or add a new one
|
2015-02-11 11:21:48 +01:00
|
|
|
|
DockerContainer existingContainer = vm.Connection.Resolve(new XenRef<DockerContainer>(newContainer));
|
2015-02-11 10:32:34 +01:00
|
|
|
|
if (existingContainer != null)
|
|
|
|
|
{
|
2015-02-11 11:21:48 +01:00
|
|
|
|
existingContainer.UpdateFrom(newContainer);
|
2015-02-11 10:32:34 +01:00
|
|
|
|
containers.Add(existingContainer);
|
|
|
|
|
}
|
|
|
|
|
else
|
2015-02-11 11:21:48 +01:00
|
|
|
|
containers.Add(newContainer);
|
2015-02-11 10:32:34 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return containers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static ComparableList<DockerContainer> GetDockerVMs(IXenObject o)
|
|
|
|
|
{
|
|
|
|
|
var vm = o as VM;
|
2015-02-12 16:24:23 +01:00
|
|
|
|
if (vm != null && vm.is_a_real_vm)
|
2015-02-11 10:32:34 +01:00
|
|
|
|
{
|
|
|
|
|
return new ComparableList<DockerContainer>(DockerContainers.GetContainersFromOtherConfig(vm));
|
|
|
|
|
}
|
|
|
|
|
return new ComparableList<DockerContainer>();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|