Linux expect로 script나 command에 패스워드 자동 입력 처리 하기

Ansible로 배포 스크립트를 만드는데 일부 작업에서 사용하는 모듈과 스크립트들이 종종
prompt로 패스워드나 이런저런 의사를 물어보는 경우가 있다.
한두번이야 대충 적당히 입력해 주겠는데 배포해야할 서버가 늘어날수록 여간 귀찮은게 아니다.
그래서 자동입력을 어떻게 해야하나 찾아보니 expect란 애를 쓰면 해결이 된다고 한다.

설치

$ apt-get install expect # 간단하네! (맥은 brew….)

작성 예

패스워드 프롬프트가 뜨면 파라메터로 넘긴 패스워드를 입력하고
ssh connect 연결 yes/not를 물어보는 프롬프트가 뜨면 yes를 입력해주는 예제

$ vi auto_password.exp
--------------------------
#!/usr/bin/expect

set timeout -1
set password [lindex $argv 0]
spawn ansible-playbook -k -i $host $playbook

expect {
      "password: " { # 프롬프트에 password: 항목이 뜨는 경우 
          send "$password\r"
          exp_continue # expect 가 반복되서 처리된다.
      }
      "connecting (yes/no)?" { # 서버에 연결 할지 물어보는 경우
          send "yes\r"
          exp_continue
      }
}
--------------------------
$ chmod 755 auto_password.exp

실행

./auto_password.exp $my_password

터미널 작업시

ssh 자동 접속 후 terminal 작업을 해야할때는 마지막에 interact를 붙인다.

#!/usr/bin/expect

set timeout -1
set password [lindex $argv 0]
spawn ssh $target_host

expect {
      "password: " { 
          send "$password\r"
      }
}

interact

끝!

— 추가 분 —

주짓수 수련기 8 – Half Guard Sweep

누운 상태에서 나의 양 다리로 상대의 한쪽 다리를 얽어매어 방어하는 형태의 가드다. 하프 가드는  Top포지션(위에서 공격해 들어오는 사람)이나 Bottom포지션(아래에서 방어하는 사람)중 누가 절대적으로 유리하다 할 수 없어서 더욱 재미있는 가드 중에 하나라고 한다. 그리고 그만큼 기술 종류도 많다고 한다. 여기저기 찾아보니 오래한 사람일수록 하프 가드를 선호 한다는 이야기도 있다.
요즘 나도 하프가드를 많이 쓴다. 씁쓸한건 나의 경우 재미 보단 내 오픈가드가 워낙 취약해서 그렇다. 내 오픈가드가 워낙 잘 뚫리다보니 눈치껏 오픈가드가 뚫릴거 같으면 재빨리 하프가드로 전환 한다. 나도 좀 남들처럼 멋지게 오픈가드 스윕 해보고 싶은데……

하프가드 기본

  1. 하프가드 기본 강좌
  2. 하프가드 주의사항

하프가드 스윕

  1. 하프가드 스윕 1번 : 언더 훅으로 백 포지션 잡기, 가장 처음 배운거, 옥토퍼스 가드로 전환이 가능한데 그건 나중에…..

  2. 하프가드 스윕 2, Shaolin Sweep이라는데 이름은 확실치 않음, 하프가드 시저라고 하는 부분도 있는데?, 요즘 내가 자주 써먹는 스윕


  3. 하프가드 스윕 3, 2번덕에 아직 써보지 못함
  4. 그외 여러가지….



그외 더 많긴한데 이거로도 힘들다;;

Python, Decorator 써본 이야기

어쩌다 python-django 로 웹 어플리케이션 하나를 만들게 되었는데 이거 은근 신세계다. django 같은 프레임워크야 뭐 많으니까 놀랄게 없더라도 python의 decorator는 나에게 뭔가 신세계를 보여줬다. java-spring에서 그렇게 복잡했던 AOP가 decorator를 쓰면 그냥 별 고민 없이 끝나버린다. 이걸 AOP라고 해도 될런지 모르겠지만 말이다. 여튼 decorator에 감탄한 나머지 까먹기 전에 decorator 파트만 정리해본다.

