LabHub
배우기 러닝패스 코스

FDE Capstone: The Warehouse Got the Same Order Three Times

Install reported done, but the agent died on startup

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

고객 호스트의 설치 요구사항을 점검해 pass·warn·fail 을 JSON 보고서와 종료 코드로 내는 사전 점검 스크립트를 만든다. 채점기가 차린 여러 환경에서 판정이 맞아야 하고, 점검은 아무것도 고치지 않아야 한다.

왜 중요한가

고객 현장의 설치 창은 한 번뿐인 경우가 많다. 지난번 설치는 "완료" 로 끝났지만 포트는 사내 프록시가 쓰고 있었고 인증서는 이미 만료돼 있었다. 사전 점검은 이런 사실을 설치 전에 근거와 함께 드러내는 도구다. 판정만이 아니라 관측값을 남겨야 고객 담당자가 다시 확인할 수 있고, 종료 코드가 일정해야 설치 자동화가 진행과 중단을 가를 수 있다. 채점기는 여러분의 문구를 믿지 않는다. 임시 디렉터리에 점유 포트·TIME_WAIT 포트·임박/만료 인증서·없는 디렉터리를 직접 만들고, 포트 번호·기준값·경로를 실행마다 바꿔 스크립트를 실행한다.

단계

  1. 고객 메모를 읽고 요구사항 7종을 /root/preflight/spec.json 에 계약의 키 이름으로 적는다. 옛 문서의 값과 지원 정책을 구분한다.
  2. /root/preflight/preflight.py 에 python_min 과 ports 점검, 보고서(summary·exit_code·checks), 종료 코드 0·1·2 를 구현한다. 명세에 없는 키의 점검은 하지 않는다.
  3. preflight.py 의 포트 점검이 TIME_WAIT 만 남은 포트를 사용 중으로 오탐하지 않게 고친다. 듣는 포트는 여전히 fail 이어야 한다.
  4. preflight.py 에 disk 점검을 넣는다. 여유 MiB 를 observed 에, 잰 경로를 measured_path 에 적고, 아직 없는 경로는 만들지 말고 가장 가까운 부모를 잰다.
  5. preflight.py 에 certs 점검을 넣는다. notAfter 를 epoch 초로 observed 에, 남은 일수를 days_left 에 적고, 만료·못 읽음은 fail, warn_days 미만은 warn 이다.
  6. preflight.py 에 files·hosts·writable_dirs 점검을 넣는다. observed 는 계약의 상태 이름을 쓰고, 쓰기 시험 파일은 지우며 없는 디렉터리는 만들지 않는다.
  7. 정상·경고·실패 호스트 전체 명세와 깨진 명세를 구분하는지 확인한다. 종료 코드는 0·1·2, 명세를 못 읽으면 보고서 없이 3 이다.
  8. spec.json 으로 이 호스트를 점검해 /root/preflight/report.json 을 남기고, /root/preflight/decision.json 에 보고서 해시·판정(go·go-with-warnings·no-go)·blockers·warnings 를 적는다.

참고

고객 메모를 명세로 옮기기

고객 메모의 요구사항 7종을 계약의 키 이름으로 /root/preflight/spec.json 에 적으세요.

메모에는 옛 문서의 값과 '돌아가긴 했다' 는 경험담이 섞여 있습니다. 점검 기준은 이번 판과 공급사 지원 정책입니다. 포트는 정수 배열, disk·certs 는 객체 배열입니다.

파이썬 판과 포트부터 판정하기

/root/preflight/preflight.py 가 python_min·ports 를 점검하고 보고서와 종료 코드 0·1·2 를 내게 하세요.

포트가 비었는지는 0.0.0.0 에 실제로 bind 해 보면 압니다. 판 비교는 sys.version_info 와 정수 튜플로 합니다. summary 는 fail 이 하나라도 있으면 fail 입니다. 채점기는 매번 다른 포트와 판 기준으로 실행합니다.

끝난 연결을 점유로 오탐하지 않기

/root/preflight/preflight.py 의 포트 점검이 TIME_WAIT 만 남은 포트는 free, 듣는 포트는 in_use 로 구분하게 하세요.

서버 쪽이 먼저 닫은 연결은 그 포트에 TIME_WAIT 를 남깁니다. 옵션 없는 bind 는 이것도 막힙니다. 소켓 옵션 하나로 TIME_WAIT 는 통과하고 진짜 리스너는 여전히 막히게 할 수 있습니다.

여유 공간을 경고와 실패로 나누기

/root/preflight/preflight.py 에 disk 점검을 넣어 observed(여유 MiB)·measured_path·pass/warn/fail 을 내게 하세요.

shutil.disk_usage 의 free 를 1024*1024 로 나눈 몫입니다. 경로가 없으면 os.path.dirname 으로 올라가며 존재하는 곳을 찾되 만들지는 않습니다. 채점기는 지금 여유 공간을 기준으로 기준값을 바꿔 가며 부족한 디스크를 흉내 냅니다.

인증서 남은 날짜를 notAfter 로 재기

/root/preflight/preflight.py 에 certs 점검을 넣어 observed(notAfter epoch 초)·days_left·판정을 내게 하세요.

openssl x509 -enddate -noout -in 파일 의 출력에서 notAfter= 뒤를 ssl.cert_time_to_seconds 로 바꿉니다. 읽지 못한 파일은 observed null 로 fail 입니다. 채점기는 여유·임박·만료·깨진 인증서를 만들어 섞습니다.

설정·호스트 이름·쓰기 권한 확인하기

/root/preflight/preflight.py 에 files·hosts·writable_dirs 점검을 넣으세요. 없는 디렉터리를 만들지 말고 쓰기 시험 파일은 지웁니다.

파일은 없음·파일 아님·빈 파일을 구분합니다. 이름 해석은 socket.getaddrinfo 가 실패하면 socket.gaierror 를 냅니다. 쓰기는 os.access 대신 tempfile.mkstemp 로 실제로 만들어 보고 지웁니다.

호스트 세 대와 깨진 명세 구분하기

/root/preflight/preflight.py 가 전체 명세에서 정상·경고·실패를 종료 코드 0·1·2 로, 읽을 수 없는 명세를 보고서 없이 3 으로 끝내는지 확인하세요.

명세 키의 순서가 바뀌어도 점검 id 는 명세에 적힌 것과 정확히 같아야 합니다. 명세 JSON 이 깨졌다면 판정할 근거가 없으니 보고서를 쓰지 않습니다.

고객 호스트에 go / no-go 내리기

spec.json 으로 점검해 /root/preflight/report.json 을 남기고, /root/preflight/decision.json 에 report_sha256·decision·blockers·warnings 를 적으세요.

decision 은 summary 에서 나옵니다(pass→go, warn→go-with-warnings, fail→no-go). blockers 는 fail 점검 id, warnings 는 warn 점검 id 입니다. 채점기는 지금 다시 점검해 보고서가 낡지 않았는지와 해시를 확인합니다. 막는 항목을 고쳐서 통과시키는 단계가 아닙니다.