SaltStack Job 管理 及 saltutil.signal_job 模塊的問題

原文連接:http://www.huangdc.com/66 html

一、什麼是 Job python

    在salt 中,每次執行一次salt命令就會產生一個Job ,Salt 實時管理的任務都是做爲Job來執行的;在maste執行一次salt 命令,minion 就會產生一個惟一的 job id ,job id 能夠在minion 機器 /var/cache/salt/minion/proc/ 查看 ,咱們能夠經過 job id 獲取到job 的執行狀態等信息 linux

例如,測試環境以下: shell

    master : 192.168.202.72 vim

    minion : 192.168.201.37 bash

咱們在master 執行一個命令: salt '192.168.201.37' cmd.run "sh /root/dc.sh" 函數

## minion 的腳本:(爲方便測試及查看,dc.sh 腳本作了 sleep 50s)
[root@localhost ~]# cat /root/dc.sh 
#!/bin/sh
i=1
while (($i<50)) ; do
    echo "$i"
    let ++i 
    sleep 1
done

## master 執行:
[root@local200-72 ~]# salt '192.168.201.37' cmd.run "sh /root/dc.sh"

## minion 查看:
[root@localhost ~]# ll /var/cache/salt/minion/proc/
total 8
-rw-r--r-- 1 root root 113 Aug  8 15:11 20150808231316960508


二、Job 經常使用管理命令  測試

(1)saltutil 模塊中的 job管理⽅法  https://docs.saltstack.com/en/develop/ref/modules/all/salt.modules.saltutil.html spa

        saltutil.running #查看minion當前正在運⾏的jobs code

        saltutil.find_job <jid> #查看指定jid的job(minion正在運⾏的jobs)

        saltutil.signal_job <jid> <single> #給指定的jid進程發送信號

        saltutil.term_job <jid> #終⽌指定的jid進程(信號爲15)

        saltutil.kill_job <jid> #終⽌指定的jid進程(信號爲9)

        ## salt '*' saltutil.signal_job <job id> 15

(2)salt runner 中的job管理⽅法 https://docs.saltstack.com/en/develop/topics/jobs/index.html

        salt-run jobs.active     #查看全部minion當前正在運⾏的jobs(在全部minions上運⾏saltutil.running)

        salt-run jobs.lookup_jid  <jid>  #從master jobs cache中查詢指定jid的運⾏結果

        salt-run jobs.list_jobs      #列出當前master jobs cache中的全部job

    

(3)runner 模塊獲取job 狀態信息

import salt.runner
opts = salt.config.master_config('/etc/salt/master')
runner = salt.runner.RunnerClient(opts)
runner.cmd('jobs.lookup_jid', [str(job_id)])


三、簡單實例 

(1)在master 執行一個命令: salt '192.168.201.37' cmd.run "sh /root/dc.sh"  ; 並查看job 的狀態

## master 窗口1執行:
[root@local200-72 ~]# salt '192.168.201.37' cmd.run "sh /root/dc.sh"

## master 窗口2查看:
[root@local200-72 ~]# salt-run jobs.active   
20150808232959218377:
    ----------
    Arguments:
        - sh /root/dc.sh
    Function:
        cmd.run
    Returned:
    Running:
        |_
          ----------
          192.168.201.37:
              15767
    Target:
        192.168.201.37
    Target-type:
        glob
    User:
        root
[root@local200-72 ~]# salt-run jobs.lookup_jid 20150808232959218377
192.168.201.37:
    1
    2
    3
   ...(省略)

## minion:
[root@localhost ~]# ll /var/cache/salt/minion/proc/
total 8
-rw-r--r-- 1 root root 113 Aug  8 15:26 20150808232959218377

(2)在master 執行一個命令: salt '192.168.201.37' cmd.run "sh /root/dc.sh"  ; 並在中途經過job id  kill 掉這個 job 

## master 窗口1執行:
[root@local200-72 ~]# salt '192.168.201.37' cmd.run "sh /root/dc.sh"


## minion:查看 job id
[root@localhost ~]# ll /var/cache/salt/minion/proc/
total 8
-rw-r--r-- 1 root root 113 Aug  8 15:44 20150808234707827791
[root@localhost ~]# ps -ef |grep dc.sh
root     16986 16985  0 15:44 ?        00:00:00 sh /root/dc.sh
[root@localhost ~]# ps -ef |grep 16985
root     16985     1  0 15:44 ?        00:00:00 /usr/bin/python2.6 /usr/bin/salt-minion -d
root     16986 16985  0 15:44 ?        00:00:00 sh /root/dc.sh

## master 查看執行 kill
[root@local200-72 ~]# salt '192.168.201.37' saltutil.signal_job 20150808234707827791 15
192.168.201.37:
    Signal 15 sent to job 20150808234707827791 at pid 16985
    
    
