Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

Commit

Permalink
Do not change process UID
Browse files Browse the repository at this point in the history
When run with sudo, Anvil changed process real UID
to SUDO_UID thus easily creating files with different owners.
This mechanism can confuse some tools (like pip)
Now, we can almost safely stop changing real UID and run
prepare as non-root and bootstrap, install, start, status,
and stop as root.

Also, this removes dependency on sudo.

Implements: blueprint no-uid-tricks
Fixes: bug #1179747
Fixes: bug #1186440
Fixes: bug #1186448

Change-Id: I7ae293aad7f0a5ba08962e6b6b709fe49b8b81ec
  • Loading branch information
Alessio Ababilov committed Jun 3, 2013
1 parent 8b06edd commit df60b50
Show file tree
Hide file tree
Showing 27 changed files with 254 additions and 351 deletions.
18 changes: 6 additions & 12 deletions anvil/__main__.py
Expand Up @@ -148,8 +148,7 @@ def ensure_anvil_dirs(root_dir):
if sh.isdir(d):
continue
LOG.info("Creating anvil directory at path: %s", d)
with sh.Rooted(True):
sh.mkdir(d, adjust_suids=True)
sh.mkdir(d)


def store_current_settings(c_settings):
Expand All @@ -159,14 +158,11 @@ def store_current_settings(c_settings):
for k in ['action', 'verbose', 'dryrun']:
if k in c_settings:
to_save.pop(k, None)
with sh.Rooted(True):
with open("/etc/anvil/settings.yaml", 'w') as fh:
fh.write("# Anvil last used settings\n")
fh.write(utils.add_header("/etc/anvil/settings.yaml",
utils.prettify_yaml(to_save)))
fh.flush()
(uid, gid) = sh.get_suids()
sh.chown("/etc/anvil/settings.yaml", uid, gid)
with open("/etc/anvil/settings.yaml", 'w') as fh:
fh.write("# Anvil last used settings\n")
fh.write(utils.add_header("/etc/anvil/settings.yaml",
utils.prettify_yaml(to_save)))
fh.flush()
except Exception as e:
LOG.debug("Failed writing to %s due to %s", "/etc/anvil/settings.yaml", e)

Expand All @@ -175,8 +171,6 @@ def ensure_perms():
# Ensure we are running as root to start...
if not sh.got_root():
raise excp.PermException("Root access required")
# Drop to usermode (which also ensures we can do this...)
sh.user_mode(quiet=False)


def main():
Expand Down
7 changes: 3 additions & 4 deletions anvil/components/base_install.py
Expand Up @@ -177,7 +177,6 @@ def __init__(self, *args, **kargs):
super(PkgUninstallComponent, self).__init__(*args, **kargs)
trace_fn = tr.trace_filename(self.get_option('trace_dir'), 'created')
self.tracereader = tr.TraceReader(trace_fn)
self.purge_packages = kargs.get('purge_packages')

def unconfigure(self):
self._unconfigure_links()
Expand All @@ -188,7 +187,7 @@ def _unconfigure_links(self):
utils.log_iterable(sym_files, logger=LOG,
header="Removing %s symlink files" % (len(sym_files)))
for fn in sym_files:
sh.unlink(fn, run_as_root=True)
sh.unlink(fn)

def post_uninstall(self):
self._uninstall_files()
Expand All @@ -203,7 +202,7 @@ def _uninstall_files(self):
utils.log_iterable(files_touched, logger=LOG,
header="Removing %s miscellaneous files" % (len(files_touched)))
for fn in files_touched:
sh.unlink(fn, run_as_root=True)
sh.unlink(fn)

