Python 으로 서버의 Disk IO 를 측정/모니터링 해보자.

 

# ------------------------------------------------------------------------------
# Disk IO (Write Count) 모니터링
# ------------------------------------------------------------------------------

import os
import sys
import time

# pip install psutil 으로 먼저 설치
import psutil

# pip install pymssql 으로 먼저 설치 (MS-SQL을 사용하는 경우)
import pymssql


interval = 60
disk_io_over = 0
max_val = 0


def send_sms(receiver, msg):
    # 자신의 환경에 맞는 문자전송시스템에 보내도록 구현


while 1:
    disks_before = psutil.disk_io_counters()
    time.sleep(interval)
    disks_after = psutil.disk_io_counters()
    disks_write_cnt_per_sec = disks_after.write_count - disks_before.write_count
    if disks_write_cnt_per_sec > max_val :
        max_val = disks_write_cnt_per_sec

    print("Cur Val : %d, Max Val : %d" % (disks_write_cnt_per_sec, max_val))

    if disks_write_cnt_per_sec > 20000 :
        if disk_io_over == 0 :
            send_sms('받는이전화번호', 'YoonHQ Disk IO Error')
            print('Disk IO Error\n')
        disk_io_over = 1
    else :
        if disk_io_over == 1 :
            send_sms('받는이전화번호', 'YoonHQ Disk IO Normal')
            print('Disk IO Normal\n')
        disk_io_over = 0


Django 의 내장 authentication 모듈을 사용하지 않는 경우, 직접 제작을 해야 하는데, login_required 라는 데코레이터가 없어서, 매번 View 에서 접근 로직을 작성해주어야 해서 번거로웠다. 아래와 같이 별도의 데코레이터를 작성해두면 로직이 바뀌더라도 하나만 변경하면 되니까 코드 관리가 좀 더 편할 것이다.

def login_required(function=None):
  def _dec(view_func):
    def _view(request, *args, **kwargs):
    # 아래 로직을 적당히 자신의 사이트에 맞게 고쳐서 쓰면 될 것이다.
      if "login_yn" not in request.session:
        return HttpResponseRedirect('/')
      else:
        return view_func(request, *args, **kwargs)
    _view.__name__ = view_func.__name__
    _view.__dict__ = view_func.__dict__
    _view.__doc__ = view_func.__doc__
    return _view
  if function is None:
    return _dec
  else:
    return _dec(function)
이번에는 Python 에서 SAN 스위치 장애를 체크하는 스크립트를 만들어보았다. Perl 의 경우와 거의 같다.

Python 2.7.3 에서 테스트하였으며, pymssql 를 별도로 설치해야 한다.

# -*- coding: cp949 -*-
# ------------------------------------------------------------------------------
# (1) SAN 스위치의 Telnet에 연결하여, switchstatusshow 명령의 결과에 따라서
#     HEALTHY 가 아니면 장애로 간주하고 담당자에게 문자메시지를 보낸다.
#
# (2) 하루에 1번 작동한다.
#
# Python Version : 2.7.3
# 
# [필요한 패키지]
# easy_install pymssql
#
# Normal Status ----------------------------------------------------------------
# SwitchState:    HEALTHY
# ------------------------------------------------------------------------------
import telnetlib
import pymssql

# ------------------------------------------------------------------------------
def send_sms(msg):
    sql = """ insert arreo_sms ( CMP_MSG_ID, 
        CMP_USR_ID, 
        WRT_DTTM, 
        RCV_PHN_ID, 
        CALLBACK, 
        SND_DTTM, 
        SND_MSG , 
        SND_PHN_ID, 
        RSRVD_ID ) 
        values ('011' + CONVERT(varchar, GETDATE(), 12) + REPLACE(CONVERT(varchar, GETDATE(), 14), ':', '') + SUBSTRING(CONVERT(VARCHAR, RAND(), 109), 3, 2), 
        '00000', 
        CONVERT(varchar, GETDATE(), 112) + REPLACE(CONVERT(varchar, GETDATE(), 8), ':', ''), 
        '%s',
        '01055555555',
        CONVERT(varchar, GETDATE(), 112) + REPLACE(CONVERT(varchar, GETDATE(), 8), ':', ''), 
        '%s', 
        'ADMIN', 
        'ADMIN' ) """ % ("메시지받을사람의전화번호", msg)
    conn = pymssql.connect(host='서버주소', user='아이디', password='비밀번호', database='DB이름')
    cur = conn.cursor()
    cur.execute(sql)
    conn.commit()
    conn.close()

# ------------------------------------------------------------------------------

devices = { "SAN_SW1" : "172.16.0.21",
            "SAN_SW2" : "172.16.0.22",
            "SAN_SW3" : "172.16.0.23",
            "SAN_SW4" : "172.16.0.24" }

for device_key in devices.keys() :
    tn = telnetlib.Telnet(devices[device_key])
    tn.read_until("login: ")
    tn.write("아이디\n")
    tn.read_until("Password: ")
    tn.write("비밀번호\n")
    tn.write("\n")
    tn.write("switchstatusshow\n")
    tn.write("exit\n")
    result = tn.read_all()
    for line in result.splitlines() :
        if "SwitchState:" in line :
            if "HEALTHY" in line :
                msg = device_key + " : Normal"
                print(msg)
                send_sms(msg)
            else :
                msg = device_key + " : Error"
                print(msg)
                send_sms(msg)


'쉽고 빠른 웹개발 Django'은 1.0버전 기준이어서 최신버전 (1.4.3)에서 막히면 진도를 더이상 나갈 수 없게 됩니다. 이에, 최신 버전에서도 진행할 수 있도록 변경된 부분을 반영하여 수정본을 작성해보았습니다. 1.4 이후 부터 디렉토리 구조가 조금 변경이 되었는데, 대부분 이 것 때문에 기존버전과 맞지 않는 부분이 생기는 것입니다. 추후 더 변경할 것이 발견되면 추가하도록 하겠습니다. 


P. 15 
Before
django_bookmarks/
    __init__.py
    manage.py
    settings.py
    urls.py
After
django_bookmarks/
    manage.py
    django_bookmarks/
        __init__.py
        settings.py
        urls.py
        wsgi.py

P. 17 
Before
DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = 'bookmarksdb'
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''
After
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'bookmarksdb',                  # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

P.30 
Before
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django_bookmarks.bookmarks',
)
After
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'bookmarks',
)

P. 37 
Before
import os.path

TEMPLATE_DIRS = (
    os.path.join(os.path.dirname(__file__), 'templates'),
)
After
import os
SETTINGS_DIR = os.path.abspath(os.path.dirname(__file__))
(SITE_ROOT, dummy) = os.path.split(SETTINGS_DIR)

TEMPLATE_DIRS = (
    os.path.join(SITE_ROOT, 'templates'),
)

P. 48 
Before
...
...
After
...
{% csrf_token %}
...

P. 55 
Before
import os.path

site_media = os.path.join(
    os.path.dirname(__file__), 'site_media'
)
After
import os

URLS_DIR = os.path.abspath(os.path.dirname(__file__))
(SITE_ROOT, dummy) = os.path.split(URLS_DIR)
site_media = os.path.join(SITE_ROOT, 'site_media')

P. 58 
Before
from django import newforms as forms
After
# -*- coding: utf-8 -*-
from django import forms


+ Recent posts