Tagged: python

Python, SaltStack 편집을 위한 vim 세팅

서버를 다루다보면 Python, SaltStack 을 작성해야 하는데 이를 위해서 윈도우즈로 다운로드 받아서 편집기를 열어서 하기가 영 귀찮습니다. 터미널을 이용해기 때문에 vim 를 이용하면 아주 편한데, 이 문서는 Python, SaltStack 편집을 위한 vim 세팅 위한 것입니다.

환경

환경이 중요합니다. 이 문서의 환경은 다음과 같습니다.

  • OS Distro: Ubuntu 16.04
  • vim version: 7.4
  • Python Virtualenv: /home/systemv 계정에 Python 가상환경을 만들었으며 여기에 각종 Python 라이브러리가 설치되어 있다.

Vundle 플러그인 설치

Vundle 은 vim 플러그인 입니다. 이 플러그인은 vim 의 각종 플러그인을 아주 편하게 설치 및 관리를 해주는 플러그인 매니저 입니다.

다음과 같이 설치 해줍니다.

git 를 이용해서 Vundle 플러그인 매니저 파일을 vim 디렉토리에 다운로드 받습니다.

.vimrc 파일 작성

이제 vim 의 환경설정 파일을 다음과 같이 작성합니다.

위와같이 작성한 후에 vim 을 실행해 명령어 모드에서 다음과 같이 입력해줍니다.

Neosnippet 설치.

이 플러그인은 코드 스냅피를 지원해줍니다. vim 설정 파일에서 Vundle 블럭 사이에 다음을 추가해줍니다.

시스템 버퍼에 있는 키워드를 완성해 줍니다.

jedi-vim 설치.

awesome Python autocompletion with VIM

Python 을 위한 자동완성 플러그인 입니다. 이는 jedi 라는 파이썬 라이브리를 설치해줘야 합니다. Python 은 가상환경을 사용하기 때문에 가상환경를 이용해서 설치해줍니다.

이제 jedi-vim 를 설치해줍니다. 역시 Vundle 를 이용해서 설치 합니다.

Powerline status bar

vim 를 사용하면서 각종 필요한 정보를 화면 아래에 상태바로 보여 줍니다.

다음과 같이 vim 설정을 해줍니다.

Python 문법 체크

이제 Python 문법 체크를 위해서는 먼저 파이썬 문법체크 라이브러리를 설치해 줍니다. 역시 가상환경에서 설치 해줍니다.

pep8, pyflakes를 문법 체크를 위한 라이브러리이며 autopep8 은 vim 플러그인에서 사용하기 위한 의존성 패키지 입니다. 이는 잘못된 문법을 자동으로 고쳐줍니다.

이제 vim 플러그인을 설치해 줍니다.

그리고 vim 설정에 다음과 같이 입력해 줍니다.

Python 문법 체크를 위해서 Autopep8 을 사용하는데 이를 vim 에서 사용할 수 있도록 도와주는 플러그인을 설치합니다.

위와같이 하면 ftplugin 디렉토리에 python_autopep8.vim 파일이 생성 됩니다.

python 을 위한 설정으로 다음과 같이 python.vim 파일을 작성해 ftplugin 디렉토리에 넣어둡니다.

위 파일은 python 파일 타입에 한해서 vim 설정을 적용해 줍니다.

SaltStack 을 위한 vim 설정.

다음과 같이 아주 간단히 설정을 할수 있습니다.

최종 .vimrc 파일 내용

 

 

Python JSON Tool 을 이용한 Readable한 JSON 출력하기.

Python 을 설치하면 JSON Tool 이 포함됩니다. Python JSON Tool 을 이용한  Readable한 JSON 출력이 가능합니다. 즉 쉘 상에서 JSON 포맷을 보기 좋게 볼수 있습니다. 보통은 다음과 같이 출력되서 쉽게 알아보기 힘듭니다.

이를 보기 좋게 출력하는 방법은 다음과 같습니다.

 

리모트 스크립트 제작기

DevOps 가 대두되면서 지속적인 배포(Continuous Delivery) 가 핵심으로 떠오르면서 수만은 서버에 한꺼번에 명령어를 내리고 파일을 전송하고 설정파일을 관리하는 소프트웨어가 인기를 끌고 있다.

대표적으로 Chef, Puppet, Saltstack, Ansible 등을 들수 있는데 이들은 지속적인 배포 뿐만 아니라 시스템과 소프트웨어를 통합해 플랫폼으로서 수많은 서버들의 상태를 동일하게 유지시켜준다.

그런데 몇 해전만 해도 이런것들이 부족했던 시절이 있었는데, 이때 내가 다니던 직장에서 수천대의 서버를 관리해야하는 일이였다. 이러한 소프트웨어가 없던 시절에 나는 개인적으로 이와 비슷한 것을 만들어 사용했는데 그때 당시로 돌아가 어떤 생각으로 만들었었는지 개선했는지를 정리해보고자 한다.

쉘 스크립트

처음에 수십대 서버에 명령어를 보내야했다. 궁리를 한 끝에 생각난 것이 쉘 스크립트로 돌리자는 거였다. 리눅스를 조금 한 사람이면 expect 라는 명령어를 알 것이다. 이 명령어는 어떤 명령어를 날렸을 경우에 돌아오는 답변을 미리 기대해(expect)해서 그것을 파싱하고 자동으로 다시 답변을 해주는 명령어였다.

수백대에 명령어를 보내야 했었는데, 수백대의 서버이름은 파일로 저장해놓고 expect 쉘 스크립트를 작성하면 될 일이였다.

그런데 이게 생각만큼 쉽지 않았다. 먼저 쉘 스크립트를 지금도 잘 모르지만, 예외처리를 하기에 힘들었다. 로그인은 성공했지만 예기치 못하게 접속이 차단되거나 기대했던 프롬프트가 나오지 않아서 명령어가 실행되지 않는등 문제가 많았다.

그래도 그때 당시에는 좋았다. 오류가 나오기도 했지만 100대중 5대 내외여서 나름대로 좋았는데, 사람이 간사한게 처음에는 불편했던것을 감수했지만 시간이 지나자 감수했던 불편함을 어떻게든 없애고 싶은 생각이 들었다. 불편했던 것들은 다음과 같았다.

  • 기대하는 프롬프트가 다양하게 나타났다.
  • 예외처리를 하기가 힘들었다.
  • 정상적인 결과나 오류등을 파일로 저장하고 싶었다.
  • 동시에 여러서버들에 실행되길 원했다.

쉘 스크립트말고 다른 프로그래밍 언어를 사용하면 최소한 예외처리나 정상적결과나 오류등을 파일로 저장하는 것이 가능해질것 같았고 평소 사용하던 Python 프로그래밍을 사용해보기로 했다.

expect 프로그래밍 for python

Python은 아주 좋은 언어임에 틀림이 없었다. expect 프로그램을 지원하는 python 라이브러리가 존재했다. pexpect 모듈이 그것이였다.

pexpect 모듈과 Python 이 지원하는 쓰레드(thread) 그리고 로깅(logging) 기능을 조합하면 좋은 꽤나 쓸만한 프로그램이 나올것이 분명해 보였다.

15번째줄에 보면 기대되는 프롬프트를 적어준다. 위 예제에서는 간단하게 나왔지만 Python이 제공하는 정규표현식을 사용할 수도 있다. 위 예제를 기반으로 쓰레드를 붙이고 로깅을 붙이고 해서 여러서버에 동시에 명령어를 넣을 수 있게 되었다.

나름대로 만족하고 있었는데, 기대되는 프롬프트가 문제였다. 리눅스는 다양한 배포판을 사용하다보니 기대하는 프롬프트가 조금씩 달랐다. 거기다 SSH 접속할때에 가끔씩 인증키가 충돌이 나는 일도 있어서 기대하는 프롬프트를 리스트로 가지고 있어야 했다.

귀찮은게 문제였다. 어떻게 하면 저런것까지 신경 안쓰면서 명령어를 날리고 로깅을 할 수 있을까 하는 문제 말이지…

pxssh 모듈

pxssh 모듈은 귀찮이즘에 적어드는 시기에 찾은 신변기(?) 였다. 이 Python 모듈은 기대하는 프롬프트를 신경쓸 필요가 없었다. 최초로 접속하는 서버일지라도 알아서 HostKey 를 교환했고 프롬프트가 달라도 알아서 해주는 매우 좋은 녀석이였다.

