Python

Python Notes — Installing Python 3 on CentOS 6, a Web Server Checker

Contents

Two posts from 2016, written while picking up Python for the first time, merged here. They follow each other naturally: install it, then immediately build something with it.

Installing Python 3 on CentOS 6

CentOS 6 ships with Python 2.6. This builds 3.5.1 from source.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
yum install zlib-devel -y
yum install openssl openssl-devel -y


wget https://www.python.org/ftp/python/3.5.1/Python-3.5.1.tar.xz
xz -d Python-3.5.1.tar.xz
# if xz is missing, install it with yum install xz
tar -xvf Python-3.5.1.tar

cd Python-3.5.1
./configure --prefix=/usr/local --enable-shared LDFLAGS="-Wl,-rpath /usr/local/lib"
make && make altinstall

# install pip
curl -k -O https://bootstrap.pypa.io/get-pip.py
python3.5 get-pip.py

make altinstall matters. make install overwrites the existing python and breaks system tools like yum. altinstall only installs it under the name python3.5.

zlib-devel and openssl-devel go in first because without them the build still succeeds, but pip cannot use SSL and installing packages fails.

Python is nice for small programs. Setting up a java project for this would be a chore.

A web server checker

With it installed, I built something small for practice: a check every ten seconds for whether a web server has died. The code covers:

  • http requests
  • threads (in place of a timer)
  • using logging
  • try-except handling
  • raise / throw
  • json parsing and reading values
  • string handling
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import threading
import urllib.request
import json
import time
import logging


logger = logging.getLogger("myLogger")

# log file setup
def config_logger():
    formatter = logging.Formatter("[%(levelname)s] %(asctime)s - %(message)s")
    file_handler = logging.FileHandler("/logs/py/log.log")
    stream_handler = logging.StreamHandler()

    file_handler.setFormatter(formatter)
    stream_handler.setFormatter(formatter)

    logger.addHandler(file_handler)
    logger.addHandler(stream_handler)
    logger.setLevel(logging.DEBUG)


def call_error(name, e):
    logger.error("%s에서 '%s'가 발생했습니다" % (name, e))


def check_server(name, url):
    try:
        check_server_private(url)
        logger.info("서버 체크 완료 name=%s" % name)
    except Exception as e:
        call_error(name, e)


def check_server_private(url):
    req = urllib.request.urlopen(url)
    try:
        if req.getcode() != 200:
            raise RuntimeError("서버 오류")
        data = req.read()
        json_object = json.loads(str(data, "utf-8"), "utf-8")
        if json_object["result_code"] != "0000":
            raise RuntimeError("서버 응답 오류")
    finally:
        req.close()


def check_all():
    check_server("server1", "http://server1/checkjson")
    check_server("server2", "http://server2/checkjson")


def run_thread():
    while True:
        check_all()
        time.sleep(10)

config_logger()


th = threading.Thread(target=run_thread)
th.start()

logger.info("모니터링 시작 합니다")

It does not only check for HTTP 200 — it also reads result_code out of the response JSON. That was to catch the case where the server is up but internally broken.

Calling req.close() inside finally is deliberate too. The socket has to close even when an exception is raised.

Running it

1
python ServerCheck.py 

Not sure a timer built that way is really okay though…

Summary

  • On CentOS 6, always use make altinstall. make install breaks yum
  • Install zlib-devel and openssl-devel first, or pip cannot use SSL
  • For server checks, read the response body rather than trusting the status code alone