## minion 繼續查看 進程及job id
[root@localhost ~]# ps -ef |grep dc.sh
root     16986 1 0 15:44 ?        00:00:00 sh /root/dc.sh
[root@localhost ~]# ll /var/cache/salt/minion/proc/
total 0

## 細心的朋友會發現,當咱們在master 執行命令調用其餘腳本的時候, saltutil.signal_job 把 job id kill 掉了,可是以前此 job 調用的腳本,並無被kill 掉 (爲何呢)


四、Job 管理中的  signal_job 問題(如上問題)

    當咱們在master 執行命令調用其餘腳本的時候, saltutil.signal_job 把 job id kill 掉了,可是以前此 job 調用的腳本,並無被kill 掉 。

    (1)linux 中,子進程及父進程的問題  , 咱們能夠來測試一下 linux 中是如何kill 掉進程及父進程的

          經過a.sh 腳本調用 dc.sh     (dc.sh 如上不變) , a.sh 以下:

            測試1 , kill 命令

[root@localhost ~]# cat a.sh 
#!/bin/sh

sh /root/dc.sh

echo "xx"
[root@localhost ~]# sh a.sh &
[root@localhost ~]# ps -ef |grep a.sh 
root     17559 14095  0 15:52 pts/2    00:00:00 sh a.sh
[root@localhost ~]# ps -ef |grep 17559
root     17559 14095  0 15:52 pts/2    00:00:00 sh a.sh
root     17560 17559  0 15:52 pts/2    00:00:00 sh /root/dc.sh
[root@localhost ~]# kill 17559
[root@localhost ~]# ps -ef |grep 17559
root     17633 17569  0 15:52 pts/3    00:00:00 grep 17559
[root@localhost ~]# ps -ef |grep dc.sh
root     17560     1  0 15:52 pts/2    00:00:00 sh /root/dc.sh

## 一樣,當kill 掉 父進程的id 17559 後, 子進程 dc.sh 仍然在運行  (發現父進程是被kill掉了,可是子進程還活着,並且PPID已經換成爲1,也就是init(1)進程)

        測試2 , kill  -9 命令  (測試結果同上)

說明: kill 通常只能殺掉單個進程,一樣,咱們也能夠發送信號給進程組

        好,測試3,kill -- -<gpid> (kill 掉進程組)  ( 注意 兩個橫線<空格>一個橫線<gpid>)

        查看組進程ID : ps efo pid,pgid,ppid,comm 

 好了,終於把 父進程和 子進程都kill 掉了,,,問題又來了,,,爲何 salt  saltutil.signal_job 並無把 子進程也kill 掉呢?

    (2)修改 minion 的 /usr/lib/python2.6/site-packages/salt/modules/saltutil.py  模塊代碼

咱們來看一下 salt saltutil 模塊的代碼:/usr/lib/python2.6/site-packages/salt/modules/saltutil.py

[root@local200-72 modules]# vim /usr/lib/python2.6/site-packages/salt/modules/saltutil.py

... (前面省略)
## 咱們直接來看一下  signal_job 函數的代碼,下面我加了註釋

def signal_job(jid, sig):
    '''
    Sends a signal to the named salt job's process

    CLI Example:

    .. code-block:: bash

        salt '*' saltutil.signal_job <job id> 15
    '''
    for data in running():
        if data['jid'] == jid:
            try:
                os.kill(int(data['pid']), sig)
                ## 這個地方,你會發現 saltutil 只是使用kill 命令,因此沒法kill 掉子進程 ; 
                ## 但你往下看代碼,你會發現 saltutil 是有去kill child_pids ,我測試後發現,data['child_pids'] 的值是爲空的; 有就是說 salt並無獲取到 child_pids 。 因此 沒法kill 掉子進程。
                ## 好了,緣由咱們知道了,咱們應該如何修改呢,固然能夠修改salt的saltutil 模塊代碼
                ## 解決方法 使用 os.killpg(gpid,sig) 
                
                ## 將上面的 os.kill(int(data['pid']), sig) 修改成 os.killpg(os.getpgid(int(data['pid'])),sig)  便可
                
                
                if 'child_pids' in data:
                    for pid in data['child_pids']:
                        os.kill(int(pid), sig)
                return 'Signal {0} sent to job {1} at pid {2}'.format(
                        int(sig),
                        jid,
                        data['pid']
                        )
            except OSError:
                path = os.path.join(__opts__['cachedir'], 'proc', str(jid))
                if os.path.isfile(path):
                    os.remove(path)
                return ('Job {0} was not running and job data has been '
                        ' cleaned up').format(jid)
    return ''
    
... (後面省略)


    好了,問題終於解決了,,,

    總結,這裏簡單描述一下 salt job 的管理及遇到saltutil.signal_job 的問題

原文連接:http://www.huangdc.com/66

相關文章
相關標籤/搜索