pxssh 모듈은 위의 예제처럼 기대되는 프롬프트는 필요가 없다. 대신 한가지 특징이 있는데, pxssh 모듈은 결과값을 before, after 변수에 저장된다. 그래서 19번째 라인처럼 값을 불러오면 된다.

그런데, 한가지 문제가 있었다. 이번에는 파일을 전송하고 싶었던 것이다.

paramiko 모듈

이런저런 고민을 풀면서 일명 자동화 명령어 프로그램을 만드는 동안에 많은 검색을 하게되면서 많은 자료를 모울 수 있다. 그러던중에 paramiko python 모듈을 보게 됐다.

paramiko 는 ssh, sftp 프로토콜을 지원줘서 python 으로 ssh, sftp 프로그래밍이 가능하도록 만들주는 라이브러리였다. 올타쿠나!! 이거야!! 그래서 명령어 전송부터해서 파일 전송을 전부 이것으로 교체하기로하고 만들었지만 문제가 있었다.

paramiko 의 SSHClient 클래스를 지원하는데 이는 SSH를 이용해서 로그인을 할 수 있도록 한것인데, 문제는 pxssh 와 비교해보니 속도면에서 많이 느렸다. (물론 내가 잘못 짠 것일 수도 있다.) 그래서 paramiko 는 파일 전송을 하는데 사용하고 명령어를 쓸때는 pxssh 를 사용하도록 스크립트 두개를 사용하도록 했다.

대충 위와같이 프로그램을 짰다.

지금은 Python에서 Fabric 프로그램이라고 많이 사용하고 있다. fabfile.py 에 관련 내용을 작성하면 fab 명령어가 이 파일을 자동으로 인식해 내부에 작성된 메소드들을 실행해주는 방법이다. 파일 전송도 가능하다.

요즘은 Chef, Puppet, Saltstack 과 같은 것들을 사용하면 파일 배포및 명령어도 아주 쉽게 할수 있는 시대에 살지만 아주 간단하게 뭔가를 하고 싶을때에 종종 만들어 두었던 python 프로그램들을 사용하곤 한다.

Thread

이 문서는 Perl Thread 문서를 기반으로 작성되었습니다. Thread 의 기초부터해서 Thread의 구현을 Perl, Python 으로 직접 구현해보고 비교하도록 하겠습니다.

출처: http://www.xav.com/perl/lib/Pod/perlthrtut.html

Thread?

쓰레드(Thread)는 프로세스(Process)보다 작은 프로그램 단위 입니다. 좀 더 정확하게 말하자면 프로그램은 적어도 한개의 프로세스로 구성되며 적어도 하나의 쓰레드로 구성됩니다. 적어도 하나의 프로세스에서 하나의 쓰레드는 결국 하나의 실행 포인트를 가집니다. 적어도 하나의 프로세스내에서 다중 쓰레드를 쓴다는 것은 결국 다중의 실행 포인트를 가진다는 것을 의미 합니다.

다중의 실행 포인트?

요즘에 멀티코어(Multi Core) CPU가 많이 나옵니다. 프로그램은 이 멀티코어 CPU에 의해서 실행되는데 프로그램이 실행될때에 1개의 코어만 사용한다면 비효율적일 것입니다. 그래서 프로그램이 실행될때에 멀티코어를 이용한다면 빠르게 동작하게 될 것입니다.

프로세스도 마찬가집니다. 비록 멀티코어가 아닐지라도 하나의 프로세스내에서 다중의 실행 포인트로 동시에 한꺼번에 실행이된다면 빠를 것입니다. 이것이 바로 쓰레드 입니다. 하나의 프로세스내에서 다중 실행 포인트로 동시에 실행되는 것, 그것이 쓰레드 입니다.

쓰레드 프로그램 모델

쓰레드에는 기본적으로 3개의 모델이 있습니다. 정확하게 말하자면 프로그램상에서 구현하는 방법론적인 것입니다.

Boss/Worker 모델

보스(Boss), 실행(Worker) 모델입니다. 하나의 보스(boss)와 여러개의 실행기들로 구성됩니다. 보스는 일을 처리하기위한 태스크(Task)를 생성하고 모은다음에 적절한 실행기에 할당합니다.

