Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.21
1.0.22
51 changes: 47 additions & 4 deletions api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,49 @@
v1alpha1 "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)

// InstanceFilter is the filter for list instances API.
type InstanceFilter struct {
Query string
Environment string
Project string
State v1pb.State
Engines []v1pb.Engine
Host string
Port string
}

// ProjectFilter is the filter for list projects API.
type ProjectFilter struct {
Query string
ExcludeDefault bool
State v1pb.State
}

// Label is the database label.
type Label struct {
Key string
Value string
}

// DatabaseFilter is the filter for list databases API.
type DatabaseFilter struct {
Query string
Environment string
Project string
Instance string
Engines []v1pb.Engine
Labels []*Label
ExcludeUnassigned bool
}

type UserFilter struct {

Check failure on line 45 in api/client.go

View workflow job for this annotation

GitHub Actions / golangci

exported: exported type UserFilter should have comment or be unexported (revive)
Name string
Email string
Project string
UserTypes []v1pb.UserType
State v1pb.State
}

// Client is the API message for Bytebase OpenAPI client.
type Client interface {
// GetCaller returns the API caller.
Expand All @@ -28,7 +71,7 @@

// Instance
// ListInstance will return instances.
ListInstance(ctx context.Context, showDeleted bool) (*v1pb.ListInstancesResponse, error)
ListInstance(ctx context.Context, filter *InstanceFilter) ([]*v1pb.Instance, error)
// GetInstance gets the instance by full name.
GetInstance(ctx context.Context, instanceName string) (*v1pb.Instance, error)
// CreateInstance creates the instance.
Expand Down Expand Up @@ -56,7 +99,7 @@
// GetDatabase gets the database by instance resource id and the database name.
GetDatabase(ctx context.Context, databaseName string) (*v1pb.Database, error)
// ListDatabase list the databases.
ListDatabase(ctx context.Context, instanceID, filter string, listAll bool) ([]*v1pb.Database, error)
ListDatabase(ctx context.Context, instanceID string, filter *DatabaseFilter, listAll bool) ([]*v1pb.Database, error)
// UpdateDatabase patches the database.
UpdateDatabase(ctx context.Context, patch *v1pb.Database, updateMasks []string) (*v1pb.Database, error)
// BatchUpdateDatabases batch updates databases.
Expand All @@ -70,7 +113,7 @@
// GetProject gets the project by project full name.
GetProject(ctx context.Context, projectName string) (*v1pb.Project, error)
// ListProject list all projects,
ListProject(ctx context.Context, showDeleted bool) ([]*v1pb.Project, error)
ListProject(ctx context.Context, filter *ProjectFilter) ([]*v1pb.Project, error)
// CreateProject creates the project.
CreateProject(ctx context.Context, projectID string, project *v1pb.Project) (*v1pb.Project, error)
// UpdateProject updates the project.
Expand Down Expand Up @@ -98,7 +141,7 @@

// User
// ListUser list all users.
ListUser(ctx context.Context, showDeleted bool) ([]*v1pb.User, error)
ListUser(ctx context.Context, filter *UserFilter) ([]*v1pb.User, error)
// CreateUser creates the user.
CreateUser(ctx context.Context, user *v1pb.User) (*v1pb.User, error)
// GetUser gets the user by name.
Expand Down
52 changes: 48 additions & 4 deletions client/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
v1pb "github.com/bytebase/bytebase/proto/generated-go/v1"
"github.com/hashicorp/terraform-plugin-log/tflog"
"google.golang.org/protobuf/encoding/protojson"

"github.com/bytebase/terraform-provider-bytebase/api"
)

// GetDatabase gets the database by the database full name.
Expand All @@ -28,15 +30,57 @@ func (c *client) GetDatabase(ctx context.Context, databaseName string) (*v1pb.Da
return &res, nil
}

