-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
For now, db get has the same output as db list. We will display more info in future commits.
- Loading branch information
Showing
5 changed files
with
229 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package koyeb | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
|
||
"github.com/koyeb/koyeb-api-client-go/api/v1/koyeb" | ||
"github.com/koyeb/koyeb-cli/pkg/koyeb/errors" | ||
"github.com/koyeb/koyeb-cli/pkg/koyeb/idmapper" | ||
"github.com/koyeb/koyeb-cli/pkg/koyeb/renderer" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// DatabaseListItemInfo wraps a service returned by the services API and it's latest deployment. | ||
type DatabaseInfo struct { | ||
Service koyeb.Service `json:"service"` | ||
Deployment koyeb.Deployment `json:"deployment"` | ||
} | ||
|
||
func (h *DatabaseHandler) Get(ctx *CLIContext, cmd *cobra.Command, args []string) error { | ||
database, err := h.ResolveDatabaseArgs(ctx, args[0]) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
resService, resp, err := ctx.Client.ServicesApi.GetService(ctx.Context, database).Execute() | ||
if err != nil { | ||
return errors.NewCLIErrorFromAPIError( | ||
fmt.Sprintf("Error while retrieving the database `%s`", args[0]), | ||
err, | ||
resp, | ||
) | ||
} | ||
|
||
resDeployment, resp, err := ctx.Client.DeploymentsApi.GetDeployment(ctx.Context, resService.Service.GetLatestDeploymentId()).Execute() | ||
if err != nil { | ||
return errors.NewCLIErrorFromAPIError( | ||
fmt.Sprintf("Error while fetching the deployment for the database service `%s`", resService.Service.GetId()), | ||
err, | ||
resp, | ||
) | ||
} | ||
|
||
full := GetBoolFlags(cmd, "full") | ||
getDatabaseReply := NewGetDatabaseReply( | ||
ctx.Mapper, | ||
DatabaseInfo{Service: resService.GetService(), Deployment: resDeployment.GetDeployment()}, | ||
full, | ||
) | ||
ctx.Renderer.Render(getDatabaseReply) | ||
return nil | ||
} | ||
|
||
type GetDatabaseReply struct { | ||
mapper *idmapper.Mapper | ||
value DatabaseInfo | ||
full bool | ||
} | ||
|
||
func NewGetDatabaseReply(mapper *idmapper.Mapper, value DatabaseInfo, full bool) *GetDatabaseReply { | ||
return &GetDatabaseReply{ | ||
mapper: mapper, | ||
value: value, | ||
full: full, | ||
} | ||
} | ||
|
||
func (GetDatabaseReply) Title() string { | ||
return "Database" | ||
} | ||
|
||
func (r *GetDatabaseReply) MarshalBinary() ([]byte, error) { | ||
return r.value.Service.MarshalJSON() | ||
} | ||
|
||
func (r *GetDatabaseReply) Headers() []string { | ||
return []string{"id", "name", "region", "engine", "status", "active_time", "used_storage", "created_at"} | ||
} | ||
|
||
func (r *GetDatabaseReply) Fields() []map[string]string { | ||
var region, engine, activeTime, usedStorage string | ||
|
||
// At the moment, we only support neon postgres so the if statement is | ||
// always true. If we add support for other providers in the future, the statement | ||
// will prevent a nil pointer dereference. | ||
if r.value.Deployment.DatabaseInfo.HasNeonPostgres() { | ||
region = r.value.Deployment.Definition.GetDatabase().NeonPostgres.GetRegion() | ||
engine = fmt.Sprintf("Postgres %d", r.value.Deployment.Definition.GetDatabase().NeonPostgres.GetPgVersion()) | ||
|
||
size, _ := strconv.Atoi(r.value.Deployment.DatabaseInfo.NeonPostgres.GetDefaultBranchLogicalSize()) | ||
// Convert to MB | ||
size = size / 1024 / 1024 | ||
// The maximum size is 3GB and is not configurable yet. | ||
maxSize := 3 * 1024 | ||
activeTimeValue, _ := strconv.ParseFloat(r.value.Deployment.DatabaseInfo.NeonPostgres.GetActiveTimeSeconds(), 32) | ||
// The maximum active time is 100h and is not configurable yet. | ||
activeTime = fmt.Sprintf("%.1fh/100h", activeTimeValue/60/60) | ||
usedStorage = fmt.Sprintf("%dMB/%dMB (%d%%)", size, maxSize, size*100/maxSize) | ||
} | ||
|
||
fields := map[string]string{ | ||
"id": renderer.FormatID(r.value.Service.GetId(), r.full), | ||
"name": r.value.Service.GetName(), | ||
"region": region, | ||
"engine": engine, | ||
"status": formatServiceStatus(r.value.Service.GetStatus()), | ||
"active_time": activeTime, | ||
"used_storage": usedStorage, | ||
"created_at": renderer.FormatTime(r.value.Service.GetCreatedAt()), | ||
} | ||
return []map[string]string{fields} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package idmapper | ||
|
||
import ( | ||
"context" | ||
"strconv" | ||
|
||
"github.com/koyeb/koyeb-api-client-go/api/v1/koyeb" | ||
"github.com/koyeb/koyeb-cli/pkg/koyeb/errors" | ||
) | ||
|
||
type DatabaseMapper struct { | ||
ctx context.Context | ||
client *koyeb.APIClient | ||
fetched bool | ||
sidMap *IDMap | ||
nameMap *IDMap | ||
} | ||
|
||
func NewDatabaseMapper(ctx context.Context, client *koyeb.APIClient) *DatabaseMapper { | ||
return &DatabaseMapper{ | ||
ctx: ctx, | ||
client: client, | ||
fetched: false, | ||
sidMap: NewIDMap(), | ||
nameMap: NewIDMap(), | ||
} | ||
} | ||
|
||
func (mapper *DatabaseMapper) ResolveID(val string) (string, error) { | ||
if IsUUIDv4(val) { | ||
return val, nil | ||
} | ||
|
||
if !mapper.fetched { | ||
err := mapper.fetch() | ||
if err != nil { | ||
return "", err | ||
} | ||
} | ||
|
||
id, ok := mapper.sidMap.GetID(val) | ||
if ok { | ||
return id, nil | ||
} | ||
|
||
id, ok = mapper.nameMap.GetID(val) | ||
if ok { | ||
return id, nil | ||
} | ||
|
||
return "", errors.NewCLIErrorForMapperResolve( | ||
"database", | ||
val, | ||
[]string{"database full UUID", "database short ID (8 characters)", "database name"}, | ||
) | ||
} | ||
|
||
func (mapper *DatabaseMapper) fetch() error { | ||
page := int64(0) | ||
offset := int64(0) | ||
limit := int64(100) | ||
for { | ||
res, resp, err := mapper.client.ServicesApi.ListServices(mapper.ctx). | ||
Types([]string{"DATABASE"}). | ||
Limit(strconv.FormatInt(limit, 10)). | ||
Offset(strconv.FormatInt(offset, 10)). | ||
Execute() | ||
if err != nil { | ||
return errors.NewCLIErrorFromAPIError( | ||
"Error listing databases to resolve the provided identifier to an object ID", | ||
err, | ||
resp, | ||
) | ||
} | ||
|
||
for _, service := range res.GetServices() { | ||
mapper.sidMap.Set(service.GetId(), getShortID(service.GetId(), 8)) | ||
mapper.nameMap.Set(service.GetId(), service.GetName()) | ||
} | ||
|
||
page++ | ||
offset = page * limit | ||
if offset >= res.GetCount() { | ||
break | ||
} | ||
} | ||
|
||
mapper.fetched = true | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters