Adds support for databases
This commit is contained in:
parent
7a99fd7cb2
commit
007e73ff4c
|
@ -0,0 +1,607 @@
|
|||
package godo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
databaseBasePath = "/v2/databases"
|
||||
databaseSinglePath = databaseBasePath + "/%s"
|
||||
databaseResizePath = databaseBasePath + "/%s/resize"
|
||||
databaseMigratePath = databaseBasePath + "/%s/migrate"
|
||||
databaseMaintenancePath = databaseBasePath + "/%s/maintenance"
|
||||
databaseBackupsPath = databaseBasePath + "/%s/backups"
|
||||
databaseUsersPath = databaseBasePath + "/%s/users"
|
||||
databaseUserPath = databaseBasePath + "/%s/users/%s"
|
||||
databaseDBPath = databaseBasePath + "/%s/dbs/%s"
|
||||
databaseDBsPath = databaseBasePath + "/%s/dbs"
|
||||
databasePoolPath = databaseBasePath + "/%s/pools/%s"
|
||||
databasePoolsPath = databaseBasePath + "/%s/pools"
|
||||
databaseReplicaPath = databaseBasePath + "/%s/replicas/%s"
|
||||
databaseReplicasPath = databaseBasePath + "/%s/replicas"
|
||||
)
|
||||
|
||||
// DatabasesService is an interface for interfacing with the databases endpoints
|
||||
// of the DigitalOcean API.
|
||||
// See: https://developers.digitalocean.com/documentation/v2#databases
|
||||
type DatabasesService interface {
|
||||
List(context.Context, *ListOptions) ([]Database, *Response, error)
|
||||
Get(context.Context, string) (*Database, *Response, error)
|
||||
Create(context.Context, *DatabaseCreateRequest) (*Database, *Response, error)
|
||||
Delete(context.Context, string) (*Response, error)
|
||||
Resize(context.Context, string, *DatabaseResizeRequest) (*Response, error)
|
||||
Migrate(context.Context, string, *DatabaseMigrateRequest) (*Response, error)
|
||||
UpdateMaintenance(context.Context, string, *DatabaseUpdateMaintenanceRequest) (*Response, error)
|
||||
ListBackups(context.Context, string, *ListOptions) ([]DatabaseBackup, *Response, error)
|
||||
GetUser(context.Context, string, string) (*DatabaseUser, *Response, error)
|
||||
ListUsers(context.Context, string, *ListOptions) ([]DatabaseUser, *Response, error)
|
||||
CreateUser(context.Context, string, *DatabaseCreateUserRequest) (*DatabaseUser, *Response, error)
|
||||
DeleteUser(context.Context, string, string) (*Response, error)
|
||||
ListDBs(context.Context, string, *ListOptions) ([]DatabaseDB, *Response, error)
|
||||
CreateDB(context.Context, string, *DatabaseCreateDBRequest) (*DatabaseDB, *Response, error)
|
||||
GetDB(context.Context, string, string) (*DatabaseDB, *Response, error)
|
||||
DeleteDB(context.Context, string, string) (*Response, error)
|
||||
ListPools(context.Context, string, *ListOptions) ([]DatabasePool, *Response, error)
|
||||
CreatePool(context.Context, string, *DatabaseCreatePoolRequest) (*DatabasePool, *Response, error)
|
||||
GetPool(context.Context, string, string) (*DatabasePool, *Response, error)
|
||||
DeletePool(context.Context, string, string) (*Response, error)
|
||||
GetReplica(context.Context, string, string) (*DatabaseReplica, *Response, error)
|
||||
ListReplicas(context.Context, string, *ListOptions) ([]DatabaseReplica, *Response, error)
|
||||
CreateReplica(context.Context, string, *DatabaseCreateReplicaRequest) (*DatabaseReplica, *Response, error)
|
||||
DeleteReplica(context.Context, string, string) (*Response, error)
|
||||
}
|
||||
|
||||
// DatabasesServiceOp handles communication with the Databases related methods
|
||||
// of the DigitalOcean API.
|
||||
type DatabasesServiceOp struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
var _ DatabasesService = &DatabasesServiceOp{}
|
||||
|
||||
// Database represents a database cluster
|
||||
type Database struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
EngineSlug string `json:"engine,omitempty"`
|
||||
VersionSlug string `json:"version,omitempty"`
|
||||
Connection *DatabaseConnection `json:"connection,omitempty"`
|
||||
Users []DatabaseUser `json:"users,omitempty"`
|
||||
NumNodes int `json:"num_nodes,omitempty"`
|
||||
SizeSlug string `json:"size,omitempty"`
|
||||
DBNames []string `json:"db_names,omitempty"`
|
||||
RegionSlug string `json:"region,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
MaintenanceWindow *DatabaseMaintenanceWindow `json:"maintenance_window,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseConnection represents a database connection
|
||||
type DatabaseConnection struct {
|
||||
URI string `json:"uri,omitempty"`
|
||||
Database string `json:"database,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
Port int `json:"port,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
SSL bool `json:"ssl,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseUser represents a user in the database
|
||||
type DatabaseUser struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseMaintenanceWindow represents the maintenance_window of a database
|
||||
// cluster
|
||||
type DatabaseMaintenanceWindow struct {
|
||||
Day string `json:"day,omitempty"`
|
||||
Hour string `json:"hour,omitempty"`
|
||||
Pending bool `json:"pending,omitempty"`
|
||||
Description []string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseBackup represents a database backup.
|
||||
type DatabaseBackup struct {
|
||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||
SizeGigabytes float64 `json:"size_gigabytes,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseCreateRequest represents a request to create a database cluster
|
||||
type DatabaseCreateRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
EngineSlug string `json:"engine,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
SizeSlug string `json:"size,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
NumNodes int `json:"num_nodes,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseResizeRequest can be used to initiate a database resize operation.
|
||||
type DatabaseResizeRequest struct {
|
||||
SizeSlug string `json:"size,omitempty"`
|
||||
NumNodes int `json:"num_nodes,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseMigrateRequest can be used to initiate a database migrate operation.
|
||||
type DatabaseMigrateRequest struct {
|
||||
Region string `json:"region,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseUpdateMaintenanceRequest can be used to update the database's maintenance window.
|
||||
type DatabaseUpdateMaintenanceRequest struct {
|
||||
Day string `json:"day,omitempty"`
|
||||
Hour string `json:"hour,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseDB represents an engine-specific database created within a database cluster
|
||||
type DatabaseDB struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// DatabaseReplica represents a read-only replica of a particular database
|
||||
type DatabaseReplica struct {
|
||||
Name string `json:"name"`
|
||||
Connection *DatabaseConnection `json:"connection"`
|
||||
Region string `json:"region"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// DatabasePool represents a database connection pool
|
||||
type DatabasePool struct {
|
||||
User string `json:"user"`
|
||||
Name string `json:"name"`
|
||||
Size int `json:"size"`
|
||||
Database string `json:"database"`
|
||||
Mode string `json:"mode"`
|
||||
Connection *DatabaseConnection `json:"connection"`
|
||||
}
|
||||
|
||||
// DatabaseCreatePoolRequest is used to create a new database connection pool
|
||||
type DatabaseCreatePoolRequest struct {
|
||||
Pool *DatabasePool `json:"pool"`
|
||||
}
|
||||
|
||||
// DatabaseCreateUserRequest is used to create a new database user
|
||||
type DatabaseCreateUserRequest struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// DatabaseCreateDBRequest is used to create a new engine-specific database within the cluster
|
||||
type DatabaseCreateDBRequest struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// DatabaseCreateReplicaRequest is used to create a new read-only replica
|
||||
type DatabaseCreateReplicaRequest struct {
|
||||
Name string `json:"name"`
|
||||
Region string `json:"region"`
|
||||
Size string `json:"size"`
|
||||
}
|
||||
|
||||
type databaseUserRoot struct {
|
||||
User *DatabaseUser `json:"user"`
|
||||
}
|
||||
|
||||
type databaseUsersRoot struct {
|
||||
Users []DatabaseUser `json:"users"`
|
||||
}
|
||||
|
||||
type databaseDBRoot struct {
|
||||
DB *DatabaseDB `json:"db"`
|
||||
}
|
||||
|
||||
type databaseDBsRoot struct {
|
||||
DBs []DatabaseDB `json:"dbs"`
|
||||
}
|
||||
|
||||
type databasesRoot struct {
|
||||
Databases []Database `json:"databases"`
|
||||
}
|
||||
|
||||
type databaseRoot struct {
|
||||
Database *Database `json:"database"`
|
||||
}
|
||||
|
||||
type databaseBackupsRoot struct {
|
||||
Backups []DatabaseBackup `json:"backups"`
|
||||
}
|
||||
|
||||
type databasePoolRoot struct {
|
||||
Pool *DatabasePool `json:"pool"`
|
||||
}
|
||||
|
||||
type databasePoolsRoot struct {
|
||||
Pools []DatabasePool `json:"pools"`
|
||||
}
|
||||
|
||||
type databaseReplicaRoot struct {
|
||||
Replica *DatabaseReplica `json:"replica"`
|
||||
}
|
||||
|
||||
type databaseReplicasRoot struct {
|
||||
Replicas []DatabaseReplica `json:"replicas"`
|
||||
}
|
||||
|
||||
// List returns a list of the Databases visible with the caller's API token
|
||||
func (svc *DatabasesServiceOp) List(ctx context.Context, opts *ListOptions) ([]Database, *Response, error) {
|
||||
path := databaseBasePath
|
||||
path, err := addOptions(path, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databasesRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Databases, resp, nil
|
||||
}
|
||||
|
||||
// Get retrieves the details of a database cluster
|
||||
func (svc *DatabasesServiceOp) Get(ctx context.Context, databaseID string) (*Database, *Response, error) {
|
||||
path := fmt.Sprintf(databaseSinglePath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Database, resp, nil
|
||||
}
|
||||
|
||||
// Create creates a database cluster
|
||||
func (svc *DatabasesServiceOp) Create(ctx context.Context, create *DatabaseCreateRequest) (*Database, *Response, error) {
|
||||
path := databaseBasePath
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPost, path, create)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Database, resp, nil
|
||||
}
|
||||
|
||||
// Delete deletes a database cluster. There is no way to recover a cluster once
|
||||
// it has been destroyed.
|
||||
func (svc *DatabasesServiceOp) Delete(ctx context.Context, databaseID string) (*Response, error) {
|
||||
path := fmt.Sprintf("%s/%s", databaseBasePath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodDelete, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Resize resizes a database cluster by number of nodes or size
|
||||
func (svc *DatabasesServiceOp) Resize(ctx context.Context, databaseID string, resize *DatabaseResizeRequest) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseResizePath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPut, path, resize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Migrate migrates a database cluster to a new region
|
||||
func (svc *DatabasesServiceOp) Migrate(ctx context.Context, databaseID string, migrate *DatabaseMigrateRequest) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseMigratePath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPut, path, migrate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// UpdateMaintenance updates the maintenance window on a cluster
|
||||
func (svc *DatabasesServiceOp) UpdateMaintenance(ctx context.Context, databaseID string, maintenance *DatabaseUpdateMaintenanceRequest) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseMaintenancePath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPut, path, maintenance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ListBackups returns a list of the current backups of a database
|
||||
func (svc *DatabasesServiceOp) ListBackups(ctx context.Context, databaseID string, opts *ListOptions) ([]DatabaseBackup, *Response, error) {
|
||||
path := fmt.Sprintf(databaseBackupsPath, databaseID)
|
||||
path, err := addOptions(path, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseBackupsRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Backups, resp, nil
|
||||
}
|
||||
|
||||
// GetUser returns the database user identified by userID
|
||||
func (svc *DatabasesServiceOp) GetUser(ctx context.Context, databaseID, userID string) (*DatabaseUser, *Response, error) {
|
||||
path := fmt.Sprintf(databaseUserPath, databaseID, userID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseUserRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.User, resp, nil
|
||||
}
|
||||
|
||||
// ListUsers returns all database users for the database
|
||||
func (svc *DatabasesServiceOp) ListUsers(ctx context.Context, databaseID string, opts *ListOptions) ([]DatabaseUser, *Response, error) {
|
||||
path := fmt.Sprintf(databaseUsersPath, databaseID)
|
||||
path, err := addOptions(path, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseUsersRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Users, resp, nil
|
||||
}
|
||||
|
||||
// CreateUser will create a new database user
|
||||
func (svc *DatabasesServiceOp) CreateUser(ctx context.Context, databaseID string, createUser *DatabaseCreateUserRequest) (*DatabaseUser, *Response, error) {
|
||||
path := fmt.Sprintf(databaseUsersPath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPost, path, createUser)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseUserRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.User, resp, nil
|
||||
}
|
||||
|
||||
// DeleteUser will delete an existing database user
|
||||
func (svc *DatabasesServiceOp) DeleteUser(ctx context.Context, databaseID, userID string) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseUserPath, databaseID, userID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodDelete, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ListDBs returns all databases for a given database cluster
|
||||
func (svc *DatabasesServiceOp) ListDBs(ctx context.Context, databaseID string, opts *ListOptions) ([]DatabaseDB, *Response, error) {
|
||||
path := fmt.Sprintf(databaseDBsPath, databaseID)
|
||||
path, err := addOptions(path, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseDBsRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.DBs, resp, nil
|
||||
}
|
||||
|
||||
// GetDB returns a single database by name
|
||||
func (svc *DatabasesServiceOp) GetDB(ctx context.Context, databaseID, name string) (*DatabaseDB, *Response, error) {
|
||||
path := fmt.Sprintf(databaseDBPath, databaseID, name)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseDBRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.DB, resp, nil
|
||||
}
|
||||
|
||||
// CreateDB will create a new database
|
||||
func (svc *DatabasesServiceOp) CreateDB(ctx context.Context, databaseID string, createDB *DatabaseCreateDBRequest) (*DatabaseDB, *Response, error) {
|
||||
path := fmt.Sprintf(databaseDBsPath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPost, path, createDB)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseDBRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.DB, resp, nil
|
||||
}
|
||||
|
||||
// DeleteDB will delete an existing database
|
||||
func (svc *DatabasesServiceOp) DeleteDB(ctx context.Context, databaseID, name string) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseDBPath, databaseID, name)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodDelete, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ListPools returns all connection pools for a given database cluster
|
||||
func (svc *DatabasesServiceOp) ListPools(ctx context.Context, databaseID string, opts *ListOptions) ([]DatabasePool, *Response, error) {
|
||||
path := fmt.Sprintf(databasePoolsPath, databaseID)
|
||||
path, err := addOptions(path, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databasePoolsRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Pools, resp, nil
|
||||
}
|
||||
|
||||
// GetPool returns a single database connection pool by name
|
||||
func (svc *DatabasesServiceOp) GetPool(ctx context.Context, databaseID, name string) (*DatabasePool, *Response, error) {
|
||||
path := fmt.Sprintf(databasePoolPath, databaseID, name)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databasePoolRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Pool, resp, nil
|
||||
}
|
||||
|
||||
// CreatePool will create a new database connection pool
|
||||
func (svc *DatabasesServiceOp) CreatePool(ctx context.Context, databaseID string, createPool *DatabaseCreatePoolRequest) (*DatabasePool, *Response, error) {
|
||||
path := fmt.Sprintf(databasePoolsPath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPost, path, createPool)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databasePoolRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Pool, resp, nil
|
||||
}
|
||||
|
||||
// DeletePool will delete an existing database connection pool
|
||||
func (svc *DatabasesServiceOp) DeletePool(ctx context.Context, databaseID, name string) (*Response, error) {
|
||||
path := fmt.Sprintf(databasePoolPath, databaseID, name)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodDelete, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetReplica returns a single database replica
|
||||
func (svc *DatabasesServiceOp) GetReplica(ctx context.Context, databaseID, name string) (*DatabaseReplica, *Response, error) {
|
||||
path := fmt.Sprintf(databaseReplicaPath, databaseID, name)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseReplicaRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Replica, resp, nil
|
||||
}
|
||||
|
||||
// ListReplicas returns all read-only replicas for a given database cluster
|
||||
func (svc *DatabasesServiceOp) ListReplicas(ctx context.Context, databaseID string, opts *ListOptions) ([]DatabaseReplica, *Response, error) {
|
||||
path := fmt.Sprintf(databaseReplicasPath, databaseID)
|
||||
path, err := addOptions(path, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseReplicasRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Replicas, resp, nil
|
||||
}
|
||||
|
||||
// CreateReplica will create a new database connection pool
|
||||
func (svc *DatabasesServiceOp) CreateReplica(ctx context.Context, databaseID string, createReplica *DatabaseCreateReplicaRequest) (*DatabaseReplica, *Response, error) {
|
||||
path := fmt.Sprintf(databaseReplicasPath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPost, path, createReplica)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseReplicaRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Replica, resp, nil
|
||||
}
|
||||
|
||||
// DeleteReplica will delete an existing database replica
|
||||
func (svc *DatabasesServiceOp) DeleteReplica(ctx context.Context, databaseID, name string) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseReplicaPath, databaseID, name)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodDelete, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
|
@ -0,0 +1,961 @@
|
|||
package godo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var db = Database{
|
||||
ID: "da4e0206-d019-41d7-b51f-deadbeefbb8f",
|
||||
Name: "dbtest",
|
||||
EngineSlug: "pg",
|
||||
VersionSlug: "11",
|
||||
Connection: &DatabaseConnection{
|
||||
URI: "postgres://doadmin:zt91mum075ofzyww@dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require",
|
||||
Database: "",
|
||||
Host: "dbtest-do-user-3342561-0.db.ondigitalocean.com",
|
||||
Port: 25060,
|
||||
User: "doadmin",
|
||||
Password: "zt91mum075ofzyww",
|
||||
SSL: true,
|
||||
},
|
||||
Users: []DatabaseUser{
|
||||
DatabaseUser{
|
||||
Name: "doadmin",
|
||||
Role: "primary",
|
||||
Password: "zt91mum075ofzyww",
|
||||
},
|
||||
},
|
||||
DBNames: []string{
|
||||
"defaultdb",
|
||||
},
|
||||
NumNodes: 3,
|
||||
RegionSlug: "sfo2",
|
||||
Status: "online",
|
||||
CreatedAt: time.Date(2019, 2, 26, 6, 12, 39, 0, time.UTC),
|
||||
MaintenanceWindow: &DatabaseMaintenanceWindow{
|
||||
Day: "monday",
|
||||
Hour: "13:51:14",
|
||||
Pending: false,
|
||||
Description: nil,
|
||||
},
|
||||
SizeSlug: "db-s-2vcpu-4gb",
|
||||
}
|
||||
|
||||
var dbJSON = `
|
||||
{
|
||||
"id": "da4e0206-d019-41d7-b51f-deadbeefbb8f",
|
||||
"name": "dbtest",
|
||||
"engine": "pg",
|
||||
"version": "11",
|
||||
"connection": {
|
||||
"uri": "postgres://doadmin:zt91mum075ofzyww@dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require",
|
||||
"database": "",
|
||||
"host": "dbtest-do-user-3342561-0.db.ondigitalocean.com",
|
||||
"port": 25060,
|
||||
"user": "doadmin",
|
||||
"password": "zt91mum075ofzyww",
|
||||
"ssl": true
|
||||
},
|
||||
"users": [
|
||||
{
|
||||
"name": "doadmin",
|
||||
"role": "primary",
|
||||
"password": "zt91mum075ofzyww"
|
||||
}
|
||||
],
|
||||
"db_names": [
|
||||
"defaultdb"
|
||||
],
|
||||
"num_nodes": 3,
|
||||
"region": "sfo2",
|
||||
"status": "online",
|
||||
"created_at": "2019-02-26T06:12:39Z",
|
||||
"maintenance_window": {
|
||||
"day": "monday",
|
||||
"hour": "13:51:14",
|
||||
"pending": false,
|
||||
"description": null
|
||||
},
|
||||
"size": "db-s-2vcpu-4gb"
|
||||
}
|
||||
`
|
||||
|
||||
var dbsJSON = fmt.Sprintf(`
|
||||
{
|
||||
"databases": [
|
||||
%s
|
||||
]
|
||||
}
|
||||
`, dbJSON)
|
||||
|
||||
func TestDatabases_List(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbSvc := client.Databases
|
||||
|
||||
want := []Database{db}
|
||||
|
||||
mux.HandleFunc("/v2/databases", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodGet)
|
||||
fmt.Fprint(w, dbsJSON)
|
||||
})
|
||||
|
||||
got, _, err := dbSvc.List(ctx, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_Get(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "da4e0206-d019-41d7-b51f-deadbeefbb8f"
|
||||
|
||||
body := fmt.Sprintf(`
|
||||
{
|
||||
"database": %s
|
||||
}
|
||||
`, dbJSON)
|
||||
|
||||
path := fmt.Sprintf("/v2/databases/%s", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodGet)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.Get(ctx, dbID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, &db, got)
|
||||
}
|
||||
|
||||
func TestDatabases_Create(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := &Database{
|
||||
ID: "8d91899c-0739-4a1a-acc5-deadbeefbb8f",
|
||||
Name: "backend-test",
|
||||
EngineSlug: "pg",
|
||||
VersionSlug: "10",
|
||||
Connection: &DatabaseConnection{
|
||||
URI: "postgres://doadmin:zt91mum075ofzyww@dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require",
|
||||
Database: "",
|
||||
Host: "dbtest-do-user-3342561-0.db.ondigitalocean.com",
|
||||
Port: 25060,
|
||||
User: "doadmin",
|
||||
Password: "zt91mum075ofzyww",
|
||||
SSL: true,
|
||||
},
|
||||
Users: nil,
|
||||
DBNames: nil,
|
||||
NumNodes: 2,
|
||||
RegionSlug: "nyc3",
|
||||
Status: "creating",
|
||||
CreatedAt: time.Date(2019, 2, 26, 6, 12, 39, 0, time.UTC),
|
||||
MaintenanceWindow: nil,
|
||||
SizeSlug: "db-s-2vcpu-4gb",
|
||||
}
|
||||
|
||||
createRequest := &DatabaseCreateRequest{
|
||||
Name: "backend-test",
|
||||
EngineSlug: "pg",
|
||||
Version: "10",
|
||||
Region: "nyc3",
|
||||
SizeSlug: "db-s-2vcpu-4gb",
|
||||
NumNodes: 2,
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"database": {
|
||||
"id": "8d91899c-0739-4a1a-acc5-deadbeefbb8f",
|
||||
"name": "backend-test",
|
||||
"engine": "pg",
|
||||
"version": "10",
|
||||
"connection": {
|
||||
"uri": "postgres://doadmin:zt91mum075ofzyww@dbtest-do-user-3342561-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require",
|
||||
"database": "",
|
||||
"host": "dbtest-do-user-3342561-0.db.ondigitalocean.com",
|
||||
"port": 25060,
|
||||
"user": "doadmin",
|
||||
"password": "zt91mum075ofzyww",
|
||||
"ssl": true
|
||||
},
|
||||
"users": null,
|
||||
"db_names": null,
|
||||
"num_nodes": 2,
|
||||
"region": "nyc3",
|
||||
"status": "creating",
|
||||
"created_at": "2019-02-26T06:12:39Z",
|
||||
"maintenance_window": null,
|
||||
"size": "db-s-2vcpu-4gb"
|
||||
}
|
||||
}`
|
||||
|
||||
mux.HandleFunc("/v2/databases", func(w http.ResponseWriter, r *http.Request) {
|
||||
v := new(DatabaseCreateRequest)
|
||||
err := json.NewDecoder(r.Body).Decode(v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testMethod(t, r, http.MethodPost)
|
||||
require.Equal(t, v, createRequest)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.Create(ctx, createRequest)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_Delete(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
path := fmt.Sprintf("/v2/databases/%s", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodDelete)
|
||||
})
|
||||
|
||||
_, err := client.Databases.Delete(ctx, "deadbeef-dead-4aa5-beef-deadbeef347d")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDatabases_Resize(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
resizeRequest := &DatabaseResizeRequest{
|
||||
SizeSlug: "db-s-16vcpu-64gb",
|
||||
NumNodes: 3,
|
||||
}
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
path := fmt.Sprintf("/v2/databases/%s/resize", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodPut)
|
||||
})
|
||||
|
||||
_, err := client.Databases.Resize(ctx, "deadbeef-dead-4aa5-beef-deadbeef347d", resizeRequest)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDatabases_Migrate(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
migrateRequest := &DatabaseMigrateRequest{
|
||||
Region: "lon1",
|
||||
}
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
path := fmt.Sprintf("/v2/databases/%s/migrate", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodPut)
|
||||
})
|
||||
|
||||
_, err := client.Databases.Migrate(ctx, "deadbeef-dead-4aa5-beef-deadbeef347d", migrateRequest)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDatabases_UpdateMaintenance(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
maintenanceRequest := &DatabaseUpdateMaintenanceRequest{
|
||||
Day: "thursday",
|
||||
Hour: "16:00",
|
||||
}
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
path := fmt.Sprintf("/v2/databases/%s/maintenance", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodPut)
|
||||
})
|
||||
|
||||
_, err := client.Databases.UpdateMaintenance(ctx, "deadbeef-dead-4aa5-beef-deadbeef347d", maintenanceRequest)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDatabases_ListBackups(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := []DatabaseBackup{
|
||||
DatabaseBackup{
|
||||
CreatedAt: time.Date(2019, 1, 11, 18, 42, 27, 0, time.UTC),
|
||||
SizeGigabytes: 0.03357696,
|
||||
},
|
||||
DatabaseBackup{
|
||||
CreatedAt: time.Date(2019, 1, 12, 18, 42, 29, 0, time.UTC),
|
||||
SizeGigabytes: 0.03364864,
|
||||
},
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"backups": [
|
||||
{
|
||||
"created_at": "2019-01-11T18:42:27Z",
|
||||
"size_gigabytes": 0.03357696
|
||||
},
|
||||
{
|
||||
"created_at": "2019-01-12T18:42:29Z",
|
||||
"size_gigabytes": 0.03364864
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
path := fmt.Sprintf("/v2/databases/%s/backups", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodGet)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.ListBackups(ctx, "deadbeef-dead-4aa5-beef-deadbeef347d", nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_GetUser(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
want := &DatabaseUser{
|
||||
Name: "name",
|
||||
Role: "foo",
|
||||
Password: "pass",
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"user": {
|
||||
"name": "name",
|
||||
"role": "foo",
|
||||
"password": "pass"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
path := fmt.Sprintf("/v2/databases/%s/users/name", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodGet)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.GetUser(ctx, dbID, "name")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_ListUsers(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
want := []DatabaseUser{
|
||||
{
|
||||
Name: "name",
|
||||
Role: "foo",
|
||||
Password: "pass",
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
Role: "foo",
|
||||
Password: "pass",
|
||||
},
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"users": [{
|
||||
"name": "name",
|
||||
"role": "foo",
|
||||
"password": "pass"
|
||||
},
|
||||
{
|
||||
"name": "bar",
|
||||
"role": "foo",
|
||||
"password": "pass"
|
||||
}]
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/users", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodGet)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.ListUsers(ctx, dbID, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_CreateUser(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
want := &DatabaseUser{
|
||||
Name: "name",
|
||||
Role: "foo",
|
||||
Password: "pass",
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"user": {
|
||||
"name": "name",
|
||||
"role": "foo",
|
||||
"password": "pass"
|
||||
}
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/users", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodPost)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.CreateUser(ctx, dbID, &DatabaseCreateUserRequest{Name: "user"})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_DeleteUser(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
path := fmt.Sprintf("/v2/databases/%s/users/user", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodDelete)
|
||||
})
|
||||
|
||||
_, err := client.Databases.DeleteUser(ctx, dbID, "user")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDatabases_ListDBs(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
want := []DatabaseDB{
|
||||
{Name: "foo"},
|
||||
{Name: "bar"},
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"dbs": [{
|
||||
"name": "foo"
|
||||
},
|
||||
{
|
||||
"name": "bar"
|
||||
}]
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/dbs", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodGet)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.ListDBs(ctx, dbID, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_CreateDB(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
want := &DatabaseDB{
|
||||
Name: "foo",
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"db": {
|
||||
"name": "foo"
|
||||
}
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/dbs", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodPost)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.CreateDB(ctx, dbID, &DatabaseCreateDBRequest{Name: "foo"})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_GetDB(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
want := &DatabaseDB{
|
||||
Name: "foo",
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"db": {
|
||||
"name": "foo"
|
||||
}
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/dbs/foo", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodGet)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.GetDB(ctx, dbID, "foo")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_DeleteDB(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
body := `
|
||||
{
|
||||
"db": {
|
||||
"name": "foo"
|
||||
}
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/dbs/foo", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodDelete)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
_, err := client.Databases.DeleteDB(ctx, dbID, "foo")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDatabases_ListPools(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
want := []DatabasePool{
|
||||
{
|
||||
Name: "pool",
|
||||
User: "user",
|
||||
Size: 10,
|
||||
Mode: "transaction",
|
||||
Database: "db",
|
||||
Connection: &DatabaseConnection{
|
||||
URI: "postgresql://user:pass@host.com/db",
|
||||
Host: "host.com",
|
||||
Port: 1234,
|
||||
User: "user",
|
||||
Password: "pass",
|
||||
SSL: true,
|
||||
Database: "db",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"pools": [{
|
||||
"name": "pool",
|
||||
"user": "user",
|
||||
"size": 10,
|
||||
"mode": "transaction",
|
||||
"database": "db",
|
||||
"connection": {
|
||||
"uri": "postgresql://user:pass@host.com/db",
|
||||
"host": "host.com",
|
||||
"port": 1234,
|
||||
"user": "user",
|
||||
"password": "pass",
|
||||
"database": "db",
|
||||
"ssl": true
|
||||
}
|
||||
}]
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/pools", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodGet)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.ListPools(ctx, dbID, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_CreatePool(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
want := &DatabasePool{
|
||||
Name: "pool",
|
||||
User: "user",
|
||||
Size: 10,
|
||||
Mode: "transaction",
|
||||
Database: "db",
|
||||
Connection: &DatabaseConnection{
|
||||
URI: "postgresql://user:pass@host.com/db",
|
||||
Host: "host.com",
|
||||
Port: 1234,
|
||||
User: "user",
|
||||
Password: "pass",
|
||||
SSL: true,
|
||||
Database: "db",
|
||||
},
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"pool": {
|
||||
"name": "pool",
|
||||
"user": "user",
|
||||
"size": 10,
|
||||
"mode": "transaction",
|
||||
"database": "db",
|
||||
"connection": {
|
||||
"uri": "postgresql://user:pass@host.com/db",
|
||||
"host": "host.com",
|
||||
"port": 1234,
|
||||
"user": "user",
|
||||
"password": "pass",
|
||||
"database": "db",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/pools", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodPost)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.CreatePool(ctx, dbID, &DatabaseCreatePoolRequest{
|
||||
Pool: &DatabasePool{
|
||||
Name: "pool",
|
||||
Database: "db",
|
||||
Size: 10,
|
||||
User: "foo",
|
||||
Mode: "transaction",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_GetPool(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
want := &DatabasePool{
|
||||
Name: "pool",
|
||||
User: "user",
|
||||
Size: 10,
|
||||
Mode: "transaction",
|
||||
Database: "db",
|
||||
Connection: &DatabaseConnection{
|
||||
URI: "postgresql://user:pass@host.com/db",
|
||||
Host: "host.com",
|
||||
Port: 1234,
|
||||
User: "user",
|
||||
Password: "pass",
|
||||
SSL: true,
|
||||
Database: "db",
|
||||
},
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"pool": {
|
||||
"name": "pool",
|
||||
"user": "user",
|
||||
"size": 10,
|
||||
"mode": "transaction",
|
||||
"database": "db",
|
||||
"connection": {
|
||||
"uri": "postgresql://user:pass@host.com/db",
|
||||
"host": "host.com",
|
||||
"port": 1234,
|
||||
"user": "user",
|
||||
"password": "pass",
|
||||
"database": "db",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/pools/pool", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodGet)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.GetPool(ctx, dbID, "pool")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_DeletePool(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
path := fmt.Sprintf("/v2/databases/%s/pools/pool", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodDelete)
|
||||
})
|
||||
|
||||
_, err := client.Databases.DeletePool(ctx, dbID, "pool")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDatabases_GetReplica(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
createdAt := time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
want := &DatabaseReplica{
|
||||
Name: "pool",
|
||||
Region: "nyc1",
|
||||
Status: "online",
|
||||
CreatedAt: createdAt,
|
||||
Connection: &DatabaseConnection{
|
||||
URI: "postgresql://user:pass@host.com/db",
|
||||
Host: "host.com",
|
||||
Port: 1234,
|
||||
User: "user",
|
||||
Password: "pass",
|
||||
SSL: true,
|
||||
Database: "db",
|
||||
},
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"replica": {
|
||||
"name": "pool",
|
||||
"region": "nyc1",
|
||||
"status": "online",
|
||||
"created_at": "` + createdAt.Format(time.RFC3339) + `",
|
||||
"connection": {
|
||||
"uri": "postgresql://user:pass@host.com/db",
|
||||
"host": "host.com",
|
||||
"port": 1234,
|
||||
"user": "user",
|
||||
"password": "pass",
|
||||
"database": "db",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/replicas/replica", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodGet)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.GetReplica(ctx, dbID, "replica")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_ListReplicas(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
createdAt := time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
want := []DatabaseReplica{
|
||||
{
|
||||
Name: "pool",
|
||||
Region: "nyc1",
|
||||
Status: "online",
|
||||
CreatedAt: createdAt,
|
||||
Connection: &DatabaseConnection{
|
||||
URI: "postgresql://user:pass@host.com/db",
|
||||
Host: "host.com",
|
||||
Port: 1234,
|
||||
User: "user",
|
||||
Password: "pass",
|
||||
SSL: true,
|
||||
Database: "db",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"replicas": [{
|
||||
"name": "pool",
|
||||
"region": "nyc1",
|
||||
"status": "online",
|
||||
"created_at": "` + createdAt.Format(time.RFC3339) + `",
|
||||
"connection": {
|
||||
"uri": "postgresql://user:pass@host.com/db",
|
||||
"host": "host.com",
|
||||
"port": 1234,
|
||||
"user": "user",
|
||||
"password": "pass",
|
||||
"database": "db",
|
||||
"ssl": true
|
||||
}
|
||||
}]
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/replicas", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodGet)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.ListReplicas(ctx, dbID, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_CreateReplica(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
createdAt := time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
want := &DatabaseReplica{
|
||||
Name: "pool",
|
||||
Region: "nyc1",
|
||||
Status: "online",
|
||||
CreatedAt: createdAt,
|
||||
Connection: &DatabaseConnection{
|
||||
URI: "postgresql://user:pass@host.com/db",
|
||||
Host: "host.com",
|
||||
Port: 1234,
|
||||
User: "user",
|
||||
Password: "pass",
|
||||
SSL: true,
|
||||
Database: "db",
|
||||
},
|
||||
}
|
||||
|
||||
body := `
|
||||
{
|
||||
"replica": {
|
||||
"name": "pool",
|
||||
"region": "nyc1",
|
||||
"status": "online",
|
||||
"created_at": "` + createdAt.Format(time.RFC3339) + `",
|
||||
"connection": {
|
||||
"uri": "postgresql://user:pass@host.com/db",
|
||||
"host": "host.com",
|
||||
"port": 1234,
|
||||
"user": "user",
|
||||
"password": "pass",
|
||||
"database": "db",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
path := fmt.Sprintf("/v2/databases/%s/replicas", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodPost)
|
||||
fmt.Fprint(w, body)
|
||||
})
|
||||
|
||||
got, _, err := client.Databases.CreateReplica(ctx, dbID, &DatabaseCreateReplicaRequest{
|
||||
Name: "replica",
|
||||
Region: "nyc1",
|
||||
Size: "db-s-2vcpu-4gb",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
func TestDatabases_DeleteReplica(t *testing.T) {
|
||||
setup()
|
||||
defer teardown()
|
||||
|
||||
dbID := "deadbeef-dead-4aa5-beef-deadbeef347d"
|
||||
|
||||
path := fmt.Sprintf("/v2/databases/%s/replicas/replica", dbID)
|
||||
|
||||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(t, r, http.MethodDelete)
|
||||
})
|
||||
|
||||
_, err := client.Databases.DeleteReplica(ctx, dbID, "replica")
|
||||
require.NoError(t, err)
|
||||
}
|
2
godo.go
2
godo.go
|
@ -65,6 +65,7 @@ type Client struct {
|
|||
Firewalls FirewallsService
|
||||
Projects ProjectsService
|
||||
Kubernetes KubernetesService
|
||||
Databases DatabasesService
|
||||
|
||||
// Optional function called after every successful request made to the DO APIs
|
||||
onRequestCompleted RequestCompletionCallback
|
||||
|
@ -179,6 +180,7 @@ func NewClient(httpClient *http.Client) *Client {
|
|||
c.StorageActions = &StorageActionsServiceOp{client: c}
|
||||
c.Tags = &TagsServiceOp{client: c}
|
||||
c.Kubernetes = &KubernetesServiceOp{client: c}
|
||||
c.Databases = &DatabasesServiceOp{client: c}
|
||||
|
||||
return c
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue