Skip to content

Commit

Permalink
Merge branch 'master' into feature/lables_tains
Browse files Browse the repository at this point in the history
  • Loading branch information
alejandrojnm committed Mar 18, 2024
2 parents 6acbff0 + 962532a commit a1fa5d1
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 220 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.20.x, 1.21.x]
go-version: [1.20.x, 1.21.x, 1.22.x]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
Expand Down
11 changes: 7 additions & 4 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Database struct {
Username string `json:"username"`
Password string `json:"password"`
DatabaseUserInfo []DatabaseUserInfo `json:"database_user_info"`
DNSEntry string `json:"dns_entry,omitempty"`
Status string `json:"status"`
}

Expand Down Expand Up @@ -69,10 +70,12 @@ type SupportedSoftwareVersion struct {

// RestoreDatabaseRequest is the request body for restoring a database
type RestoreDatabaseRequest struct {
Software string `json:"software"`
NetworkID string `json:"network_id"`
Backup string `json:"backup"`
Region string `json:"region"`
// Name is the name of the database restore
Name string `json:"name"`
// Backup is the name of the database backup
Backup string `json:"backup"`
// Region is the name of the region
Region string `json:"region"`
}

// ListDatabases returns a list of all databases
Expand Down
119 changes: 92 additions & 27 deletions database_backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,61 @@ import (
"bytes"
"encoding/json"
"fmt"
"strings"
"time"
)

// Scheduled represents scheduled backups
type Scheduled struct {
Name string `json:"name,omitempty"`
Schedule string `json:"schedule,omitempty"`
Count int32 `json:"count,omitempty"`
Backups []string `json:"backups,omitempty"`
}

// Manual represents manual backups
type Manual struct {
Backup string `json:"backup,omitempty"`
}

// DatabaseBackup represents a backup
type DatabaseBackup struct {
DatabaseName string `json:"database_name"`
DatabaseID string `json:"database_id"`
Software string `json:"software"`
Scheduled *Scheduled `json:"scheduled,omitempty"`
Manual []Manual `json:"manual,omitempty"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Software string `json:"software,omitempty"`
Status string `json:"status,omitempty"`
Schedule string `json:"schedule,omitempty"`
DatabaseName string `json:"database_name,omitempty"`
DatabaseID string `json:"database_id,omitempty"`
IsScheduled bool `json:"is_scheduled,omitempty"`
CreatedAt time.Time `json:"created_at"`
}

// PaginatedDatabaseBackup is the structure for list response from DB endpoint
type PaginatedDatabaseBackup struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
Pages int `json:"pages"`
Items []DatabaseBackup `json:"items"`
}

// DatabaseBackupCreateRequest represents a backup create request
type DatabaseBackupCreateRequest struct {
Name string `json:"name"`
// Name is the name of the database backup to be created
Name string `json:"name"`
// Schedule is used for scheduled backup
Schedule string `json:"schedule"`
Count int32 `json:"count"`
Type string `json:"type"`
Region string `json:"region"`
// Types is used for manual backup
Type string `json:"type"`
// Region is name of the region
Region string `json:"region"`
}

// DatabaseBackupUpdateRequest represents a backup update request
type DatabaseBackupUpdateRequest struct {
Name string `json:"name"`
// Name is name name of the backup
Name string `json:"name"`
// Schedule is schedule for scheduled backup
Schedule string `json:"schedule"`
Count int32 `json:"count"`
Region string `json:"region"`
// Region is name of the region
Region string `json:"region"`
}

// ListDatabaseBackup lists backups for database
func (c *Client) ListDatabaseBackup(did string) (*DatabaseBackup, error) {
func (c *Client) ListDatabaseBackup(did string) (*PaginatedDatabaseBackup, error) {
resp, err := c.SendGetRequest(fmt.Sprintf("/v2/databases/%s/backups", did))
if err != nil {
return nil, decodeError(err)
}

back := &DatabaseBackup{}
back := &PaginatedDatabaseBackup{}
if err := json.NewDecoder(bytes.NewReader(resp)).Decode(&back); err != nil {
return nil, decodeError(err)
}
Expand Down Expand Up @@ -89,3 +95,62 @@ func (c *Client) CreateDatabaseBackup(did string, v *DatabaseBackupCreateRequest

return result, nil
}

// DeleteDatabaseBackup deletes a database backup
func (c *Client) DeleteDatabaseBackup(dbid, id string) (*SimpleResponse, error) {
resp, err := c.SendDeleteRequest(fmt.Sprintf("/v2/databases/%s/backups/%s", dbid, id))
if err != nil {
return nil, decodeError(err)
}

return c.DecodeSimpleResponse(resp)
}

// GetDatabaseBackup finds a database by the database UUID
func (c *Client) GetDatabaseBackup(dbid, id string) (*DatabaseBackup, error) {
resp, err := c.SendGetRequest(fmt.Sprintf("/v2/databases/%s/backups/%s", dbid, id))
if err != nil {
return nil, decodeError(err)
}

bk := &DatabaseBackup{}
if err := json.NewDecoder(bytes.NewReader(resp)).Decode(bk); err != nil {
return nil, err
}

return bk, nil
}

// FindDatabaseBackup finds a database by either part of the ID or part of the name
func (c *Client) FindDatabaseBackup(dbid, search string) (*DatabaseBackup, error) {
backups, err := c.ListDatabaseBackup(dbid)
if err != nil {
return nil, decodeError(err)
}

exactMatch := false
partialMatchesCount := 0
result := DatabaseBackup{}

for _, value := range backups.Items {
if strings.EqualFold(value.Name, search) || value.ID == search {
exactMatch = true
result = value
} else if strings.Contains(strings.ToUpper(value.Name), strings.ToUpper(search)) || strings.Contains(value.ID, search) {
if !exactMatch {
result = value
partialMatchesCount++
}
}
}

if exactMatch || partialMatchesCount == 1 {
return &result, nil
} else if partialMatchesCount > 1 {
err := fmt.Errorf("unable to find %s because there were multiple matches", search)
return nil, MultipleMatchesError.wrap(err)
} else {
err := fmt.Errorf("unable to find %s, zero matches", search)
return nil, ZeroMatchesError.wrap(err)
}
}
29 changes: 29 additions & 0 deletions disk_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"errors"
"fmt"
"strings"

"golang.org/x/mod/semver"
)

// DiskImage represents a DiskImage for launching instances from
Expand Down Expand Up @@ -105,3 +107,30 @@ func (c *Client) GetDiskImageByName(name string) (*DiskImage, error) {

return nil, errors.New("diskimage not found")
}

// GetMostRecentDistro finds the highest version of a specified distro
func (c *Client) GetMostRecentDistro(name string) (*DiskImage, error) {
resp, err := c.ListDiskImages()
if err != nil {
return nil, decodeError(err)
}

var highestVersionDistro *DiskImage

for _, diskimage := range resp {
if strings.Contains(diskimage.Name, name) {
if highestVersionDistro == nil {
highestVersionDistro = &diskimage
} else {
if semver.Compare(highestVersionDistro.Version, diskimage.Version) < 0 {
highestVersionDistro = &diskimage
}
}
}
}
if highestVersionDistro == nil {
return nil, fmt.Errorf("%s image not found", name)
}

return highestVersionDistro, nil
}
17 changes: 17 additions & 0 deletions disk_image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,20 @@ func TestGetDiskImageByName(t *testing.T) {
t.Errorf("Expected %s, got %s", "329d473e-f110-4852-b2fa-fe65aa6bff4a", got.ID)
}
}

func TestGetMostRecentDistro(t *testing.T) {
client, server, _ := NewClientForTesting(map[string]string{
"/v2/disk_images": `[{ "ID": "329d473e-f110-4852-b2fa-fe65aa6bff4a", "Name": "ubuntu-bionic", "Version": "18.04", "State": "available", "Distribution": "ubuntu", "Description": "", "Label": "bionic" }, { "ID": "77bea4dd-bfd4-492c-823d-f92eb6dd962d", "Name": "ubuntu-focal", "Version": "20.04", "State": "available", "Distribution": "ubuntu", "Description": "", "Label": "focal" }]`,
})
defer server.Close()

got, err := client.GetMostRecentDistro("ubuntu")
if err != nil {
t.Errorf("Request returned an error: %s", err)
return
}

if got.Name != "ubuntu-focal" {
t.Errorf("Expected %s, got %s", "ubuntu-focal", got.Name)
}
}
12 changes: 12 additions & 0 deletions fake_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type FakeClient struct {
OrganisationTeamMembers map[string][]TeamMember
LoadBalancers []LoadBalancer
Pools []KubernetesPool
PingErr error
// Snapshots []Snapshot
// Templates []Template
}
Expand Down Expand Up @@ -184,6 +185,9 @@ type Clienter interface {
CreateLoadBalancer(r *LoadBalancerConfig) (*LoadBalancer, error)
UpdateLoadBalancer(id string, r *LoadBalancerUpdateConfig) (*LoadBalancer, error)
DeleteLoadBalancer(id string) (*SimpleResponse, error)

// Ping
Ping() error
}

// NewFakeClient initializes a Client that doesn't attach to a
Expand Down Expand Up @@ -262,6 +266,14 @@ func NewFakeClient() (*FakeClient, error) {
}, nil
}

// Ping implemented in a fake way for automated tests
func (c *FakeClient) Ping() error {
if c.PingErr != nil {
return c.PingErr
}
return nil
}

func (c *FakeClient) generateID() string {
c.LastID++
return strconv.FormatInt(c.LastID, 10)
Expand Down
27 changes: 27 additions & 0 deletions fake_client_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package civogo

import (
"errors"
"testing"

. "github.com/onsi/gomega"
Expand Down Expand Up @@ -257,3 +258,29 @@ func TestKubernetesClustersPools(t *testing.T) {
g.Expect(err).To(BeNil())
g.Expect(pool.Count).To(Equal(4))
}

func TestPing(t *testing.T) {
// Create a new FakeClient with a non-nil PingErr
client := &FakeClient{
PingErr: errors.New("ping error"),
}

// Call the Ping method
err := client.Ping()

// Check if the error returned by Ping is the same as the one we set
if err == nil || err.Error() != "ping error" {
t.Errorf("Expected 'ping error', got '%v'", err)
}

// Reset PingErr to nil
client.PingErr = nil

// Call the Ping method again
err = client.Ping()

// Check if the error is nil this time
if err != nil {
t.Errorf("Expected nil, got '%v'", err)
}
}
20 changes: 19 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/civo/civogo

go 1.16
go 1.20

require (
github.com/google/go-querystring v1.1.0
Expand All @@ -9,4 +9,22 @@ require (
k8s.io/apimachinery v0.27.1
)

require (
github.com/go-logr/logr v1.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
golang.org/x/mod v0.16.0
golang.org/x/net v0.8.0 // indirect
golang.org/x/text v0.8.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.90.1 // indirect
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
)

replace github.com/onsi/gomega => github.com/onsi/gomega v1.19.0
Loading

0 comments on commit a1fa5d1

Please sign in to comment.