diff --git a/service/databases/model.go b/service/databases/model.go index 3a86a78..eb4989e 100644 --- a/service/databases/model.go +++ b/service/databases/model.go @@ -41,24 +41,6 @@ func (o CreateDatabase) String() string { return internal.ToString(o) } -type CreateActiveActiveDatabase struct { - DryRun *bool `json:"dryRun,omitempty"` - Name *string `json:"name,omitempty"` - Protocol *string `json:"protocol,omitempty"` - MemoryLimitInGB *float64 `json:"memoryLimitInGb,omitempty"` - SupportOSSClusterAPI *bool `json:"supportOSSClusterApi,omitempty"` - UseExternalEndpointForOSSClusterAPI *bool `json:"useExternalEndpointForOSSClusterApi,omitempty"` - GlobalDataPersistence *string `json:"dataPersistence,omitempty"` - GlobalSourceIP []*string `json:"sourceIp,omitempty"` - GlobalPassword *string `json:"password,omitempty"` - GlobalAlerts []*CreateAlert `json:"alerts,omitempty"` - LocalThroughputMeasurement []*LocalThroughput `json:"localThroughputMeasurement,omitempty"` -} - -func (o CreateActiveActiveDatabase) String() string { - return internal.ToString(o) -} - type CreateThroughputMeasurement struct { By *string `json:"by,omitempty"` Value *int `json:"value,omitempty"` @@ -201,25 +183,6 @@ func (o UpdateDatabase) String() string { return internal.ToString(o) } -type UpdateActiveActiveDatabase struct { - DryRun *bool `json:"dryRun,omitempty"` - MemoryLimitInGB *float64 `json:"memoryLimitInGb,omitempty"` - SupportOSSClusterAPI *bool `json:"supportOSSClusterApi,omitempty"` - UseExternalEndpointForOSSClusterAPI *bool `json:"useExternalEndpointForOSSClusterApi,omitempty"` - ClientSSLCertificate *string `json:"clientSslCertificate,omitempty"` - EnableTls *bool `json:"enableTls,omitempty"` - GlobalDataPersistence *string `json:"globalDataPersistence,omitempty"` - GlobalPassword *string `json:"globalPassword,omitempty"` - GlobalSourceIP []*string `json:"globalSourceIp,omitempty"` - GlobalAlerts []*UpdateAlert `json:"globalAlerts,omitempty"` - Regions []*LocalRegionProperties `json:"regions,omitempty"` - DataEvictionPolicy *string `json:"dataEvictionPolicy,omitempty"` -} - -func (o UpdateActiveActiveDatabase) String() string { - return internal.ToString(o) -} - type UpdateThroughputMeasurement struct { By *string `json:"by,omitempty"` Value *int `json:"value,omitempty"` @@ -238,42 +201,6 @@ func (o UpdateAlert) String() string { return internal.ToString(o) } -type LocalRegionProperties struct { - Region *string `json:"region,omitempty"` - RemoteBackup *DatabaseBackupConfig `json:"remoteBackup,omitempty"` - LocalThroughputMeasurement *LocalThroughput `json:"localThroughputMeasurement,omitempty"` - DataPersistence *string `json:"dataPersistence,omitempty"` - Password *string `json:"password,omitempty"` - SourceIP []*string `json:"sourceIp,omitempty"` - Alerts []*UpdateAlert `json:"alerts,omitempty"` -} - -func (o LocalRegionProperties) String() string { - return internal.ToString(o) -} - -type LocalThroughput struct { - Region *string `json:"region,omitempty"` - WriteOperationsPerSecond *int `json:"writeOperationsPerSecond,omitempty"` - ReadOperationsPerSecond *int `json:"readOperationsPerSecond,omitempty"` -} - -func (o LocalThroughput) String() string { - return internal.ToString(o) -} - -type DatabaseBackupConfig struct { - Active *bool `json:"active,omitempty"` - Interval *string `json:"interval,omitempty"` - TimeUTC *string `json:"timeUTC,omitempty"` - StorageType *string `json:"storageType,omitempty"` - StoragePath *string `json:"storagePath,omitempty"` -} - -func (o DatabaseBackupConfig) String() string { - return internal.ToString(o) -} - type Import struct { SourceType *string `json:"sourceType,omitempty"` ImportFromURI []*string `json:"importFromUri,omitempty"` diff --git a/service/databases/model_active_active.go b/service/databases/model_active_active.go new file mode 100644 index 0000000..8153d46 --- /dev/null +++ b/service/databases/model_active_active.go @@ -0,0 +1,148 @@ +package databases + +import ( + "time" + + "github.com/RedisLabs/rediscloud-go-api/internal" +) + +type ActiveActiveDatabase struct { + ID *int `json:"databaseId,omitempty"` + Name *string `json:"name,omitempty"` + Protocol *string `json:"protocol,omitempty"` + Status *string `json:"status,omitempty"` + MemoryStorage *string `json:"memoryStorage,omitempty"` + ActiveActiveRedis *bool `json:"activeActiveRedis,omitempty"` + ActivatedOn *time.Time `json:"activatedOn,omitempty"` + LastModified *time.Time `json:"lastModified,omitempty"` + SupportOSSClusterAPI *bool `json:"supportOSSClusterApi,omitempty"` + UseExternalEndpointForOSSClusterAPI *bool `json:"useExternalEndpointForOSSClusterApi,omitempty"` + Replication *bool `json:"replication,omitempty"` + DataEvictionPolicy *string `json:"dataEvictionPolicy,omitempty"` + CrdbDatabases []*CrdbDatabase `json:"crdbDatabases,omitempty"` +} + +func (o ActiveActiveDatabase) String() string { + return internal.ToString(o) +} + +type CrdbDatabase struct { + Provider *string `json:"provider,omitempty"` + Region *string `json:"region,omitempty"` + RedisVersionCompliance *string `json:"redisVersionCompliance,omitempty"` + PublicEndpoint *string `json:"publicEndpoint,omitempty"` + PrivateEndpoint *string `json:"privateEndpoint,omitempty"` + MemoryLimitInGB *float64 `json:"memoryLimitInGb,omitempty"` + MemoryUsedInMB *float64 `json:"memoryUsedInMb,omitempty"` + ReadOperationsPerSecond *int `json:"readOperationsPerSecond,omitempty"` + WriteOperationsPerSecond *int `json:"writeOperationsPerSecond,omitempty"` + DataPersistence *string `json:"dataPersistence,omitempty"` + Alerts []*Alert `json:"alerts,omitempty"` + Security *Security `json:"security,omitempty"` + Backup *Backup `json:"backup,omitempty"` +} + +func (o CrdbDatabase) String() string { + return internal.ToString(o) +} + +type Backup struct { + Enabled *bool `json:"enableRemoteBackup,omitempty"` + Interval *string `json:"interval,omitempty"` + Destination *string `json:"destination,omitempty"` +} + +func (o Backup) String() string { + return internal.ToString(o) +} + +type CreateActiveActiveDatabase struct { + DryRun *bool `json:"dryRun,omitempty"` + Name *string `json:"name,omitempty"` + Protocol *string `json:"protocol,omitempty"` + MemoryLimitInGB *float64 `json:"memoryLimitInGb,omitempty"` + SupportOSSClusterAPI *bool `json:"supportOSSClusterApi,omitempty"` + UseExternalEndpointForOSSClusterAPI *bool `json:"useExternalEndpointForOSSClusterApi,omitempty"` + GlobalDataPersistence *string `json:"dataPersistence,omitempty"` + GlobalSourceIP []*string `json:"sourceIp,omitempty"` + GlobalPassword *string `json:"password,omitempty"` + GlobalAlerts []*CreateAlert `json:"alerts,omitempty"` + LocalThroughputMeasurement []*LocalThroughput `json:"localThroughputMeasurement,omitempty"` +} + +func (o CreateActiveActiveDatabase) String() string { + return internal.ToString(o) +} + +type LocalThroughput struct { + Region *string `json:"region,omitempty"` + WriteOperationsPerSecond *int `json:"writeOperationsPerSecond,omitempty"` + ReadOperationsPerSecond *int `json:"readOperationsPerSecond,omitempty"` +} + +func (o LocalThroughput) String() string { + return internal.ToString(o) +} + +type UpdateActiveActiveDatabase struct { + DryRun *bool `json:"dryRun,omitempty"` + MemoryLimitInGB *float64 `json:"memoryLimitInGb,omitempty"` + SupportOSSClusterAPI *bool `json:"supportOSSClusterApi,omitempty"` + UseExternalEndpointForOSSClusterAPI *bool `json:"useExternalEndpointForOSSClusterApi,omitempty"` + ClientSSLCertificate *string `json:"clientSslCertificate,omitempty"` + EnableTls *bool `json:"enableTls,omitempty"` + GlobalDataPersistence *string `json:"globalDataPersistence,omitempty"` + GlobalPassword *string `json:"globalPassword,omitempty"` + GlobalSourceIP []*string `json:"globalSourceIp,omitempty"` + GlobalAlerts []*UpdateAlert `json:"globalAlerts,omitempty"` + Regions []*LocalRegionProperties `json:"regions,omitempty"` + DataEvictionPolicy *string `json:"dataEvictionPolicy,omitempty"` +} + +func (o UpdateActiveActiveDatabase) String() string { + return internal.ToString(o) +} + +type LocalRegionProperties struct { + Region *string `json:"region,omitempty"` + RemoteBackup *DatabaseBackupConfig `json:"remoteBackup,omitempty"` + LocalThroughputMeasurement *LocalThroughput `json:"localThroughputMeasurement,omitempty"` + DataPersistence *string `json:"dataPersistence,omitempty"` + Password *string `json:"password,omitempty"` + SourceIP []*string `json:"sourceIp,omitempty"` + Alerts []*UpdateAlert `json:"alerts,omitempty"` +} + +func (o LocalRegionProperties) String() string { + return internal.ToString(o) +} + +type DatabaseBackupConfig struct { + Active *bool `json:"active,omitempty"` + Interval *string `json:"interval,omitempty"` + TimeUTC *string `json:"timeUTC,omitempty"` + StorageType *string `json:"storageType,omitempty"` + StoragePath *string `json:"storagePath,omitempty"` +} + +func (o DatabaseBackupConfig) String() string { + return internal.ToString(o) +} + +type listActiveActiveDatabaseResponse struct { + AccountId *string `json:"accountId,omitempty"` + Subscription []*listActiveActiveDbSubscription `json:"subscription,omitempty"` +} + +func (o listActiveActiveDatabaseResponse) String() string { + return internal.ToString(o) +} + +type listActiveActiveDbSubscription struct { + ID *int `json:"subscriptionId,omitempty"` + Databases []*ActiveActiveDatabase `json:"databases,omitempty"` +} + +func (o listActiveActiveDbSubscription) String() string { + return internal.ToString(o) +} diff --git a/service/databases/service.go b/service/databases/service.go index a90938e..7de7fb2 100644 --- a/service/databases/service.go +++ b/service/databases/service.go @@ -56,24 +56,6 @@ func (a *API) Create(ctx context.Context, subscription int, db CreateDatabase) ( return id, nil } -// Create will create a new database for the subscription and return the identifier of the database. -func (a *API) ActiveActiveCreate(ctx context.Context, subscription int, db CreateActiveActiveDatabase) (int, error) { - var task taskResponse - err := a.client.Post(ctx, fmt.Sprintf("create database for subscription %d", subscription), fmt.Sprintf("/subscriptions/%d/databases", subscription), db, &task) - if err != nil { - return 0, err - } - - a.logger.Printf("Waiting for new database for subscription %d to finish being created", subscription) - - id, err := a.task.WaitForResourceId(ctx, *task.ID) - if err != nil { - return 0, err - } - - return id, nil -} - // List will return a ListDatabase that is capable of paging through all of the databases associated with a // subscription. func (a *API) List(ctx context.Context, subscription int) *ListDatabase { @@ -109,24 +91,6 @@ func (a *API) Update(ctx context.Context, subscription int, database int, update return nil } -// Update will update certain values of an existing database. -func (a *API) ActiveActiveUpdate(ctx context.Context, subscription int, database int, update UpdateActiveActiveDatabase) error { - var task taskResponse - err := a.client.Put(ctx, fmt.Sprintf("update database %d for subscription %d", database, subscription), fmt.Sprintf("/subscriptions/%d/databases/%d/regions", subscription, database), update, &task) - if err != nil { - return err - } - - a.logger.Printf("Waiting for database %d for subscription %d to finish being updated", database, subscription) - - err = a.task.Wait(ctx, *task.ID) - if err != nil { - return err - } - - return nil -} - // Delete will destroy an existing database. func (a *API) Delete(ctx context.Context, subscription int, database int) error { var task taskResponse diff --git a/service/databases/service_active_active.go b/service/databases/service_active_active.go new file mode 100644 index 0000000..fd564cb --- /dev/null +++ b/service/databases/service_active_active.go @@ -0,0 +1,153 @@ +package databases + +import ( + "context" + "fmt" + "net/http" + "strconv" + + "github.com/RedisLabs/rediscloud-go-api/internal" + "github.com/RedisLabs/rediscloud-go-api/redis" +) + +// Create will create a new database for the subscription and return the identifier of the database. +func (a *API) ActiveActiveCreate(ctx context.Context, subscription int, db CreateActiveActiveDatabase) (int, error) { + var task taskResponse + err := a.client.Post(ctx, fmt.Sprintf("create database for subscription %d", subscription), fmt.Sprintf("/subscriptions/%d/databases", subscription), db, &task) + if err != nil { + return 0, err + } + + a.logger.Printf("Waiting for new database for subscription %d to finish being created", subscription) + + id, err := a.task.WaitForResourceId(ctx, *task.ID) + if err != nil { + return 0, err + } + + return id, nil +} + +// Update will update certain values of an existing database. +func (a *API) ActiveActiveUpdate(ctx context.Context, subscription int, database int, update UpdateActiveActiveDatabase) error { + var task taskResponse + err := a.client.Put(ctx, fmt.Sprintf("update database %d for subscription %d", database, subscription), fmt.Sprintf("/subscriptions/%d/databases/%d/regions", subscription, database), update, &task) + if err != nil { + return err + } + + a.logger.Printf("Waiting for database %d for subscription %d to finish being updated", database, subscription) + + err = a.task.Wait(ctx, *task.ID) + if err != nil { + return err + } + + return nil +} + +// List will return a ListDatabase that is capable of paging through all of the databases associated with a +// subscription. +func (a *API) ListActiveActive(ctx context.Context, subscription int) *ListActiveActiveDatabase { + return newListActiveActiveDatabase(ctx, a.client, subscription, 100) +} + +// Get will retrieve an existing database. +func (a *API) GetActiveActive(ctx context.Context, subscription int, database int) (*ActiveActiveDatabase, error) { + var db ActiveActiveDatabase + err := a.client.Get(ctx, fmt.Sprintf("get database %d for subscription %d", subscription, database), fmt.Sprintf("/subscriptions/%d/databases/%d", subscription, database), &db) + if err != nil { + return nil, wrap404Error(subscription, database, err) + } + + return &db, nil +} + +type ListActiveActiveDatabase struct { + client HttpClient + subscription int + ctx context.Context + pageSize int + + offset int + page []*ActiveActiveDatabase + err error + fin bool + value *ActiveActiveDatabase +} + +func newListActiveActiveDatabase(ctx context.Context, client HttpClient, subscription int, pageSize int) *ListActiveActiveDatabase { + return &ListActiveActiveDatabase{client: client, subscription: subscription, ctx: ctx, pageSize: pageSize} +} + +// Next attempts to retrieve the next page of databases and will return false if no more databases were found. +// Any error that occurs within this function can be retrieved from the `Err()` function. +func (d *ListActiveActiveDatabase) Next() bool { + if d.err != nil { + return false + } + + if d.fin { + return false + } + + if len(d.page) == 0 { + if err := d.nextPage(); err != nil { + d.setError(err) + return false + } + } + + d.updateValue() + + return true +} + +// Value returns the current page of databases. +func (d *ListActiveActiveDatabase) Value() *ActiveActiveDatabase { + return d.value +} + +// Err returns any error that occurred while trying to retrieve the next page of databases. +func (d *ListActiveActiveDatabase) Err() error { + return d.err +} + +func (d *ListActiveActiveDatabase) nextPage() error { + u := fmt.Sprintf("/subscriptions/%d/databases", d.subscription) + q := map[string][]string{ + "limit": {strconv.Itoa(d.pageSize)}, + "offset": {strconv.Itoa(d.offset)}, + } + + var list listActiveActiveDatabaseResponse + err := d.client.GetWithQuery(d.ctx, fmt.Sprintf("list databases for %d", d.subscription), u, q, &list) + if err != nil { + return err + } + + if len(list.Subscription) != 1 || redis.IntValue(list.Subscription[0].ID) != d.subscription { + return fmt.Errorf("server didn't respond with just a single subscription") + } + + d.page = list.Subscription[0].Databases + d.offset += d.pageSize + + return nil +} + +func (d *ListActiveActiveDatabase) updateValue() { + d.value = d.page[0] + d.page = d.page[1:] +} + +func (d *ListActiveActiveDatabase) setError(err error) { + if httpErr, ok := err.(*internal.HTTPError); ok && httpErr.StatusCode == http.StatusNotFound { + d.fin = true + } else { + d.err = err + } + + d.page = nil + d.value = nil +}