def _uninstall_dirs(self):
dirs_made = self.tracereader.dirs_made()
Expand All @@ -212,4 +211,4 @@ def _uninstall_dirs(self):
utils.log_iterable(dirs_alive, logger=LOG,
header="Removing %s created directories" % (len(dirs_alive)))
for dir_name in dirs_alive:
sh.deldir(dir_name, run_as_root=True)
sh.deldir(dir_name)
2 changes: 1 addition & 1 deletion anvil/components/base_testing.py
Expand Up @@ -135,7 +135,7 @@ def run_tests(self):
if self.get_bool_option("verbose", default_value=False):
null_fh = None
try:
sh.execute(*cmd, stdout_fh=None, stderr_fh=null_fh, cwd=app_dir, env_overrides=env)
sh.execute(cmd, stdout_fh=None, stderr_fh=null_fh, cwd=app_dir, env_overrides=env)
except excp.ProcessExecutionError as e:
if self.get_bool_option("ignore-test-failures", default_value=False):
LOG.warn("Ignoring test failure of component %s: %s", colorizer.quote(self.name), e)
Expand Down
2 changes: 1 addition & 1 deletion anvil/components/cinder.py
Expand Up @@ -45,7 +45,7 @@ def post_install(self):

def _sync_db(self):
LOG.info("Syncing cinder to database: %s", colorizer.quote(self.configurator.DB_NAME))
cmds = [{'cmd': SYNC_DB_CMD, 'run_as_root': True}]
cmds = [{'cmd': SYNC_DB_CMD}]
utils.execute_template(*cmds, cwd=self.bin_dir, params=self.config_params(None))

def config_params(self, config_fn):
Expand Down
2 changes: 1 addition & 1 deletion anvil/components/configurators/glance.py
Expand Up @@ -72,7 +72,7 @@ def _config_adjust_api(self, config):
LOG.debug("Ensuring file system store directory %r exists and is empty." % (img_store_dir))
if sh.isdir(img_store_dir):
sh.deldir(img_store_dir)
sh.mkdirslist(img_store_dir, tracewriter=self.installer.tracewriter, adjust_suids=True)
sh.mkdirslist(img_store_dir, tracewriter=self.installer.tracewriter)

def _config_adjust_reg(self, config):
self._config_adjust_api_reg(config)
Expand Down
2 changes: 1 addition & 1 deletion anvil/components/db.py
Expand Up @@ -154,7 +154,7 @@ def _run_action(self, action, check_exit_code=True):
cmd = self._get_command(action)
if not cmd:
raise NotImplementedError("No distro command provided to perform action %r" % (action))
return sh.execute(*cmd, run_as_root=True, check_exit_code=check_exit_code)
return sh.execute(cmd, check_exit_code=check_exit_code)

def start(self):
if self.statii()[0].status != bruntime.STATUS_STARTED:
Expand Down
2 changes: 1 addition & 1 deletion anvil/components/glance.py
Expand Up @@ -52,7 +52,7 @@ def post_install(self):

def _sync_db(self):
LOG.info("Syncing glance to database: %s", colorizer.quote(self.configurator.DB_NAME))
cmds = [{'cmd': SYNC_DB_CMD, 'run_as_root': True}]
cmds = [{'cmd': SYNC_DB_CMD}]
utils.execute_template(*cmds, cwd=self.bin_dir, params=self.config_params(None))

@property
Expand Down
2 changes: 0 additions & 2 deletions anvil/components/helpers/db.py
Expand Up @@ -46,7 +46,6 @@ def drop_db(distro, dbtype, user, pw, dbname, **kwargs):
cmds = list()
cmds.append({
'cmd': dropcmd,
'run_as_root': False,
})
utils.execute_template(*cmds, params=params)
else:
Expand All @@ -67,7 +66,6 @@ def create_db(distro, dbtype, user, pw, dbname, **kwargs):
cmds = list()
cmds.append({
'cmd': createcmd,
'run_as_root': False,
})
utils.execute_template(*cmds, params=params)
else:
Expand Down
20 changes: 9 additions & 11 deletions anvil/components/helpers/nova.py
Expand Up @@ -93,9 +93,8 @@ def _stop_dnsmasq(self):
continue
cwd = ''
cmdline = ''
with sh.Rooted(True):
cwd = proc.getcwd()
cmdline = " ".join(proc.cmdline)
cwd = proc.getcwd()
cmdline = " ".join(proc.cmdline)
to_try = False
for t in [cwd, cmdline]:
if t.lower().find("nova") != -1:
Expand All @@ -107,8 +106,7 @@ def _stop_dnsmasq(self):
header="Killing leftover nova dnsmasq processes with process ids",
logger=nconf.LOG)
for pid in to_kill:
with sh.Rooted(True):
sh.kill(pid)
sh.kill(pid)

