mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
1) Fixed process watcher status message when user has stopped the process.
2) Saved the process state in sqlite database.
This commit is contained in:
33
web/migrations/versions/b5b87fdfcb30_.py
Normal file
33
web/migrations/versions/b5b87fdfcb30_.py
Normal file
@@ -0,0 +1,33 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
"""Added state of the utility process
|
||||
|
||||
Revision ID: b5b87fdfcb30
|
||||
Revises: ece2e76bf60e
|
||||
Create Date: 2018-10-24 12:37:59.487969
|
||||
|
||||
"""
|
||||
from pgadmin.model import db
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'b5b87fdfcb30'
|
||||
down_revision = 'ece2e76bf60e'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
db.engine.execute(
|
||||
'ALTER TABLE process ADD COLUMN process_state INTEGER DEFAULT 0'
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
@@ -36,6 +36,11 @@ if IS_PY2:
|
||||
else:
|
||||
from io import StringIO
|
||||
|
||||
PROCESS_NOT_STARTED = 0
|
||||
PROCESS_STARTED = 1
|
||||
PROCESS_FINISHED = 2
|
||||
PROCESS_TERMINATED = 3
|
||||
|
||||
|
||||
def get_current_time(format='%Y-%m-%d %H:%M:%S.%f %z'):
|
||||
"""
|
||||
@@ -113,6 +118,8 @@ class BatchProcess(object):
|
||||
self.etime = p.end_time
|
||||
# Exit code
|
||||
self.ecode = p.exit_code
|
||||
# Process State
|
||||
self.process_state = p.process_state
|
||||
|
||||
def _create_process(self, _desc, _cmd, _args):
|
||||
ctime = get_current_time(format='%y%m%d%H%M%S%f')
|
||||
@@ -166,6 +173,8 @@ class BatchProcess(object):
|
||||
self.etime = None
|
||||
# Exit code
|
||||
self.ecode = None
|
||||
# Process State
|
||||
self.process_state = PROCESS_NOT_STARTED
|
||||
|
||||
# Arguments
|
||||
self.args = _args
|
||||
@@ -393,6 +402,14 @@ class BatchProcess(object):
|
||||
p.start_time = p.end_time = get_current_time()
|
||||
if not p.exit_code:
|
||||
p.exit_code = self.ecode
|
||||
p.process_state = PROCESS_FINISHED
|
||||
db.session.commit()
|
||||
else:
|
||||
# Update the process state to "Started"
|
||||
p = Process.query.filter_by(
|
||||
pid=self.id, user_id=current_user.id
|
||||
).first()
|
||||
p.process_state = PROCESS_STARTED
|
||||
db.session.commit()
|
||||
|
||||
def status(self, out=0, err=0):
|
||||
@@ -480,7 +497,8 @@ class BatchProcess(object):
|
||||
return {
|
||||
'start_time': self.stime,
|
||||
'exit_code': self.ecode,
|
||||
'execution_time': execution_time
|
||||
'execution_time': execution_time,
|
||||
'process_state': self.process_state
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -496,7 +514,8 @@ class BatchProcess(object):
|
||||
},
|
||||
'start_time': self.stime,
|
||||
'exit_code': self.ecode,
|
||||
'execution_time': execution_time
|
||||
'execution_time': execution_time,
|
||||
'process_state': self.process_state
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
@@ -597,7 +616,8 @@ class BatchProcess(object):
|
||||
'etime': p.end_time,
|
||||
'exit_code': p.exit_code,
|
||||
'acknowledge': p.acknowledge,
|
||||
'execution_time': execution_time
|
||||
'execution_time': execution_time,
|
||||
'process_state': p.process_state
|
||||
})
|
||||
|
||||
if changed:
|
||||
@@ -679,6 +699,9 @@ class BatchProcess(object):
|
||||
try:
|
||||
process = psutil.Process(p.utility_pid)
|
||||
process.terminate()
|
||||
# Update the process state to "Terminated"
|
||||
p.process_state = PROCESS_TERMINATED
|
||||
db.session.commit()
|
||||
except psutil.Error as e:
|
||||
current_app.logger.warning(
|
||||
_("Unable to kill the background process '{0}'").format(
|
||||
|
@@ -29,7 +29,7 @@ define('misc.bgprocess', [
|
||||
details: false,
|
||||
notify: (_.isUndefined(notify) || notify),
|
||||
curr_status: null,
|
||||
state: 0, // 0: NOT Started, 1: Started, 2: Finished
|
||||
state: 0, // 0: NOT Started, 1: Started, 2: Finished, 3: Terminated
|
||||
completed: false,
|
||||
|
||||
id: info['id'],
|
||||
@@ -124,6 +124,9 @@ define('misc.bgprocess', [
|
||||
if ('exit_code' in data)
|
||||
self.exit_code = data.exit_code;
|
||||
|
||||
if ('process_state' in data)
|
||||
self.state = data.process_state;
|
||||
|
||||
if ('out' in data) {
|
||||
self.out = data.out && data.out.pos;
|
||||
|
||||
@@ -183,7 +186,9 @@ define('misc.bgprocess', [
|
||||
}
|
||||
|
||||
if (!_.isNull(self.exit_code)) {
|
||||
if (self.exit_code == 0) {
|
||||
if (self.state === 3) {
|
||||
self.curr_status = gettext('Terminated by user.');
|
||||
} else if (self.exit_code == 0) {
|
||||
self.curr_status = gettext('Successfully completed.');
|
||||
} else {
|
||||
self.curr_status = S(
|
||||
@@ -349,18 +354,19 @@ define('misc.bgprocess', [
|
||||
self.curr_status
|
||||
);
|
||||
|
||||
if (self.exit_code === 0) {
|
||||
$status_bar.addClass('bg-success');
|
||||
} else if (self.exit_code == 1) {
|
||||
$status_bar.addClass('bg-failed');
|
||||
}
|
||||
|
||||
// Enable/Disable stop process button
|
||||
var $btn_stop_process = $(self.container.find('.bg-process-stop'));
|
||||
if (isNaN(parseInt(self.exit_code))) {
|
||||
$btn_stop_process.removeClass('disabled');
|
||||
$btn_stop_process.attr('disabled', false);
|
||||
} else {
|
||||
$btn_stop_process.addClass('disabled');
|
||||
$btn_stop_process.attr('disabled', true);
|
||||
if (self.exit_code === 0 && self.state != 3) {
|
||||
$status_bar.addClass('bg-success');
|
||||
$status_bar.removeClass('bg-failed');
|
||||
} else {
|
||||
$status_bar.addClass('bg-failed');
|
||||
$status_bar.removeClass('bg-success');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.show_detailed_view.apply(self);
|
||||
@@ -382,11 +388,7 @@ define('misc.bgprocess', [
|
||||
}
|
||||
|
||||
var container = panel.$container,
|
||||
status_class = (
|
||||
(self.exit_code === 0) ?
|
||||
'bg-bgprocess-success' : (self.exit_code == 1) ?
|
||||
'bg-bgprocess-failed' : ''
|
||||
),
|
||||
status_class = '',
|
||||
$logs = container.find('.bg-process-watcher'),
|
||||
$header = container.find('.bg-process-details'),
|
||||
$footer = container.find('.bg-process-footer'),
|
||||
@@ -394,9 +396,14 @@ define('misc.bgprocess', [
|
||||
|
||||
// Enable/Disable stop process button
|
||||
if (isNaN(parseInt(self.exit_code))) {
|
||||
$btn_stop_process.removeClass('disabled');
|
||||
$btn_stop_process.attr('disabled', false);
|
||||
} else {
|
||||
$btn_stop_process.addClass('disabled');
|
||||
$btn_stop_process.attr('disabled', true);
|
||||
if (self.exit_code === 0 && self.state != 3) {
|
||||
status_class = 'bg-bgprocess-success';
|
||||
} else {
|
||||
status_class = 'bg-bgprocess-failed';
|
||||
}
|
||||
}
|
||||
|
||||
// On Click event to stop the process.
|
||||
@@ -483,6 +490,8 @@ define('misc.bgprocess', [
|
||||
|
||||
stop_process: function() {
|
||||
var self = this;
|
||||
// Set the state to terminated.
|
||||
self.state = 3;
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
timeout: 30000,
|
||||
|
@@ -29,7 +29,7 @@ from flask_sqlalchemy import SQLAlchemy
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
SCHEMA_VERSION = 20
|
||||
SCHEMA_VERSION = 21
|
||||
|
||||
##########################################################################
|
||||
#
|
||||
@@ -259,6 +259,7 @@ class Process(db.Model):
|
||||
exit_code = db.Column(db.Integer(), nullable=True)
|
||||
acknowledge = db.Column(db.String(), nullable=True)
|
||||
utility_pid = db.Column(db.Integer, nullable=False)
|
||||
process_state = db.Column(db.Integer, nullable=False)
|
||||
|
||||
|
||||
class Keys(db.Model):
|
||||
|
@@ -15,9 +15,9 @@ from pgadmin.utils.route import BaseTestGenerator
|
||||
from pickle import dumps, loads
|
||||
|
||||
if sys.version_info < (3, 3):
|
||||
from mock import patch
|
||||
from mock import patch, MagicMock
|
||||
else:
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
|
||||
class BatchProcessTest(BaseTestGenerator):
|
||||
@@ -141,6 +141,7 @@ class BatchProcessTest(BaseTestGenerator):
|
||||
))
|
||||
|
||||
db_mock.session.add.side_effect = db_session_add_mock
|
||||
db_mock.session.commit = MagicMock(return_value=True)
|
||||
|
||||
get_server_details_mock.return_value = \
|
||||
self.class_params['name'],\
|
||||
@@ -165,12 +166,29 @@ class BatchProcessTest(BaseTestGenerator):
|
||||
self.assertTrue(db_mock.session.add.called)
|
||||
|
||||
# Check start method
|
||||
self._check_start(popen_mock, p)
|
||||
self._check_start(popen_mock, p, backup_obj)
|
||||
|
||||
# Check list method
|
||||
self._check_list(p, backup_obj)
|
||||
|
||||
def _check_start(self, popen_mock, p):
|
||||
@patch('pgadmin.misc.bgprocess.processes.Process')
|
||||
def _check_start(self, popen_mock, p, backup_obj, process_mock):
|
||||
class TestMockProcess():
|
||||
def __init__(self, desc, args, cmd):
|
||||
self.pid = 1
|
||||
self.exit_code = 1
|
||||
self.start_time = '2018-04-17 06:18:56.315445 +0000'
|
||||
self.end_time = None
|
||||
self.desc = dumps(desc)
|
||||
self.arguments = " ".join(args)
|
||||
self.command = cmd
|
||||
self.acknowledge = None
|
||||
self.process_state = 0
|
||||
|
||||
mock_result = process_mock.query.filter_by.return_value
|
||||
mock_result.first.return_value = TestMockProcess(
|
||||
backup_obj, self.class_params['args'], self.class_params['cmd'])
|
||||
|
||||
cmd_test = self.class_params['cmd']
|
||||
assert_true = self.assertTrue
|
||||
|
||||
@@ -202,6 +220,7 @@ class BatchProcessTest(BaseTestGenerator):
|
||||
self.arguments = " ".join(args)
|
||||
self.command = cmd
|
||||
self.acknowledge = None
|
||||
self.process_state = 0
|
||||
|
||||
process_mock.query.filter_by.return_value = [
|
||||
TestMockProcess(backup_obj,
|
||||
|
@@ -15,9 +15,9 @@ from pgadmin.utils.route import BaseTestGenerator
|
||||
from pickle import dumps, loads
|
||||
|
||||
if sys.version_info < (3, 3):
|
||||
from mock import patch
|
||||
from mock import patch, MagicMock
|
||||
else:
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
|
||||
class BatchProcessTest(BaseTestGenerator):
|
||||
@@ -89,6 +89,7 @@ class BatchProcessTest(BaseTestGenerator):
|
||||
mock_result.first.return_value = mock_obj
|
||||
|
||||
db_mock.session.add.side_effect = db_session_add_mock
|
||||
db_mock.session.commit = MagicMock(return_value=True)
|
||||
|
||||
maintenance_obj = Message(
|
||||
self.class_params['sid'],
|
||||
@@ -106,12 +107,30 @@ class BatchProcessTest(BaseTestGenerator):
|
||||
self.assertTrue(db_mock.session.add.called)
|
||||
|
||||
# Check start method
|
||||
self._check_start(popen_mock, p)
|
||||
self._check_start(popen_mock, p, maintenance_obj)
|
||||
|
||||
# Check list method
|
||||
self._check_list(p, maintenance_obj)
|
||||
|
||||
def _check_start(self, popen_mock, p):
|
||||
@patch('pgadmin.misc.bgprocess.processes.Process')
|
||||
def _check_start(self, popen_mock, p, maintenance_obj, process_mock):
|
||||
class TestMockProcess():
|
||||
def __init__(self, desc, args, cmd):
|
||||
self.pid = 1
|
||||
self.exit_code = 1
|
||||
self.start_time = '2018-04-17 06:18:56.315445 +0000'
|
||||
self.end_time = None
|
||||
self.desc = dumps(desc)
|
||||
self.arguments = " ".join(args)
|
||||
self.command = cmd
|
||||
self.acknowledge = None
|
||||
self.process_state = 0
|
||||
|
||||
mock_result = process_mock.query.filter_by.return_value
|
||||
mock_result.first.return_value = TestMockProcess(
|
||||
maintenance_obj, self.class_params['args'],
|
||||
self.class_params['cmd'])
|
||||
|
||||
cmd_test = self.class_params['cmd']
|
||||
assert_true = self.assertTrue
|
||||
|
||||
@@ -143,6 +162,7 @@ class BatchProcessTest(BaseTestGenerator):
|
||||
self.arguments = " ".join(args)
|
||||
self.command = cmd
|
||||
self.acknowledge = None
|
||||
self.process_state = 0
|
||||
|
||||
process_mock.query.filter_by.return_value = [
|
||||
TestMockProcess(maintenance_obj,
|
||||
|
@@ -15,9 +15,9 @@ from pgadmin.utils.route import BaseTestGenerator
|
||||
from pickle import dumps, loads
|
||||
|
||||
if sys.version_info < (3, 3):
|
||||
from mock import patch
|
||||
from mock import patch, MagicMock
|
||||
else:
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
|
||||
class BatchProcessTest(BaseTestGenerator):
|
||||
@@ -89,6 +89,7 @@ class BatchProcessTest(BaseTestGenerator):
|
||||
self.class_params['port']
|
||||
|
||||
db_mock.session.add.side_effect = db_session_add_mock
|
||||
db_mock.session.commit = MagicMock(return_value=True)
|
||||
|
||||
restore_obj = RestoreMessage(
|
||||
self.class_params['sid'],
|
||||
@@ -106,12 +107,30 @@ class BatchProcessTest(BaseTestGenerator):
|
||||
self.assertTrue(db_mock.session.add.called)
|
||||
|
||||
# Check start method
|
||||
self._check_start(popen_mock, p)
|
||||
self._check_start(popen_mock, p, restore_obj)
|
||||
|
||||
# Check list method
|
||||
self._check_list(p, restore_obj)
|
||||
|
||||
def _check_start(self, popen_mock, p):
|
||||
@patch('pgadmin.misc.bgprocess.processes.Process')
|
||||
def _check_start(self, popen_mock, p, restore_obj, process_mock):
|
||||
class TestMockProcess():
|
||||
def __init__(self, desc, args, cmd):
|
||||
self.pid = 1
|
||||
self.exit_code = 1
|
||||
self.start_time = '2018-04-17 06:18:56.315445 +0000'
|
||||
self.end_time = None
|
||||
self.desc = dumps(desc)
|
||||
self.arguments = " ".join(args)
|
||||
self.command = cmd
|
||||
self.acknowledge = None
|
||||
self.process_state = 0
|
||||
|
||||
mock_result = process_mock.query.filter_by.return_value
|
||||
mock_result.first.return_value = TestMockProcess(
|
||||
restore_obj, self.class_params['args'],
|
||||
self.class_params['cmd'])
|
||||
|
||||
cmd_test = self.class_params['cmd']
|
||||
assert_true = self.assertTrue
|
||||
|
||||
@@ -143,6 +162,7 @@ class BatchProcessTest(BaseTestGenerator):
|
||||
self.arguments = " ".join(args)
|
||||
self.command = cmd
|
||||
self.acknowledge = None
|
||||
self.process_state = 0
|
||||
|
||||
process_mock.query.filter_by.return_value = [
|
||||
TestMockProcess(restore_obj,
|
||||
|
Reference in New Issue
Block a user