Files
anvil/devstack/utils.py

289 lines
9.4 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import netifaces
import operator
import os
import platform
import re
import string
import sys
from termcolor import colored
from devstack import constants
from devstack import exceptions as excp
from devstack import log as logging
from devstack import shell as sh
from devstack import version
PARAM_SUB_REGEX = re.compile(r"%([\w\d]+?)%")
LOG = logging.getLogger("devstack.util")
def get_dependencies(component):
deps = constants.COMPONENT_DEPENDENCIES.get(component, list())
return sorted(deps)
def resolve_dependencies(components):
new_components = list()
for c in components:
component_deps = list(set(fetch_dependencies(c)))
if(len(component_deps)):
new_components = new_components + component_deps
new_components.append(c)
return set(new_components)
def execute_template(*cmds, **kargs):
if(not cmds or len(cmds) == 0):
return
params_replacements = kargs.pop('params')
ignore_missing = kargs.pop('ignore_missing', False)
for cmdinfo in cmds:
cmd_to_run_templ = cmdinfo.get("cmd")
cmd_to_run = list()
for piece in cmd_to_run_templ:
if(params_replacements and len(params_replacements)):
cmd_to_run.append(param_replace(piece, params_replacements,
ignore_missing=ignore_missing))
else:
cmd_to_run.append(piece)
stdin_templ = cmdinfo.get('stdin')
stdin = None
if(stdin_templ and len(stdin_templ)):
stdin_full = list()
for piece in stdin_templ:
if(params_replacements and len(params_replacements)):
stdin_full.append(param_replace(piece, params_replacements,
ignore_missing=ignore_missing))
else:
stdin_full.append(piece)
stdin = joinlinesep(*stdin_full)
root_run = cmdinfo.get('run_as_root', False)
sh.execute(*cmd_to_run, run_as_root=root_run, process_input=stdin, **kargs)
def fetch_dependencies(component, add=False):
if(add):
deps = list([component])
else:
deps = list()
cdeps = get_dependencies(component)
if(cdeps and len(cdeps)):
for d in cdeps:
deps = deps + fetch_dependencies(d, True)
return deps
def prioritize_components(components):
#get the right component order (by priority)
mporder = dict()
priorities = constants.COMPONENT_NAMES_PRIORITY
for c in components:
priority = priorities.get(c)
if(priority == None):
priority = sys.maxint
mporder[c] = priority
#sort by priority value
priority_order = sorted(mporder.iteritems(), key=operator.itemgetter(1))
#extract the right order
component_order = [x[0] for x in priority_order]
return component_order
def component_paths(root, component_name):
component_root = sh.joinpths(root, component_name)
tracedir = sh.joinpths(component_root, constants.COMPONENT_TRACE_DIR)
appdir = sh.joinpths(component_root, constants.COMPONENT_APP_DIR)
cfgdir = sh.joinpths(component_root, constants.COMPONENT_CONFIG_DIR)
return (component_root, tracedir, appdir, cfgdir)
def load_json(fn):
data = sh.load_file(fn)
lines = data.splitlines()
new_lines = list()
for line in lines:
if(line.lstrip().startswith('#')):
continue
new_lines.append(line)
data = joinlinesep(*new_lines)
return json.loads(data)
def get_host_ip(cfg=None):
ip = None
if(cfg):
cfg_ip = cfg.get('default', 'host_ip')
if(cfg_ip and len(cfg_ip)):
ip = cfg_ip
if(ip == None):
interfaces = get_interfaces()
def_info = interfaces.get(constants.DEFAULT_NET_INTERFACE)
if(def_info):
ipinfo = def_info.get(constants.DEFAULT_NET_INTERFACE_IP_VERSION)
if(ipinfo):
ip = ipinfo.get('addr')
if(ip == None):
msg = "Your host does not have an ip address!"
raise excp.NoIpException(msg)
LOG.debug("Determined host ip to be: \"%s\"" % (ip))
return ip
def get_interfaces():
interfaces = dict()
for intfc in netifaces.interfaces():
interface_info = dict()
interface_addresses = netifaces.ifaddresses(intfc)
ip6 = interface_addresses.get(netifaces.AF_INET6)
if(ip6 and len(ip6)):
#just take the first
interface_info[constants.IPV6] = ip6[0]
ip4 = interface_addresses.get(netifaces.AF_INET)
if(ip4 and len(ip4)):
#just take the first
interface_info[constants.IPV4] = ip4[0]
#there are others but this is good for now
interfaces[intfc] = interface_info
return interfaces
def determine_distro():
plt = platform.platform()
#ensure its a linux distro
(distname, version, id) = platform.linux_distribution()
if(not distname):
return (None, plt)
#attempt to match it to our platforms
found_os = None
for (known_os, pattern) in constants.KNOWN_DISTROS.items():
if(pattern.search(plt)):
found_os = known_os
break
return (found_os, plt)
def get_pip_list(distro, component):
LOG.info("Getting pip packages for distro %s and component %s." % (distro, component))
all_pkgs = dict()
fns = constants.PIP_MAP.get(component)
if(fns == None):
return all_pkgs
#load + merge them
for fn in fns:
js = load_json(fn)
distro_pkgs = js.get(distro)
if(distro_pkgs and len(distro_pkgs)):
combined = dict(all_pkgs)
for (pkgname, pkginfo) in distro_pkgs.items():
#we currently just overwrite
combined[pkgname] = pkginfo
all_pkgs = combined
return all_pkgs
def get_pkg_list(distro, component):
LOG.info("Getting packages for distro %s and component %s." % (distro, component))
all_pkgs = dict()
fns = constants.PKG_MAP.get(component)
if(fns == None):
return all_pkgs
#load + merge them
for fn in fns:
js = load_json(fn)
distro_pkgs = js.get(distro)
if(distro_pkgs and len(distro_pkgs)):
combined = dict(all_pkgs)
for (pkgname, pkginfo) in distro_pkgs.items():
if(pkgname in all_pkgs.keys()):
oldpkginfo = all_pkgs.get(pkgname) or dict()
newpkginfo = dict(oldpkginfo)
for (infokey, infovalue) in pkginfo.items():
#this is expected to be a list of cmd actions
#so merge that accordingly
if(infokey == constants.PRE_INSTALL or infokey == constants.POST_INSTALL):
oldinstalllist = oldpkginfo.get(infokey) or []
infovalue = oldinstalllist + infovalue
newpkginfo[infokey] = infovalue
combined[pkgname] = newpkginfo
else:
combined[pkgname] = pkginfo
all_pkgs = combined
return all_pkgs
def joinlinesep(*pieces):
return os.linesep.join(pieces)
def param_replace(text, replacements, ignore_missing=False):
if(not replacements or len(replacements) == 0):
return text
if(len(text) == 0):
return text
if(ignore_missing):
LOG.debug("Performing parameter replacements (ignoring missing) on %s" % (text))
else:
LOG.debug("Performing parameter replacements (not ignoring missing) on %s" % (text))
def replacer(match):
org = match.group(0)
name = match.group(1)
v = replacements.get(name)
if(v == None and ignore_missing):
v = org
elif(v == None and not ignore_missing):
msg = "No replacement found for parameter %s" % (org)
raise excp.NoReplacementException(msg)
else:
LOG.debug("Replacing [%s] with [%s]" % (org, str(v)))
return str(v)
return PARAM_SUB_REGEX.sub(replacer, text)
def welcome(program_action):
formatted_action = constants.WELCOME_MAP.get(program_action, "")
ver_str = version.version_string()
lower = "!%s %s!" % (formatted_action.upper(), ver_str)
welcome = r'''
___ ____ _____ _ _ ____ _____ _ ____ _ __
/ _ \| _ \| ____| \ | / ___|_ _|/ \ / ___| |/ /
| | | | |_) | _| | \| \___ \ | | / _ \| | | ' /
| |_| | __/| |___| |\ |___) || |/ ___ \ |___| . \
\___/|_| |_____|_| \_|____/ |_/_/ \_\____|_|\_\
'''
#this seems needed, weird...
welcome = " " + welcome.strip()
max_len = 0
for line in welcome.splitlines():
if(len(line) > max_len):
max_len = len(line)
lower_out = colored(constants.PROG_NICE_NAME, 'green') + \
": " + colored(lower, 'blue')
center_len = (max_len + max_len/3)
lower_out = string.center(lower_out, center_len)
msg = welcome + os.linesep + lower_out
print(msg)