Commit 996d32fd authored by Rafael Monnerat's avatar Rafael Monnerat

Unpriviledged boot and bang

This change allow us to use slapos node boot/bang under a slaprunner (or any non-root environment).

It should be usefull to not create ad-hoc implementation for those procedures.

/cc @jerome @tomo @Nicolas

See merge request !214
parents 0ab33235 7e462a6f
...@@ -27,10 +27,10 @@ ...@@ -27,10 +27,10 @@
# #
############################################################################## ##############################################################################
from slapos.cli.command import must_be_root
from slapos.cli.config import ConfigCommand from slapos.cli.config import ConfigCommand
from slapos.bang import do_bang from slapos.bang import do_bang
from slapos.util import string_to_boolean
from slapos.cli.command import check_root_user
class BangCommand(ConfigCommand): class BangCommand(ConfigCommand):
...@@ -41,11 +41,17 @@ class BangCommand(ConfigCommand): ...@@ -41,11 +41,17 @@ class BangCommand(ConfigCommand):
def get_parser(self, prog_name): def get_parser(self, prog_name):
ap = super(BangCommand, self).get_parser(prog_name) ap = super(BangCommand, self).get_parser(prog_name)
ap.add_argument('-m', '--message', ap.add_argument('-m', '--message', help='Message for bang')
help='Message for bang')
return ap return ap
@must_be_root
def take_action(self, args): def take_action(self, args):
configp = self.fetch_config(args) configp = self.fetch_config(args)
root_check = True
if configp.has_option('slapos', 'root_check'):
root_check = configp.getboolean('slapos', 'root_check')
if root_check:
check_root_user(self)
do_bang(configp, args.message) do_bang(configp, args.message)
...@@ -37,14 +37,17 @@ import os ...@@ -37,14 +37,17 @@ import os
import netifaces import netifaces
import socket import socket
from netaddr import valid_ipv4, valid_ipv6 from netaddr import valid_ipv4, valid_ipv6
from slapos.cli.command import must_be_root from slapos.cli.command import check_root_user
from slapos.cli.entry import SlapOSApp from slapos.cli.entry import SlapOSApp
from slapos.cli.config import ConfigCommand from slapos.cli.config import ConfigCommand
from slapos.format import isGlobalScopeAddress from slapos.format import isGlobalScopeAddress
from slapos.util import string_to_boolean
import argparse
def _removeTimestamp(instancehome, partition_base_name): def _removeTimestamp(instancehome, partition_base_name):
""" """
Remove .timestamp from all partitions Remove .timestamp from all partitions
""" """
timestamp_glob_path = os.path.join( timestamp_glob_path = os.path.join(
instancehome, instancehome,
...@@ -54,6 +57,7 @@ def _removeTimestamp(instancehome, partition_base_name): ...@@ -54,6 +57,7 @@ def _removeTimestamp(instancehome, partition_base_name):
print("Removing %s" % timestamp_path) print("Removing %s" % timestamp_path)
os.remove(timestamp_path) os.remove(timestamp_path)
def _runBang(app): def _runBang(app):
""" """
Launch slapos node format. Launch slapos node format.
...@@ -64,6 +68,7 @@ def _runBang(app): ...@@ -64,6 +68,7 @@ def _runBang(app):
return 0 return 0
return 1 return 1
def _runFormat(app): def _runFormat(app):
""" """
Launch slapos node format. Launch slapos node format.
...@@ -74,14 +79,15 @@ def _runFormat(app): ...@@ -74,14 +79,15 @@ def _runFormat(app):
return 0 return 0
return 1 return 1
def _ping(hostname): def _ping(hostname):
""" """
Ping a hostname Ping a hostname
""" """
print("[BOOT] Invoking ipv4 ping to %s..." % hostname) print("[BOOT] Invoking ipv4 ping to %s..." % hostname)
p = subprocess.Popen( p = subprocess.Popen(["ping", "-c", "2", hostname],
["ping", "-c", "2", hostname], stdout=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE) stderr=subprocess.PIPE)
stdout, stderr = p.communicate() stdout, stderr = p.communicate()
if p.returncode == 0: if p.returncode == 0:
print("[BOOT] IPv4 network reachable...") print("[BOOT] IPv4 network reachable...")
...@@ -89,8 +95,9 @@ def _ping(hostname): ...@@ -89,8 +95,9 @@ def _ping(hostname):
print("[BOOT] [ERROR] IPv4 network unreachable...") print("[BOOT] [ERROR] IPv4 network unreachable...")
return 0 return 0
def _ping6(hostname): def _ping6(hostname):
""" """
Ping an ipv6 address Ping an ipv6 address
""" """
print("[BOOT] Invoking ipv6 ping to %s..." % hostname) print("[BOOT] Invoking ipv6 ping to %s..." % hostname)
...@@ -104,18 +111,21 @@ def _ping6(hostname): ...@@ -104,18 +111,21 @@ def _ping6(hostname):
print("[BOOT] [ERROR] IPv6 network unreachable...") print("[BOOT] [ERROR] IPv6 network unreachable...")
return 0 return 0
def _test_ping(hostname): def _test_ping(hostname):
is_ready = _ping(hostname) is_ready = _ping(hostname)
while is_ready == 0: while is_ready == 0:
sleep(5) sleep(5)
is_ready = _ping(hostname) is_ready = _ping(hostname)
def _test_ping6(hostname): def _test_ping6(hostname):
is_ready = _ping6(hostname) is_ready = _ping6(hostname)
while is_ready == 0: while is_ready == 0:
sleep(5) sleep(5)
is_ready = _ping6(hostname) is_ready = _ping6(hostname)
def _ping_hostname(hostname): def _ping_hostname(hostname):
is_ready = _ping6(hostname) is_ready = _ping6(hostname)
while is_ready == 0: while is_ready == 0:
...@@ -126,6 +136,7 @@ def _ping_hostname(hostname): ...@@ -126,6 +136,7 @@ def _ping_hostname(hostname):
# try ping on ipv6 # try ping on ipv6
is_ready = _ping6(hostname) is_ready = _ping6(hostname)
def _waitIpv6Ready(ipv6_interface): def _waitIpv6Ready(ipv6_interface):
""" """
test if ipv6 is ready on ipv6_interface test if ipv6 is ready on ipv6_interface
...@@ -140,7 +151,7 @@ def _waitIpv6Ready(ipv6_interface): ...@@ -140,7 +151,7 @@ def _waitIpv6Ready(ipv6_interface):
else: else:
ipv6_address = "" ipv6_address = ""
print("[BOOT] [ERROR] No IPv6 found on interface %r, " print("[BOOT] [ERROR] No IPv6 found on interface %r, "
"try again in 5 seconds..." % ipv6_interface) "try again in 5 seconds..." % ipv6_interface)
sleep(5) sleep(5)
class BootCommand(ConfigCommand): class BootCommand(ConfigCommand):
...@@ -156,36 +167,50 @@ class BootCommand(ConfigCommand): ...@@ -156,36 +167,50 @@ class BootCommand(ConfigCommand):
help='Message for bang') help='Message for bang')
return ap return ap
@must_be_root
def take_action(self, args): def take_action(self, args):
configp = self.fetch_config(args) configp = self.fetch_config(args)
instance_root = configp.get('slapos','instance_root') instance_root = configp.get('slapos','instance_root')
partition_base_name = configp.get('slapformat', 'partition_base_name') partition_base_name = "slappart"
if configp.has_option('slapformat', 'partition_base_name'):
partition_base_name = configp.get('slapformat', 'partition_base_name')
master_url = urlparse(configp.get('slapos','master_url')) master_url = urlparse(configp.get('slapos','master_url'))
master_hostname = master_url.hostname master_hostname = master_url.hostname
root_check = True
if configp.has_option('slapos', 'root_check'):
root_check = configp.getboolean('slapos', 'root_check')
if root_check:
check_root_user(self)
# Check that we have IPv6 ready # Check that we have IPv6 ready
if configp.has_option('slapformat', 'ipv6_interface'): if configp.has_option('slapformat', 'ipv6_interface'):
ipv6_interface = configp.get('slapformat', 'ipv6_interface') ipv6_interface = configp.get('slapformat', 'ipv6_interface')
else: elif configp.has_option('slapformat', 'interface_name'):
ipv6_interface = configp.get('slapformat', 'interface_name') ipv6_interface = configp.get('slapformat', 'interface_name')
_waitIpv6Ready(ipv6_interface) else:
# It is most likely the we are running on unpriviledged environment
# so we for slapformat handle it.
ipv6_interface = None
if ipv6_interface is not None:
_waitIpv6Ready(ipv6_interface)
# Check that node can ping master # Check that node can ping master
if valid_ipv4(master_hostname): if valid_ipv4(master_hostname):
_test_ping(master_hostname) _test_ping(master_hostname)
elif valid_ipv6(master_hostname): elif valid_ipv6(master_hostname):
_test_ping6(master_hostname) _test_ping6(master_hostname)
else: else:
# hostname # hostname
_ping_hostname(master_hostname) _ping_hostname(master_hostname)
app = SlapOSApp() app = SlapOSApp()
# Make sure slapos node format returns ok # Make sure slapos node format returns ok
while not _runFormat(app): while not _runFormat(app):
print("[BOOT] [ERROR] Fail to format, try again in 15 seconds...") print("[BOOT] [ERROR] Fail to format, try again in 15 seconds...")
sleep(15) sleep(15)
# Make sure slapos node bang returns ok # Make sure slapos node bang returns ok
while not _runBang(app): while not _runBang(app):
print("[BOOT] [ERROR] Fail to bang, try again in 15 seconds...") print("[BOOT] [ERROR] Fail to bang, try again in 15 seconds...")
......
...@@ -336,7 +336,8 @@ class TestCliBoot(CliMixin): ...@@ -336,7 +336,8 @@ class TestCliBoot(CliMixin):
SlapOSApp().run.assert_any_call(['node', 'bang', '-m', 'Reboot']) SlapOSApp().run.assert_any_call(['node', 'bang', '-m', 'Reboot'])
# timestamp files have been removed # timestamp files have been removed
self.assertFalse(os.path.exists(timestamp)) self.assertFalse(os.path.exists(timestamp),
timestamp)
class TestCliNode(CliMixin): class TestCliNode(CliMixin):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment