Skip to main content

3 posts tagged with "script"

View All Tags

· 6 min read

빌드와 배포를 자동화하는 작업을 진행하는 도중에 Database에 data를 쓰고 업데이트 하는 기능이 필요하게 되었다. 이 경우 여러가지 방법이 있을 수 있지만 최대한 간단하게, 추가 개발없이 진행하고 싶었다. (Shell script에서)

1. 과거에 사용했던 방법들

간단히 Java로 DB와 connection을 맺고 CRUD를 하는 모듈을 개발해서 사용했던 적이 있다. Jar로 묶어 놓으면 script에서는 jar에 parameter만 몇 개 넘겨서 실행하면 가능했다. 하지만 난 그 당시의 소스를 가지고 있지 않고 간단하더라도 개발을 추가로 하기가 귀찮았다. 시간도 없었고.

두번째로 groovy script를 사용했었다. Groovy 자체가 java와 유사한 부분이 많기 때문에 작성이 어렵지 않았고 그렇게 만들어진 groovy script를 shell에서 호출하는 것도 어렵지는 않다. 하지만 역시 추가로 script를 구현하는게 번거롭고 어딘가에 script를 보관하고 사용해야 한다는게 마음에 걸렸다. 난 단지 하나의 shell script로만 해당 기능을 구현하고 싶었다.

마지막으로 사용해봤던 방법은 REST API를 구현하고 shell script에서는 curl을 이용해 REST API를 호출하는 방법인데, 꽤 괜찮은 방법이 아닌가 생각했었지만 역시 REST API를 구현해야 하는 부담이 있었다. 하지만 대규모 개발이 아니라면 node.js로 충분히 할만하다. (간단하면 개발하는데 그리 오래 걸리지도 않는다)

2. Command line에서 query 실행하기

그동안 사용할 일이 없었기 때문에 MySQL client 실행옵션 중에 -e가 있다는 걸 이번에 알았다. -e 옵션은 뒤에 오는 query 문을 실행해주는 역할을 하는데 이 옵션만 사용하더라도 단 한 줄의 명령으로 원하는 기능을 수행하게 만들 수 있다.

3. Password prompt

한 줄의 명령으로 원하는 기능에 근접했지만 항상 password prompt가 뜨는 문제에 봉착했다. expect를 사용하거나 하면 되겠지만 그것보다 간단한 방법을 원했다. 그리고 찾은게

mysql -uuser_id -ppassword

-p 옵션에 password를 붙여쓰면 따로 묻지 않는다. 그 사이에 공백이 있다면 password prompt를 띄우라는 걸로 인식하고 뒤에 있는 password를 사용하려는 DB schema로 인식한다.

4. Inserted id를 알고 싶어요

또 다른 문제. DB에 insert 하고 특정 작업 이후에 insert된 레코드를 update 해야 했는데 id 이외에 유일한 값을 특정하기가 어려웠다. 강제로라도 유일한 값을 만들수는 있을 것 같았는데 그것을 위해 DB 구조를 변경해야 할 것 같아서 마음에 들지 않았다. 그래서 생각한 방법은 insert 이후에 아래의 query를 바로 실행하는 것이었다.

select last_insert_id();

마지막으로 추가된 id를 알려준다.

5. Shell script에서 text로 된 query 결과를 parsing 해야 하는가?

위의 문제를 해결하니 다른 문제가 등장했다. MySQL client에서 직접 select query를 실행하면 결과를 mysql만의 형태로 돌려준다는 것이었다. Json이나 xml과 같은 정규화된 문자열이 아니라 특수문자로 column의 경계가 그려진 문자열들. 처음엔 이것을 parsing 해야 하나 생각했는데 말도 안되는거라 생각했다. 의미도 없고. 그래서 찾은게 -s와 -N 옵션인데, -s는 silent를 -N은 column name 출력을 하지 않는다. 어차피 마지막에 추가된 id만 알면 되기 때문에 column은 단 하나뿐이고 진정 내가 원하는 것은 그 column의 값일 뿐이다. 두 옵션을 사용해 query를 실행하면 id만 달랑 떨어진다.

6. 결과

mysql -uuser_id -ppassword db_schema -s -N -e "insert_query_with_last_insert_id"

위의 형태로 실행하면 password를 묻지도 않고 insert를 한 후 추가된 id만 받을 수 있다. 단 한줄만으로.

Password가 공개될 여지가 있는데 insert 하려는 값을 parameter로 받는 별도의 script 파일로 만들어서 읽기권한을 제어하는 방법을 사용하는게 어떨까 생각한다. 그게 간단하니까.

· 3 min read

원격지에서 samba로 공유되고 있는 파일이 존재하는지를 확인하기 위해서 smbclient를 이용해봤다.

아래와 같은 command를 shell에서 호출하고 나서

smbclient //${server}/${service} ${password} -c "ls ${dir}/${file}"

exit code를 $?로 판단하면 파일이 존재유무를 손쉽게 확인할 수 있다.

고생을 했던게 ${service}.

단순히 알고 있는게 samba 경로였기 때문에 전체 경로를 다 넣어보니 연결이 안되었었다.

samba로 공유된 파일들에 대해서 나처럼 경로에 대한 정보만 알고 있다면 첫번째 디렉토리만 service 항목에 넣으면 된다.

패스워드 유출 문제가 불안하면 authentication file을 만들어서 입력하는 방법도 옵션으로 제공하고 있다.

-c는 접속 후 전송할 command를 추가할 때 사용하는 옵션.

나머지는 smbclient의 man page를 참조하면 되겠다.

man page에도 나오지만 authentication file은 아래의 형태로 생성해서 -A 옵션으로 파일명을 명시해야 한다.

username = <value>
password = <value>
domain = <value>

난 왜 이 것을 시도했는가?

자동화 시스템에서 파일을 scp로 전송 후 파일이 제대로 전송되었다면 특정 사이트에 경로를 기록해야 하는 상황이었다.

scp를 사용했으면 ssh로 command 전송해서 하면 되지 않나? 라는 생각이 들지만

문제는 파일이 쌓이는 서버쪽 정보는 내가 전혀 알지도 못하고 알게 두지도 않았다.

scp로 전송시 필요한 ssh password도 내가 아닌 알고 있는 제3자가 입력해서 암호화되어 저장된 그런 상태...

원격지에 파일이 전송되는 경로가 사실은 Samba 뿐 아니라 FTP로 운영되는 경로이기도 했는데, 역시나 FTP 정보를 알 수도 없었다.

어디까지나 일반 사용자 입장에서 서버 요구사항을 해결해야 했던 경험.

· 8 min read

처음 자동화 업무를 시작하면서부터 ssh를 본격적으로 사용하기 시작했다.

그 당시에도 ssh가 제대로 지원되지 않는 환경인 경우 (거의 임베디드 리눅스 환경) 제대로 지원될 수 있도록 기능이나 기타 필요한 내용들을 관련 개발부서에 요청하곤 했었다. ssh를 사용하면 할수록 자동화에 필수적이라는 생각이 드는 이유는

1. 매우 간단하다

어차피 command의 형태로 되어있고 형식이 간단하고 linux와 os x의 경우 기본으로 포함되어 있기 때문에 특별히 뭘 구현하지 않아도 된다.

2. 인증여부를 묻지 않게 할 수 있다

간단하게 장비간 key만 교환하고 등록하면 인증시 계정의 패스워드가 아니라 key의 패스워드를 묻게 되는데 key 생성시 패스워드 없이 생성이 가능하기 때문에 인증여부를 묻지 않는 것처럼 보일 수 있다. 장비에 대한 제어를 자동으로 해야 하는데 인증여부 등을 묻거나 하면 해결하기가 어렵다. 물론 제어 가능하도록 무언가를 구현해서 사용해도 된다. 하지만 구석에 박혀있는 작은 기능이 필요할 때 이전에 구현된 거대한 덩어리들을 수정하지 않아도 되니 꽤 유용하다.

