1、編寫啓動腳本shell
1.寫一個啓動腳本。bash
對mencached作啓動腳本。運維
2.先把一個結構搭建好。ide
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方法。memcached
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命令。測試
3.3.繼續定義2個方法,一個是定義pid的絕對路徑,一個是定義寫入pid文件的方法。spa
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方法完整.net
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命令。
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.
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