일반 데코레이터

  1. 이렇게 코딩하고 실행하면
    # 얘가 데코레이터
    def decorator(func):
        def decorator(*args, **kwargs):
            print("%s %s" % (func.__name__, "before"))
            result = func(*args, **kwargs)
            print("%s %s" % (func.__name__ , "after"))
            return result
        return decorator
    
    # 함수에 데코레이터를 붙여준다.
    @decorator
    def func(x, y):
        print(x + y)
        return x + y
    
    func(1,2)
  2. 이런 결과가 나온다. 아! 신통방통 하다!
    func before
    3
    func after
  3. @데코레이터는 사실 이거랑 같은 의미라고 한다
    def decorator(func):
        def decorator(*args, **kwargs):
            print("%s %s" % (func.__name__, "before"))
            result = func(*args, **kwargs)
            print("%s %s" % (func.__name__ , "after"))
            return result
        return decorator
    
    def func(x, y):
        print(x + y)
        return x + y
    
    func2 = decorator(func)
    func2(1,2)

파라메터를 가지는 데코레이터

  1. 데코레이터에 뭔가 파라메터를 전달하고 싶을데는 약간 복잡하긴 하지만 역시 다 된다! function을 감싸는 decorator를 다시 감싸주면 된다.
    # 얘가 파라메터도 붙는 데코레이터
    def decorator_with_param(param):
        def wrapper(func):
            def decorator(*args, **kwargs):
                print(param)
                print("%s %s" % (func.__name__, "before"))
                result = func(*args, **kwargs)
                print("%s %s" % (func.__name__ , "after"))
                return result
            return decorator
        return wrapper
    
    @decorator_with_param("hello, decorator!")
    def func(x, y):
        print(x + y)
        return x + y
    
    func(1,2)
  2. 결과는 이렇게 나온다!
    hello, decorator!
    func before
    3
    func after

그런데 func.__doc__이 나오지 않는다. 아,  망했다!

  1. 원랜 이렇게 나와야한다. 그래야 Swagger UI 같은애랑 붙일때 자동으로 문서화가 된다.
    def func(x, y):
        """
        x와 y를 더합니다.
        :param x:
        :param y:
        :return:
        """
        print(x + y)
        return x + y
    
    print(func.__doc__)
    
    ---- 출력 ----
    
     x와 y를 더합니다.
     :param x:
     :param y:
     :return:
  2. 그런데 데코레이션을 붙이는 순강 망한다. __doc__이 안나온다. 실제로 django api application을 만들면서 api endpoint 메소드들을 decorator로 신나게 감쌌더니 Sweager UI에서 doc 처리하지 못해 공백 API 가이드만 한가득 나왔다.
    def decorator(func):
        def decorator(*args, **kwargs):
            print("%s %s" % (func.__name__, "before"))
            result = func(*args, **kwargs)
            print("%s %s" % (func.__name__ , "after"))
            return result
        return decorator
    
    @decorator
    def func(x, y):
        """
        x와 y를 더합니다.
        :param x:
        :param y:
        :return:
        """
        print(x + y)
        return x + y
    
    print(func.__doc__)
    
    ---- 출력 ----
    None # 아, 망했어요!
  3. 생각해보면 당연한 일이다. 실행시간에 실제로 접근하는 메타데이터는 func가 아니라 데코레이터가 만들어준 wrapper의 메터데이터니 제대로 나올리가 없다. 그렇다. 우린 망했다.
  4. 그렇다고 진짜 망한건 아니다. decorator에 @wraps 달아주면 모든것이 해결된다. 모든 decorator에는 반드시 @wraps를 달아주자. 그것이 모두가 행복해지는 길이다. 이유는 찾아보기 귀찮아서 생략. (대충 소스 보니 func의 __doc__ 같은 meta 정보를 wrapper에 복사해 넣는거 같은데 확실한건 아님!)
    from functools import wraps
    
    # 파라메터 없는 데코레이터에도 @wraps 붙여주고
    def decorator(func):
        @wraps(func)
        def decorator(*args, **kwargs):
            print("%s %s" % (func.__name__, "before"))
            result = func(*args, **kwargs)
            print("%s %s" % (func.__name__, "after"))
            return result
        return decorator
    
    
    # 파라메터 있는 데코레이터에도 @wraps 붙여주고
    def decorator_with_param(param):
        def wrapper(func):
            @wraps(func)
            def decorator(*args, **kwargs):
                print(param)
                print("%s %s" % (func.__name__, "before"))
                result = func(*args, **kwargs)
                print("%s %s" % (func.__name__ , "after"))
                return result
            return decorator
        return wrapper
    
    
    @decorator
    def func(x, y):
        """
        x와 y를 더합니다.
        :param x:
        :param y:
        :return:
        """
        print(x + y)
        return x + y
    
    
    @decorator_with_param("hello, decorator!")
    def func2(x, y):
        """
        x와 y를 더합니다.
        :param x:
        :param y:
        :return:
        """
        print(x + y)
        return x + y
    
    
    print(func.__doc__)
    func(1, 2)
    print(func2.__doc__)
    func2(1, 2)
  5. 실행하니 잘 나오네!
      x와 y를 더합니다.
     :param x:
     :param y:
     :return:
     
    func before
    3
    func after
    
     x와 y를 더합니다.
     :param x:
     :param y:
     :return:
     
    hello, decorator!
    func2 before
    3
    func2 after
    
    

