소니 AVCHD 파일 변환기 없이 맥북에서 읽어오기

이미지
 아주예전에 구입했던 소니 HDR-CX12 모델. 생각보다 쓰지 않고 처박혀 있던 녀석을 꺼낸 이유는 꼬맹이가 비디오 촬영에 흥미를 가졌기 때문이다. 다른 컴팩트 카메라를 한대 손에 쥐어 주었는데, 얼마전 찍은 동영상 아빠한테 보여준다고 뛰어오다 떨어트려서 아작이 나버렸다. ㅠㅠ 생각난 김에 처박혀 있던 카메라를 줄려고 꺼내어 보았는데, 특별히 문제 없이 동작중이다. 2008년 모델인데 아무 문제 없이 움직이고 있다. 사스가 소니! 다만 문제는 테스트 용으로 촬영한 동영상을 보려고 메모리 카드에서 파일을 읽어보니 달랑 AVCHD 란 파일 하나만 존재하고 있다. 혹시나 싶어 인터넷에서 매뉴얼을 찾아 읽어보아도, 전용 드라이버를 설치하라고 하는데, 이게 또 귀차니즘이 마구 몰려온다. 같은 avchd 이니 확장자를 m2ts 로 바꾸면 어떨가 싶어 확장자를 바꾸어 보았는데 뜬금 없이 디렉토리로 표시된다.    디렉토리로 되었으니 열어보아야지 하는 마음으로 열어보니 이번엔 BDMV 라는 확장자도 없는 파일이 또 표시되길래 혹시나 싶어 이 파일도 확장자를 m2ts 로 바꾸어 주었다. 확장자를 바꾸어 주니 이 파일도 디렉토리로 표시되었다.   와우, 그랬더니 여러가지 파일과 디렉토리가 표시된다. 이게 바로 처음 메모리 카드를 넣었을때의 비디오 인덱스인 듯 하다. 파일이름에도 인덱스가 들어 있고,디렉토리도 딱 보니 클립, 플레이 리스트, 스트리밍 동영상 등등 어디서 많이 들어본 단어 들이다. 동영상 파일은 예상대로 STREAM 디렉토리 안에 존재하고 있었고 확장자는 MTS 로 맥용 동영상 플레이어인 IINA에서 바로 플레이 할 수 있는 걸 확인했다. IINA에서 다른 동영상 포맷으로 변환은 안되지만 다른 어플을 이용하면 간단하게 처리 할 수 있을 듯 하다. m2ts 가 이런 형식으로 되어 있는 것도 오늘 처음 알았다. 나중을 위하여 메모 겸 남겨 놓는다.  

slack+slash command+API Gateway를 이용한 SSM 명령실행

목표

slack에서 slash command 를 이용하여 특정 명령어를 입력하면 SSM을 이용하여 지정한 ec2에서 지정된 명령을 실행하여 그 결과를 slack 에 출력한다. 여기에서는 각 ec2에서 free -m 명령을 실행 한 후 그 결과를 출력하도록 한다.

전제조건 : 대상 EC2는 ssm을 이용한 명령실행이 가능한 상황이어야 한다.

AWS설정

IAM 설정

slash command를 api gateway에서 받은 후, lambda에서 ssm을 호출한다. 그러기 위해서 lambda 함수에는 ssm과 로그 출력을 위한 cloudwatch logs 에 대한 권한이 필요하다.

  • IAM 에서 role을 선택하여 role을 작성
  • lambda를 선택해주고 일단 다음, 다음을 클릭하여 적당한 이름을 주고 role을 생성하였다.
  • 작성한 role을 선택후 「AmazonSSMFullAccess」AWS관리 Policy를 추가
  • inline policy를 선택하여 아래 json내용으로 적당한 이름을 지정하여 추가(이외에도 쓸일이 있다면 policy를 따로 생성한후 지정하는 것도 좋다. 이 policy가 없으면 cloudwatch logs에 로그 출력이 불가능.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:DescribeLogStreams",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "*"
        }
    ]
}

Lambda 함수 작성

lambda를 먼저 만드느냐, api gateway를 먼저 만드느냐 정해진 방법은 없다. 각 장단점이 있고 익숙한 방식이 있을터이니 편한 방법으로 작성해도 문제 없다. 최종적으로 api gateay를 trigger로 지정한 lambda function이 실행되면 OK.

  • lamda에서 함수 작성을 선택하여 Author from scratch를 선택
    • Function name을 적당히 넣어주고, Runtime은 Python3.8을 지정
    • Execution role에서 Use an existing role을 선택후 위에서 작성한 role을 지정하여 create function.

여기서 add trigger를 클릭하여 api gateway를 지정할 수도 있지만, 난 따로 만들겠다.

