Skip to content

Commit

Permalink
postgres commands
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeldwan committed Jan 19, 2021
1 parent 973ab31 commit 77c8533
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 5 deletions.
9 changes: 6 additions & 3 deletions api/resource_apps.go
@@ -1,9 +1,9 @@
package api

func (client *Client) GetApps() ([]App, error) {
func (client *Client) GetApps(role *string) ([]App, error) {
query := `
query {
apps(type: "container", first: 400) {
query($role: String) {
apps(type: "container", first: 400, role: $role) {
nodes {
id
name
Expand All @@ -22,6 +22,9 @@ func (client *Client) GetApps() ([]App, error) {
`

req := client.NewRequest(query)
if role != nil {
req.Var("role", *role)
}

data, err := client.Run(req)
if err != nil {
Expand Down
108 changes: 108 additions & 0 deletions api/resource_postgres.go
@@ -0,0 +1,108 @@
package api

func (client *Client) CreatePostgresCluster(organizationID string, name string) (*TemplateDeployment, error) {
query := `
mutation($input: CreatePostgresClusterInput!) {
createPostgresCluster(input: $input) {
templateDeployment {
id
status
apps {
nodes {
name
state
status
}
}
}
}
}
`

req := client.NewRequest(query)
req.Var("input", map[string]string{
"organizationId": organizationID,
"name": name,
})

data, err := client.Run(req)
if err != nil {
return nil, err
}

return &data.CreatePostgresCluster.TemplateDeployment, nil
}

func (client *Client) GetTemplateDeployment(id string) (*TemplateDeployment, error) {
query := `
query($id: ID!) {
templateDeploymentNode: node(id: $id) {
... on TemplateDeployment {
id
status
apps {
nodes {
name
state
status
}
}
}
}
}
`

req := client.NewRequest(query)
req.Var("id", id)

data, err := client.Run(req)
if err != nil {
return nil, err
}

return data.TemplateDeploymentNode, nil
}

func (client *Client) AttachPostgresCluster(input AttachPostgresClusterInput) (*App, *App, error) {
query := `
mutation($input: AttachPostgresClusterInput!) {
attachPostgresCluster(input: $input) {
app {
name
}
postgresClusterApp {
name
}
}
}
`

req := client.NewRequest(query)
req.Var("input", input)

data, err := client.Run(req)
if err != nil {
return nil, nil, err
}

return &data.AttachPostgresCluster.App, &data.AttachPostgresCluster.PostgresClusterApp, nil
}

func (client *Client) DetachPostgresCluster(postgresAppName string, appName string) error {
query := `
mutation($input: DetachPostgresClusterInput!) {
detachPostgresCluster(input: $input) {
clientMutationId
}
}
`

req := client.NewRequest(query)
req.Var("input", map[string]string{
"postgresClusterAppId": postgresAppName,
"appId": appName,
})

_, err := client.Run(req)
return err
}
29 changes: 29 additions & 0 deletions api/types.go
Expand Up @@ -36,6 +36,10 @@ type Query struct {
VMSizes []VMSize
}

// aliases & nodes

TemplateDeploymentNode *TemplateDeployment

// hack to let us alias node to a type
// DNSZone *DNSZone

Expand Down Expand Up @@ -156,6 +160,15 @@ type Query struct {
SetPagerdutyHandler *struct {
Handler *HealthCheckHandler
}

CreatePostgresCluster *struct {
TemplateDeployment TemplateDeployment
}

AttachPostgresCluster *struct {
App App
PostgresClusterApp App
}
}

// carries the privkey; this is the only time it can be retrieved
Expand All @@ -170,6 +183,7 @@ type Definition map[string]interface{}
type App struct {
ID string
Name string
State string
Status string
Deployed bool
Hostname string
Expand Down Expand Up @@ -831,3 +845,18 @@ type SetPagerdutyHandlerInput struct {
Name string `json:"name"`
PagerdutyToken string `json:"pagerdutyToken"`
}

type TemplateDeployment struct {
ID string
Status string
Apps *struct {
Nodes []App
}
}

type AttachPostgresClusterInput struct {
AppID string `json:"appId"`
PostgresClusterAppID string `json:"postgresClusterAppId"`
DatabaseName *string `json:"databaseName,omitempty"`
VariableName *string `json:"variableName,omitempty"`
}
2 changes: 1 addition & 1 deletion cmd/apps.go
Expand Up @@ -85,7 +85,7 @@ func newAppsCommand() *Command {
}

func runAppsList(ctx *cmdctx.CmdContext) error {
listapps, err := ctx.Client.API().GetApps()
listapps, err := ctx.Client.API().GetApps(nil)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/list.go
Expand Up @@ -81,7 +81,7 @@ func runListApps(commandContext *cmdctx.CmdContext) error {

exact := commandContext.Config.GetBool("exact")

apps, err := commandContext.Client.API().GetApps()
apps, err := commandContext.Client.API().GetApps(nil)
if err != nil {
return err
}
Expand Down
133 changes: 133 additions & 0 deletions cmd/postgres.go
@@ -0,0 +1,133 @@
package cmd

import (
"errors"
"fmt"
"os"
"time"

"github.com/spf13/cobra"
"github.com/superfly/flyctl/api"
"github.com/superfly/flyctl/cmd/presenters"
"github.com/superfly/flyctl/cmdctx"
"github.com/superfly/flyctl/docstrings"
)

func newPostgresCommand() *Command {
domainsStrings := docstrings.Get("postgres")
cmd := BuildCommandKS(nil, nil, domainsStrings, os.Stdout, requireSession)

listStrings := docstrings.Get("postgres.list")
listCmd := BuildCommandKS(cmd, runPostgresList, listStrings, os.Stdout, requireSession)
listCmd.Args = cobra.MaximumNArgs(1)

createStrings := docstrings.Get("postgres.create")
createCmd := BuildCommandKS(cmd, runCreatePostgresCluster, createStrings, os.Stdout, requireSession)
createCmd.AddStringFlag(StringFlagOpts{Name: "organization"})
createCmd.AddStringFlag(StringFlagOpts{Name: "name"})

attachStrngs := docstrings.Get("postgres.attach")
attachCmd := BuildCommandKS(cmd, runAttachPostgresCluster, attachStrngs, os.Stdout, requireSession, requireAppName)
attachCmd.AddStringFlag(StringFlagOpts{Name: "postgres-app"})
attachCmd.AddStringFlag(StringFlagOpts{Name: "database-name"})
attachCmd.AddStringFlag(StringFlagOpts{Name: "variable-name"})

return cmd
}

func runPostgresList(ctx *cmdctx.CmdContext) error {
apps, err := ctx.Client.API().GetApps(api.StringPointer("postgres_cluster"))
if err != nil {
return err
}

if ctx.OutputJSON() {
ctx.WriteJSON(apps)
return nil
}

return ctx.Render(&presenters.Apps{Apps: apps})
}

func runCreatePostgresCluster(ctx *cmdctx.CmdContext) error {
orgSlug, _ := ctx.Config.GetString("organization")
org, err := selectOrganization(ctx.Client.API(), orgSlug)
if err != nil {
return err
}

name, _ := ctx.Config.GetString("name")
if name == "" {
return errors.New("name is required")
}

fmt.Fprintf(ctx.Out, "Creating postgres cluster %s in organization %s, this will take a minute...\n", name, org.Slug)

td, err := ctx.Client.API().CreatePostgresCluster(org.ID, name)
if err != nil {
return err
}

for {
td, err = ctx.Client.API().GetTemplateDeployment(td.ID)
if err != nil {
return err
}

if td.Status == "failed" {
fmt.Fprintf(ctx.Out, "Failed to create postgres cluster, please try again\n")
break
} else if td.Status == "completed" {
app := td.Apps.Nodes[0]
if app.Status == "running" && app.State == "DEPLOYED" {
fmt.Fprintf(ctx.Out, "Postgres cluster created: %s\n", td.Apps.Nodes[0].Name)
break
}

}

fmt.Println("launching...")

time.Sleep(1 * time.Second)
}

return nil
}

func runAttachPostgresCluster(ctx *cmdctx.CmdContext) error {
postgresAppName, _ := ctx.Config.GetString("postgres-app")
appName := ctx.AppName

input := api.AttachPostgresClusterInput{
AppID: appName,
PostgresClusterAppID: postgresAppName,
}

if dbName, _ := ctx.Config.GetString("database-name"); dbName != "" {
input.DatabaseName = api.StringPointer(dbName)
}
if varName, _ := ctx.Config.GetString("variable-name"); varName != "" {
input.VariableName = api.StringPointer(varName)
}

app, postgresApp, err := ctx.Client.API().AttachPostgresCluster(input)

if err != nil {
return err
}

fmt.Printf("Postgres cluster %s is now attached to %s\n", postgresApp.Name, app.Name)

return nil
}

// func runPostgresClusterAttach(ctx *cmdctx.CmdContext) error {
// name, _ := ctx.Config.GetString("name")
// if name == "" {
// return errors.New("name is required")
// }

// fmt.Fprintf(ctx.Out, "Creating postgres cluster %s in organization %s, this will take a minute...\n", name, org.Slug)

// return nil
// }
1 change: 1 addition & 0 deletions cmd/root.go
Expand Up @@ -107,6 +107,7 @@ func init() {
newVolumesCommand(),
newWireGuardCommand(),
newChecksCommand(),
newPostgresCommand(),
)

initConfig()
Expand Down
16 changes: 16 additions & 0 deletions docstrings/gen.go
Expand Up @@ -476,6 +476,22 @@ about the Fly platform.`,
return KeyStrings{"vm-sizes", "List VM Sizes",
`View a list of VM sizes which can be used with the FLYCTL SCALE VM command`,
}
case "postgres":
return KeyStrings{"postgres", "Manage postgres clusters",
`Manage postgres clusters`,
}
case "postgres.attach":
return KeyStrings{"attach", "Attach a postgres cluster to an app",
`Attach a postgres cluster to an app`,
}
case "postgres.create":
return KeyStrings{"create", "Create a postgres cluster",
`Create a postgres cluster`,
}
case "postgres.list":
return KeyStrings{"list", "list postgres clusters",
`list postgres clusters`,
}
case "regions":
return KeyStrings{"regions", "Manage regions",
`Configure the region placement rules for an application.`,
Expand Down
18 changes: 18 additions & 0 deletions helpgen/flyctlhelp.toml
Expand Up @@ -492,6 +492,24 @@ about the Fly platform.
longHelp = """Show current Fly platform status in a browser
"""

[postgres]
usage = "postgres"
shortHelp = "Manage postgres clusters"
longHelp = "Manage postgres clusters"
[postgres.attach]
usage = "attach"
shortHelp = "Attach a postgres cluster to an app"
longHelp = "Attach a postgres cluster to an app"
[postgres.list]
usage = "list"
shortHelp = "list postgres clusters"
longHelp = "list postgres clusters"
[postgres.create]
usage = "create"
shortHelp = "Create a postgres cluster"
longHelp = "Create a postgres cluster"


[regions]
usage = "regions"
shortHelp = "Manage regions"
Expand Down

0 comments on commit 77c8533

Please sign in to comment.