rc脚本的编写,普通和daemon模式启动

一、编写启动脚本

1.写一个启动脚本。

对mencached做启动脚本。

2.先把一个结构搭建好。

import sys
class Progames(object):  # 创建一个类
    def __init__(self, name, progame, workdir, args):  # 通过构造函数,在脚本运行的时候就传入4个参数,就不用手动去指定参数了。
        self.name = name
        self.progame = progame
        self.args = args
        self.workdir = workdir
    def _init(self):       #初始化普通的方法。判断有没有目录,如果没有就创建。
     
    def start(self):  # 定义start 方法。启动程序
        
    def stop(self):  # 定义stop方法,关闭程序
 
    def restart(self):  # 定义重启方法,重启程序,也就是执行关闭和启动的方法。
        self.stop()
        self.start()
    def status(self):  # 定义status方法,查看运行情况
    
    def help(self):  # 定义help方法,查看帮助
 
 
def main():  # 定义一个函数,通过调用这个函数来控制程序。
    name = 'memcached'                                   #这几个参数就是调用类时初始化传入的参数
    progame = '/usr/bin/memcached'
    workdir = '/var/tmp/memcached'
    args = '-u nobody -p 11211 -c 1024 -m 64'
    pm = Progames(name = name,
                  progame = progame,
                  workdir = workdir,
                  args = args)
      try:                                #判断输入的第一个参数 类似$1
        cmd = sys.argv[1]
    except IndexError, e:              #当捕获了indexerror错误后,输出错误信息
        print("Option error")
        sys.exit()
    if cmd == 'start':               #如果参数为start ,调用start方法
        pm.start()
    elif cm == 'stop':               #如果参数为start ,调用stop方法
        pm.stop()
    elif cm == 'restart':            #如果参数为start ,调用restart方法
        pm.restart()
    elif cm == 'status':             #如果参数为start ,调用status方法
        pm.status()
    else:                            #如果都不是以上参数,输出help信息
        pm.help()
if __name__ == '__main__':  # 如果调用的是本身,就启动main函数。
    main()

3.编写start方法。

3.1.先对_init方法进行编写。

def _init(self):
      if not os.path.exists(self.workdir):     #判断文件是否存在。如果不存在,创建目录
            os.mkdir(self.workdir)               #不存在就创建目录,
            os.chdir(self.workdir)               #进入目录,chdir 类似cd命令
2.调用from subprocess import PIPE,Popen 来执行shell
from subprocess import PIPE,Popen
    def start(self):  
       cmd = self.progame + ' '+ self.args   #定义启动的命令。shell下的启动命令。
cmd = Popen(cmd,stdout=PIPE,shell=True)
self.pid = p.pid          #p.pid可以得到进程号。用一个对象属性接收一下,方便写入到pid文件中

3.2.测试Popen函数,可以看到执行了shell命令。

1.jpg

3.3.继续定义2个方法,一个是定义pid的绝对路径,一个是定义写入pid文件的方法。

def _pidFile(self):                          #判断pid文件
        return os.path.join(self.workdir,"%s.pid" % self.name)   #连接路径和文件名,形成pid的绝对路径
    def _writePid(self):                         #定义写入pid值得方法。
        if self.pid:                             #如果有pid
            with open(self._pidFile(),'w') as fd:     #打开pid文件写入
                fd.write(str(self.pid))               #得到的值是数值型的,需要转换str 才可以写入


3.4.start方法完整

3.4.1.定义start方法前,先定义了2个方法_pidFile,_writePid ,一个是定义pid文件的路径,和写入PID文件的值。

def _pidFile(self):                          #返回文件路径的方法。
        return os.path.join(self.workdir,"%s.pid" % self.name)   #连接路径和文件名,形成pid的绝对路径
    def _writePid(self):                         #定义写入pid值得方法。
        if self.pid:                             #如果有pid
            with open(self._pidFile(),'w') as fd:     #打开pid文件写入
                fd.write(str(self.pid))               #得到的值是数值型的,需要转换str 才可以写入
    def start(self):  # 定义start 方法。启动程序
        self._init()                                  #调用判断pid文件是否存在的方法
        cmd = self.progame + ' '+ self.args           #定义启动的命令。shell下的启动命令。
        p  = Popen(cmd,stdout=PIPE,shell=True)
        self.pid = p.pid
        self._writePid()     #调用写入方法。
        print("%s start sucessfull" % (self.name))