def _clean_iptables(self):
# Nova doesn't seem to cleanup its iptables rules that it
Expand Down Expand Up @@ -136,7 +134,7 @@ def translate_rule(line, start_search, start_replace):
# Isolate the nova rules
clean_rules = []
list_cmd = ['iptables', '--list-rules', '--verbose']
(stdout, _stderr) = sh.execute(*list_cmd, run_as_root=True)
(stdout, _stderr) = sh.execute(list_cmd)
for line in stdout.splitlines():
line = line.strip()
if not line_matcher(line, "-A"):
Expand All @@ -149,7 +147,7 @@ def translate_rule(line, start_search, start_replace):
# Isolate the nova nat rules
clean_nats = []
nat_cmd = ['iptables', '--list-rules', '--verbose', '--table', 'nat']
(stdout, _stderr) = sh.execute(*nat_cmd, run_as_root=True)
(stdout, _stderr) = sh.execute(nat_cmd)
for line in stdout.splitlines():
line = line.strip()
if not line_matcher(line, "-A"):
Expand All @@ -162,7 +160,7 @@ def translate_rule(line, start_search, start_replace):
# Isolate the nova chains
clean_chains = []
chain_cmd = ['iptables', '--list-rules', '--verbose']
(stdout, _stderr) = sh.execute(*chain_cmd, run_as_root=True)
(stdout, _stderr) = sh.execute(chain_cmd)
for line in stdout.splitlines():
if not line_matcher(line, "-N"):
continue
Expand All @@ -174,7 +172,7 @@ def translate_rule(line, start_search, start_replace):
# Isolate the nova nat chains
clean_nat_chains = []
nat_chain_cmd = ['iptables', '--list-rules', '--verbose', '--table', 'nat']
(stdout, _stderr) = sh.execute(*nat_chain_cmd, run_as_root=True)
(stdout, _stderr) = sh.execute(nat_chain_cmd)
for line in stdout.splitlines():
if not line_matcher(line, "-N"):
continue
Expand All @@ -187,11 +185,11 @@ def translate_rule(line, start_search, start_replace):
for r in clean_rules + clean_chains:
pieces = r.split(None)
pieces = ['iptables'] + pieces
sh.execute(*pieces, run_as_root=True, shell=True)
sh.execute(pieces, shell=True)
for r in clean_nats + clean_nat_chains:
pieces = r.split(None)
pieces = ['iptables', '--table', 'nat'] + pieces
sh.execute(*pieces, run_as_root=True, shell=True)
sh.execute(pieces, shell=True)

def clean(self):
self._stop_dnsmasq()
Expand Down
56 changes: 27 additions & 29 deletions anvil/components/helpers/virt.py
Expand Up @@ -59,7 +59,7 @@ def __init__(self, service_wait, distro):

def _service_status(self):
cmd = self.distro.get_command('libvirt', 'status')
(stdout, stderr) = sh.execute(*cmd, run_as_root=True, check_exit_code=False)
(stdout, stderr) = sh.execute(cmd, check_exit_code=False)
combined = (stdout + stderr)
if combined.lower().find("running") != -1 or combined.lower().find('start') != -1:
return (_ALIVE, combined)
Expand All @@ -78,7 +78,7 @@ def _destroy_domain(self, libvirt, conn, dom_name):

def restart_service(self):
cmd = self.distro.get_command('libvirt', 'restart')
sh.execute(*cmd, run_as_root=True)
sh.execute(cmd)

