Apache 웹 서버, Configtest 체크 만들기
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()’ 에 있습니다.