이런 모델은 GUI나 서버 프로그램에서 흔하게 사용됩니다. 메인 쓰레드는 특정 이벤트(Event)가 발생할때까지 기다리며 처리(process)를 위해서 실행기(Worker)에게 이벤트를 통해서 보내집니다. 이렇게 이벤트를 실행기(Worker)에게 보내고 난후에 보스는 다른 이벤트를 기다립니다.

보스(Boss) 쓰레드는 적은 일을 합니다. 태스크가 다른 메소드보다 좀더 빠른 처리가 필요하지 않는다면 가장 최적의 사용자 응답시간을 가지게 됩니다.

Work Crew 모델

work crew 모델은 기본적으로 서로다른 데이터 부분을 갖는 같은 일을 처리하기위해서 여러개의 쓰레드를 가집니다. 이것은 전통적으로 병렬프로세싱(Paraller Processing)과 벡터 프로세싱(Vector Processor)와 유사합니다.

이 모델은 특정한 환경에 적합한데, 서로다른 프로세서들을 통해서 다중의 쓰레드들 분배해 프로그램을 실행하는 시스템과 같은 특정한 경우입니다. ray tracing 이나 렌더링 엔진에 적합한데, 개별적인 스레드들이 사용자에게 비주얼한 피드백을 줄수 있는 중간 결과물들을 전달할 수 있는 곳에도 적합니다.

Pipeline 모델

파이프라인(Pipeline)은 태크스(Task)를 스텝(Step)으로 나눕니다. 그리고 하나 스텝의 결과를 다음 쓰레드 처리기에 전달합니다. 각각의 쓰레드는 각 데이터 조각을 가지며 라인상에서 다음 쓰레드에 결과를 전달합니다.

이 모델은 병렬 처리를 하는 두개 이상의 다중 쓰레드를 처리하는 다중 프로세서를 가진다면 중요한 의미를 지닙니다. 이 모델은 개별적인 태스크를 작고 단순하게 유지하는 경향이 있으며 I/O나 시스템 콜과 같이 다른부분의 파이프 라인이 처리를 위해서 특정 파이프 라인를 블럭(block)하는 것을 허용하기도 합니다. 만약 다른 프로세서들에서 파이프라인의 일부를 실행한다면 각 프로세서는 그것을 캐시로 다룰 수 있는 이득을 얻을 수 있습니다.

이 모델은 또한 서브루틴 콜을 실행하기위해서 다른 쓰레드를 생성하는 것보다 재귀적 프로그래밍에서 유용합니다. 프라임과 피보나치 수혈은 파이프라인델을 잘 보여주는 폼(form)입니다.

Native Threads

시스템에서 쓰레드를 구현하는데에는 여러가지 방법이 있습니다. 쓰레드를 구현하는데에는 OS 제작사와 버전에 의존적입니다. 보통 초기버전에서는 단순하지만 버전이 향상됨에 따라 정교해(sophisticated) 집니다.

쓰레드에는 3가지의 기본 카테고리가 존재합니다. User-mode threads, kernel threads, multiprocessor kernel threads 입니다.

User-mode 쓰레드는 프로그램이나 라이브러 전체를 거쳐서 생존하는 쓰레드 입니다. 이 모델에서 OS는 쓰레드에 대해서 아무것도 알지 못합니다. 이 모델을 구현하기는 쉽고 대부분의 OS는 이를 초기에 지원합니다. 이 모델의 단점은 OS가 쓰레드를 알지 못하기 때문에 하나의 쓰레드는 모든 다른 쓰레들을 블럭할 수 있습니다. 전통적 블럭킹 활동에는 시스템 콜, 대부분의 I/O, sleep과 같은 것이 있습니다.

Kernel Threads 는 좀 더 진화한 버전입니다. OS는 커널 쓰레드에 대해서 알고 있으며 그들에대해서 통제권한을 가집니다. 커널 쓰레드와 유저 쓰레드의 주요한 차이점은 블럭킹입니다. 커널 쓰레드에서 하나의 쓰레드 블럭은 다른 쓰레드를 블럭하지 않습니다. 이것은 사용자 쓰레드는 없는 것으로 커널은 프로세스 레벨에서 블럭을 하지 쓰레드 레벨에서 블럭을 하지 않습니다.