func buildDatabaseQuery(filter *api.DatabaseFilter) string {
params := []string{}

if v := filter.Query; v != "" {
params = append(params, fmt.Sprintf(`name.matches("%s")`, strings.ToLower(v)))
}
if v := filter.Environment; v != "" {
params = append(params, fmt.Sprintf(`environment == "%s"`, v))
}
if v := filter.Project; v != "" {
params = append(params, fmt.Sprintf(`project == "%s"`, v))
}
if v := filter.Instance; v != "" {
params = append(params, fmt.Sprintf(`instance == "%s"`, v))
}
if filter.ExcludeUnassigned {
params = append(params, "exclude_unassigned == true")
}
if v := filter.Engines; len(v) > 0 {
engines := []string{}
for _, e := range v {
engines = append(engines, fmt.Sprintf(`"%s"`, e.String()))
}
params = append(params, fmt.Sprintf(`engine in [%s]`, strings.Join(engines, ", ")))
}
if v := filter.Labels; len(v) > 0 {
labelMap := map[string][]string{}
for _, label := range v {
if _, ok := labelMap[label.Key]; !ok {
labelMap[label.Key] = []string{}
}
labelMap[label.Key] = append(labelMap[label.Key], label.Value)
}
for key, values := range labelMap {
params = append(params, fmt.Sprintf(`label == "%s:%s"`, key, strings.Join(values, ",")))
}
}

return fmt.Sprintf("filter=%s", url.QueryEscape(strings.Join(params, " && ")))
}