API Gateway 설정

  • api gateway에서 Create API를 선택후, REST API를 작성
  • API name을 적당히 입력해 주고 API를 생성
  • Resource를 선택후 Action에서 Create Resource를 선택 후 적당한 이름을 주고(여기에선 free를 지정) resource를 생성
  • /free 를 선택후 Action에서 Create Method를 선택후 Any를 지정
  • Intergration type에서 Lambda Function지정후 Region확인 하고 Use Lambda Proxy Intergration을 선택
  • 위에서 작성한 Lamda Function 이름을 지정 하여 Save하고 Permisson 추가에서 OK
  • Method Execution이 표시되면 Method Execution에서 Response Body for 200의 application/json 을 삭제
  • 완성된 any를 선택 후, actions에서 deply api를 선택하여 deply한다.
  • 왼쪽에서 stages를 선택하면 지정한 stage가 생성되어 있다. /free 를 확인하면 Invoke URL가 생성되어 있으니 메모
  • lambda function을 확인하면 trigger에 지정한 api gateway가 설정되어 있는 것을 확인

Lamda 코드

잘 알지도 못하는 python으로 겨우겨우 만들어 냈다. python다운 코드가 아니지만 잘 모르니 어쩔 수 없다.

import boto3
import json
import time
import requests

from urllib.parse import parse_qs

SLACKTOKEN = '<slack token>'
target_instances = ['<대상 ec2 ID>','대상 ec2 ID','대상 ec2 ID']

def command(ssm, instance, commands):
    r = ssm.send_command(
        InstanceIds = [instance],
        DocumentName = "AWS-RunShellScript",
        Parameters = {
            "commands": [
                commands
            ]
        }
    )
    command_id = r['Command']['CommandId']
    while True:
        time.sleep(0.2)
        res = ssm.list_command_invocations(
            CommandId = command_id,
            Details = True
        )

        invocations = res['CommandInvocations']
        status = invocations[0]['Status']
        print ("Get status : " + status)
        if status == "Failed":
            return ("Command 실행 에러")
        elif status == "Success":
            print ("Success!! return command result at " + instance)
            account = invocations[0]['CommandPlugins'][0]['Output']
            return account
        else:
            print ("Waiting Lambda function for 0.2s")


def lambda_handler(event, context):
    # TODO implement
    print ("Start Script")
    params = parse_qs(event['body'])
    token = params['token'][0]
    user = params['user_id'][0]
    print ("Get Token from posted data : " + token)
    if token != SLACKTOKEN:
        print ("Invalied Token, terminate process")
        return {
            "statusCode": 400,
            "headers": {
                "Content-Type:": "application/json"
            },
            "body": json.dumps({
                "response_type": "ephemeral",
                "text": "Invalid Token"
            })
        }
    retpost_url = params['response_url'][0]
    print ("Get response_url from posted data : " + retpost_url)
    
    str_command = "date;hostname;free -m;echo ''"

    print ("Create boto3 client for ssm")
    client = boto3.client(
        'ssm',
        region_name='ap-northeast-1',
    )

    comment=""
    print ("Into the for Loop with array of Instances")
    for str_instance in target_instances:
        print ("Excute command with ssm :" + str_instance)
        comment += command(client, str_instance, str_command)
    
    print ("add codesnipet on result")
    comment = "<@" + user + ">\r\n" + "```\r\n" + comment + "\r\n```"
    
    print ("return result : \r\n" + comment)
    print ("Making Object for posting to slack")
    
    obj_slack = {
        "response_type": "in_channel",
        "text": comment
    }
    requests.post(retpost_url, data=json.dumps(obj_slack))
    
    return {
        "statusCode": 200,
        "headers": {
            "Content-Type": "application/json"
        },
        "body": json.dumps(obj_slack)
    }

Slack 설정

slack slash command 어플리케이션이 이미 등록되어 있다고 가정하고, slash command에서 새로운 request를 작성한다.

  • command 를 /free 로 지정
  • URL은 API Gateway에서 확인한 Invoke URL을 지정
  • Method는 Post
  • token은 메모하여 Lambda코드에 삽입
  • 그외에 적당한 내용을 지정하여 저장

최종확인

slack에서 /free 를 입력하여 지정한 ec2의 free 결과가 표시되는 것을 확인한다. 실행이 잘 안될 경우엔 cloudwatch logs를 확인하자.

  • slash command의 timeout이 3초이기 때문에 여러대의 ec2에서 free -m 을 실행한 결과가 timeout되어 버린다. 어떻게 해결은 했는데 기억이.... 기억나는 대로 추가.
 

댓글

이 블로그의 인기 게시물

소니 AVCHD 파일 변환기 없이 맥북에서 읽어오기

해외거주 국민을 위한 "교민폰" 사용후기

CISCO 2960s 초기화 후 기본 설정