|
Packit Service |
a04d08 |
# Copyright (C) 2011 Canonical Ltd.
|
|
Packit Service |
a04d08 |
# Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
|
|
Packit Service |
a04d08 |
# Copyright (C) 2012 Yahoo! Inc.
|
|
Packit Service |
a04d08 |
#
|
|
Packit Service |
a04d08 |
# Author: Scott Moser <scott.moser@canonical.com>
|
|
Packit Service |
a04d08 |
# Author: Juerg Hafliger <juerg.haefliger@hp.com>
|
|
Packit Service |
a04d08 |
# Author: Joshua Harlow <harlowja@yahoo-inc.com>
|
|
Packit Service |
a04d08 |
#
|
|
Packit Service |
a04d08 |
# This file is part of cloud-init. See LICENSE file for license information.
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
import base64
|
|
Packit Service |
a04d08 |
import os
|
|
Packit Service |
a04d08 |
import re
|
|
Packit Service |
a04d08 |
import time
|
|
Packit Service |
9bfd13 |
from xml.dom import minidom
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
from cloudinit import log as logging
|
|
Packit Service |
a04d08 |
from cloudinit import sources
|
|
Packit Service |
9bfd13 |
from cloudinit import subp
|
|
Packit Service |
a04d08 |
from cloudinit import util
|
|
Packit Service |
a04d08 |
from cloudinit.sources.helpers.vmware.imc.config \
|
|
Packit Service |
a04d08 |
import Config
|
|
Packit Service |
a04d08 |
from cloudinit.sources.helpers.vmware.imc.config_custom_script \
|
|
Packit Service |
a04d08 |
import PreCustomScript, PostCustomScript
|
|
Packit Service |
a04d08 |
from cloudinit.sources.helpers.vmware.imc.config_file \
|
|
Packit Service |
a04d08 |
import ConfigFile
|
|
Packit Service |
a04d08 |
from cloudinit.sources.helpers.vmware.imc.config_nic \
|
|
Packit Service |
a04d08 |
import NicConfigurator
|
|
Packit Service |
a04d08 |
from cloudinit.sources.helpers.vmware.imc.config_passwd \
|
|
Packit Service |
a04d08 |
import PasswordConfigurator
|
|
Packit Service |
a04d08 |
from cloudinit.sources.helpers.vmware.imc.guestcust_error \
|
|
Packit Service |
a04d08 |
import GuestCustErrorEnum
|
|
Packit Service |
a04d08 |
from cloudinit.sources.helpers.vmware.imc.guestcust_event \
|
|
Packit Service |
a04d08 |
import GuestCustEventEnum as GuestCustEvent
|
|
Packit Service |
a04d08 |
from cloudinit.sources.helpers.vmware.imc.guestcust_state \
|
|
Packit Service |
a04d08 |
import GuestCustStateEnum
|
|
Packit Service |
a04d08 |
from cloudinit.sources.helpers.vmware.imc.guestcust_util import (
|
|
Packit Service |
a04d08 |
enable_nics,
|
|
Packit Service |
a04d08 |
get_nics_to_enable,
|
|
Packit Service |
a04d08 |
set_customization_status,
|
|
Packit Service |
9bfd13 |
get_tools_config,
|
|
Packit Service |
9bfd13 |
set_gc_status
|
|
Packit Service |
a04d08 |
)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
LOG = logging.getLogger(__name__)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
CONFGROUPNAME_GUESTCUSTOMIZATION = "deployPkg"
|
|
Packit Service |
a04d08 |
GUESTCUSTOMIZATION_ENABLE_CUST_SCRIPTS = "enable-custom-scripts"
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class DataSourceOVF(sources.DataSource):
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
dsname = "OVF"
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def __init__(self, sys_cfg, distro, paths):
|
|
Packit Service |
a04d08 |
sources.DataSource.__init__(self, sys_cfg, distro, paths)
|
|
Packit Service |
a04d08 |
self.seed = None
|
|
Packit Service |
a04d08 |
self.seed_dir = os.path.join(paths.seed_dir, 'ovf')
|
|
Packit Service |
a04d08 |
self.environment = None
|
|
Packit Service |
a04d08 |
self.cfg = {}
|
|
Packit Service |
a04d08 |
self.supported_seed_starts = ("/", "file://")
|
|
Packit Service |
a04d08 |
self.vmware_customization_supported = True
|
|
Packit Service |
a04d08 |
self._network_config = None
|
|
Packit Service |
a04d08 |
self._vmware_nics_to_enable = None
|
|
Packit Service |
a04d08 |
self._vmware_cust_conf = None
|
|
Packit Service |
a04d08 |
self._vmware_cust_found = False
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def __str__(self):
|
|
Packit Service |
a04d08 |
root = sources.DataSource.__str__(self)
|
|
Packit Service |
a04d08 |
return "%s [seed=%s]" % (root, self.seed)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _get_data(self):
|
|
Packit Service |
a04d08 |
found = []
|
|
Packit Service |
a04d08 |
md = {}
|
|
Packit Service |
a04d08 |
ud = ""
|
|
Packit Service |
a04d08 |
vmwareImcConfigFilePath = None
|
|
Packit Service |
a04d08 |
nicspath = None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
defaults = {
|
|
Packit Service |
a04d08 |
"instance-id": "iid-dsovf",
|
|
Packit Service |
a04d08 |
}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
(seedfile, contents) = get_ovf_env(self.paths.seed_dir)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
system_type = util.read_dmi_data("system-product-name")
|
|
Packit Service |
a04d08 |
if system_type is None:
|
|
Packit Service |
a04d08 |
LOG.debug("No system-product-name found")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if seedfile:
|
|
Packit Service |
a04d08 |
# Found a seed dir
|
|
Packit Service |
a04d08 |
seed = os.path.join(self.paths.seed_dir, seedfile)
|
|
Packit Service |
a04d08 |
(md, ud, cfg) = read_ovf_environment(contents)
|
|
Packit Service |
a04d08 |
self.environment = contents
|
|
Packit Service |
a04d08 |
found.append(seed)
|
|
Packit Service |
a04d08 |
elif system_type and 'vmware' in system_type.lower():
|
|
Packit Service |
a04d08 |
LOG.debug("VMware Virtualization Platform found")
|
|
Packit Service |
a04d08 |
if not self.vmware_customization_supported:
|
|
Packit Service |
a04d08 |
LOG.debug("Skipping the check for "
|
|
Packit Service |
a04d08 |
"VMware Customization support")
|
|
Packit Service |
a04d08 |
elif not util.get_cfg_option_bool(
|
|
Packit Service |
a04d08 |
self.sys_cfg, "disable_vmware_customization", True):
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
search_paths = (
|
|
Packit Service |
a04d08 |
"/usr/lib/vmware-tools", "/usr/lib64/vmware-tools",
|
|
Packit Service |
a04d08 |
"/usr/lib/open-vm-tools", "/usr/lib64/open-vm-tools")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
plugin = "libdeployPkgPlugin.so"
|
|
Packit Service |
a04d08 |
deployPkgPluginPath = None
|
|
Packit Service |
a04d08 |
for path in search_paths:
|
|
Packit Service |
a04d08 |
deployPkgPluginPath = search_file(path, plugin)
|
|
Packit Service |
a04d08 |
if deployPkgPluginPath:
|
|
Packit Service |
a04d08 |
LOG.debug("Found the customization plugin at %s",
|
|
Packit Service |
a04d08 |
deployPkgPluginPath)
|
|
Packit Service |
a04d08 |
break
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if deployPkgPluginPath:
|
|
Packit Service |
a04d08 |
# When the VM is powered on, the "VMware Tools" daemon
|
|
Packit Service |
a04d08 |
# copies the customization specification file to
|
|
Packit Service |
a04d08 |
# /var/run/vmware-imc directory. cloud-init code needs
|
|
Packit Service |
a04d08 |
# to search for the file in that directory.
|
|
Packit Service |
a04d08 |
max_wait = get_max_wait_from_cfg(self.ds_cfg)
|
|
Packit Service |
a04d08 |
vmwareImcConfigFilePath = util.log_time(
|
|
Packit Service |
a04d08 |
logfunc=LOG.debug,
|
|
Packit Service |
a04d08 |
msg="waiting for configuration file",
|
|
Packit Service |
a04d08 |
func=wait_for_imc_cfg_file,
|
|
Packit Service |
a04d08 |
args=("cust.cfg", max_wait))
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
LOG.debug("Did not find the customization plugin.")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if vmwareImcConfigFilePath:
|
|
Packit Service |
a04d08 |
LOG.debug("Found VMware Customization Config File at %s",
|
|
Packit Service |
a04d08 |
vmwareImcConfigFilePath)
|
|
Packit Service |
a04d08 |
nicspath = wait_for_imc_cfg_file(
|
|
Packit Service |
a04d08 |
filename="nics.txt", maxwait=10, naplen=5)
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
LOG.debug("Did not find VMware Customization Config File")
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
LOG.debug("Customization for VMware platform is disabled.")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if vmwareImcConfigFilePath:
|
|
Packit Service |
a04d08 |
self._vmware_nics_to_enable = ""
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
cf = ConfigFile(vmwareImcConfigFilePath)
|
|
Packit Service |
a04d08 |
self._vmware_cust_conf = Config(cf)
|
|
Packit Service |
9bfd13 |
set_gc_status(self._vmware_cust_conf, "Started")
|
|
Packit Service |
9bfd13 |
|
|
Packit Service |
a04d08 |
(md, ud, cfg) = read_vmware_imc(self._vmware_cust_conf)
|
|
Packit Service |
a04d08 |
self._vmware_nics_to_enable = get_nics_to_enable(nicspath)
|
|
Packit Service |
a04d08 |
imcdirpath = os.path.dirname(vmwareImcConfigFilePath)
|
|
Packit Service |
a04d08 |
product_marker = self._vmware_cust_conf.marker_id
|
|
Packit Service |
a04d08 |
hasmarkerfile = check_marker_exists(
|
|
Packit Service |
a04d08 |
product_marker, os.path.join(self.paths.cloud_dir, 'data'))
|
|
Packit Service |
a04d08 |
special_customization = product_marker and not hasmarkerfile
|
|
Packit Service |
a04d08 |
customscript = self._vmware_cust_conf.custom_script_name
|
|
Packit Service |
9bfd13 |
|
|
Packit Service |
9bfd13 |
# In case there is a custom script, check whether VMware
|
|
Packit Service |
9bfd13 |
# Tools configuration allow the custom script to run.
|
|
Packit Service |
9bfd13 |
if special_customization and customscript:
|
|
Packit Service |
9bfd13 |
defVal = "false"
|
|
Packit Service |
9bfd13 |
if self._vmware_cust_conf.default_run_post_script:
|
|
Packit Service |
9bfd13 |
LOG.debug(
|
|
Packit Service |
9bfd13 |
"Set default value to true due to"
|
|
Packit Service |
9bfd13 |
" customization configuration."
|
|
Packit Service |
9bfd13 |
)
|
|
Packit Service |
9bfd13 |
defVal = "true"
|
|
Packit Service |
9bfd13 |
|
|
Packit Service |
9bfd13 |
custScriptConfig = get_tools_config(
|
|
Packit Service |
9bfd13 |
CONFGROUPNAME_GUESTCUSTOMIZATION,
|
|
Packit Service |
9bfd13 |
GUESTCUSTOMIZATION_ENABLE_CUST_SCRIPTS,
|
|
Packit Service |
9bfd13 |
defVal)
|
|
Packit Service |
9bfd13 |
if custScriptConfig.lower() != "true":
|
|
Packit Service |
9bfd13 |
# Update the customization status if custom script
|
|
Packit Service |
9bfd13 |
# is disabled
|
|
Packit Service |
a04d08 |
msg = "Custom script is disabled by VM Administrator"
|
|
Packit Service |
a04d08 |
LOG.debug(msg)
|
|
Packit Service |
a04d08 |
set_customization_status(
|
|
Packit Service |
a04d08 |
GuestCustStateEnum.GUESTCUST_STATE_RUNNING,
|
|
Packit Service |
a04d08 |
GuestCustErrorEnum.GUESTCUST_ERROR_SCRIPT_DISABLED)
|
|
Packit Service |
a04d08 |
raise RuntimeError(msg)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
ccScriptsDir = os.path.join(
|
|
Packit Service |
a04d08 |
self.paths.get_cpath("scripts"),
|
|
Packit Service |
a04d08 |
"per-instance")
|
|
Packit Service |
a04d08 |
except Exception as e:
|
|
Packit Service |
a04d08 |
_raise_error_status(
|
|
Packit Service |
a04d08 |
"Error parsing the customization Config File",
|
|
Packit Service |
a04d08 |
e,
|
|
Packit Service |
a04d08 |
GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
|
|
Packit Service |
9bfd13 |
vmwareImcConfigFilePath,
|
|
Packit Service |
9bfd13 |
self._vmware_cust_conf)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if special_customization:
|
|
Packit Service |
a04d08 |
if customscript:
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
precust = PreCustomScript(customscript, imcdirpath)
|
|
Packit Service |
a04d08 |
precust.execute()
|
|
Packit Service |
a04d08 |
except Exception as e:
|
|
Packit Service |
a04d08 |
_raise_error_status(
|
|
Packit Service |
a04d08 |
"Error executing pre-customization script",
|
|
Packit Service |
a04d08 |
e,
|
|
Packit Service |
a04d08 |
GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
|
|
Packit Service |
9bfd13 |
vmwareImcConfigFilePath,
|
|
Packit Service |
9bfd13 |
self._vmware_cust_conf)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
LOG.debug("Preparing the Network configuration")
|
|
Packit Service |
a04d08 |
self._network_config = get_network_config_from_conf(
|
|
Packit Service |
a04d08 |
self._vmware_cust_conf,
|
|
Packit Service |
a04d08 |
True,
|
|
Packit Service |
a04d08 |
True,
|
|
Packit Service |
a04d08 |
self.distro.osfamily)
|
|
Packit Service |
a04d08 |
except Exception as e:
|
|
Packit Service |
a04d08 |
_raise_error_status(
|
|
Packit Service |
a04d08 |
"Error preparing Network Configuration",
|
|
Packit Service |
a04d08 |
e,
|
|
Packit Service |
a04d08 |
GuestCustEvent.GUESTCUST_EVENT_NETWORK_SETUP_FAILED,
|
|
Packit Service |
9bfd13 |
vmwareImcConfigFilePath,
|
|
Packit Service |
9bfd13 |
self._vmware_cust_conf)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if special_customization:
|
|
Packit Service |
a04d08 |
LOG.debug("Applying password customization")
|
|
Packit Service |
a04d08 |
pwdConfigurator = PasswordConfigurator()
|
|
Packit Service |
a04d08 |
adminpwd = self._vmware_cust_conf.admin_password
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
resetpwd = self._vmware_cust_conf.reset_password
|
|
Packit Service |
a04d08 |
if adminpwd or resetpwd:
|
|
Packit Service |
a04d08 |
pwdConfigurator.configure(adminpwd, resetpwd,
|
|
Packit Service |
a04d08 |
self.distro)
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
LOG.debug("Changing password is not needed")
|
|
Packit Service |
a04d08 |
except Exception as e:
|
|
Packit Service |
a04d08 |
_raise_error_status(
|
|
Packit Service |
a04d08 |
"Error applying Password Configuration",
|
|
Packit Service |
a04d08 |
e,
|
|
Packit Service |
a04d08 |
GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
|
|
Packit Service |
9bfd13 |
vmwareImcConfigFilePath,
|
|
Packit Service |
9bfd13 |
self._vmware_cust_conf)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if customscript:
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
postcust = PostCustomScript(customscript,
|
|
Packit Service |
a04d08 |
imcdirpath,
|
|
Packit Service |
a04d08 |
ccScriptsDir)
|
|
Packit Service |
a04d08 |
postcust.execute()
|
|
Packit Service |
a04d08 |
except Exception as e:
|
|
Packit Service |
a04d08 |
_raise_error_status(
|
|
Packit Service |
a04d08 |
"Error executing post-customization script",
|
|
Packit Service |
a04d08 |
e,
|
|
Packit Service |
a04d08 |
GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
|
|
Packit Service |
9bfd13 |
vmwareImcConfigFilePath,
|
|
Packit Service |
9bfd13 |
self._vmware_cust_conf)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if product_marker:
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
setup_marker_files(
|
|
Packit Service |
a04d08 |
product_marker,
|
|
Packit Service |
a04d08 |
os.path.join(self.paths.cloud_dir, 'data'))
|
|
Packit Service |
a04d08 |
except Exception as e:
|
|
Packit Service |
a04d08 |
_raise_error_status(
|
|
Packit Service |
a04d08 |
"Error creating marker files",
|
|
Packit Service |
a04d08 |
e,
|
|
Packit Service |
a04d08 |
GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED,
|
|
Packit Service |
9bfd13 |
vmwareImcConfigFilePath,
|
|
Packit Service |
9bfd13 |
self._vmware_cust_conf)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
self._vmware_cust_found = True
|
|
Packit Service |
a04d08 |
found.append('vmware-tools')
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# TODO: Need to set the status to DONE only when the
|
|
Packit Service |
a04d08 |
# customization is done successfully.
|
|
Packit Service |
a04d08 |
util.del_dir(os.path.dirname(vmwareImcConfigFilePath))
|
|
Packit Service |
a04d08 |
enable_nics(self._vmware_nics_to_enable)
|
|
Packit Service |
a04d08 |
set_customization_status(
|
|
Packit Service |
a04d08 |
GuestCustStateEnum.GUESTCUST_STATE_DONE,
|
|
Packit Service |
a04d08 |
GuestCustErrorEnum.GUESTCUST_ERROR_SUCCESS)
|
|
Packit Service |
9bfd13 |
set_gc_status(self._vmware_cust_conf, "Successful")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
np = [('com.vmware.guestInfo', transport_vmware_guestinfo),
|
|
Packit Service |
a04d08 |
('iso', transport_iso9660)]
|
|
Packit Service |
a04d08 |
name = None
|
|
Packit Service |
a04d08 |
for name, transfunc in np:
|
|
Packit Service |
a04d08 |
contents = transfunc()
|
|
Packit Service |
a04d08 |
if contents:
|
|
Packit Service |
a04d08 |
break
|
|
Packit Service |
a04d08 |
if contents:
|
|
Packit Service |
a04d08 |
(md, ud, cfg) = read_ovf_environment(contents)
|
|
Packit Service |
a04d08 |
self.environment = contents
|
|
Packit Service |
a04d08 |
found.append(name)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# There was no OVF transports found
|
|
Packit Service |
a04d08 |
if len(found) == 0:
|
|
Packit Service |
a04d08 |
return False
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if 'seedfrom' in md and md['seedfrom']:
|
|
Packit Service |
a04d08 |
seedfrom = md['seedfrom']
|
|
Packit Service |
a04d08 |
seedfound = False
|
|
Packit Service |
a04d08 |
for proto in self.supported_seed_starts:
|
|
Packit Service |
a04d08 |
if seedfrom.startswith(proto):
|
|
Packit Service |
a04d08 |
seedfound = proto
|
|
Packit Service |
a04d08 |
break
|
|
Packit Service |
a04d08 |
if not seedfound:
|
|
Packit Service |
a04d08 |
LOG.debug("Seed from %s not supported by %s",
|
|
Packit Service |
a04d08 |
seedfrom, self)
|
|
Packit Service |
a04d08 |
return False
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
(md_seed, ud) = util.read_seeded(seedfrom, timeout=None)
|
|
Packit Service |
a04d08 |
LOG.debug("Using seeded cache data from %s", seedfrom)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
md = util.mergemanydict([md, md_seed])
|
|
Packit Service |
a04d08 |
found.append(seedfrom)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Now that we have exhausted any other places merge in the defaults
|
|
Packit Service |
a04d08 |
md = util.mergemanydict([md, defaults])
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
self.seed = ",".join(found)
|
|
Packit Service |
a04d08 |
self.metadata = md
|
|
Packit Service |
a04d08 |
self.userdata_raw = ud
|
|
Packit Service |
a04d08 |
self.cfg = cfg
|
|
Packit Service |
a04d08 |
return True
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def _get_subplatform(self):
|
|
Packit Service |
a04d08 |
system_type = util.read_dmi_data("system-product-name").lower()
|
|
Packit Service |
a04d08 |
if system_type == 'vmware':
|
|
Packit Service |
a04d08 |
return 'vmware (%s)' % self.seed
|
|
Packit Service |
a04d08 |
return 'ovf (%s)' % self.seed
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_public_ssh_keys(self):
|
|
Packit Service |
a04d08 |
if 'public-keys' not in self.metadata:
|
|
Packit Service |
a04d08 |
return []
|
|
Packit Service |
a04d08 |
pks = self.metadata['public-keys']
|
|
Packit Service |
a04d08 |
if isinstance(pks, (list)):
|
|
Packit Service |
a04d08 |
return pks
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
return [pks]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# The data sources' config_obj is a cloud-config formatted
|
|
Packit Service |
a04d08 |
# object that came to it from ways other than cloud-config
|
|
Packit Service |
a04d08 |
# because cloud-config content would be handled elsewhere
|
|
Packit Service |
a04d08 |
def get_config_obj(self):
|
|
Packit Service |
a04d08 |
return self.cfg
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
@property
|
|
Packit Service |
a04d08 |
def network_config(self):
|
|
Packit Service |
a04d08 |
return self._network_config
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class DataSourceOVFNet(DataSourceOVF):
|
|
Packit Service |
a04d08 |
def __init__(self, sys_cfg, distro, paths):
|
|
Packit Service |
a04d08 |
DataSourceOVF.__init__(self, sys_cfg, distro, paths)
|
|
Packit Service |
a04d08 |
self.seed_dir = os.path.join(paths.seed_dir, 'ovf-net')
|
|
Packit Service |
9bfd13 |
self.supported_seed_starts = ("http://", "https://")
|
|
Packit Service |
a04d08 |
self.vmware_customization_supported = False
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_max_wait_from_cfg(cfg):
|
|
Packit Service |
a04d08 |
default_max_wait = 90
|
|
Packit Service |
a04d08 |
max_wait_cfg_option = 'vmware_cust_file_max_wait'
|
|
Packit Service |
a04d08 |
max_wait = default_max_wait
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if not cfg:
|
|
Packit Service |
a04d08 |
return max_wait
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
max_wait = int(cfg.get(max_wait_cfg_option, default_max_wait))
|
|
Packit Service |
a04d08 |
except ValueError:
|
|
Packit Service |
a04d08 |
LOG.warning("Failed to get '%s', using %s",
|
|
Packit Service |
a04d08 |
max_wait_cfg_option, default_max_wait)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if max_wait <= 0:
|
|
Packit Service |
a04d08 |
LOG.warning("Invalid value '%s' for '%s', using '%s' instead",
|
|
Packit Service |
a04d08 |
max_wait, max_wait_cfg_option, default_max_wait)
|
|
Packit Service |
a04d08 |
max_wait = default_max_wait
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return max_wait
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def wait_for_imc_cfg_file(filename, maxwait=180, naplen=5,
|
|
Packit Service |
a04d08 |
dirpath="/var/run/vmware-imc"):
|
|
Packit Service |
a04d08 |
waited = 0
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
while waited < maxwait:
|
|
Packit Service |
a04d08 |
fileFullPath = os.path.join(dirpath, filename)
|
|
Packit Service |
a04d08 |
if os.path.isfile(fileFullPath):
|
|
Packit Service |
a04d08 |
return fileFullPath
|
|
Packit Service |
a04d08 |
LOG.debug("Waiting for VMware Customization Config File")
|
|
Packit Service |
a04d08 |
time.sleep(naplen)
|
|
Packit Service |
a04d08 |
waited += naplen
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_network_config_from_conf(config, use_system_devices=True,
|
|
Packit Service |
a04d08 |
configure=False, osfamily=None):
|
|
Packit Service |
a04d08 |
nicConfigurator = NicConfigurator(config.nics, use_system_devices)
|
|
Packit Service |
a04d08 |
nics_cfg_list = nicConfigurator.generate(configure, osfamily)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return get_network_config(nics_cfg_list,
|
|
Packit Service |
a04d08 |
config.name_servers,
|
|
Packit Service |
a04d08 |
config.dns_suffixes)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_network_config(nics=None, nameservers=None, search=None):
|
|
Packit Service |
a04d08 |
config_list = nics
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if nameservers or search:
|
|
Packit Service |
a04d08 |
config_list.append({'type': 'nameserver', 'address': nameservers,
|
|
Packit Service |
a04d08 |
'search': search})
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return {'version': 1, 'config': config_list}
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# This will return a dict with some content
|
|
Packit Service |
a04d08 |
# meta-data, user-data, some config
|
|
Packit Service |
a04d08 |
def read_vmware_imc(config):
|
|
Packit Service |
a04d08 |
md = {}
|
|
Packit Service |
a04d08 |
cfg = {}
|
|
Packit Service |
a04d08 |
ud = None
|
|
Packit Service |
a04d08 |
if config.host_name:
|
|
Packit Service |
a04d08 |
if config.domain_name:
|
|
Packit Service |
a04d08 |
md['local-hostname'] = config.host_name + "." + config.domain_name
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
md['local-hostname'] = config.host_name
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if config.timezone:
|
|
Packit Service |
a04d08 |
cfg['timezone'] = config.timezone
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
md['instance-id'] = "iid-vmware-imc"
|
|
Packit Service |
a04d08 |
return (md, ud, cfg)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# This will return a dict with some content
|
|
Packit Service |
a04d08 |
# meta-data, user-data, some config
|
|
Packit Service |
a04d08 |
def read_ovf_environment(contents):
|
|
Packit Service |
a04d08 |
props = get_properties(contents)
|
|
Packit Service |
a04d08 |
md = {}
|
|
Packit Service |
a04d08 |
cfg = {}
|
|
Packit Service |
a04d08 |
ud = None
|
|
Packit Service |
a04d08 |
cfg_props = ['password']
|
|
Packit Service |
a04d08 |
md_props = ['seedfrom', 'local-hostname', 'public-keys', 'instance-id']
|
|
Packit Service |
a04d08 |
for (prop, val) in props.items():
|
|
Packit Service |
a04d08 |
if prop == 'hostname':
|
|
Packit Service |
a04d08 |
prop = "local-hostname"
|
|
Packit Service |
a04d08 |
if prop in md_props:
|
|
Packit Service |
a04d08 |
md[prop] = val
|
|
Packit Service |
a04d08 |
elif prop in cfg_props:
|
|
Packit Service |
a04d08 |
cfg[prop] = val
|
|
Packit Service |
a04d08 |
elif prop == "user-data":
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
ud = base64.b64decode(val.encode())
|
|
Packit Service |
a04d08 |
except Exception:
|
|
Packit Service |
a04d08 |
ud = val.encode()
|
|
Packit Service |
a04d08 |
return (md, ud, cfg)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Returns tuple of filename (in 'dirname', and the contents of the file)
|
|
Packit Service |
a04d08 |
# on "not found", returns 'None' for filename and False for contents
|
|
Packit Service |
a04d08 |
def get_ovf_env(dirname):
|
|
Packit Service |
a04d08 |
env_names = ("ovf-env.xml", "ovf_env.xml", "OVF_ENV.XML", "OVF-ENV.XML")
|
|
Packit Service |
a04d08 |
for fname in env_names:
|
|
Packit Service |
a04d08 |
full_fn = os.path.join(dirname, fname)
|
|
Packit Service |
a04d08 |
if os.path.isfile(full_fn):
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
contents = util.load_file(full_fn)
|
|
Packit Service |
a04d08 |
return (fname, contents)
|
|
Packit Service |
a04d08 |
except Exception:
|
|
Packit Service |
a04d08 |
util.logexc(LOG, "Failed loading ovf file %s", full_fn)
|
|
Packit Service |
a04d08 |
return (None, False)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def maybe_cdrom_device(devname):
|
|
Packit Service |
a04d08 |
"""Test if devname matches known list of devices which may contain iso9660
|
|
Packit Service |
a04d08 |
filesystems.
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
Be helpful in accepting either knames (with no leading /dev/) or full path
|
|
Packit Service |
a04d08 |
names, but do not allow paths outside of /dev/, like /dev/foo/bar/xxx.
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
if not devname:
|
|
Packit Service |
a04d08 |
return False
|
|
Packit Service |
9bfd13 |
elif not isinstance(devname, str):
|
|
Packit Service |
a04d08 |
raise ValueError("Unexpected input for devname: %s" % devname)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# resolve '..' and multi '/' elements
|
|
Packit Service |
a04d08 |
devname = os.path.normpath(devname)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# drop leading '/dev/'
|
|
Packit Service |
a04d08 |
if devname.startswith("/dev/"):
|
|
Packit Service |
a04d08 |
# partition returns tuple (before, partition, after)
|
|
Packit Service |
a04d08 |
devname = devname.partition("/dev/")[-1]
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# ignore leading slash (/sr0), else fail on / in name (foo/bar/xvdc)
|
|
Packit Service |
a04d08 |
if devname.startswith("/"):
|
|
Packit Service |
a04d08 |
devname = devname.split("/")[-1]
|
|
Packit Service |
a04d08 |
elif devname.count("/") > 0:
|
|
Packit Service |
a04d08 |
return False
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# if empty string
|
|
Packit Service |
a04d08 |
if not devname:
|
|
Packit Service |
a04d08 |
return False
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# default_regex matches values in /lib/udev/rules.d/60-cdrom_id.rules
|
|
Packit Service |
a04d08 |
# KERNEL!="sr[0-9]*|hd[a-z]|xvd*", GOTO="cdrom_end"
|
|
Packit Service |
a04d08 |
default_regex = r"^(sr[0-9]+|hd[a-z]|xvd.*)"
|
|
Packit Service |
a04d08 |
devname_regex = os.environ.get("CLOUD_INIT_CDROM_DEV_REGEX", default_regex)
|
|
Packit Service |
a04d08 |
cdmatch = re.compile(devname_regex)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return cdmatch.match(devname) is not None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Transport functions are called with no arguments and return
|
|
Packit Service |
a04d08 |
# either None (indicating not present) or string content of an ovf-env.xml
|
|
Packit Service |
a04d08 |
def transport_iso9660(require_iso=True):
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Go through mounts to see if it was already mounted
|
|
Packit Service |
a04d08 |
mounts = util.mounts()
|
|
Packit Service |
a04d08 |
for (dev, info) in mounts.items():
|
|
Packit Service |
a04d08 |
fstype = info['fstype']
|
|
Packit Service |
a04d08 |
if fstype != "iso9660" and require_iso:
|
|
Packit Service |
a04d08 |
continue
|
|
Packit Service |
a04d08 |
if not maybe_cdrom_device(dev):
|
|
Packit Service |
a04d08 |
continue
|
|
Packit Service |
a04d08 |
mp = info['mountpoint']
|
|
Packit Service |
a04d08 |
(_fname, contents) = get_ovf_env(mp)
|
|
Packit Service |
a04d08 |
if contents is not False:
|
|
Packit Service |
a04d08 |
return contents
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if require_iso:
|
|
Packit Service |
a04d08 |
mtype = "iso9660"
|
|
Packit Service |
a04d08 |
else:
|
|
Packit Service |
a04d08 |
mtype = None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# generate a list of devices with mtype filesystem, filter by regex
|
|
Packit Service |
a04d08 |
devs = [dev for dev in
|
|
Packit Service |
a04d08 |
util.find_devs_with("TYPE=%s" % mtype if mtype else None)
|
|
Packit Service |
a04d08 |
if maybe_cdrom_device(dev)]
|
|
Packit Service |
a04d08 |
for dev in devs:
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
a04d08 |
(_fname, contents) = util.mount_cb(dev, get_ovf_env, mtype=mtype)
|
|
Packit Service |
a04d08 |
except util.MountFailedError:
|
|
Packit Service |
a04d08 |
LOG.debug("%s not mountable as iso9660", dev)
|
|
Packit Service |
a04d08 |
continue
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if contents is not False:
|
|
Packit Service |
a04d08 |
return contents
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def transport_vmware_guestinfo():
|
|
Packit Service |
a04d08 |
rpctool = "vmware-rpctool"
|
|
Packit Service |
a04d08 |
not_found = None
|
|
Packit Service |
9bfd13 |
if not subp.which(rpctool):
|
|
Packit Service |
a04d08 |
return not_found
|
|
Packit Service |
a04d08 |
cmd = [rpctool, "info-get guestinfo.ovfEnv"]
|
|
Packit Service |
a04d08 |
try:
|
|
Packit Service |
9bfd13 |
out, _err = subp.subp(cmd)
|
|
Packit Service |
a04d08 |
if out:
|
|
Packit Service |
a04d08 |
return out
|
|
Packit Service |
a04d08 |
LOG.debug("cmd %s exited 0 with empty stdout: %s", cmd, out)
|
|
Packit Service |
9bfd13 |
except subp.ProcessExecutionError as e:
|
|
Packit Service |
a04d08 |
if e.exit_code != 1:
|
|
Packit Service |
a04d08 |
LOG.warning("%s exited with code %d", rpctool, e.exit_code)
|
|
Packit Service |
a04d08 |
LOG.debug(e)
|
|
Packit Service |
a04d08 |
return not_found
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def find_child(node, filter_func):
|
|
Packit Service |
a04d08 |
ret = []
|
|
Packit Service |
a04d08 |
if not node.hasChildNodes():
|
|
Packit Service |
a04d08 |
return ret
|
|
Packit Service |
a04d08 |
for child in node.childNodes:
|
|
Packit Service |
a04d08 |
if filter_func(child):
|
|
Packit Service |
a04d08 |
ret.append(child)
|
|
Packit Service |
a04d08 |
return ret
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def get_properties(contents):
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
dom = minidom.parseString(contents)
|
|
Packit Service |
a04d08 |
if dom.documentElement.localName != "Environment":
|
|
Packit Service |
a04d08 |
raise XmlError("No Environment Node")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if not dom.documentElement.hasChildNodes():
|
|
Packit Service |
a04d08 |
raise XmlError("No Child Nodes")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
envNsURI = "http://schemas.dmtf.org/ovf/environment/1"
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# could also check here that elem.namespaceURI ==
|
|
Packit Service |
a04d08 |
# "http://schemas.dmtf.org/ovf/environment/1"
|
|
Packit Service |
a04d08 |
propSections = find_child(dom.documentElement,
|
|
Packit Service |
a04d08 |
lambda n: n.localName == "PropertySection")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
if len(propSections) == 0:
|
|
Packit Service |
a04d08 |
raise XmlError("No 'PropertySection's")
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
props = {}
|
|
Packit Service |
a04d08 |
propElems = find_child(propSections[0],
|
|
Packit Service |
a04d08 |
(lambda n: n.localName == "Property"))
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
for elem in propElems:
|
|
Packit Service |
a04d08 |
key = elem.attributes.getNamedItemNS(envNsURI, "key").value
|
|
Packit Service |
a04d08 |
val = elem.attributes.getNamedItemNS(envNsURI, "value").value
|
|
Packit Service |
a04d08 |
props[key] = val
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return props
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
def search_file(dirpath, filename):
|
|
Packit Service |
a04d08 |
if not dirpath or not filename:
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
for root, _dirs, files in os.walk(dirpath):
|
|
Packit Service |
a04d08 |
if filename in files:
|
|
Packit Service |
a04d08 |
return os.path.join(root, filename)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
return None
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
class XmlError(Exception):
|
|
Packit Service |
a04d08 |
pass
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Used to match classes to dependencies
|
|
Packit Service |
a04d08 |
datasources = (
|
|
Packit Service |
a04d08 |
(DataSourceOVF, (sources.DEP_FILESYSTEM, )),
|
|
Packit Service |
a04d08 |
(DataSourceOVFNet, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)),
|
|
Packit Service |
a04d08 |
)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Return a list of data sources that match this set of dependencies
|
|
Packit Service |
a04d08 |
def get_datasource_list(depends):
|
|
Packit Service |
a04d08 |
return sources.list_from_depends(depends, datasources)
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# To check if marker file exists
|
|
Packit Service |
a04d08 |
def check_marker_exists(markerid, marker_dir):
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
Check the existence of a marker file.
|
|
Packit Service |
a04d08 |
Presence of marker file determines whether a certain code path is to be
|
|
Packit Service |
a04d08 |
executed. It is needed for partial guest customization in VMware.
|
|
Packit Service |
a04d08 |
@param markerid: is an unique string representing a particular product
|
|
Packit Service |
a04d08 |
marker.
|
|
Packit Service |
a04d08 |
@param: marker_dir: The directory in which markers exist.
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
if not markerid:
|
|
Packit Service |
a04d08 |
return False
|
|
Packit Service |
a04d08 |
markerfile = os.path.join(marker_dir, ".markerfile-" + markerid + ".txt")
|
|
Packit Service |
a04d08 |
if os.path.exists(markerfile):
|
|
Packit Service |
a04d08 |
return True
|
|
Packit Service |
a04d08 |
return False
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# Create a marker file
|
|
Packit Service |
a04d08 |
def setup_marker_files(markerid, marker_dir):
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
Create a new marker file.
|
|
Packit Service |
a04d08 |
Marker files are unique to a full customization workflow in VMware
|
|
Packit Service |
a04d08 |
environment.
|
|
Packit Service |
a04d08 |
@param markerid: is an unique string representing a particular product
|
|
Packit Service |
a04d08 |
marker.
|
|
Packit Service |
a04d08 |
@param: marker_dir: The directory in which markers exist.
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
LOG.debug("Handle marker creation")
|
|
Packit Service |
a04d08 |
markerfile = os.path.join(marker_dir, ".markerfile-" + markerid + ".txt")
|
|
Packit Service |
a04d08 |
for fname in os.listdir(marker_dir):
|
|
Packit Service |
a04d08 |
if fname.startswith(".markerfile"):
|
|
Packit Service |
a04d08 |
util.del_file(os.path.join(marker_dir, fname))
|
|
Packit Service |
a04d08 |
open(markerfile, 'w').close()
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
9bfd13 |
def _raise_error_status(prefix, error, event, config_file, conf):
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
Raise error and send customization status to the underlying VMware
|
|
Packit Service |
a04d08 |
Virtualization Platform. Also, cleanup the imc directory.
|
|
Packit Service |
a04d08 |
"""
|
|
Packit Service |
a04d08 |
LOG.debug('%s: %s', prefix, error)
|
|
Packit Service |
a04d08 |
set_customization_status(
|
|
Packit Service |
a04d08 |
GuestCustStateEnum.GUESTCUST_STATE_RUNNING,
|
|
Packit Service |
a04d08 |
event)
|
|
Packit Service |
9bfd13 |
set_gc_status(conf, prefix)
|
|
Packit Service |
a04d08 |
util.del_dir(os.path.dirname(config_file))
|
|
Packit Service |
a04d08 |
raise error
|
|
Packit Service |
a04d08 |
|
|
Packit Service |
a04d08 |
# vi: ts=4 expandtab
|