// ListDatabase list all databases.
func (c *client) ListDatabase(ctx context.Context, parent, filter string, listAll bool) ([]*v1pb.Database, error) {
func (c *client) ListDatabase(ctx context.Context, parent string, filter *api.DatabaseFilter, listAll bool) ([]*v1pb.Database, error) {
res := []*v1pb.Database{}
pageToken := ""
startTime := time.Now()
query := buildDatabaseQuery(filter)

for {
startTimePerPage := time.Now()
resp, err := c.listDatabasePerPage(ctx, parent, filter, pageToken, 500)
resp, err := c.listDatabasePerPage(ctx, parent, query, pageToken, 500)
if err != nil {
return nil, err
}
Expand All @@ -63,11 +107,11 @@ func (c *client) ListDatabase(ctx context.Context, parent, filter string, listAl
// listDatabasePerPage list the databases.
func (c *client) listDatabasePerPage(ctx context.Context, parent, filter, pageToken string, pageSize int) (*v1pb.ListDatabasesResponse, error) {
requestURL := fmt.Sprintf(
"%s/%s/%s/databases?filter=%s&page_size=%d&page_token=%s",
"%s/%s/%s/databases?%s&page_size=%d&page_token=%s",
c.url,
c.version,
parent,
url.QueryEscape(filter),
filter,
pageSize,
url.QueryEscape(pageToken),
)
Expand Down
88 changes: 86 additions & 2 deletions client/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,99 @@ import (
"context"
"fmt"
"net/http"
"net/url"
"strings"
"time"

v1pb "github.com/bytebase/bytebase/proto/generated-go/v1"
"github.com/hashicorp/terraform-plugin-log/tflog"
"google.golang.org/protobuf/encoding/protojson"

"github.com/bytebase/terraform-provider-bytebase/api"
)

func buildInstanceQuery(filter *api.InstanceFilter) string {
params := []string{}
showDeleted := v1pb.State_DELETED == filter.State

if v := filter.Query; v != "" {
params = append(params, fmt.Sprintf(`(name.matches("%s") || resource_id.matches("%s"))`, strings.ToLower(v), strings.ToLower(v)))
}
if v := filter.Project; v != "" {
params = append(params, fmt.Sprintf(`project == "%s"`, v))
}
if v := filter.Environment; v != "" {
params = append(params, fmt.Sprintf(`environment == "%s"`, v))
}
if v := filter.Host; v != "" {
params = append(params, fmt.Sprintf(`host == "%s"`, v))
}
if v := filter.Port; v != "" {
params = append(params, fmt.Sprintf(`port == "%s"`, v))
}
if v := filter.Engines; len(v) > 0 {
engines := []string{}
for _, e := range v {
engines = append(engines, fmt.Sprintf(`"%s"`, e.String()))
}
params = append(params, fmt.Sprintf(`engine in [%s]`, strings.Join(engines, ", ")))
}
if showDeleted {
params = append(params, fmt.Sprintf(`state == "%s"`, filter.State.String()))
}

if len(params) == 0 {
return fmt.Sprintf("showDeleted=%v", showDeleted)
}

return fmt.Sprintf("filter=%s&showDeleted=%v", url.QueryEscape(strings.Join(params, " && ")), showDeleted)
}

// ListInstance will return instances.
func (c *client) ListInstance(ctx context.Context, showDeleted bool) (*v1pb.ListInstancesResponse, error) {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/%s/instances?showDeleted=%v", c.url, c.version, showDeleted), nil)
func (c *client) ListInstance(ctx context.Context, filter *api.InstanceFilter) ([]*v1pb.Instance, error) {
res := []*v1pb.Instance{}
pageToken := ""
startTime := time.Now()
query := buildInstanceQuery(filter)

for {
startTimePerPage := time.Now()
resp, err := c.listInstancePerPage(ctx, query, pageToken, 500)
if err != nil {
return nil, err
}
res = append(res, resp.Instances...)
tflog.Debug(ctx, "[list instance per page]", map[string]interface{}{
"count": len(resp.Instances),
"ms": time.Since(startTimePerPage).Milliseconds(),
})

pageToken = resp.NextPageToken
if pageToken == "" {
break
}
}

tflog.Debug(ctx, "[list instance]", map[string]interface{}{
"total": len(res),
"ms": time.Since(startTime).Milliseconds(),
})

return res, nil
}

// listInstancePerPage list the instance.
func (c *client) listInstancePerPage(ctx context.Context, query, pageToken string, pageSize int) (*v1pb.ListInstancesResponse, error) {
requestURL := fmt.Sprintf(
"%s/%s/instances?%s&page_size=%d&page_token=%s",
c.url,
c.version,
query,
pageSize,
url.QueryEscape(pageToken),
)

req, err := http.NewRequestWithContext(ctx, "GET", requestURL, nil)
if err != nil {
return nil, err
}
Expand Down
34 changes: 29 additions & 5 deletions client/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
v1pb "github.com/bytebase/bytebase/proto/generated-go/v1"
"github.com/hashicorp/terraform-plugin-log/tflog"
"google.golang.org/protobuf/encoding/protojson"

"github.com/bytebase/terraform-provider-bytebase/api"
)

// GetProject gets the project by project full name.
Expand Down Expand Up @@ -69,15 +71,37 @@ func (c *client) SetProjectIAMPolicy(ctx context.Context, projectName string, up
return &res, nil
}

func buildProjectQuery(filter *api.ProjectFilter) string {
params := []string{}
showDeleted := v1pb.State_DELETED == filter.State

if v := filter.Query; v != "" {
params = append(params, fmt.Sprintf(`(name.matches("%s") || resource_id.matches("%s"))`, strings.ToLower(v), strings.ToLower(v)))
}
if filter.ExcludeDefault {
params = append(params, "exclude_default == true")
}
if showDeleted {
params = append(params, fmt.Sprintf(`state == "%s"`, filter.State.String()))
}

if len(params) == 0 {
return fmt.Sprintf("showDeleted=%v", showDeleted)
}

return fmt.Sprintf("filter=%s&showDeleted=%v", url.QueryEscape(strings.Join(params, " && ")), showDeleted)
}

// ListProject list all projects.
func (c *client) ListProject(ctx context.Context, showDeleted bool) ([]*v1pb.Project, error) {
func (c *client) ListProject(ctx context.Context, filter *api.ProjectFilter) ([]*v1pb.Project, error) {
res := []*v1pb.Project{}
pageToken := ""
startTime := time.Now()
query := buildProjectQuery(filter)

for {
startTimePerPage := time.Now()
resp, err := c.listProjectPerPage(ctx, showDeleted, pageToken, 500)
resp, err := c.listProjectPerPage(ctx, query, pageToken, 500)
if err != nil {
return nil, err
}
Expand All @@ -102,12 +126,12 @@ func (c *client) ListProject(ctx context.Context, showDeleted bool) ([]*v1pb.Pro
}

// listProjectPerPage list the projects.
func (c *client) listProjectPerPage(ctx context.Context, showDeleted bool, pageToken string, pageSize int) (*v1pb.ListProjectsResponse, error) {
func (c *client) listProjectPerPage(ctx context.Context, query, pageToken string, pageSize int) (*v1pb.ListProjectsResponse, error) {
requestURL := fmt.Sprintf(
"%s/%s/projects?showDeleted=%v&page_size=%d&page_token=%s",
"%s/%s/projects?%s&page_size=%d&page_token=%s",
c.url,
c.version,
showDeleted,
query,
pageSize,
url.QueryEscape(pageToken),
)
Expand Down
Loading
Loading