|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
# Copyright 2012-2016 Mir Calculate. http://www.calculate-linux.org
|
|
|
#
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
# You may obtain a copy of the License at
|
|
|
#
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
#
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
# See the License for the specific language governing permissions and
|
|
|
# limitations under the License.
|
|
|
|
|
|
from __future__ import print_function
|
|
|
from __future__ import absolute_import
|
|
|
import os
|
|
|
import pickle
|
|
|
import threading
|
|
|
from os import path
|
|
|
import random
|
|
|
from calculate.core.server.core_interfaces import CoreServiceInterface
|
|
|
from calculate.lib.utils.files import listDirectory, readFile, readLinesFile
|
|
|
from calculate.lib.utils.tools import ignore
|
|
|
import socket
|
|
|
|
|
|
from .cert_cmd import find_cert_id
|
|
|
|
|
|
|
|
|
class ProcessStatus(object):
|
|
|
SuccessFinished = 0
|
|
|
Worked = 1
|
|
|
FailedFinished = 2
|
|
|
NotFound = 3
|
|
|
Paused = 4
|
|
|
|
|
|
|
|
|
class ProcessMode(object):
|
|
|
CoreDaemon = "core"
|
|
|
LocalCall = "local"
|
|
|
|
|
|
|
|
|
def get_symlink_commands():
|
|
|
"""
|
|
|
Получить список команд утилит
|
|
|
"""
|
|
|
symlinks = "/var/lib/calculate/calculate-core/conf/symlinks"
|
|
|
for line in readLinesFile(symlinks):
|
|
|
yield line.strip()
|
|
|
yield "/usr/bin/cl-core"
|
|
|
yield "/usr/bin/cl-update"
|
|
|
yield "/usr/bin/cl-core-patch"
|
|
|
|
|
|
|
|
|
def search_worked_process(method_name, clVars,
|
|
|
statuses=(ProcessStatus.Worked,)):
|
|
|
"""
|
|
|
Найти все работающие процессы
|
|
|
|
|
|
Возвращает список процессов со статусом Worked и существующем системным
|
|
|
процессом
|
|
|
"""
|
|
|
|
|
|
def generator():
|
|
|
pids = clVars.Get('core.cl_core_pids_path')
|
|
|
for pidfile in listDirectory(pids, fullPath=True):
|
|
|
try:
|
|
|
status = pickle.load(open(pidfile))
|
|
|
if ((method_name is None or status['name'] == method_name) and
|
|
|
status['status'] in statuses):
|
|
|
pid_path = path.join("/proc", str(status['os_pid']))
|
|
|
if path.exists(pid_path):
|
|
|
cmdline = readFile(path.join(pid_path, "cmdline"))
|
|
|
if cmdline and any(x in cmdline
|
|
|
for x in get_symlink_commands()):
|
|
|
yield status['os_pid']
|
|
|
except (socket.error, ValueError, KeyError, EOFError, OSError):
|
|
|
pass
|
|
|
|
|
|
return list(generator())
|
|
|
|
|
|
|
|
|
worked_filter = lambda x: x['status'] == ProcessStatus.Worked
|
|
|
|
|
|
|
|
|
def search_worked_process2(clVars, filter_func=lambda x: True,
|
|
|
status_filter=worked_filter):
|
|
|
pids = clVars.Get('core.cl_core_pids_path')
|
|
|
for pidfile in listDirectory(pids, fullPath=True):
|
|
|
try:
|
|
|
status = pickle.load(open(pidfile))
|
|
|
if status_filter(status) and filter_func(status):
|
|
|
pid_path = path.join("/proc", str(status['os_pid']))
|
|
|
if path.exists(pid_path):
|
|
|
cmdline = readFile(path.join(pid_path, "cmdline"))
|
|
|
if cmdline and any(x in cmdline
|
|
|
for x in get_symlink_commands()):
|
|
|
yield status['os_pid']
|
|
|
except (socket.error, ValueError, KeyError, EOFError, OSError):
|
|
|
pass
|
|
|
|
|
|
|
|
|
def get_pid_info(clVars, statuses=(ProcessStatus.Worked,)):
|
|
|
"""
|
|
|
Получить информацию о процессах
|
|
|
"""
|
|
|
|
|
|
def generator():
|
|
|
pids = clVars.Get('core.cl_core_pids_path')
|
|
|
for pidfile in listDirectory(pids, fullPath=True):
|
|
|
try:
|
|
|
status = pickle.load(open(pidfile))
|
|
|
if status['status'] in statuses:
|
|
|
if path.exists(path.join("/proc", str(status['os_pid']))):
|
|
|
yield status
|
|
|
except (socket.error, ValueError, KeyError, EOFError, OSError):
|
|
|
pass
|
|
|
|
|
|
return list(generator())
|
|
|
|
|
|
# try:
|
|
|
# pidfile = path.join(pids,str(pid))
|
|
|
# status = pickle.load(open(pidfile))
|
|
|
# return status
|
|
|
# except (socket.error, ValueError, IOError, KeyError, EOFError, OSError):
|
|
|
# return None
|
|
|
|
|
|
|
|
|
def clear_finished_pids(clVars):
|
|
|
"""
|
|
|
Удалить все идентификационные файлы завершившихся процессов
|
|
|
"""
|
|
|
pids = clVars.Get('core.cl_core_pids_path')
|
|
|
for pidfile in listDirectory(pids, fullPath=True):
|
|
|
try:
|
|
|
d = pickle.load(open(pidfile))
|
|
|
if path.exists(path.join("/proc", str(d['os_pid']))):
|
|
|
continue
|
|
|
except Exception:
|
|
|
pass
|
|
|
with ignore(OSError):
|
|
|
os.unlink(pidfile)
|
|
|
|
|
|
|
|
|
# process management
|
|
|
class CoreWsdl(CoreServiceInterface):
|
|
|
#for debugging:
|
|
|
gen_pid_testing_val = "Gen pid represents"
|
|
|
|
|
|
# delete process id from list process
|
|
|
@staticmethod
|
|
|
def del_pid(cls, pid):
|
|
|
try:
|
|
|
rst = []
|
|
|
pid_str = str(pid)
|
|
|
|
|
|
# open the file list of process
|
|
|
with open(cls.pids_file) as fd:
|
|
|
t = fd.read()
|
|
|
for line in t.splitlines():
|
|
|
# Leave all but removed
|
|
|
if line != pid_str:
|
|
|
rst.append(line)
|
|
|
|
|
|
# write all in file
|
|
|
fd = open(cls.pids_file, 'w')
|
|
|
fd.write('\n'.join(rst))
|
|
|
fd.write('\n') # with join we lose the last newline char
|
|
|
fd.close()
|
|
|
cls.glob_process_dict.pop(pid)
|
|
|
cls.glob_progress_dict.pop(pid)
|
|
|
cls.glob_table_dict.pop(pid)
|
|
|
cls.glob_frame_list.pop(pid)
|
|
|
with ignore(OSError):
|
|
|
rm_fn = path.join(cls.pids, "%d.pid" % pid)
|
|
|
if path.exists(rm_fn):
|
|
|
os.unlink(rm_fn)
|
|
|
return 0
|
|
|
except Exception:
|
|
|
return 1
|
|
|
|
|
|
# find process id in file processes, 1 - yes, 0 - none
|
|
|
@staticmethod
|
|
|
def find_pid_in_file(cls, find_pid):
|
|
|
temp_line = ''
|
|
|
|
|
|
# create, if file not exists
|
|
|
if not os.path.exists(cls.pids_file):
|
|
|
temp = open(cls.pids_file, 'w')
|
|
|
temp.close()
|
|
|
with open(cls.pids_file) as fd:
|
|
|
t = fd.read()
|
|
|
# for each line
|
|
|
for line in t.splitlines():
|
|
|
try:
|
|
|
temp_line = int(line)
|
|
|
except ValueError:
|
|
|
pass
|
|
|
# if process id found
|
|
|
if temp_line == find_pid:
|
|
|
return 1
|
|
|
fd.close()
|
|
|
return 0
|
|
|
|
|
|
# add process id in file
|
|
|
@staticmethod
|
|
|
def add_pid_in_file(cls, pid):
|
|
|
pid_t = str(pid)
|
|
|
fd = open(cls.pids_file, 'a')
|
|
|
fd.write(pid_t)
|
|
|
fd.write('\n')
|
|
|
fd.close()
|
|
|
return 0
|
|
|
|
|
|
# issue new pid for created process
|
|
|
@staticmethod
|
|
|
def gen_pid(cls):
|
|
|
while True:
|
|
|
new_pid = random.randint(1, cls.max_pid)
|
|
|
# flag = 1 - exists, 0 - missing in PID_FILE
|
|
|
if cls.find_pid_in_file(cls, new_pid) == 0:
|
|
|
cls.add_pid_in_file(cls, new_pid)
|
|
|
return new_pid
|
|
|
|
|
|
@staticmethod
|
|
|
def check_sid_cert(cls, sid):
|
|
|
curThread = threading.currentThread()
|
|
|
certificate = curThread.client_cert
|
|
|
cert_id = find_cert_id(certificate, cls.data_path, cls.certbase)
|
|
|
|
|
|
# if certificate not found in database
|
|
|
if cert_id == 0:
|
|
|
return -1
|
|
|
# check, This certificate is launched session
|
|
|
# Data taken from sid.db
|
|
|
flag = 0
|
|
|
# create, if file not exists
|
|
|
if not os.path.exists(cls.sids_file):
|
|
|
return 0
|
|
|
# temp = open(cls.sids_file, 'w')
|
|
|
# temp.close()
|
|
|
fd = open(cls.sids_file, 'r')
|
|
|
while 1:
|
|
|
try:
|
|
|
# read all on one record
|
|
|
list_sid = pickle.load(fd)
|
|
|
except (EOFError, KeyError, IOError):
|
|
|
break
|
|
|
# when session id equal readable...
|
|
|
if int(sid) == int(list_sid[0]):
|
|
|
# ... and certificate id equal launched this session...
|
|
|
if int(cert_id) == int(list_sid[1]):
|
|
|
# ... set flag
|
|
|
flag = 1
|
|
|
fd.close()
|
|
|
# if validation fails
|
|
|
return flag
|
|
|
|
|
|
@staticmethod
|
|
|
def serv_pid_kill(cls, pid, sid):
|
|
|
""" Set flag to complete the process """
|
|
|
check_sid = cls.check_sid_cert(cls, sid)
|
|
|
if not check_sid:
|
|
|
return -2
|
|
|
|
|
|
# write complete flag (pid_list[6] = 1) in process file
|
|
|
if not os.path.exists(cls.pids):
|
|
|
os.mkdir(cls.pids)
|
|
|
if pid not in cls.process_pid:
|
|
|
return 3
|
|
|
meth = cls.process_pid[pid]
|
|
|
if meth.is_alive():
|
|
|
try:
|
|
|
os.kill(meth.pid, 2)
|
|
|
except OSError as e:
|
|
|
print('No such process %d' % meth.pid, e)
|
|
|
return 1
|
|
|
return 0
|