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):