Telegram 챗봇으로 DigitalOcean 제어하기
0. 시작에 앞서
챗봇을 만들어 보신 경험이 없으시다면 Python으로 Telegram 챗봇 시작하기를 먼저 읽어보시기 바랍니다.
어떤 언어를 사용하나요?
- Python을 이용합니다.
어떤 메신저를 이용하나요?
- Telegram 메신저를 이용합니다.
제작된 코드는 챗봇 호스팅 서비스인 BotHub.Studio를 이용해 실행됩니다.
1. 어떤 기능을 만들어 보나요?
DigitalOcean에서 제공하는 API를 활용하여 Droplet 을 관리하는 기능을 제작하게 됩니다. 본 예제를 통해 BotHub.Studio의 Property 기능과 Telegram Keyboards 를 활용해 볼 수 있습니다.
자주 사용하는 기능이 있다면 예제를 활용해 직접 추가해서 사용하실 수 있습니다.
2. 환경 준비하기
2.1 DigitalOcean에서 Access Token 생성하기
홈페이지 로그인 후 API 메뉴에서 Generate New Token을 진행합니다.
생성한 Access token은 잘 기록해 둡니다.
2.2 Telegram에서 Access Token 생성하기
텔레그램 검색창에서 @BotFather 를 찾습니다. 또는 https://t.me/BotFather 으로 연결 하셔도 됩니다.
/newbot 명령을 이용해 새로운 봇을 생성합니다.
생성된 Access token은 기록해 둡니다.
2.3 BotHub.Studio 등록 & CLI 설치하기
챗봇 호스팅 서비스 BotHub.Studio 회원 가입 후 아래와 같이 CLI 도구를 설치합니다.
pip install bothub-cli
계정 연결을 위해 configure 을 실행합니다.
(BotHub.Studio 계정이 필요합니다.)
bothub configure
프로젝트 폴더를 생성합니다.
mkdir DigitalOceanBot
cd DigitalOceanBot
bothub init
init 작업이 완료되면 기본 코드가 생성됩니다.
|-- bothub
| |-- bot.py
| `-- __init__.py
|-- bothub.yml
|-- requirements.txt
`-- tests
텔레그램 메신저를 연결합니다.
bothub channel add telegram --api-key=<api-key>
처음 프로젝트를 생성하면 기본으로 EchoBot 코드가 들어있어 바로 deploy를 통해 동작하는지 확인해 봅니다.
bothub deploy
3. API 연동하기
방금 생성한 챗봇 프로젝트 안에 bothub/doapi.py
라는 파일을 만들고 아래 클래스를 작성해봅시다.
DigitalOcean API를 이용해 간단하게 Droplet을 생성하고, 목록을 가져오고, 삭제할 수 있습니다.
import jsonfrom urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.request import Request
from urllib.request import urlopenclass DigitalOcean(object):
base_url = ‘https://api.digitalocean.com/v2/droplets' def __init__(self, api_key):
self.headers = {
‘content-type’: ‘application/json’,
‘authorization’: ‘Bearer {}’.format(api_key)
} def get_droplets(self):
req = Request(url=’{}page=1&per_page=5' \
.format(self.base_url),headers = self.headers) try:
with urlopen(req) as response:
return json.loads(response.read().decode(‘utf8’))
except HTTPError as e:
return e.code def delete_droplet(self, droplet_id):
req = Request(url=’{}/{}’.format(self.base_url,droplet_id),\
headers=self.headers, method=’DELETE’) try:
with urlopen(req) as response:
return response.getcode()
except HTTPError as e:
return e.code def create_droplet(self, name, region, image):
values = {‘name’: name, ‘region’: region, ‘size’: ‘512mb’, \
‘image’: ‘ubuntu-{}’.format(image)}
data = json.dumps(values).encode(‘utf8’)
req = Request(self.base_url, data=data,\
headers=self.headers) with urlopen(req) as response:
return json.loads(response.read().decode(‘utf8’)) def simplify(self, result):
return [
{
‘id’: entry.get(‘id’),
‘name’: entry.get(‘name’),
‘status’: entry.get(‘status’)
}
for entry in result.get(‘droplets’)
]
Droplet 생성은 편의상 Name, Region, Image 만 선택하도록 되어 있으며, Size 는 512mb 로 지정해 두었습니다.
4. 챗봇 연동하기
4.1 Image, Region 정의하기
Droplet 생성을 위해 필요한 몇가지 정보를 사전에 Property에 저장해 둡니다.
bothub property set image [“14–04-x64”,”16–04–2-x64",”16–10-x64",”17–04-x64"]bothub property set region [ “nyc1”, “nyc3”, “sfo1”, “sfo2”, “sgp1” ]
4.2 Access token 등록
텔레그램의 경우 /start 메시지와 함께 봇이 시작됩니다. 첫 시작과 함께 Access token을 입력받아 사용하도록 하겠습니다.
bothub/bot.py
파일에서 Bot
class의 handle_message
메소드를 아래와 같이 적용합니다.
from bothub_client.bot import BaseBot
from bothub_client.messages import Message
from .doapi import DigitalOceanclass Bot(BaseBot):
def handle_message(self, event, context):
message = event.get(‘content’) if message == ‘/start’:
self.set_start_message(event) else:
data = self.get_user_data()
api_key = data.get('api') if api_key:
self.verify_api(message, event)
return def set_start_message(self, event):
data = self.get_user_data()
data[‘api’] = True
self.set_user_data(data)
self.send_message(‘DigitalOcean Droplet 관리를 시작합니다.\n’ \
‘API사용을 위해 Access token을 입력해주세요.’) def verify_api(self, api_key, event):
d = DigitalOcean(api_key)
res = d.get_droplets()
if res == 401:
self.send_message('Access token이 올바르지 않습니다.\n'\
'다시 입력해주세요.')
else:
data = self.get_user_data()
data['api'] = False
data['api_key'] = api_key
self.set_user_data(data)
message = Message(event).set_text('등록이 완료되었습니다.')
message.add_keyboard_button('Create Droplet')
message.add_keyboard_button('List all Droplets')
self.send_message(message)
Access token이 확인되면 텔레그램 키보드에 ‘Create Droplet’, ‘List all Droplets’ 가 생성됩니다.
4.3 Droplet 생성하기
등록된 Access token을 이용해 Droplet 생성을 해보겠습니다. (편의를 위해 위 코드중 일부는 생략해 두었습니다. 기존 코드를 삭제하지 말고 추가하시면 됩니다.)
class Bot(BaseBot):
def handle_message(self, event, context):
message = event.get(‘content’)
if message == ‘/start’:
self.set_start_message(event)
elif message == ‘Create Droplet’:
self.set_image(event)
elif message == ‘List all Droplets’:
self.list_droplets(event)
elif message.startswith(‘/delete ‘):
_, droplet_id = message.split()
self.delete_droplet(droplet_id, event)
elif message.startswith(‘/region ‘):
_, image = message.split()
self.set_data(‘image’, image)
self.set_region(event)
elif message.startswith(‘/name ‘):
_, region = message.split()
self.set_data(‘region’, region)
self.set_name(event)
# in case of natural language
else:
data = self.get_user_data()
api_key = data.get(‘api’)
set_name = data.get(‘set_name’)
if api_key:
self.verify_api(message, event)
return
elif set_name:
self.create_droplet(message, event)
return def set_data(self, type, value):
data = self.get_user_data()
data[type] = value
self.set_user_data(data) def set_image(self, event):
images = self.get_project_data()['image']
message = Message(event).set_text('이미지를 선택해주세요.')
for image in images:
message.add_postback_button(image, '/region {}' \
.format(image))
self.send_message(message) def set_region(self, event):
regions = self.get_project_data()['region']
message = Message(event).set_text('Region을 선택해주세요.')
for region in regions:
message.add_postback_button(region, '/name {}' \
.format(region))
self.send_message(message) def set_name(self, event):
self.send_message('hostname을 입력해주세요.')
data = self.get_user_data()
data['set_name'] = True
self.set_user_data(data) def create_droplet(self, name, event):
d = DigitalOcean(self.api_key())
image = self.get_user_data()['image']
region = self.get_user_data()['region']
self.send_message(image, region)
droplet = d.create_droplet(name, region, image)
if not droplet:
self.send_message('Droplet 생성에 실패했습니다.')
data = self.get_user_data()
data['set_name'] = False
self.set_user_data(data)
return self.send_message('id: {} name: {} status: {}\n' \
'Created successfully'\
.format(droplet['droplet']['id'], \
droplet['droplet']['name'], droplet['droplet']['status']))
data = self.get_user_data()
data['set_name'] = False
self.set_user_data(data) def api_key(self):
api_key = self.get_user_data()['api_key']
return api_key
4.4 Droplet 목록 가져오기 & 삭제하기
삭제하기 버튼이 포함된 Droplet 목록을 가져오도록 아래의 내용을 추가합니다.
def list_droplets(self, event):
d = DigitalOcean(self.api_key())
droplets = d.simplify(d.get_droplets())
if not droplets:
self.send_message(‘생성된 Droplet이 없습니다.’)
return for droplet in droplets:
msg = Message(event).set_text(‘id: {} name: {} status: {}’\
.format(droplet[‘id’],\
droplet[‘name’],\
droplet[‘status’])) \
.add_quick_reply(‘Delete’, ‘/delete {}’\
.format(droplet[‘id’])) self.send_message(msg)def delete_droplet(self, droplet_id, event):
d = DigitalOcean(self.api_key())
res = d.delete_droplet(droplet_id)
if res == 204:
self.send_message(‘id: {} Droplet 삭제되었습니다.’\
.format(droplet_id))
elif res == 404:
self.send_message(‘id: {} Droplet이 존재하지 않습니다.’\
.format(droplet_id))
else:
self.send_message(‘에러 발생. Droplet 목록을 다시 확인해주세요.’)
작성된 최종 코드는 Github에서 확인하실 수 있습니다.
또 위에 작성된 코드로 동작하는 테스트 가능한 챗봇은 텔레그램에서 @Digital_Ocean_Bot 을 검색하시거나 t.me/Digital_Ocean_Bot 를 통해서 확인해 보실 수 있습니다.
5. 참고자료
본 아티클 관련 문의는 BotHub.Studio Community를 통해 지원받으실 수 있습니다. 챗봇 도입 및 제휴 문의는 bothub@bothub.sutdio로 연락해주세요.