|
|
|
import requests
|
|
|
|
from flask import current_app
|
|
|
|
from app import config
|
|
|
|
|
|
|
|
|
|
|
|
class DigitalOcean(object):
|
|
|
|
base = 'https://api.digitalocean.com/v2/'
|
|
|
|
headers = {
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
'Authorization': 'Bearer ' + config.DO_TOKEN
|
|
|
|
}
|
|
|
|
|
|
|
|
def make_req(self, method, endpoint, data=None):
|
|
|
|
url = self.base + endpoint
|
|
|
|
current_app.logger.info(f'{method.upper()} - {url}')
|
|
|
|
if method == 'post':
|
|
|
|
r = requests.post(url, timeout=8, headers=self.headers, json=data)
|
|
|
|
elif method == 'get':
|
|
|
|
r = requests.get(url, timeout=8, headers=self.headers)
|
|
|
|
elif method == 'delete':
|
|
|
|
r = requests.delete(url, timeout=8, headers=self.headers)
|
|
|
|
else:
|
|
|
|
return 'method not defined'
|
|
|
|
r.raise_for_status()
|
|
|
|
return r
|
|
|
|
|
|
|
|
# Account meta
|
|
|
|
def show_account(self):
|
|
|
|
r = self.make_req('get', 'account')
|
|
|
|
return r.json()['account']
|
|
|
|
|
|
|
|
# Domains and records
|
|
|
|
def create_record(self, name, ip_addr, type='A'):
|
|
|
|
data = {
|
|
|
|
'type': type,
|
|
|
|
'name': name,
|
|
|
|
'data': ip_addr
|
|
|
|
}
|
|
|
|
r = self.make_req('post', f'domains/{config.DO_DOMAIN}/records', data)
|
|
|
|
return r.json()['domain_record']
|
|
|
|
|
|
|
|
def delete_record(self, record_id):
|
|
|
|
if record_id:
|
|
|
|
route = f'domains/{config.DO_DOMAIN}/records/{record_id}'
|
|
|
|
r = self.make_req('delete', route)
|
|
|
|
if r.status_code == 204:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
# SSH Keys
|
|
|
|
def create_key(self, name, public_key):
|
|
|
|
data = {
|
|
|
|
'name': name,
|
|
|
|
'public_key': public_key.strip()
|
|
|
|
}
|
|
|
|
return self.make_req('post', 'account/keys', data)
|
|
|
|
|
|
|
|
def list_keys(self):
|
|
|
|
return self.make_req('get', 'account/keys')
|
|
|
|
|
|
|
|
# Volumes
|
|
|
|
def create_volume(self, name, region):
|
|
|
|
data = {
|
|
|
|
'name': name,
|
|
|
|
'size_gigabytes': int(config.DO_DROPLET_STORAGE_GB),
|
|
|
|
'region': region,
|
|
|
|
'filesystem_type': 'ext4'
|
|
|
|
}
|
|
|
|
r = self.make_req('post', 'volumes', data)
|
|
|
|
return r.json()['volume']
|
|
|
|
|
|
|
|
def list_volumes(self):
|
|
|
|
r = self.make_req('get', 'volumes')
|
|
|
|
return r.json()['volumes']
|
|
|
|
|
|
|
|
def check_volume_exists(self, name, region):
|
|
|
|
r = self.make_req('get', f'volumes?name={name}®ion={region}')
|
|
|
|
if r.json()['volumes'] == list():
|
|
|
|
return (False, None)
|
|
|
|
else:
|
|
|
|
return (True, r.json()['volumes'][0]['id'])
|
|
|
|
|
|
|
|
def show_volume(self, volume_id):
|
|
|
|
r = self.make_req('get', f'volumes/{volume_id}')
|
|
|
|
return r.json()['volume']
|
|
|
|
|
|
|
|
# Droplets
|
|
|
|
def create_droplet(self, name, region, extra_vols=[]):
|
|
|
|
# First check that droplet name does not exist
|
|
|
|
de = self.check_droplet_exists(name)
|
|
|
|
if de[0]:
|
|
|
|
return self.show_droplet(de[1])
|
|
|
|
data = {
|
|
|
|
'name': name,
|
|
|
|
'region': region,
|
|
|
|
'size': config.DO_DROPLET_SIZE,
|
|
|
|
'image': config.DO_DROPLET_IMAGE,
|
|
|
|
'ssh_keys': [
|
|
|
|
int(config.DO_SSH_KEY)
|
|
|
|
],
|
|
|
|
'backups': False,
|
|
|
|
'ipv6': True,
|
|
|
|
'user_data': f'#!/bin/bash\nwget https://raw.githubusercontent.com/lalanza808/docker-monero-node/master/cloud-init.sh -q -O - | DOMAIN={name}.node.{config.DO_DOMAIN} ACME_EMAIL={config.ADMIN_EMAIL} GRAF_PASS={config.GRAF_PASS} GRAF_USER={config.GRAF_USER} bash',
|
|
|
|
'private_networking': None,
|
|
|
|
'volumes': extra_vols,
|
|
|
|
'tags': []
|
|
|
|
}
|
|
|
|
r = self.make_req('post', 'droplets', data)
|
|
|
|
return r.json()['droplet']
|
|
|
|
|
|
|
|
def destroy_droplet(self, droplet_id):
|
|
|
|
if droplet_id:
|
|
|
|
route = f'droplets/{droplet_id}/destroy_with_associated_resources/dangerous'
|
|
|
|
self.headers['X-Dangerous'] = 'true'
|
|
|
|
r = self.make_req('delete', route)
|
|
|
|
if r.status_code == 202:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def show_droplet(self, droplet_id):
|
|
|
|
if droplet_id:
|
|
|
|
r = self.make_req('get', f'droplets/{droplet_id}')
|
|
|
|
return r.json()['droplet']
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def check_droplet_exists(self, name):
|
|
|
|
r = self.make_req('get', 'droplets')
|
|
|
|
droplets = r.json()['droplets']
|
|
|
|
for d in droplets:
|
|
|
|
if d['name'] == name:
|
|
|
|
return (True, d['id'])
|
|
|
|
return (False, None)
|
|
|
|
|
|
|
|
# Pricing
|
|
|
|
def get_droplet_price_usd_per_hour(self, size):
|
|
|
|
sizes = {
|
|
|
|
's-1vcpu-1gb': .00744,
|
|
|
|
's-1vcpu-2gb': .015,
|
|
|
|
's-2vcpu-2gb': .022,
|
|
|
|
's-2vcpu-4gb': .030,
|
|
|
|
's-4vcpu-8gb': .060,
|
|
|
|
's-8vcpu-16gb': .119,
|
|
|
|
}
|
|
|
|
return sizes[size]
|
|
|
|
|
|
|
|
def get_volume_price_usd_per_hour(self, size_gb):
|
|
|
|
return round(0.105 * size_gb / 730, 3)
|
|
|
|
|
|
|
|
|
|
|
|
do = DigitalOcean()
|