|
|
@@ -11,6 +11,7 @@ import io
|
|
|
import json
|
|
|
import os
|
|
|
import pickle
|
|
|
+import platform
|
|
|
import re
|
|
|
import socket
|
|
|
import string
|
|
|
@@ -18,6 +19,7 @@ import subprocess
|
|
|
import time
|
|
|
import traceback
|
|
|
import uuid
|
|
|
+import __main__ as main
|
|
|
|
|
|
from io import StringIO
|
|
|
|
|
|
@@ -25,7 +27,15 @@ import OpenSSL
|
|
|
from oslo_config import cfg
|
|
|
from oslo_log import log as logging
|
|
|
from oslo_serialization import jsonutils
|
|
|
+
|
|
|
+import netifaces
|
|
|
import paramiko
|
|
|
+# NOTE(gsamfira): I am aware that this is not ideal, but pip
|
|
|
+# developers have decided to move all logic inside an _internal
|
|
|
+# package, and I really don't want to do an exec call to pip
|
|
|
+# just to get installed packages and their versions, when I can
|
|
|
+# simply call a function.
|
|
|
+from pip._internal.operations import freeze
|
|
|
from six.moves.urllib import parse
|
|
|
from webob import exc
|
|
|
|
|
|
@@ -77,6 +87,46 @@ exec %(cmdline)s
|
|
|
"""
|
|
|
|
|
|
|
|
|
+def _get_local_ips():
|
|
|
+ ifaces = netifaces.interfaces()
|
|
|
+ ret = []
|
|
|
+ for iface in ifaces:
|
|
|
+ if iface == "lo":
|
|
|
+ continue
|
|
|
+ addrs = netifaces.ifaddresses(iface)
|
|
|
+ ret.append(
|
|
|
+ {
|
|
|
+ iface: {
|
|
|
+ "ipv4": addrs.get(netifaces.AF_INET),
|
|
|
+ "ipv6": addrs.get(netifaces.AF_INET6),
|
|
|
+ },
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return ret
|
|
|
+
|
|
|
+
|
|
|
+def _get_host_os_info():
|
|
|
+ info = None
|
|
|
+ # This exists on all modern Linux systems
|
|
|
+ if os.path.isfile("/etc/os-release"):
|
|
|
+ with open("/etc/os-release") as fd:
|
|
|
+ info = fd.read().split('\n')
|
|
|
+ return info
|
|
|
+
|
|
|
+
|
|
|
+def get_diagnostics_info():
|
|
|
+ # TODO(gsamfira): decide if we want any other kind of
|
|
|
+ # diagnostics.
|
|
|
+ packages = list(freeze.freeze())
|
|
|
+ return {
|
|
|
+ "application": os.path.basename(main.__file__),
|
|
|
+ "packages": packages,
|
|
|
+ "os_info": _get_host_os_info(),
|
|
|
+ "hostname": platform.node(),
|
|
|
+ "ip_addresses": _get_local_ips(),
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
def setup_logging():
|
|
|
logging.setup(CONF, 'coriolis')
|
|
|
|
|
|
@@ -394,40 +444,6 @@ def to_dict(obj, max_depth=10):
|
|
|
return jsonutils.loads(jsonutils.dumps(obj, default=_to_primitive))
|
|
|
|
|
|
|
|
|
-def topological_graph_sorting(items, id="id", depends_on="depends_on",
|
|
|
- sort_key=None):
|
|
|
- """Kahn's algorithm"""
|
|
|
- if sort_key:
|
|
|
- # Sort siblings
|
|
|
- items = sorted(items, key=lambda t: t[sort_key], reverse=True)
|
|
|
-
|
|
|
- a = []
|
|
|
- for i in items:
|
|
|
- a.append({"id": i[id],
|
|
|
- "depends_on": list(i[depends_on] or []),
|
|
|
- "item": i})
|
|
|
-
|
|
|
- s = []
|
|
|
- l = []
|
|
|
- for n in a:
|
|
|
- if not n["depends_on"]:
|
|
|
- s.append(n)
|
|
|
- while s:
|
|
|
- n = s.pop()
|
|
|
- l.append(n["item"])
|
|
|
-
|
|
|
- for m in a:
|
|
|
- if n["id"] in m["depends_on"]:
|
|
|
- m["depends_on"].remove(n["id"])
|
|
|
- if not m["depends_on"]:
|
|
|
- s.append(m)
|
|
|
-
|
|
|
- if len(l) != len(a):
|
|
|
- raise ValueError("The graph contains cycles")
|
|
|
-
|
|
|
- return l
|
|
|
-
|
|
|
-
|
|
|
def load_class(class_path):
|
|
|
LOG.debug('Loading class \'%s\'' % class_path)
|
|
|
parts = class_path.rsplit('.', 1)
|