이것은 큰 진전으로 쓰레드된 프로그램은 쓰레드되지 않은 프로그램에 비해서 큰 성능을 제공합니다. 예를들어 I/O 블럭인 쓰레드는 다른 것을 수행하는 스레드를 블럭하지 않습니다.

특정 시점에서 커널 쓰레딩이 쓰레드에 인터럽트(Interrupt)를 걸게되면 프로그램이 만들어낸 묵시적인 락킹(locking) 소비(?)를 해제시킵니다. 예를들어 단순하게 $a = $a + 2 를 생각해보면 다른 쓰레드에서 $a를 바꿨고 그 사이에 값을 가지고 오거나 새로운 값을 저장하는 사이에 $a를 다른 쓰레드에서 보여진다면 커널 쓰레드는 예상치 못한 행동을 할수 있습니다.

멀티프로세서(Multiprocessor) 커널 쓰레드는 쓰레드 지원에서 최종 종착지입니다. 멀티 CPU를 가진 시스템에서의 멀티프로세서 커널 쓰레드에서 OS는른 CPU에서 동시에 실행하기위해서 두개 혹은 그 이상의 쓰레드를 스케줄 합니다.

이것은 하나 혹은 그 이상의 쓰레드에서 동시에 실행시켰을때 쓰레드된 프로그램에서 매우 큰 성능을 제공합니다. 반면에 기본 커널 쓰레드에서 나타나지ㄶ았던 naggin synchronization 이슈가 나타납니다.

Cooperative multitasking 시스템에서 제어(control)를 하지못하도록 쓰레드를 운영해 왔습니다. 만약 쓰레드가 yield function 을 호출하면, 제어를 회수합니다. 또, 쓰레드가 I/O와 같은 블럭을 발생시키는 무언가를 실행했을때도 제어를 회수합니다. cooperative multitasking 구현상에서 하나의 쓰레드는 CPU time 에 대해서 모든 다른 것들을 소모시킵니다.

Preemptive multitasking 시스템은 다음 쓰레드를 결정하는 동안 일정한 간격으로 쓰레드를 인터럽트 합니다. preemptive multitasking 시스템에서는 보통 하나의 쓰레드가 CPU를 독점하지 않습니다.

어떤 시스템에서는 cooperative 와 preemptive 쓰레드를 동시에 운영할 수도 있습니다. (realtime 우선순위에서는 cooperative, normal 우선순위에서는 preemptive)

Thread in Perl

이제 Perl에서 쓰레드를 사용하는법을 익혀보겠습니다. 먼저 Perl 이 쓰레드를 사용할 수 있는지를 체크해야 합니다. Perl 을 컴파일 설치할때에 Thread 관련 옵션을 지정하지 않았다면 쓰레드가 사용불가 일수도 있습니다. 따라서 Perl 쓰레드를 사용할때는 코드 맨 앞에 다음과 같이 해줌으로서 Thread 지원여부를 체크할 수 있습니다.

위 코드를 실행했을때 오류 메시지가 나온다면 Perl 이 Thread를 지원하지 않는 것임으로 다시 설치해줘야 합니다.

Perl에서 Thread를 사용하는 것은 기타 언어에서와 거의 흡사합니다.

Thread를 생성할때는 new 메소드를 이용합니다. 서브 프로시져명을 첫번째 인자로 주고 그 프로시져에 인자로 전달할 파라메터를 나열하면 됩니다. 위의 예제는 사실 유용하지 못합니다. 어짜피 실행포인트가 하나인데 구지 쓰레드를 쓸일이 없기 때문입니다. 하지만 다음과 같이 쓰레드를 여려개를 만들면 효과가 있게 됩니다.

출력 결과

여기서 주목해야 할 것이 있습니다. 마지막 줄에 “A thread exited while 2 threads were running.” 쓰레드는 자원을 공유 합니다. 메모리나 cpu 도 공유를 하는데, 그야말로 프로그램의 모든것을 공유하는 것입니다. 그런데 어느 Thread가 먼저 끝날지 모릅니다. 어떤 Thread 가 프로그램을 종료한다면 다른 Thread는 실행이 중단되고 종료 되겠죠. 위의 마지막 줄은 그러한 상황으로 발생된 메시지 입니다. 해결방법은 다음과 같습니다.