3. 권한만 있다면 해당 OS의 거의 모든 기능을 사용할 수 있다

ssh도 shell 이므로 shell에서 할 수 있는 기능들은 거의 사용 가능하다. 단 한번에 수행되어야 하는 작업이 많은 경우 문제가 생기기도 하고 command가 복잡해져서 나의 경우엔 복잡한 작업을 수행하는 script를 하나 따로 만들어서 ssh로는 그 작업을 하는 script만 호출하는 식으로 처리하곤 한다.

4. 파일 전송이 간단하다

ssh와 시리즈로 사용하는 scp로 파일 전송을 하곤 하는데, ftp를 별도로 서비스하거나 mount 같은 걸 하지 않아도 되니 아쉬울 때 쓰기 좋다.

 

하지만 ssh로 도배를 해보니 몇가지 아쉬운 점이 있었는데

1. 귀찮은 키교환

자동화에 사용하는 장비 수가 늘어날수록 키를 서로 교환하고 등록하는 과정이 무척 귀찮아진다. 이 과정 마저도 어느정도 자동화를 할 수도 있지만 신규 장비에 접속해서 키는 생성해야 하니 짜증스럽다. 예를 들어 한번에 장비가 10대만 늘었다고 하더라도 반복작업이 수십회는 된다. 장비간 키교환이 귀찮아 아예 키를 통째로 전송해서 같은 키를 사용하기도 하는데 이 경우 보안문제도 신경쓰인다.

2. 늘어나는 script

ssh가 간편하기도 하고 간단한 기능을 쉽게 땜질하는게 가능하지만 땜질이 늘어날수록 script가 늘어나게 된다. 한 번은 script가 수십개가 되었던 적도 있었는데 아무리 작명을 잘해도 어떤게 어떤건지 내용을 열어보거나 실행해봐야 아는 상태에 이르렀다. 게다가 특정 장비간 기능이 달랐기 때문에 script도 퍼져있어서 관리하기가 쉽지 않았다.

3. Known host 문제

장비의 IP가 변경되는 경우 서로 키를 교환하고 있는 상태이기 때문에 인증에는 문제가 없다고 하더라도 변경된 IP로 접속한 기록이 없기 때문에 최초 접속시 known host로 등록할거냐고 묻는다. 이게 자동화에 방해가 되므로 IP 변경시 한번씩은 접속을 해주거나 known host로 등록을 해줘야 하는 번거로움이 발생한다. 물론 sshd 설정에 아예 known host 여부를 따지지 않게 하는 부분이 있긴 하지만 자동화 이외의 다른 용도로 사용되거나 하면 그런 설정을 하기가 꺼려진다.

 

그래서 적합한 방안이라고 생각하는 것들은 이렇다.

1. Script의 공용화

Script는 가능한 적게 만드는게 좋을 것 같다. 그리고 여러 장비에서 사용해야 하는 script 라면 script는 장비 하나에만 두고 공통으로 사용할 수 있는 방안을 마련하는게 좋을 것 같다. 처음엔 한 곳에 script를 두고 필요할 때 마다 다른 장비에 복사해서 호출하게 하곤 했었는데 영 지저분하고 특정 상황에서는 script를 복사하면 안되는 경우도 있어서, 아예 script가 있는 경로를 각 장비에서 mount 해서 사용해보고 있는데 아직은 괜찮은 것 같지만 좀 더 지나봐야 알겠다.

2. 기능의 구조화 및 정리

단편적인 기능들을 간단하게 추가만 하다가 어느 시점이 되면 기능들을 모아서 별도의 모듈로 개발하는게 좋겠다는 생각을 한다. 물론 공수가 들어가는 문제이지만...

3. 별도의 인증과정

무작정 키를 장비 한대에서 등록하고 관리하고 교환하고 할 게 아니라 인증 기능을 담당하는 장비나 서비스를 별도로 분리하는게 좋을 것 같다. 난 이 작업을 진행하는 것 자체가 꽤 재미있을 것 같다. 이미 나와있는 것들도 많겠지만.