def wait_active(self):
# TODO(harlowja) fix this by using the component wait active...
Expand All @@ -99,7 +99,6 @@ def check_virt(self, virt_type):
self.wait_active()
cmds = [{
'cmd': self.distro.get_command('libvirt', 'verify'),
'run_as_root': True,
}]
mp = {
'VIRT_PROTOCOL': virt_protocol,
Expand All @@ -123,30 +122,29 @@ def clear_domains(self, virt_type, inst_prefix):
if not virt_protocol:
LOG.warn("Could not clear out libvirt domains, no known protocol for virt type: %s", colorizer.quote(virt_type))
return
with sh.Rooted(True):
LOG.info("Attempting to clear out leftover libvirt domains using protocol: %s", colorizer.quote(virt_protocol))
try:
self.restart_service()
self.wait_active()
except (excp.StartException, IOError) as e:
LOG.warn("Could not restart the libvirt daemon due to: %s", e)
return
LOG.info("Attempting to clear out leftover libvirt domains using protocol: %s", colorizer.quote(virt_protocol))
try:
self.restart_service()
self.wait_active()
except (excp.StartException, IOError) as e:
LOG.warn("Could not restart the libvirt daemon due to: %s", e)
return
try:
conn = libvirt.open(virt_protocol)
except libvirt.libvirtError as e:
LOG.warn("Could not connect to libvirt using protocol %s due to: %s", colorizer.quote(virt_protocol), e)
return
with contextlib.closing(conn) as ch:
try:
conn = libvirt.open(virt_protocol)
except libvirt.libvirtError as e:
LOG.warn("Could not connect to libvirt using protocol %s due to: %s", colorizer.quote(virt_protocol), e)
return
with contextlib.closing(conn) as ch:
try:
defined_domains = ch.listDefinedDomains()
kill_domains = list()
for domain in defined_domains:
if domain.startswith(inst_prefix):
kill_domains.append(domain)
if kill_domains:
utils.log_iterable(kill_domains, logger=LOG,
header="Found %s old domains to destroy" % (len(kill_domains)))
for domain in sorted(kill_domains):
self._destroy_domain(libvirt, ch, domain)
except libvirt.libvirtError, e:
LOG.warn("Could not clear out libvirt domains due to: %s", e)
defined_domains = ch.listDefinedDomains()
kill_domains = list()
for domain in defined_domains:
if domain.startswith(inst_prefix):
kill_domains.append(domain)
if kill_domains:
utils.log_iterable(kill_domains, logger=LOG,
header="Found %s old domains to destroy" % (len(kill_domains)))
for domain in sorted(kill_domains):
self._destroy_domain(libvirt, ch, domain)
except libvirt.libvirtError, e:
LOG.warn("Could not clear out libvirt domains due to: %s", e)
11 changes: 5 additions & 6 deletions anvil/components/horizon.py
Expand Up @@ -82,11 +82,10 @@ def _setup_logs(self, clear=False):
utils.log_iterable(log_fns, logger=LOG,
header="Adjusting %s log files" % (len(log_fns)))
for fn in log_fns:
with sh.Rooted(True):
if clear:
sh.unlink(fn, True)
sh.touch_file(fn, die_if_there=False, tracewriter=self.tracewriter)
sh.chmod(fn, 0666)
if clear:
sh.unlink(fn, True)
sh.touch_file(fn, die_if_there=False, tracewriter=self.tracewriter)
sh.chmod(fn, 0666)
return len(log_fns)

def _configure_files(self):
Expand Down Expand Up @@ -137,7 +136,7 @@ def _run_action(self, action, check_exit_code=True):
cmd = self.distro.get_command('apache', action)
if not cmd:
raise NotImplementedError("No distro command provided to perform action %r" % (action))
return sh.execute(*cmd, run_as_root=True, check_exit_code=check_exit_code)
return sh.execute(cmd, check_exit_code=check_exit_code)

def restart(self):
self._run_action('restart')
Expand Down
6 changes: 3 additions & 3 deletions anvil/components/keystone.py
Expand Up @@ -63,7 +63,7 @@ def post_install(self):
def _sync_db(self):
LOG.info("Syncing keystone to database: %s", colorizer.quote(self.configurator.DB_NAME))
sync_cmd = MANAGE_CMD + ['db_sync']
cmds = [{'cmd': sync_cmd, 'run_as_root': True}]
cmds = [{'cmd': sync_cmd}]
utils.execute_template(*cmds, cwd=self.bin_dir, params=self.config_params(None))

@property
Expand All @@ -86,9 +86,9 @@ def _setup_pki(self):
LOG.info("Setting up keystone's pki support.")
for value in kconf.PKI_FILES.values():
sh.mkdirslist(sh.dirname(sh.joinpths(self.configurator.link_dir, value)),
tracewriter=self.tracewriter, adjust_suids=True)
tracewriter=self.tracewriter)
pki_cmd = MANAGE_CMD + ['pki_setup']
cmds = [{'cmd': pki_cmd, 'run_as_root': True}]
cmds = [{'cmd': pki_cmd}]
utils.execute_template(*cmds, cwd=self.bin_dir, params=self.config_params(None))

