Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Databases: Add OpenSearch index CRUD support #1571

Merged
merged 4 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Step 1: Build
FROM golang:1.21-alpine AS build
FROM golang:1.22-alpine AS build
danaelhe marked this conversation as resolved.
Show resolved Hide resolved

ARG GOARCH=amd64
ENV OUT_D /out
Expand Down
62 changes: 62 additions & 0 deletions commands/databases.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ For PostgreSQL and MySQL clusters, you can also provide a disk size in MiB to sc
cmd.AddCommand(databaseConfiguration())
cmd.AddCommand(databaseTopic())
cmd.AddCommand(databaseEvents())
cmd.AddCommand(databaseIndex())

return cmd
}
Expand Down Expand Up @@ -2548,3 +2549,64 @@ func RunDatabaseEvents(c *CmdConfig) error {
item := &displayers.DatabaseEvents{DatabaseEvents: dbEvents}
return c.Display(item)
}

func databaseIndex() *Command {
cmd := &Command{
Command: &cobra.Command{
Use: "indexes",
Short: `Display commands to manage indexes for opensearch clusters`,
Long: `The subcommands under ` + "`" + `doctl databases indexes` + "`" + ` enable the management of indexes for opensearch clusters`,
},
}

indexListDetails := `
This command lists the following details for each index in an opensearch cluster:

- The Name of the index.
- The Status of the index.
- The Health of the index.
- The Number of Shards in the index.
- The Number of Replicas in the index.
- The Number of Documents in the index.
- The Size of the index.
`

CmdBuilder(cmd, RunDatabaseIndexList, "list <database-uuid>", "Retrieve a list of indexes for a given opensearch cluster", indexListDetails, Writer, displayerType(&displayers.DatabaseOpenSearchIndexes{}), aliasOpt("ls"))
cmdDatabaseIndexDelete := CmdBuilder(cmd, RunDatabaseIndexDelete, "delete <database-uuid> <index-name>", "Deletes an opensearch index by index name", "", Writer, aliasOpt("rm"))
AddBoolFlag(cmdDatabaseIndexDelete, doctl.ArgForce, doctl.ArgShortForce, false, "Deletes the opensearch index without a confirmation prompt")

return cmd
}

func RunDatabaseIndexList(c *CmdConfig) error {
if len(c.Args) == 0 {
return doctl.NewMissingArgsErr(c.NS)
}

databaseID := c.Args[0]
indexes, err := c.Databases().ListIndexes(databaseID)
if err != nil {
return err
}
item := &displayers.DatabaseOpenSearchIndexes{DatabaseIndexes: indexes}
return c.Display(item)
}

func RunDatabaseIndexDelete(c *CmdConfig) error {
if len(c.Args) < 2 {
return doctl.NewMissingArgsErr(c.NS)
}

force, err := c.Doit.GetBool(c.NS, doctl.ArgForce)
if err != nil {
return err
}

if force || AskForConfirmDelete("opensearch index", 1) == nil {
databaseID := c.Args[0]
indexName := c.Args[1]
return c.Databases().DeleteIndex(databaseID, indexName)
}

return errOperationAborted
}
1 change: 1 addition & 0 deletions commands/databases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ func TestDatabasesCommand(t *testing.T) {
"sql-mode",
"configuration",
"topics",
"indexes",
)
}

Expand Down
57 changes: 57 additions & 0 deletions commands/displayers/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -1691,3 +1691,60 @@ func (dr *DatabaseEvents) KV() []map[string]any {
}
return out
}

type DatabaseOpenSearchIndexes struct {
DatabaseIndexes do.DatabaseIndexes
}

var _ Displayable = &DatabaseOpenSearchIndexes{}

func (dt *DatabaseOpenSearchIndexes) JSON(out io.Writer) error {
return writeJSON(dt.DatabaseIndexes, out)
}

func (dt *DatabaseOpenSearchIndexes) Cols() []string {
return []string{
"Index Name",
"Status",
"Health",
"Size",
"Docs",
"Create At",
"Number of Shards",
"Number of Replica",
}
}

func (dt *DatabaseOpenSearchIndexes) ColMap() map[string]string {

return map[string]string{
"Index Name": "Index Name",
"Status": "Status",
"Health": "Health",
"Size": "Size",
"Docs": "Docs",
"Create At": "Create At",
"Number of Shards": "Number of Shards",
"Number of Replica": "Number of Replica",
}
}