join 은 다른 Thread 가 작업을 마치기를 기다립니다. 그래서 모든 Thread가 작업을 마치면 쓰레드는 소멸되죠. 이렇게되면 위의 문제는 해결이 되는거겠죠. 위 코드를 다음과 같이 바꾸면 효율적일 것입니다.

for 문과 foreach 문을 이용해서 Thread를 생성하고 join 하도록 되었습니다.

Thread 관리

Thread를 생성하고 끝내는 방법을 배웠습니다. 그런데 여기서 한가지 드는 의문이 있습니다. 예를들어서 5천대 서버에 뭔가를 할려고 한다면 Thread를 5천개를 만들어야 합니다. 그런데 Thread도 자원을 소모하게 되어 있어서 이렇게 많이 생성을 한다면 메모리를 많이 소비하게 됩니다. 더군다나 5천개의 Thread를 동시에 실행한다는 것은 CPU에게는 좀더 빠르게 왔다리 갔다리 하면서 일을 해야한다는 것을 뜻하게 되고 이는 결국 OS의 Context Switch 개수를 높이게 되고 이는 결국 서버에 부하를 유발하게 됩니다.

그래서 Thread 를 50개 정도만 생성하고 그중에서 끝나는 Thread에게 다시 일을 막기는 식으로 하면 시스템도 보호하고 원하는 작업을 모두 끝낼수가 있습니다. 쉽게말해서 Thread poll 과 같은 개념이라고 보시면 됩니다. 5천개의 서버목록을 Queue에 넣은다음에 Thread를 20개를 생성하고 Thread가 이 큐에서 가져다 쓰게 하면 효율적일 것입니다.

이와같은 개념을 Perl Thread에서는 지원하고 있습니다.

위 코드는 Thread::Queue 를 이용해 Thread 관리를 통해서 구현된 것입니다. Thread의 개수는 변수 $threadcount 에서 지정되고 각각의 Thread들은 enqueue 메소드를 통해서 queue에 넣어집니다. 그리고 dequeue 를 통해서 Thread를 사용하고 있지요. join 시에 사용되는 threads->list 는 Thread들의 객체(?)를 들고 있기 때문에 이를 활용하면 join을 쉽게 구현할 수 있습니다. 수천개의 같은 일을해야하는 경우 $threadcount 는 20으로 제한되어 있기때문에 20개의 Thread만 가지고 수천개를 처리하게 됩니다.

동시성 문제

동시성 문제는 컴퓨터 세계에서는 매우 중요하게 다루어지는 대상입니다. 대부분의 프로그램이 단일작업을 하는것이 아닌 다중 작업, 즉 Thread 라든지 Multi processing 기반으로 작성되어진다면 십중팔구 동시성문제를 해결하지 않고는 올바르게 작동할 수 없습니다. 동시성 문제를 가장 신경쓰는 분야중 하나는 아마도 데이터베이스 시스템일 것입니다.

데이터베이스에서의 동시성 문제는, 예들들면 한순간에 동시에 두명이 레코드를 접근한다고 생각하면 하나는 Select를 다른 하나는 Delete 를 했을 경우 과연 어떻게 될것인가 하는 문제입니다. 데이터베이스 시스템은 다중 접속을 허용하는 프로그램이며 동시에 두명 이상이 같은 레코드를 조회할 가능성이 항상 존재하게 됩니다. 두명 이상의 조회하는 가운데 모든 사람이 같은 명령을 내릴수도 있고 위와같이 Delete 하는 쿼리를 내릴수도 있는데 이럴경우 되돌려주는 결과물을 어떻게 할 것인가 하는 문제가 생깁니다. 이게 바로 데이터베이스 시스템에서 신경쓸수 밖에 없는 동시성 문제입니다.

Thread 에서도 이와 비슷한 동시성 문제가 발견이 됩니다. 파일을 쓰거나 변수를 조작할 경우에 주로 발생한다. 이를 해결하는 방법을 없을까? 어떤 Thread 가 자원에 접근하고 있을때에 그 자원에 대해서 다른 Thread가 못쓰게 하면 되지 않을까? 이를 위해서 Thread는 Lock, Mutex, semaphore 를 지원합니다. 여기서는 perl 에서 lock 을 이요하는 방법을 알아보겠습니다.