4.编写stop和status方法

4.1.stop方法的思路,判断这个程序在不在运行,如果在运行找到进程号,kill掉,并删除pid文件,如果不在运行,查看pid文件是否存在。如果存在删掉。如果都不存在,说明已经stop了

4.2.使用pidof命令可以得到程序是否在运行,并且获取到进程号,还是调用Popen方法来运行shell的pidof命令。

rc脚本的编写,普通和daemon模式启动_第1张图片

4.3.定义一个获取pid的方法

 def _getPid(self):                               #定义获取pid的方法。
        p = Popen(['pidof',self.name],stdout=PIPE)        #执行获取PID的命令
        pid = p.stdout.read().strip()                  #获取到的PID分割一下,删除换行符
        return pid                                     #返回pid的值

4.4.kill进程号

使用os模块里的kill方法。

os.kill(PIDnumber,15) 一般kill的信号是15.

rc脚本的编写,普通和daemon模式启动_第2张图片

4.5.stop方法完整版。

 def _getPid(self):                               #定义获取pid的方法。
        p = Popen(['pidof',self.name],stdout=PIPE)        #执行获取PID的命令
        pid = p.stdout.read().strip()                  #获取到的PID分割一下,删除换行符
        return pid                                     #返回pid的值
    def stop(self):  # 定义stop方法,关闭程序
        pid = self._getPid()                          #获取PID
        if pid:                                       #如果有PID的话
            os.kill(int(pid),15)                     #因为获取到的是一个字符串,要转换×××才可以杀死
            if os.path.exists(self._pidFile()):      #如果pid文件存在
                os.remove(self._pidFile())           #删除文件
            print("%s is stopped" % self.name)

4.6.status方法思路:判断pid 是否存在,如果存在就说明在运行。不在就没运行

   def status(self):  # 定义status方法,查看运行情况
        pid = self._getPid()              #判断pid是否存在
        if pid:
            print("%s is running" % self.name)
        else:
            print("$s is not running" % self.name)

4.7.定义help方法

 def help(self):  # 定义help方法,查看帮助
        print("Usage: %s {start|restart|stop|status}" % __file__)   #%__file__ 类似shell的$0代表脚本本身。

完整的代码:

import sys
import os
from subprocess import PIPE,Popen    #调用shell命令行。
class Progames(object):  # 创建一个类
    def __init__(self, name, progame, workdir, args):  # 通过构造函数,在脚本运行的时候就传入4个参数,就不用手动去指定参数了。
        self.name = name
        self.progame = progame
        self.args = args
        self.workdir = workdir
    def _init(self):       #初始化普通的方法。判断有没有目录,如果没有就创建。
        if not os.path.exists(self.workdir):     #判断文件是否存在。如果不存在,创建目录
            os.mkdir(self.workdir)               #不存在就创建目录,
            os.chdir(self.workdir)               #进入目录,chdir 类似cd命令
    def _pidFile(self):                          #返回文件路径的方法。
        return os.path.join(self.workdir,"%s.pid" % self.name)   #连接路径和文件名,形成pid的绝对路径
    def _writePid(self):                         #定义写入pid值得方法。
        if self.pid:                             #如果有pid
            with open(self._pidFile(),'w') as fd:     #打开pid文件写入
                fd.write(str(self.pid))               #得到的值是数值型的,需要转换str 才可以写入
    def start(self):  # 定义start 方法。启动程序
        pid = self._getPid()                          #获取PID
        if pid:                                       #如果有PID提示。
            print("%s is running" % self.name)
            sys.exit()
        self._init()                                  #调用判断pid文件是否存在的方法
        cmd = self.progame + ' '+ self.args           #定义启动的命令。shell下的启动命令。
        p = Popen(cmd,stdout=PIPE,shell=True)
        self.pid = p.pid
        self._writePid()     #调用写入方法。
        print("%s start sucessfull" % (self.name))
    def _getPid(self):                               #定义获取pid的方法。
        p = Popen(['pidof',self.name],stdout=PIPE)        #执行获取PID的命令
        pid = p.stdout.read().strip()                  #获取到的PID分割一下,删除换行符
        return pid                                     #返回pid的值
    def stop(self):  # 定义stop方法,关闭程序
        pid = self._getPid()                          #获取PID
        if pid:                                       #如果有PID的话
            os.kill(int(pid),15)                     #因为获取到的是一个字符串,要转换×××才可以杀死
            if os.path.exists(self._pidFile()):      #如果pid文件存在
                os.remove(self._pidFile())           #删除文件
            print("%s is stopped" % self.name)
    def restart(self):  # 定义重启方法,重启程序,也就是执行关闭和启动的方法。
        self.stop()
        self.start()
    def status(self):  # 定义status方法,查看运行情况
        pid = self._getPid()              #判断pid是否存在
        if pid:
            print("%s is running" % self.name)
        else:
            print("$s is not running" % self.name)
    def help(self):  # 定义help方法,查看帮助
        print("Usage: %s {start|restart|stop|status}" % __file__)   #%__file__ 类似shell的$0代表脚本本身。
 