class로도 decorator 선언이 가능하다고도 합니다.

class로 만드는게 뭔가 낙타표기도 되고 그래서 뭔가 그 뭔가 멋져보이는거 같은데 여기엔 치명적인 단점이 있다. @wraps를 붙일수가 없다. 그나마 parameter를 가지는 데코레이터의 경우 __call__ 시점에서 wrapper를 만들면서 @wraps를 붙여줄수 있는데 parameter가 없는 데코레이터의 경우 wraps를 붙일 방법이 보이질 않는다. 이거 저거 찾아보니 결국 __doc__, __name__들을 복사해 넣는데 이럴거면 그냥 function으로 데코레이터 만들란다.

from functools import wraps

# 그냥 Class 데코레이터, @wraps를 붙일만한데가 보이지 않는다.
class Decorator:
    def __init__ (self, func):
        self.func = func

    def __call__ (self, *args, **kwargs):
        print("%s %s" % (self.func.__name__, "before"))
        result = self.func(*args, **kwargs)
        print("%s %s" % (self.func.__name__, "after"))
        return result


# 파레매터를 가지는 Class 데코레이터, __call__에서 @wraps를 넣어준다.
class DecoratorWithParam:
    def __init__ (self, param):
        self.param = param

    def __call__ (self, func):
        @wraps(func)
        def decorator(*args, **kwargs):
            print(self.param)
            print("%s %s" % (func.__name__, "before"))
            result = func(*args, **kwargs)
            print("%s %s" % (func.__name__, "after"))
        return decorator


@Decorator
def func(x, y):
    """
    x와 y를 더합니다.
    :param x:
    :param y:
    :return:
    """
    print(x + y)
    return x + y

@DecoratorWithParam("hello, decorator!")
def func2(x, y):
    """
    x와 y를 더합니다.
    :param x:
    :param y:
    :return:
    """
    print(x + y)
    return x + y


print(func.__doc__)
func(1,2)
print(func2.__doc__)
func2(1,2)

---- 출력 ----
None # 아, 이거 짜증나네
func before
3
func after

 x와 y를 더합니다.
 :param x:
 :param y:
 :return:
 
hello, decorator!
func2 before
3
func2 after

끝!