func (dt *DatabaseOpenSearchIndexes) KV() []map[string]any {
out := make([]map[string]any, 0, len(dt.DatabaseIndexes))

for _, t := range dt.DatabaseIndexes {
o := map[string]any{
"Index Name": t.IndexName,
"Number of Shards": t.NumberofShards,
"Number of Replica": t.NumberofReplicas,
"Status": t.Status,
"Health": t.Health,
"Size": t.Size,
"Docs": t.Docs,
"Create At": t.CreateTime,
}
out = append(out, o)
}

return out
}
45 changes: 45 additions & 0 deletions do/databases.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ type DatabaseEvent struct {
// DatabaseEvents is a slice of DatabaseEvent
type DatabaseEvents []DatabaseEvent

// DatabaseIndexes is a slice of DatabaseIndex
type DatabaseIndexes []DatabaseIndex

// DatabaseIndex is a wrapper for godo.DatabaseIndex
type DatabaseIndex struct {
*godo.DatabaseIndex
}

// DatabasesService is an interface for interacting with DigitalOcean's Database API
type DatabasesService interface {
List() (Databases, error)
Expand Down Expand Up @@ -194,6 +202,9 @@ type DatabasesService interface {
DeleteTopic(string, string) error

ListDatabaseEvents(string) (DatabaseEvents, error)

ListIndexes(string) (DatabaseIndexes, error)
DeleteIndex(string, string) error
}

type databasesService struct {
Expand Down Expand Up @@ -789,3 +800,37 @@ func (ds *databasesService) ListDatabaseEvents(databaseID string) (DatabaseEvent
}
return list, nil
}

func (ds *databasesService) ListIndexes(databaseID string) (DatabaseIndexes, error) {
f := func(opt *godo.ListOptions) ([]any, *godo.Response, error) {
list, resp, err := ds.client.Databases.ListIndexes(context.TODO(), databaseID, opt)
if err != nil {
return nil, nil, err
}

si := make([]any, len(list))
for i := range list {
si[i] = list[i]
}

return si, resp, err
}

si, err := PaginateResp(f)
if err != nil {
return nil, err
}

list := make(DatabaseIndexes, len(si))
for i := range si {
t := si[i].(godo.DatabaseIndex)
list[i] = DatabaseIndex{DatabaseIndex: &t}
}
return list, nil
}

func (ds *databasesService) DeleteIndex(databaseID, indexName string) error {
_, err := ds.client.Databases.DeleteIndex(context.TODO(), databaseID, indexName)

return err
}
29 changes: 29 additions & 0 deletions do/mocks/DatabasesService.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.22
require (
github.com/blang/semver v3.5.1+incompatible
github.com/creack/pty v1.1.21
github.com/digitalocean/godo v1.118.0
github.com/digitalocean/godo v1.121.0
github.com/docker/cli v24.0.5+incompatible
github.com/docker/docker v25.0.6+incompatible
github.com/docker/docker-credential-helpers v0.7.0 // indirect
Expand All @@ -30,7 +30,7 @@ require (
github.com/stretchr/testify v1.8.4
golang.org/x/crypto v0.22.0
golang.org/x/net v0.24.0 // indirect
golang.org/x/oauth2 v0.19.0
golang.org/x/oauth2 v0.22.0
golang.org/x/sys v0.20.0 // indirect
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.26.2
Expand Down Expand Up @@ -121,7 +121,7 @@ require (
go.opentelemetry.io/otel/trace v1.19.0 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.10.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/digitalocean/godo v1.118.0 h1:lkzGFQmACrVCp7UqH1sAi4JK/PWwlc5aaxubgorKmC4=
github.com/digitalocean/godo v1.118.0/go.mod h1:Vk0vpCot2HOAJwc5WE8wljZGtJ3ZtWIc8MQ8rF38sdo=
github.com/digitalocean/godo v1.121.0 h1:ilXiHuEnhbJs2fmFEPX0r/QQ6KfiOIMAhJN3f8NiCfI=
github.com/digitalocean/godo v1.121.0/go.mod h1:WQVH83OHUy6gC4gXpEVQKtxTd4L5oCp+5OialidkPLY=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc=
Expand Down Expand Up @@ -517,8 +517,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down Expand Up @@ -599,8 +599,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
Expand Down
69 changes: 69 additions & 0 deletions integration/database_opensearch_index_delete_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package integration

import (
"fmt"
"net/http"
"net/http/httptest"
"net/http/httputil"
"os/exec"
"strings"
"testing"

"github.com/sclevine/spec"
"github.com/stretchr/testify/require"
)

var _ = suite("database/index/delete", func(t *testing.T, when spec.G, it spec.S) {
var (
expect *require.Assertions
server *httptest.Server
)

it.Before(func() {
expect = require.New(t)

server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
switch req.URL.Path {
case "/v2/databases/some-database-id/indexes/some-index-id":
auth := req.Header.Get("Authorization")
if auth != "Bearer some-magic-token" {
w.WriteHeader(http.StatusTeapot)
}

if req.Method != http.MethodDelete {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}

w.WriteHeader(http.StatusNoContent)
default:
dump, err := httputil.DumpRequest(req, true)
if err != nil {
t.Fatal("failed to dump request")
}

t.Fatalf("received unknown request: %s", dump)
}
}))
})

when("all required flags are passed", func() {
it("deletes the database", func() {
cmd := exec.Command(builtBinaryPath,
"-t", "some-magic-token",
"-u", server.URL,
"database",
"indexes",
"delete",
"some-database-id",
"some-index-id",
"-f",
)

output, err := cmd.CombinedOutput()
expect.NoError(err, fmt.Sprintf("received error output: %s", output))
expect.Equal(strings.TrimSpace(""), strings.TrimSpace(string(output)))
expect.Empty(output)
})
})
})
Loading
Loading