def main():  # 定义一个函数,通过调用这个函数来控制程序。
    name = 'memcached'                                   #这几个参数就是调用类时初始化传入的参数
    progame = '/usr/bin/memcached'
    workdir = '/var/tmp/memcached'
    args = '-u nobody -p 11211 -c 1024 -m 64'
    pm = Progames(name = name,
                  progame = progame,
                  workdir = workdir,
                  args = args)
    try:                                #判断输入的第一个参数 类似$1
        cmd = sys.argv[1]
    except IndexError, e:              #当捕获了indexerror错误后,输出错误信息
        print("Option error")
        sys.exit()
    if cmd == 'start':               #如果参数为start ,调用start方法
        pm.start()
    elif cm == 'stop':               #如果参数为start ,调用stop方法
        pm.stop()
    elif cm == 'restart':            #如果参数为start ,调用restart方法
        pm.restart()
    elif cm == 'status':             #如果参数为start ,调用status方法
        pm.status()
    else:                            #如果都不是以上参数,输出help信息
        pm.help()
 
if __name__ == '__main__':  # 如果调用的是本身,就启动main函数。
    main()

这就完成了一个启动脚本,但是这个启动脚本不是daemon方式运行的。


5.以daemon方式启动脚本

5.1.当我们执行了start后如果在次执行start ,会发现pid的文件数值会改变,但是进程的pid号还是没有改变的。这就有一个小bug了

 pid = self._getPid()                          #获取PID
        if pid:                                       #如果有PID提示。
            print("%s is running" % self.name)
            sys.exit()

    在start方法里加上这段代码就可以了,如果有pid提示正在运行然后退出脚本

5.2.用daemon的方式写脚本。可以使用默认参数运行,在文件中定义参数,以定义的文件为主。完整代码如下:

