diff --git a/README.md b/README.md index 130d6b04..73fa3779 100644 --- a/README.md +++ b/README.md @@ -10,28 +10,32 @@ ## Table of Contents +- [Table of Contents](#table-of-contents) - [How to install](#how-to-install) - [Configurations](#configurations) -- [Features](#features) +- [Features](#features) - [Examples](#examples) - - [Listing the droplets](#listing-the-droplets) - - [Listing the droplets by tags](#listing-the-droplets-by-tags) - - [Add a tag to a droplet](#add-a-tag-to-a-droplet) - - [Shutdown all droplets](#shutdown-all-droplets) - - [Creating a Droplet and checking its status](#creating-a-droplet-and-checking-its-status) - - [Checking the status of the droplet](#checking-the-status-of-the-droplet) - - [Add SSHKey into DigitalOcean Account](#add-sshkey-into-digitalocean-account) - - [Creating a new droplet with all your SSH keys](#creating-a-new-droplet-with-all-your-ssh-keys) - - [Creating a Firewall](#creating-a-firewall) - - [Listing the domains](#listing-the-domains) - - [Listing records of a domain](#listing-records-of-a-domain) - - [Creating a domain record](#creating-a-domain-record) - - [Update a domain record](#update-a-domain-record) + - [Listing the droplets](#listing-the-droplets) + - [Listing the droplets by tags](#listing-the-droplets-by-tags) + - [Add a tag to a droplet](#add-a-tag-to-a-droplet) + - [Shutdown all droplets](#shutdown-all-droplets) + - [Creating a Droplet and checking its status](#creating-a-droplet-and-checking-its-status) + - [Checking the status of the droplet](#checking-the-status-of-the-droplet) + - [Add SSHKey into DigitalOcean Account](#add-sshkey-into-digitalocean-account) + - [Creating a new droplet with all your SSH keys](#creating-a-new-droplet-with-all-your-ssh-keys) + - [Creating a Firewall](#creating-a-firewall) + - [Get, create, list and destroy database clusters](#get-create-list-and-destroy-database-clusters) + - [Listing the domains](#listing-the-domains) + - [Listing records of a domain](#listing-records-of-a-domain) + - [Creating a domain record](#creating-a-domain-record) + - [Update a domain record](#update-a-domain-record) - [Getting account requests/hour limits status](#getting-account-requestshour-limits-status) - [Session customization](#session-customization) + - [Configure retries in case of connection error](#configure-retries-in-case-of-connection-error) + - [Configure a hook on specified answer](#configure-a-hook-on-specified-answer) - [Testing](#testing) - - [Test using Docker](#test-using-docker) - - [Testing using pytest manually](#testing-using-pytest-manually) + - [Test using Docker](#test-using-docker) + - [Testing using pytest manually](#testing-using-pytest-manually) - [Links](#links) ## How to install @@ -69,6 +73,7 @@ python-digitalocean support all the features provided via digitalocean.com APIs, * Perform Snapshot * Enable/Disable automatic Backups * Restore root password of a Droplet +* Get, create, list, and destroy database clusters **[⬆ back to top](#table-of-contents)** @@ -223,6 +228,42 @@ firewall.create() **[⬆ back to top](#table-of-contents)** +### Get, create, list and destroy database clusters + +This example shows how to get, create, list and destroy database clusters, replicas, databases, and database users: + +```python +from digitalocean import Database + +db = Database(token=TOKEN) + +# Create a database cluster +print(db.create.cluster(name='test-db', engine='mysql', size='db-s-1vcpu-1gb', region='nyc1', num_nodes=1)) + +# Get a single database clusters +print(db.get.cluster('1e7a4056-9b2c-4ac0-96b1-6119f5ee9f10')) + +# List all database clusters +print(db.list.clusters()) + +# Destroy a database cluster +print(db.destroy.cluster('1e7a4056-9b2c-4ac0-96b1-6119f5ee9f10')) + +# Create a database replica +print(db.create.replica('test-db-replica', 'db-s-1vcpu-1gb')) + +# Get a database replica +print(db.get.replica('1e7a4056-9b2c-4ac0-96b1-6119f5ee9f10', 'test-db-replica')) + +# List all database replicas +print(db.list.replicas('1e7a4056-9b2c-4ac0-96b1-6119f5ee9f10')) + +# Destroy a database cluster +print(db.destroy.cluster('1e7a4056-9b2c-4ac0-96b1-6119f5ee9f10', 'test-db-replica')) + +# Additionally, you can do the same functionality with databases within a cluster and database users among other features +``` + ### Listing the domains This example shows how to list all the active domains: diff --git a/digitalocean/Database.py b/digitalocean/Database.py new file mode 100644 index 00000000..e30d2365 --- /dev/null +++ b/digitalocean/Database.py @@ -0,0 +1,218 @@ +# -*- coding: utf-8 -*- +from .baseapi import BaseAPI, POST, DELETE, PUT + +__SIZE_SLUG__ = [ + 'db-s-1vcpu-1gb', + 'db-s-1vcpu-2gb', + 'db-s-2vcpu-4gb', + 'db-s-4vcpu-8gb', + 'db-s-6vcpu-16gb', + 'db-s-8vcpu-32gb', + 'db-s-16vcpu-64gb' +] + +__DB_ENGINES__ = { + 'pg': { + 'versions': ['10','11'] + }, + 'mysql': { + 'versions': ['8'] + }, + 'redis':{ + 'versions': ['5'] + } +} + + +class DatabaseCreate(BaseAPI): + + def __init__(self, *args, **kwargs): + super(DatabaseCreate, self).__init__(*args, **kwargs) + + + def cluster(self, name, engine, size, region, num_nodes, version=None, tags=None): + if __DB_ENGINES__[engine]: + params = { + "name": name, + "engine": engine, + "size": size, + "region": region, + "num_nodes": int(num_nodes) + } + if version: + if version in __DB_ENGINES__[engine]['versions']: + params['version'] = version + else: + raise AttributeError('Please provide a valid database version') + if tags and isinstance(tags, list): + params['tags'] = tags + + data = self.get_data('databases/', type=POST, params=params) + + if data: + return data['database'] + else: + return 'Error creating database' + + def replica(self, name, size, region=None, tags=None, db_id=None): + params = {} + params['name'] = name + if size in __SIZE_SLUG__: + params['size'] = size + if region: + params['region'] = region + if tags: + params['tags'] = tags + + if db_id: + data = self.get_data("databases/{}/replicas".format(db_id), type='POST', params=params) + else: + data = self.get_data("databases/{}/replicas".format(self.id), type='POST', params=params) + + if data: + return data['replica'] + else: + return 'Error creating replica' + + def user(self, name, db_id=None): + params = {} + params['name'] = name + + if db_id: + data = self.get_data("databases/{}/users".format(db_id), type='POST', params=params) + else: + data = self.get_data("databases/{}/users".format(self.id), type='POST', params=params) + + if data: + return data['users'] + else: + return 'Error creating users' + + def database(self, name, db_id=None): + params = {} + params['name'] = name + + if db_id: + data = self.get_data("databases/{}/dbs".format(db_id), type='POST', params=params) + else: + data = self.get_data("databases/{}/dbs".format(self.id), type='POST', params=params) + + if data: + return data['db'] + else: + return 'Error creating database' + + +class DatabaseList(BaseAPI): + + def __init__(self, *args, **kwargs): + super(DatabaseList, self).__init__(*args, **kwargs) + + def clusters(self, tag_name=None): + if tag_name: + data = self.get_data("databases?tag_name={}".format(tag_name)) + else: + data = self.get_data("databases") + return None if not data else data['databases'] + + def backups(self, db_id): + data = self.get_data("databases/{}/backups".format(db_id)) + return None if not data else data['backups'] + + def replicas(self, db_id): + data = self.get_data("databases/{}/replicas".format(db_id)) + return None if not data else data['replicas'] + + def users(self, db_id): + data = self.get_data("databases/{}/users".format(db_id)) + return None if not data else data['users'] + + def databases(self, db_id): + data = self.get_data("databases/{}/dbs".format(db_id)) + return None if not data else data['dbs'] + + +class DatabaseGet(BaseAPI): + + def __init__(self, *args, **kwargs): + super(DatabaseGet, self).__init__(*args, **kwargs) + + def cluster(self, db_id): + data = self.get_data("databases/{}".format(db_id)) + return None if not data else data['database'] + + def replica(self, db_id, replica_name): + data = self.get_data("databases/{}/replicas/{}".format(db_id, replica_name)) + return None if not data else data['replica'] + + def user(self, db_id, username): + data = self.get_data("databases/{}/users/{}".format(db_id, username)) + return None if not data else data['user'] + + +class DatabaseDestroy(BaseAPI): + + def __init__(self, *args, **kwargs): + super(DatabaseDestroy, self).__init__(*args, **kwargs) + + def cluster(self, db_id): + data = self.get_data("databases/{}".format(db_id), type='DELETE') + return None if not data else True + + def replica(self, db_id, replica_name): + data = self.get_data("databases/{}/replicas/{}".format(db_id, replica_name), type='DELETE') + return None if not data else True + + def user(self, db_id, username): + data = self.get_data("databases/{}/users/{}".format(db_id, username), type='DELETE') + return None if not data else True + + def database(self, db_id, db_name): + data = self.get_data("databases/{}/dbs/{}".format(db_id, db_name), type='DELETE') + return None if not data else True + +class Database(BaseAPI): + + def __init__(self, *args, **kwargs): + super(Database, self).__init__(*args, **kwargs) + self.args = args + self.kwargs = kwargs + pass + + @property + def create(self): + return DatabaseCreate(*self.args, **self.kwargs) + + @property + def destroy(self): + return DatabaseDestroy(*self.args, **self.kwargs) + + @property + def list(self): + return DatabaseList(*self.args, **self.kwargs) + + @property + def get(self): + return DatabaseGet(*self.args, **self.kwargs) + + def resize(self, size, num_nodes, db_id): + params = {} + if size in __SIZE_SLUG__: + params['size'] = size + params['num_nodes'] = int(num_nodes) + data = self.get_data('databases/{}/resize'.format(db_id), type='PUT', params=params) + return None if not data else True + + def migrate(self, region, db_id): + params = {} + params['region'] = region + data = self.get_data('databases/{}/migrate'.format(db_id), type='PUT', params=params) + return None if not data else True + + def maintenance(self, day, hour, db_id): + params = {} + params['day'] = day + params['hour'] = hour + data = self.get_data('databases/{}/maintenance'.format(db_id), type='PUT', params=params) + return None if not data else True + diff --git a/digitalocean/__init__.py b/digitalocean/__init__.py index 1de3d859..9177326b 100644 --- a/digitalocean/__init__.py +++ b/digitalocean/__init__.py @@ -27,3 +27,4 @@ from .Certificate import Certificate from .Snapshot import Snapshot from .Firewall import Firewall, InboundRule, OutboundRule, Destinations, Sources +from .Database import Database \ No newline at end of file