Apache 웹 서버 시스템을 다루다보면 자주 접하게 되는 문제가 Apache 웹 서버의 재시작 문제입니다. 이것이 왜 문제가 되는가 하면, 재시작을 위해서는 Apache 웹 서버의 설정 파일들이 문제가 없는지에 대한 테스트가 선행되어야 하기 때문입니다.
다행스럽게도 Apache 는 설정 파일에 대한 적합성 테스트를 제공 합니다.
|
1 2 3 4 5 |
# Apache 웹 서버의 Configtest /usr/local/apache2/bin/httpd -t AH00112: Warning: DocumentRoot [/home/memolog/www] does not exist AH00112: Warning: DocumentRoot [/home/wpblog/www] does not exist Syntax OK |
만일 설정파일에 문제가 있다면 다음과 같이 됩니다.
|
1 2 3 4 5 6 7 8 |
# Apache 설정 파일에 문제가 있을때 출력 /usr/local/apache2/bin/httpd -t httpd: Syntax error on line 481 of /usr/local/apache2/conf/httpd.conf: Expected </IfModule> but saw </IfModul> # Apache 설정 파일에 문제가 있을때 출력2 /usr/local/apache2/bin/httpd -t AH00526: Syntax error on line 488 of /usr/local/apache2/conf/httpd.conf: Invalid command 'adlkjfl', perhaps misspelled or defined by a module not included in the server configuration |
Apache 웹 서버는 어떻게 설정 파일에 문법 체크를 하는 걸까?
1. server/main.c
httpd 실행파일은 server/main.c 에서부터 만들어집니다. 이 파일에는 main() 함수가 존재하고 Switch 문으로 httpd 의 옵션들을 받도록 되어 있습니다.
|
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 |
case 'L': ap_show_directives(); destroy_and_exit_process(process, 0); case 't': configtestonly = 1; break; case 'T': ap_document_root_check = 0; break; case 'S': configtestonly = 1; new = (char **)apr_array_push(ap_server_config_defines); *new = "DUMP_VHOSTS"; break; case 'M': configtestonly = 1; new = (char **)apr_array_push(ap_server_config_defines); *new = "DUMP_MODULES"; break; case 'h': case '?': usage(process); } |
configtest 옵션을 주면 내부적으로 configtestonly 값이 1루 세팅 됩니다.
|
657 658 659 660 661 |
if (configtestonly) { ap_run_test_config(pconf, server_conf); ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "Syntax OK"); destroy_and_exit_process(process, 0); } |
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 : 비정상 종료
|
1 2 3 4 5 6 7 8 9 |
]# /usr/local/apache2/bin/httpd -t AH00526: Syntax error on line 492 of /usr/local/apache2/conf/httpd.conf: Invalid command 'asdf', perhaps misspelled or defined by a module not included in the server configuration ]# echo $? 1 ]# /usr/local/apache2/bin/httpd -t Syntax OK ]# echo $? 0 |
그런데, Apache 웹 서버도 Configtest 를 진행해서 ‘Syntax OK’ , ‘Syntax error’ 는 stderr 로 메시지를 리턴합니다.
|
1 2 3 4 5 |
]# /usr/local/apache2/bin/httpd -t > result.out AH00526: Syntax error on line 492 of /usr/local/apache2/conf/httpd.conf: Invalid command 'asdf', perhaps misspelled or defined by a module not included in the server configuration ]# cat result.out ]# |
이렇게 파일에 저장이 되지 않습니다. 다음과 같이하면 파일에 저장이 됩니다.
|
1 2 3 4 5 6 7 |
]# /usr/local/apache2/bin/httpd -t 2> result.out ]# cat result.out AH00526: Syntax error on line 492 of /usr/local/apache2/conf/httpd.conf: Invalid command 'asdf', perhaps misspelled or defined by a module not included in the server configuration ]# /usr/local/apache2/bin/httpd -t 2> result.out ]# cat result.out Syntax OK |
Apache 웹 서버는 설정 검사 결과가 통과되던 안되던 메시지는 stderr 로 메시지를 출력 합니다. 단, 쉘 리턴 변수만 달리 됩니다.
3. python 으로 체크 테스트 만들기
python 의 apache configtest 모듈이 있다면 좋았겠지만, 그런게 없더군요. 결국에는 python 에서 외부명령어를 사용하는 방법밖에 없습니다.
python 에서 외부명령어 사용을 위한 방법에는 다양하지만, subprocess 를 이용해 보겠습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/usr/bin/python # -*- coding: utf-8 -*- import sys import subprocess p = subprocess.Popen('httpd -t', stdout=subprocess.PIPE, shell=True, stderr=sys.stdout) (output, err) = p.communicate() p_status = p.wait() if 'Syntax OK' in output and p_status == 0: print 'Config file oK' else: print 'Config file fails' |
위 코드에서 핵심은 Popen 객체에 stderr=sys.stdout 를 주고 외부 프로세스가 끝나기를 기다려 리턴값을 받는 ‘p_status = p.wait()’ 에 있습니다.