def warm_configs(self):
Expand Down
5 changes: 1 addition & 4 deletions anvil/components/nova.py
Expand Up @@ -35,28 +35,25 @@

# This makes the database be in sync with nova
DB_SYNC_CMD = [
{'cmd': ['$BIN_DIR/nova-manage', '--config-file', '$CFG_FILE', 'db', 'sync'], 'run_as_root': True},
{'cmd': ['$BIN_DIR/nova-manage', '--config-file', '$CFG_FILE', 'db', 'sync']},
]

# Used to create a fixed network when initializating nova
FIXED_NET_CMDS = [
{
'cmd': ['$BIN_DIR/nova-manage', '--config-file', '$CFG_FILE',
'network', 'create', 'private', '$FIXED_RANGE', '1', '$FIXED_NETWORK_SIZE'],
'run_as_root': True,
},
]

# Used to create a floating network + test floating pool
FLOATING_NET_CMDS = [
{
'cmd': ['$BIN_DIR/nova-manage', '--config-file', '$CFG_FILE', 'floating', 'create', '$FLOATING_RANGE'],
'run_as_root': True,
},
{
'cmd': ['$BIN_DIR/nova-manage', '--config-file', '$CFG_FILE',
'floating', 'create', '--ip_range=$TEST_FLOATING_RANGE', '--pool=$TEST_FLOATING_POOL'],
'run_as_root': True,
},
]

Expand Down
2 changes: 1 addition & 1 deletion anvil/components/quantum.py
Expand Up @@ -43,7 +43,7 @@ def post_install(self):

def _sync_db(self):
LOG.info("Syncing quantum to database: %s", colorizer.quote(self.configurator.DB_NAME))
#cmds = [{"cmd": SYNC_DB_CMD, "run_as_root": True}]
#cmds = [{"cmd": SYNC_DB_CMD}]
#utils.execute_template(*cmds, cwd=self.bin_dir,
# params=self.config_params(None))

Expand Down
6 changes: 3 additions & 3 deletions anvil/components/rabbit.py
Expand Up @@ -43,7 +43,7 @@ def pre_uninstall(self):
self.runtime.start()
self.runtime.wait_active()
cmd = self.distro.get_command('rabbit-mq', 'change_password') + [RESET_BASE_PW]
sh.execute(*cmd, run_as_root=True)
sh.execute(cmd)
LOG.info("Restarting so that your rabbit-mq password is reflected.")
self.runtime.restart()
self.runtime.wait_active()
Expand All @@ -67,7 +67,7 @@ def _setup_pw(self):
self.runtime.wait_active()
cmd = list(self.distro.get_command('rabbit-mq', 'change_password'))
cmd += [user_id, rhelper.get_shared_passwords(self)['pw']]
sh.execute(*cmd, run_as_root=True)
sh.execute(cmd)
LOG.info("Restarting so that your rabbit-mq password is reflected.")
self.runtime.restart()
self.runtime.wait_active()
Expand Down Expand Up @@ -123,7 +123,7 @@ def _run_action(self, action, check_exit_code=True):
# RHEL seems to have this bug also...
with TemporaryFile() as s_fh:
with TemporaryFile() as e_fh:
sh.execute(*cmd, run_as_root=True,
sh.execute(cmd,
stdout_fh=s_fh, stderr_fh=e_fh,
check_exit_code=check_exit_code)
# Read from the file handles instead of the typical output...
Expand Down

0 comments on commit df60b50

Please sign in to comment.