1. 程式人生 > >第一次任務完成經歷的總結

第一次任務完成經歷的總結

第一次任務完成經歷的總結:

任務簡介:

為Openstack的元件cloudkitty新增一個計費通知feature的子功能,通知傳送功能。具體的要求是,提供4個郵件介面和一個簡訊介面給上游呼叫,並將上游傳入的data分為四類渲染成指定的html並通過郵件傳送api傳送給客戶,同時把一類data通過簡訊api傳送給客戶。
雖然這只是一個小小的功能但是花了1個禮拜(5個工作日完成了這個活)。

閱讀準備:

首先先介紹下cloudkitty,cloudkitty是openstack專案的一個計費作為服務(Rating as a service)的專案。cloudkitty在以下四個層面高度元件話:

  • input data sources (collectors)
  • rating policies (rating pipeline)
  • output storage (storage)
  • output file format (writers, used to generate reports)

這次任務做的便是第三四層級的活。

任務抽象

簡單任務抽象的緣由:

之前自己有寫過一些程式,面向物件的程式設計思想也瞭解,但是從來都沒有仔細的去思考過在實際的編碼過程中更好地使用面向物件的思維方式來解決問題。在這次任務的一開始,我都沒有考慮過用面向物件的方法去解決這個問題,但是專案使用的是stevedore

來動態載入服務的,為了使整體更加的協調,同時為了與排程服務解耦,所以通知傳送服務所以必須用類來封裝方法。

抽象對我造成的挑戰:

由於從通知方式出發去抽象的話,兩種方式需要的介面數不一樣,所以父類寫介面不合適,所以我就想從傳送的郵件內容來設定父類盒子類,父類實現傳送郵件和簡訊的方法,子類直接呼叫就行。雖然這樣實現了複用,但是排程程者得去初始化很多子類的例項,並要知道對應的子類是否需要傳送簡訊。後來找了超哥聊了下,發現從方式的角度去抽象才是最好的。對於不需要使用的內容簡訊傳送可以進行空實現,在父類中定義介面,呼叫者以下便可以看明白。
第一次使用python中的介面實現方式,這裡記錄下:

@six.
add_metaclass(abc.ABCMeta) class NotifierService(object): def __init__(self): pass @abc.abstractmethod def notify_user_arrearing_lightly(self): """send normal user arrearing notification in less than pridict_day days. """ @abc.abstractmethod def notify_admin_arrearing_lightly(self): """send admin all arrearing users in less than pridict_day days with email. """ @abc.abstractmethod def notify_admin_arrearing_strongly(self): """send admin all arrearing users in less than 30days with email.""" @abc.abstractmethod def notify_admin_releasing_strongly(self): """send admin all resource releasing users in less than ( max_day - float_variable ) days.

其他的就不寫了。

stevedore之坑:

這個物件自動載入的包,會把物件初始化的報錯資訊給吃掉並且不會向外部呼叫拋異常,並把這個異常寫入到日誌中。這個即便是單步除錯也無法定位問題。直到在超哥的幫助下逐個排除問題後,最後翻查日誌的時候發現問題的。開發陌生專案的時候,有日誌一定要關注,這樣可以少走很多彎路,特別是使用一些庫的時候。

oslo_config庫之坑:

第一次使用這個庫,看了下官方的文件就瞭解了下一些options的型別和demo卻沒有發現必須要將自己定義的Options註冊到conf中才能使用其中的配置值,這裡舉個例子:

notification_opts = [
    cfg.StrOpt('origin',
               help='SMS and Email api origin'),
    cfg.ListOpt('emails',
                help='Emails of administrator of platform'), ]

CONF = cfg.CONF
CONF.register_opts(notification_opts, 'notification')

在定義完option後必須要通過register_opts方法將options註冊到conf物件中。

經驗分享:

這次的部署是使用kolla-ansible的方式來進行的,所以所有的服務都跑在容器裡面。如果想要測試的話,就得將程式碼更新到容器中,然後再重啟容器服務才能才能夠工作。但是這樣操作的話非常麻煩,下面分享幾個方便的小技巧:

修改容器啟動命令,讓工作遠離重啟:

玩過kolla-ansible的朋友都知道:每一個用kolla-ansible啟動的容器在“/etc/kolla/容器名下”都會有一個config.json的檔案。這個檔名中的command鍵值存放了容器中服務的啟動命令,一旦這個命令啟動的程序掛了,容器便會重啟,這裡我們改為sleep 111111111111111111 讓其一直休眠。這樣容器便不會掛了。

git更新程式碼:

當代碼改動變得非常多而雜的時候手動更新程式碼便不再合適了。所以我們要藉助工具來完成程式碼的更新,git是我們的首選,因為映象中是使用pip安裝的包,所以檔案目錄結構和專案的檔案目錄結構基本沒什麼變化。可以使用以下命令操作:

1.
#如果你修改的不再stage中
git diff  > patch
#如果在stage中
git diff  --cached > patch

git diff  branchname --cached > patch
2.將patch檔案scp到部署機上
scp patch remote:/root

3.使用docker cp指令將patch複製到容器中
docker cp patch cloudkitty_api:/root

4.用git初始化專案的部署目錄,並將當前的程式碼提交個patch,這步操作需要設定下郵箱
docker exec -u root -it cloudkitty bash
cd /var/lib/kolla/venv/lib/python2.7/site-packages/cloudkitty
git init 
git add .
git config --global user.email "[email protected]"
git commit -m 'init'

5.在這裡如果path中有requirements和setup.cfg檔案請把他們刪除掉,因為安裝檔案中不存在這些東西。
docker exec -u root -it cloudkitty bash
cd /var/lib/kolla/venv/lib/python2.7/site-packages/
git apply /root/patch