diff --git a/base-buildout.cfg b/base-buildout.cfg index d23600abc..76a588bd5 100644 --- a/base-buildout.cfg +++ b/base-buildout.cfg @@ -61,7 +61,7 @@ command = postgresql-server postgresql-devel kernel-ml btrfs-progs rsync \ nfs-utils avahi netatalk smartmontools net-tools sos hdparm \ postfix cyrus-sasl-plain yum-cron nano usbutils pciutils shellinabox \ - epel-release cryptsetup docker-ce + epel-release cryptsetup docker-ce python-distro [rpm-deps-nut] recipe = plone.recipe.command @@ -99,7 +99,6 @@ gunicorn = 19.7.1 supervisor = 3.0b1 python = 2.7.3 djangorecipe = 1.9 -psycopg2 = 2.6 [django] recipe = djangorecipe @@ -145,9 +144,12 @@ on_update = true cmds = ${buildout:directory}/bin/django collectstatic --noinput -i admin -v 0 [docker-conf] +# Consider inline sed of system's /usr/lib/systemd/system/docker.service +# that way we pick up new versions on each build. +# Or depricate and rely on docker_service.py to inline edit and assert. recipe = collective.recipe.template input = ${buildout:directory}/conf/docker.service.in -output = ${buildout:directory}/conf/docker.service +output = ${buildout:directory}/conf/docker-rockstor.service [rockstor-systemd-conf] recipe = collective.recipe.template diff --git a/conf/django-hack b/conf/django-hack index c17ed4f24..4ba835b76 100755 --- a/conf/django-hack +++ b/conf/django-hack @@ -24,7 +24,7 @@ sys.path[0:0] = [ join(base, 'eggs/oauthlib-1.0.1-py2.7.egg'), join(base, 'eggs/psutil-3.3.0-py2.7-linux-x86_64.egg'), join(base, 'eggs/psycogreen-1.0-py2.7.egg'), - join(base, 'eggs/psycopg2-2.6-py2.7-linux-x86_64.egg'), + join(base, 'eggs/psycopg2-2.7.4-py2.7-linux-x86_64.egg'), join(base, 'eggs/python_engineio-1.0.3-py2.7.egg'), join(base, 'eggs/python_socketio-1.6.0-py2.7.egg'), join(base, 'eggs/pytz-2014.3-py2.7.egg'), diff --git a/conf/docker-distroid-notes.service.txt b/conf/docker-distroid-notes.service.txt new file mode 100644 index 000000000..42f3c1d00 --- /dev/null +++ b/conf/docker-distroid-notes.service.txt @@ -0,0 +1,13 @@ +Files with a name pattern of: docker-distroid.service + +where distroid = distro.id() + +are currently hand copied from their distro docker package origin, usually: +/usr/lib/systemd/system/docker.service + +src/rockstor/smart_manager/views/docker_service.py then stream edits them. + +See docker_service.py for pre-instantiation edit details. + +Auto edit is performed on Docker service enable event within Web-UI and +attempts to honour all existing dockerd arguments. \ No newline at end of file diff --git a/conf/docker-generic.service b/conf/docker-generic.service new file mode 100644 index 000000000..41b3849a0 --- /dev/null +++ b/conf/docker-generic.service @@ -0,0 +1,46 @@ +[Unit] +Description=Docker Application Container Engine +Documentation=https://docs.docker.com +BindsTo=containerd.service +After=network-online.target firewalld.service +Wants=network-online.target + +[Service] +Type=notify +# the default is not to use systemd for cgroups because the delegate issues still +# exists and systemd currently does not support the cgroup feature set required +# for containers run by docker +ExecStart=/usr/bin/dockerd -H unix:// +ExecReload=/bin/kill -s HUP $MAINPID +TimeoutSec=0 +RestartSec=2 +Restart=always + +# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229. +# Both the old, and new location are accepted by systemd 229 and up, so using the old location +# to make them work for either version of systemd. +StartLimitBurst=3 + +# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230. +# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make +# this option work for either version of systemd. +StartLimitInterval=60s + +# Having non-zero Limit*s causes performance problems due to accounting overhead +# in the kernel. We recommend using cgroups to do container-local accounting. +LimitNOFILE=infinity +LimitNPROC=infinity +LimitCORE=infinity + +# Comment TasksMax if your systemd version does not supports it. +# Only systemd 226 and above support this option. +TasksMax=infinity + +# set delegate yes so that systemd does not reset the cgroups of docker containers +Delegate=yes + +# kill only the docker process, not all processes in the cgroup +KillMode=process + +[Install] +WantedBy=multi-user.target diff --git a/conf/docker-opensuse-leap.service b/conf/docker-opensuse-leap.service new file mode 100644 index 000000000..1444d851b --- /dev/null +++ b/conf/docker-opensuse-leap.service @@ -0,0 +1,35 @@ +[Unit] +Description=Docker Application Container Engine +Documentation=http://docs.docker.com +After=network.target containerd.socket containerd.service lvm2-monitor.service SuSEfirewall2.service +Requires=containerd.socket containerd.service + +[Service] +EnvironmentFile=/etc/sysconfig/docker + +# While Docker has support for socket activation (-H fd://), this is not +# enabled by default because enabling socket activation means that on boot your +# containers won't start until someone tries to administer the Docker daemon. +Type=notify +ExecStart=/usr/bin/dockerd --containerd /run/containerd/containerd.sock --add-runtime oci=/usr/sbin/docker-runc $DOCKER_NETWORK_OPTIONS $DOCKER_OPTS +ExecReload=/bin/kill -s HUP $MAINPID + +# Having non-zero Limit*s causes performance problems due to accounting overhead +# in the kernel. We recommend using cgroups to do container-local accounting. +LimitNOFILE=infinity +LimitNPROC=infinity +LimitCORE=infinity + +# Uncomment TasksMax if your systemd version supports it. +# Only systemd 226 and above support this property. +TasksMax=infinity + +# Set delegate yes so that systemd does not reset the cgroups of docker containers +# Only systemd 218 and above support this property. +Delegate=yes + +# This is not necessary because of how we set up containerd. +#KillMode=process + +[Install] +WantedBy=multi-user.target diff --git a/conf/docker-opensuse-tumbleweed.service b/conf/docker-opensuse-tumbleweed.service new file mode 100644 index 000000000..986b97508 --- /dev/null +++ b/conf/docker-opensuse-tumbleweed.service @@ -0,0 +1,34 @@ +[Unit] +Description=Docker Application Container Engine +Documentation=http://docs.docker.com +After=network.target lvm2-monitor.service SuSEfirewall2.service + +[Service] +EnvironmentFile=/etc/sysconfig/docker + +# While Docker has support for socket activation (-H fd://), this is not +# enabled by default because enabling socket activation means that on boot your +# containers won't start until someone tries to administer the Docker daemon. +Type=notify +ExecStart=/usr/bin/dockerd --add-runtime oci=/usr/sbin/docker-runc $DOCKER_NETWORK_OPTIONS $DOCKER_OPTS +ExecReload=/bin/kill -s HUP $MAINPID + +# Having non-zero Limit*s causes performance problems due to accounting overhead +# in the kernel. We recommend using cgroups to do container-local accounting. +LimitNOFILE=infinity +LimitNPROC=infinity +LimitCORE=infinity + +# Uncomment TasksMax if your systemd version supports it. +# Only systemd 226 and above support this property. +TasksMax=infinity + +# Set delegate yes so that systemd does not reset the cgroups of docker containers +# Only systemd 218 and above support this property. +Delegate=yes + +# This is not necessary because of how we set up containerd. +#KillMode=process + +[Install] +WantedBy=multi-user.target diff --git a/conf/docker.service.in b/conf/docker.service.in index 5a21366f7..2817f412d 100644 --- a/conf/docker.service.in +++ b/conf/docker.service.in @@ -1,7 +1,7 @@ [Unit] Description=Docker Application Container Engine Documentation=http://docs.docker.com -After=network.target docker.socket rockstor-bootstrap.service +After=network.target docker.socket Requires=docker.socket [Service] diff --git a/conf/settings.conf.in b/conf/settings.conf.in index 60d03c29e..ba2f8668c 100644 --- a/conf/settings.conf.in +++ b/conf/settings.conf.in @@ -19,6 +19,7 @@ along with this program. If not, see . # Django settings for Rockstor project. import os +import subprocess, distro DEBUG = ${django-settings-conf:debug} TEMPLATE_DEBUG = DEBUG @@ -416,4 +417,23 @@ TASK_SCHEDULER = { 'max_log': 100 #max number of task log entries to keep } -OAUTH2_PROVIDER_APPLICATION_MODEL = 'oauth2_provider.Application' \ No newline at end of file +OAUTH2_PROVIDER_APPLICATION_MODEL = 'oauth2_provider.Application' + +# Setup OS specific command paths via 'which cmd' calls +# N.B. this method will not work with an alias, ie in CentOS +# which ls +# alias ls='ls --color=auto' +# /usr/bin/ls +# The following have been tested in CentOS, openSUSE Leap15, and Tumbleweed +UDEVADM = subprocess.check_output(["which", "udevadm"]).rstrip() +SHUTDOWN = subprocess.check_output(["which", "shutdown"]).rstrip() +CHKCONFIG_BIN = subprocess.check_output(["which", "chkconfig"]).rstrip() + +# Establish our OS base id, name, and version: +# Use id for code path decisions. Others are for Web-UI display purposes. +# Examples given are for CentOS Rockstor variant, Leap 15, and Tumblweed. +OS_DISTRO_ID = distro.id() # rockstor, opensuse-leap, opensuse-tumbleweed +OS_DISTRO_NAME = distro.name() # Rockstor, openSUSE Leap, openSUSE Tumbleweed +# Note that the following will capture the build os version. +# For live updates (running system) we call distro.version() directly in code. +OS_DISTRO_VERSION = distro.version() # 3, 15.0 ,20181107 diff --git a/setup.py b/setup.py index 665491411..8d5f54539 100644 --- a/setup.py +++ b/setup.py @@ -76,12 +76,13 @@ 'mock == 1.0.1', 'psutil == 3.3.0', 'psycogreen == 1.0', - 'psycopg2 == 2.6', + 'psycopg2 == 2.7.4', 'python-socketio == 1.6.0', 'pytz == 2014.3', 'pyzmq == 15.0.0', 'requests == 1.1.0', 'six == 1.10.0', + 'distro', ] ) diff --git a/src/rockstor/fs/btrfs.py b/src/rockstor/fs/btrfs.py index 829904ee7..0695fb769 100644 --- a/src/rockstor/fs/btrfs.py +++ b/src/rockstor/fs/btrfs.py @@ -34,12 +34,12 @@ logger = logging.getLogger(__name__) -MKFS_BTRFS = '/sbin/mkfs.btrfs' -BTRFS = '/sbin/btrfs' -MOUNT = '/bin/mount' -UMOUNT = '/bin/umount' +MKFS_BTRFS = '/usr/sbin/mkfs.btrfs' +BTRFS = '/usr/sbin/btrfs' +MOUNT = '/usr/bin/mount' +UMOUNT = '/usr/bin/umount' DEFAULT_MNT_DIR = '/mnt2/' -RMDIR = '/bin/rmdir' +RMDIR = '/usr/bin/rmdir' QID = '2015' # The following model/db default setting is also used when quotas are disabled. PQGROUP_DEFAULT = settings.MODEL_DEFS['pqgroup'] diff --git a/src/rockstor/scripts/docker_wrapper.py b/src/rockstor/scripts/docker_wrapper.py index 7c974c277..3456465e4 100644 --- a/src/rockstor/scripts/docker_wrapper.py +++ b/src/rockstor/scripts/docker_wrapper.py @@ -23,9 +23,23 @@ DOCKERD = '/usr/bin/dockerd' +ROCKSTOR_DOCKER_OPTS = [ + '--log-driver=journald', + '--storage-driver', 'btrfs', + '--storage-opt', 'btrfs.min_space=1G'] + def main(): - mnt_pt = sys.argv[1] + # We expect the last element of our argument list to be the mount point as + # docker_service.py formats it that way.: + mnt_pt = sys.argv[-1] + # N.B. sys.argv[0] is name of script itself and always present. + system_docker_opts = [] + if len(sys.argv) > 2: + # We have at least 1 additional argument passed so extract it/them ie: + # [script-name, additional-arg, mount-point] + # we extract additional-arg (or it's plural counterpart) as a list. + system_docker_opts = sys.argv[1:-1] sname = mnt_pt.split('/')[-1] try: so = Share.objects.get(name=sname) @@ -33,6 +47,6 @@ def main(): except Exception as e: sys.exit('Failed to mount Docker root(%s). Exception: %s' % (mnt_pt, e.__str__())) - run_command([DOCKERD, '--log-driver=journald', '--storage-driver', - 'btrfs', '--storage-opt', 'btrfs.min_space=1G', '--data-root', - mnt_pt]) + cmd = [DOCKERD] + ROCKSTOR_DOCKER_OPTS + system_docker_opts + \ + ['--data-root', mnt_pt] + run_command(cmd) diff --git a/src/rockstor/scripts/initrock.py b/src/rockstor/scripts/initrock.py index e155a0a4a..106b572bf 100644 --- a/src/rockstor/scripts/initrock.py +++ b/src/rockstor/scripts/initrock.py @@ -347,7 +347,17 @@ def main(): logger.debug('Deleting /var/lib/pgsql/data') shutil.rmtree('/var/lib/pgsql/data') logging.info('initializing Postgresql...') - run_command(['/usr/bin/postgresql-setup', 'initdb']) + # Conditionally run this only if found (CentOS/RedHat script) + if os.path.isfile('/usr/bin/postgresql-setup'): + logger.debug('running postgresql-setup initdb') + # Legacy (CentOS) db init command + run_command(['/usr/bin/postgresql-setup', 'initdb']) + else: + ## In eg openSUSE run the generic initdb from postgresql##-server + if os.path.isfile('/usr/bin/initdb'): + logger.debug('running generic initdb on {}'.format(pg_data)) + run_command( + ['su', '-', 'postgres', '-c', '/usr/bin/initdb', pg_data]) logging.info('Done.') run_command([SYSCTL, 'restart', 'postgresql']) run_command([SYSCTL, 'status', 'postgresql']) diff --git a/src/rockstor/smart_manager/data_collector.py b/src/rockstor/smart_manager/data_collector.py index c6feaedf6..5f4d6b58b 100644 --- a/src/rockstor/smart_manager/data_collector.py +++ b/src/rockstor/smart_manager/data_collector.py @@ -51,6 +51,7 @@ from system.services import service_status # noqa E402 from cli.api_wrapper import APIWrapper # noqa E402 from system.pkg_mgmt import (update_check, yum_check) # noqa E402 +import distro import logging # noqa E402 logger = logging.getLogger(__name__) @@ -838,6 +839,7 @@ class SysinfoNamespace(RockstorIO): start = False supported_kernel = settings.SUPPORTED_KERNEL_VERSION + os_distro_name = settings.OS_DISTRO_NAME # This function is run once on every connection def on_connect(self, sid, environ): @@ -857,6 +859,7 @@ def on_connect(self, sid, environ): self.spawn(self.prune_logs, sid) self.spawn(self.send_localtime, sid) self.spawn(self.send_uptime, sid) + self.spawn(self.send_distroinfo, sid) self.spawn(self.shutdown_status, sid) self.spawn(self.pool_degraded_status, sid) self.spawn(self.pool_dev_stats, sid) @@ -868,11 +871,18 @@ def on_disconnect(self, sid): self.start = False def send_uptime(self): - # Seems redundant + while self.start: self.emit('uptime', {'key': 'sysinfo:uptime', 'data': uptime()}) gevent.sleep(60) + def send_distroinfo(self): + while self.start: + data = {'distro': self.os_distro_name, 'version': distro.version()} + self.emit('distro_info', + {'key': 'sysinfo:distro_info', 'data': data}) + gevent.sleep(600) + def send_localtime(self): while self.start: diff --git a/src/rockstor/smart_manager/views/docker_service.py b/src/rockstor/smart_manager/views/docker_service.py index e9967c5e1..b3d4de39e 100644 --- a/src/rockstor/smart_manager/views/docker_service.py +++ b/src/rockstor/smart_manager/views/docker_service.py @@ -15,7 +15,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ - from rest_framework.response import Response from storageadmin.util import handle_exception from system.services import systemctl @@ -27,10 +26,16 @@ from fs.btrfs import mount_share import re import shutil +import distro import logging logger = logging.getLogger(__name__) +DOCKERD = '/usr/bin/dockerd' + +# Distro's for which we have known working conf/docker-distroid.service files. +KNOWN_DISTRO_IDS = ['rockstor', 'opensuse-leap', 'opensuse-tumbleweed'] + class DockerServiceView(BaseServiceDetailView): name = 'docker' @@ -40,45 +45,63 @@ def _validate_root(self, request, root): return Share.objects.get(name=root) except Exception as e: logger.exception(e) - e_msg = ('Share(%s) does not exist' % root) + e_msg = 'Share name ({}) does not exist.'.format(root) handle_exception(Exception(e_msg), request) @transaction.atomic def post(self, request, command): service = Service.objects.get(name=self.name) - if (command == 'config'): + if command == 'config': config = request.data.get('config', None) root_share = config['root_share'] self._validate_root(request, root_share) self._save_config(service, config) - elif (command == 'start'): + elif command == 'start': try: config = self._get_config(service) - except: + except Exception as e: + logger.exception(e) e_msg = ('Cannot start without configuration. ' - 'Please configure(System->Services) and try again.') + 'Please configure (System->Services) and try again.') handle_exception(Exception(e_msg), request) share = self._validate_root(request, config['root_share']) - mnt_pt = ('%s%s' % (settings.MNT_PT, share.name)) + mnt_pt = '{}{}'.format(settings.MNT_PT, share.name) if not share.is_mounted: mount_share(share, mnt_pt) - inf = ('%s/docker.service' % (settings.CONFROOT)) + docker_wrapper = '{}bin/docker-wrapper'.format(settings.ROOT_DIR) + distro_id = distro.id() # for Leap 15 <--> Tumbleweed moves. + if distro_id not in KNOWN_DISTRO_IDS: + distro_id = 'generic' + # TODO: Consider sourcing /usr/lib/systemd/system/docker.service + inf = '{}/docker-{}.service'.format(settings.CONFROOT, distro_id) outf = '/etc/systemd/system/docker.service' with open(inf) as ino, open(outf, 'w') as outo: for l in ino.readlines(): - if (re.match('ExecStart=', l) is not None): - outo.write('%s %s\n' % (l.strip(), mnt_pt)) + if re.match('ExecStart=', l) is not None: + outo.write('{} {}\n'.format( + l.strip().replace(DOCKERD, docker_wrapper, 1), + mnt_pt)) + elif re.match('Type=notify', l) is not None: + # Our docker wrapper use need NotifyAccess=all: avoids + # "Got notification message from PID ####1, but + # reception only permitted for main PID ####2" + outo.write(l) + outo.write('NotifyAccess=all\n') + elif re.match('After=', l) is not None: + outo.write('{} {}\n'.format( + l.strip(), 'rockstor-bootstrap.service')) else: outo.write(l) - socket_file = ('%s/docker.socket' % (settings.CONFROOT)) - shutil.copy(socket_file, '/etc/systemd/system/docker.socket') + if distro_id == 'rockstor': + socket_file = '{}/docker.socket'.format(settings.CONFROOT) + shutil.copy(socket_file, '/etc/systemd/system/docker.socket') systemctl(self.name, 'enable') systemctl(self.name, 'start') - elif (command == 'stop'): + elif command == 'stop': systemctl(self.name, 'stop') systemctl(self.name, 'disable') return Response() diff --git a/src/rockstor/storageadmin/static/storageadmin/css/style.css b/src/rockstor/storageadmin/static/storageadmin/css/style.css index 908c456df..731afa809 100644 --- a/src/rockstor/storageadmin/static/storageadmin/css/style.css +++ b/src/rockstor/storageadmin/static/storageadmin/css/style.css @@ -841,7 +841,10 @@ label.error { font-size: 12px; color: #b94a48; } #appliance-loadavg { float:right; - color: #fff; + padding-left: 5px; + color: #ffffff; + font-family: Roboto-Light; + font-size: 12px; } #yum-msg { @@ -865,6 +868,22 @@ label.error { font-size: 12px; color: #b94a48; } } } +#uptime { + float: right; + padding-left: 10px; + color: #FFFFFF; + font-family: Roboto-Light; + font-size: 12px; +} + +#distro-info { + float: right; + padding-left: 10px; + color: #FFFFFF; + font-family: Roboto-Light; + font-size: 12px; +} + hr.module-sep { margin: 0; border: 0; border-top: 1px solid #ddd; } @@ -2767,14 +2786,6 @@ This file is generated by `grunt build`, do not edit it by hand. font-weight:bold; } -#uptime { - float: right; - padding-left: 10px; - color: #FFFFFF; - font-family: Roboto-Light; - font-size: 12px; -} - .gentleselect-label { background-color: white; } diff --git a/src/rockstor/storageadmin/static/storageadmin/js/router.js b/src/rockstor/storageadmin/static/storageadmin/js/router.js index 71286ab51..ae47b0a38 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/router.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/router.js @@ -1026,6 +1026,11 @@ $(document).ready(function() { $loadavg.text('Linux: ' + data); }; + var distroInfo = function(data) { + $('#distro-info').text(data.distro); + $('#distro-info').attr('title', data.version); + }; + var displayLocaleTime = function(data) { $('#local-time > span').text(data); @@ -1189,6 +1194,7 @@ $(document).ready(function() { RockStorSocket.addListener(kernelInfo, this, 'sysinfo:kernel_info'); + RockStorSocket.addListener(distroInfo, this, 'sysinfo:distro_info'); RockStorSocket.addListener(displayLoadAvg, this, 'sysinfo:uptime'); RockStorSocket.addListener(displayLocaleTime, this, 'sysinfo:localtime'); RockStorSocket.addListener(displayYumUpdates, this, 'sysinfo:yum_updates'); diff --git a/src/rockstor/storageadmin/templates/storageadmin/base.html b/src/rockstor/storageadmin/templates/storageadmin/base.html index 9b377290b..9e48c9274 100644 --- a/src/rockstor/storageadmin/templates/storageadmin/base.html +++ b/src/rockstor/storageadmin/templates/storageadmin/base.html @@ -171,6 +171,7 @@
+
diff --git a/src/rockstor/system/acl.py b/src/rockstor/system/acl.py index 837e0e7e8..a7e776565 100644 --- a/src/rockstor/system/acl.py +++ b/src/rockstor/system/acl.py @@ -18,8 +18,8 @@ from osi import run_command -CHOWN = '/bin/chown' -CHMOD = '/bin/chmod' +CHOWN = '/usr/bin/chown' +CHMOD = '/usr/bin/chmod' def chown(share, owner, group=None, recursive=False): diff --git a/src/rockstor/system/iscsi.py b/src/rockstor/system/iscsi.py index e9db3ad4a..45ce771cb 100644 --- a/src/rockstor/system/iscsi.py +++ b/src/rockstor/system/iscsi.py @@ -19,7 +19,7 @@ from osi import run_command TGTADM_BIN = '/usr/sbin/tgtadm' -DD_BIN = '/bin/dd' +DD_BIN = '/usr/bin/dd' def create_target_device(tid, tname): diff --git a/src/rockstor/system/osi.py b/src/rockstor/system/osi.py index 2025aca48..89c753ca8 100644 --- a/src/rockstor/system/osi.py +++ b/src/rockstor/system/osi.py @@ -41,7 +41,7 @@ CAT = '/usr/bin/cat' CHATTR = '/usr/bin/chattr' -DD = '/bin/dd' +DD = '/usr/bin/dd' DEFAULT_MNT_DIR = '/mnt2/' EXPORTFS = '/usr/sbin/exportfs' GRUBBY = '/usr/sbin/grubby' @@ -50,15 +50,15 @@ HOSTNAMECTL = '/usr/bin/hostnamectl' LS = '/usr/bin/ls' LSBLK = '/usr/bin/lsblk' -MKDIR = '/bin/mkdir' -MOUNT = '/bin/mount' +MKDIR = '/usr/bin/mkdir' +MOUNT = '/usr/bin/mount' NMCLI = '/usr/bin/nmcli' -RMDIR = '/bin/rmdir' -SHUTDOWN = '/usr/sbin/shutdown' +RMDIR = '/usr/bin/rmdir' +SHUTDOWN = settings.SHUTDOWN SYSTEMCTL_BIN = '/usr/bin/systemctl' SYSTEMD_ESCAPE = '/usr/bin/systemd-escape' -UDEVADM = '/usr/sbin/udevadm' -UMOUNT = '/bin/umount' +UDEVADM = settings.UDEVADM +UMOUNT = '/usr/bin/umount' WIPEFS = '/usr/sbin/wipefs' RTC_WAKE_FILE = '/sys/class/rtc/rtc0/wakealarm' RETURN_BOOLEAN = True @@ -1151,13 +1151,32 @@ def get_virtio_disk_serial(device_name): def system_shutdown(delta='now'): # New delta param default to now used to pass a 2 min delay # for scheduled tasks reboot/shutdown - return run_command([SHUTDOWN, '-h', delta]) - + try: + cmd = [SHUTDOWN, '-h', delta] + o, e, rc = run_command(cmd) + except CommandException as e: + # Catch / log harmless -15 return code - command executes as expected. + if e.rc == -15: + logger.info('Ignoring rc=-15 from command ({}).'.format(cmd)) + return e.out, e.err, e.rc + # otherwise we raise an exception as normal. + raise e + return o, e, rc def system_reboot(delta='now'): # New delta param default to now used to pass a 2 min delay # for scheduled tasks reboot/shutdown - return run_command([SHUTDOWN, '-r', delta]) + try: + cmd = [SHUTDOWN, '-r', delta] + o, e, rc = run_command(cmd) + except CommandException as e: + # Catch / log harmless -15 return code - command executes as expected. + if e.rc == -15: + logger.info('Ignoring rc=-15 from command ({}).'.format(cmd)) + return e.out, e.err, e.rc + # otherwise we raise an exception as normal. + raise e + return o, e, rc def system_suspend(): diff --git a/src/rockstor/system/pkg_mgmt.py b/src/rockstor/system/pkg_mgmt.py index c2c992df9..038215d69 100644 --- a/src/rockstor/system/pkg_mgmt.py +++ b/src/rockstor/system/pkg_mgmt.py @@ -26,6 +26,10 @@ from datetime import (datetime, timedelta) import requests from django.conf import settings +from system.exceptions import CommandException +import logging + +logger = logging.getLogger(__name__) YUM = '/usr/bin/yum' RPM = '/usr/bin/rpm' @@ -92,9 +96,20 @@ def current_version(): def rpm_build_info(pkg): - version = None + version = 'Unknown Version' date = None - o, e, rc = run_command([YUM, 'info', 'installed', '-v', pkg]) + try: + o, e, rc = run_command([YUM, 'info', 'installed', '-v', pkg]) + except CommandException as e: + # Catch "No matching Packages to list" so we can return None, None. + emsg = 'Error: No matching Packages to list' + # By checking both the first error element and the second to last we + # catch one yum waiting for another to release yum lock. + if e.err[0] == emsg or e.err[-2] == emsg: + logger.info('No "rockstor" package found: source install?') + return version, date + # otherwise we raise an exception as normal. + raise e for l in o: if (re.match('Buildtime', l) is not None): # eg: "Buildtime : Tue Dec 5 13:34:06 2017" @@ -109,7 +124,7 @@ def rpm_build_info(pkg): version = l.strip().split()[2] if (re.match('Release ', l) is not None): version = '%s-%s' % (version, l.strip().split()[2]) - return (version, date) + return version, date def switch_repo(subscription, on=True): @@ -207,9 +222,14 @@ def update_run(subscription=None, yum_update=False): with open(npath, 'w') as atfo: if not yum_update: atfo.write('%s stop rockstor\n' % SYSTEMCTL) + # rockstor-pre stop ensures initrock re-run on next rockstor start + atfo.write('%s stop rockstor-pre\n' % SYSTEMCTL) atfo.write('/usr/bin/find %s -name "*.pyc" -type f -delete\n' % settings.ROOT_DIR) atfo.write('%s --setopt=timeout=600 -y update\n' % YUM) + # account for moving from dev/source to package install: + atfo.write('%s --setopt=timeout=600 -y install rockstor\n' % YUM) + # the following rockstor start invokes rockstor-pre (initrock) also atfo.write('%s start rockstor\n' % SYSTEMCTL) else: atfo.write('%s --setopt=timeout=600 -y -x rock* update\n' % YUM) diff --git a/src/rockstor/system/samba.py b/src/rockstor/system/samba.py index ec3ad6d81..362901573 100644 --- a/src/rockstor/system/samba.py +++ b/src/rockstor/system/samba.py @@ -29,7 +29,7 @@ TESTPARM = '/usr/bin/testparm' SMB_CONFIG = '/etc/samba/smb.conf' SYSTEMCTL = '/usr/bin/systemctl' -CHMOD = '/bin/chmod' +CHMOD = '/usr/bin/chmod' RS_SHARES_HEADER = '####BEGIN: Rockstor SAMBA CONFIG####' RS_SHARES_FOOTER = '####END: Rockstor SAMBA CONFIG####' RS_AD_HEADER = '####BEGIN: Rockstor ACTIVE DIRECTORY CONFIG####' diff --git a/src/rockstor/system/services.py b/src/rockstor/system/services.py index 09ceba01a..eddc0ec69 100644 --- a/src/rockstor/system/services.py +++ b/src/rockstor/system/services.py @@ -24,8 +24,7 @@ import os from shutil import move - -CHKCONFIG_BIN = '/sbin/chkconfig' +CHKCONFIG_BIN = settings.CHKCONFIG_BIN AUTHCONFIG = '/usr/sbin/authconfig' SSHD_CONFIG = '/etc/ssh/sshd_config' SYSTEMCTL_BIN = '/usr/bin/systemctl' diff --git a/src/rockstor/system/ssh.py b/src/rockstor/system/ssh.py index 1e9479e8f..b3eb13a7a 100644 --- a/src/rockstor/system/ssh.py +++ b/src/rockstor/system/ssh.py @@ -26,8 +26,8 @@ SSHD_CONFIG = '/etc/ssh/sshd_config' -MKDIR = '/bin/mkdir' -MOUNT = '/bin/mount' +MKDIR = '/usr/bin/mkdir' +MOUNT = '/usr/bin/mount' USERMOD = '/usr/sbin/usermod' SFTP_REGEX = 'Subsystem\s+sftp' SFTP_STR = 'Subsystem\tsftp\tinternal-sftp' diff --git a/src/rockstor/system/util.py b/src/rockstor/system/util.py index fa9bc1b46..cc74dd917 100644 --- a/src/rockstor/system/util.py +++ b/src/rockstor/system/util.py @@ -18,7 +18,7 @@ from osi import run_command -TAR = '/bin/tar' +TAR = '/usr/bin/tar' def archive_logs(outfile, log_dir):