위 예제를 보면 lock 을 어떻게 사용하는지를 한눈에 알수 있습니다. 파일에 쓰기 작업을 하기 전에 lock 을 걸어서 동시성 문제를 해결하고 있지요.

Thread in Python

Python 에서도 Thread를 지원하고 위의 내용을 모두 적용해서 사용할 수 있습니다. queue를 이용해 Thread를 관리하고 lock 을 사용해서 동시성문제를 해결하는 것은 완전 perl 비슷합니다. 오히려 python 이 좀더 직관적이다라고 볼수 있지요. 그런데 문제가 있습니다. Thread Queue 를 사용하기 위해서는 Python 버전 2.6 이상 사용해야 합니다.

Thread에 대한 것과 Queue 를 이용한 방법은 아래의 링크에 매우 잘 설명이되어 있습니다.

http://www.ibm.com/developerworks/kr/library/au-threadingpython/index.html

Python 의 동시성 문제도 Perl 과 같이 lock 을 씁니다. 예를 들면 다음과 같습니다.

lock객체를 얻어서 lock 을 얻고 lock 을 풀어줘야 합니다.

 

Apache 웹 서버, Configtest 체크 만들기

Apache 웹 서버 시스템을 다루다보면 자주 접하게 되는 문제가 Apache 웹 서버의 재시작 문제입니다. 이것이 왜 문제가 되는가 하면, 재시작을 위해서는 Apache 웹 서버의 설정 파일들이 문제가 없는지에 대한 테스트가 선행되어야 하기 때문입니다.

다행스럽게도 Apache 는 설정 파일에 대한 적합성 테스트를 제공 합니다.

만일 설정파일에 문제가 있다면 다음과 같이 됩니다.

Apache 웹 서버는 어떻게 설정 파일에 문법 체크를 하는 걸까?

1. server/main.c

httpd 실행파일은 server/main.c 에서부터 만들어집니다. 이 파일에는 main() 함수가 존재하고 Switch 문으로 httpd 의 옵션들을 받도록 되어 있습니다.

configtest 옵션을 주면 내부적으로 configtestonly 값이 1루 세팅 됩니다.

Apache 에서 configtest 를 실행하면 바로 위 구문이 실행됩니다. ap_run_test_config 가 실행되네요. ap_run* 은 일종의 매크로 같은 것인것으로 보인다.

server/config.c 에는 Apache의 설정 파일들을 읽고, 검사를 하고, 추가된 모듈이 있다면 모듈에 맞게 문법을 검사 합니다.

내용이 복잡한데, 어째되었던간에 결과는 다음과 같은 문자열을 화면에 뿌리도록 되어 있습니다.

  • ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, “Syntax OK”);
  • return apr_pstrcat(p, “Syntax error in -C/-c directive: “, errmsg, NULL);
  • return apr_psprintf(p, “Syntax error on line %d of %s: %s”,

위와같이 문제가 없으면 ‘Syntax OK’, 문제가 있으면 ‘Syntax error’ 라는 문장을 가진 문자열을 리턴 합니다.

2. 쉘 종료 변수와 stdout, stderr

쉘은 프로그램이 정상 종료나 비정상 종료에 대해 다음과 같은 환경변수를 가집니다.

  • 0 : 정상종료
  • 1 : 비정상 종료

그런데, Apache 웹 서버도 Configtest 를 진행해서 ‘Syntax OK’ , ‘Syntax error’ 는 stderr 로 메시지를 리턴합니다.

이렇게 파일에 저장이 되지 않습니다.  다음과 같이하면 파일에 저장이 됩니다.

Apache 웹 서버는 설정 검사 결과가 통과되던 안되던 메시지는 stderr 로 메시지를 출력 합니다. 단, 쉘 리턴 변수만 달리 됩니다.

3. python 으로 체크 테스트 만들기

python 의 apache configtest 모듈이 있다면 좋았겠지만, 그런게 없더군요. 결국에는 python 에서 외부명령어를 사용하는 방법밖에 없습니다.

python 에서 외부명령어 사용을 위한 방법에는 다양하지만, subprocess 를 이용해 보겠습니다.

위 코드에서 핵심은 Popen 객체에 stderr=sys.stdout 를 주고 외부 프로세스가 끝나기를 기다려 리턴값을 받는 ‘p_status = p.wait()’ 에 있습니다.