import sys
import os
from subprocess import PIPE,Popen    #调用shell命令行。
class Progames(object):  # 创建一个类
         args = {'USER':'memcached',            #创建默认参数,所有方法都可以调用
     'PORT':11211,
     'MAXCONN':1024,
'CACHESIZE' : 64
'OPTIONS': ''}
   def __init__(self, name, progame, workdir, ):  # 通过构造函数,在脚本运行的时候就传入4个参数,就不用手动去指定参数了。
        self.name = name
        self.progame = progame
        self.workdir = workdir
    def _init(self):       #初始化普通的方法。判断有没有目录,如果没有就创建。
        if not os.path.exists(self.workdir):     #判断文件是否存在。如果不存在,创建目录
            os.mkdir(self.workdir)               #不存在就创建目录,
            os.chdir(self.workdir)               #进入目录,chdir 类似cd命令
    def _pidFile(self):                          #返回文件路径的方法。
        return os.path.join(self.workdir,"%s.pid" % self.name)   #连接路径和文件名,形成pid的绝对路径
    def _writePid(self):                         #定义写入pid值得方法。
        if self.pid:                             #如果有pid
            with open(self._pidFile(),'w') as fd:     #打开pid文件写入
                fd.write(str(self.pid))               #得到的值是数值型的,需要转换str 才可以写入
    def _readConf(self,f):             #定义一个查看参数文件的方法。
    with open(f) as fd:            #打开参数文件
    lines = readlines()      #获取里面的值
    return dict(i.strip().replace('"','').split('=') for i in lines)   
    #使用列表重写的方式得到一个字典类型的值,strip去掉空格,replace替换"双引号为单引号,split 以=号来进行切割。最后的到一个字典。
    def _parseArgs(self):            #定义一个使用参数文件覆盖默认参数的值得方法。
      conf = self._readConf('/etc/sysconfig/memcached')      #定义打开的参数文件路径
    if 'USER' in conf:              #判断如果字典里有USER这个KEY就用参数文件里的值去替换默认参数里的值。下面也是一个意思。
        self.args['USER'] = conf['USER']
    if 'PORT' in conf:
        self.args['PORT'] = conf['PORT']
    if 'MAXCONN' in conf:
        self.args['MAXCONN'] = conf['MAXCONN']
    if 'CACHESIZE' in conf:
        self.args['CACHESIZE'] = conf['CACHESIZE']
    options = ['-u' ,self.args['USER'],          #定义启动参数
    '-p',self.args['PORT]',
    '-m',self.args['CACHESIZE'],
    '-c',self.args['MAXCONN' ]]
     os.system('chown %s %s' % (self.args['USER'],self.workdir))   #对PID目录进行授权,可以写入文件。
return options                     #返回启动参数列表。
    def start(self):  # 定义start 方法。启动程序
        pid = self._getPid()                          #获取PID
        if pid:                                       #如果有PID提示。
            print("%s is running" % self.name)
            sys.exit()
        self._init()                                  #调用判断pid文件是否存在的方法
        cmd = [self.progame] + self._parseArgs() ['-d','-P',self._pidFile()]           #定义启动的命令。shell下的启动命令。
        p = Popen(cmd,stdout=PIPE)      #默认是false
        print("%s start sucessfull" % (self.name))
    def _getPid(self):                               #定义获取pid的方法。
        p = Popen(['pidof',self.name],stdout=PIPE)        #执行获取PID的命令
        pid = p.stdout.read().strip()                  #获取到的PID分割一下,删除换行符
        return pid                                     #返回pid的值
    def stop(self):  # 定义stop方法,关闭程序
        pid = self._getPid()                          #获取PID
        if pid:                                       #如果有PID的话
            os.kill(int(pid),15)                     #因为获取到的是一个字符串,要转换×××才可以杀死
            if os.path.exists(self._pidFile()):      #如果pid文件存在
                os.remove(self._pidFile())           #删除文件
            print("%s is stopped" % self.name)
    def restart(self):  # 定义重启方法,重启程序,也就是执行关闭和启动的方法。
        self.stop()
        self.start()
    def status(self):  # 定义status方法,查看运行情况
        pid = self._getPid()              #判断pid是否存在
        if pid:
            print("%s is running" % self.name)
        else:
            print("$s is not running" % self.name)
    def help(self):  # 定义help方法,查看帮助
        print("Usage: %s {start|restart|stop|status}" % __file__)   #%__file__ 类似shell的$0代表脚本本身。
 
def main():  # 定义一个函数,通过调用这个函数来控制程序。
    name = 'memcached'                                   #这几个参数就是调用类时初始化传入的参数
    progame = '/usr/bin/memcached'
    workdir = '/var/tmp/memcached'
    pm = Progames(name = name,
                  progame = progame,
                  workdir = workdir)
    try:                                #判断输入的第一个参数 类似$1
        cmd = sys.argv[1]
    except IndexError, e:              #当捕获了indexerror错误后,输出错误信息
        print("Option error")
        sys.exit()
    if cmd == 'start':               #如果参数为start ,调用start方法
        pm.start()
    elif cm == 'stop':               #如果参数为start ,调用stop方法
        pm.stop()
    elif cm == 'restart':            #如果参数为start ,调用restart方法
        pm.restart()
    elif cm == 'status':             #如果参数为start ,调用status方法
        pm.status()
    else:                            #如果都不是以上参数,输出help信息
        pm.help()
 
if __name__ == '__main__':  # 如果调用的是本身,就启动main函数。
    main()

这样就写好了一个以daemon方式启动的脚本。通过定义一个class,然后4个主要核心方法,start stop status restart 来围绕编写的。



--------------------- 

作者:运维白菜鹏 

来源:CSDN 

原文:https://blog.csdn.net/shuaizy2017/article/details/79069790

版权声明:本文为博主原创文章,转载请附上博文链接!