-
-
Save ajbouh/292554473480cdbb24595e67f69445ba to your computer and use it in GitHub Desktop.
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
package main | |
import ( | |
"context" | |
"encoding/json" | |
"flag" | |
"fmt" | |
"log" | |
"os" | |
"github.com/logrusorgru/aurora" | |
"github.com/.../fly/internal/apiext" | |
"github.com/.../fly/internal/appconfig" | |
"github.com/.../fly/internal/client" | |
"github.com/.../fly/internal/render" | |
"github.com/.../fly/internal/secrets" | |
"github.com/superfly/flyctl/api" | |
) | |
var ( | |
appName = flag.String("app_name", os.Getenv("FLY_APP_NAME"), "Name of the app") | |
orgID = flag.String("organization_id", os.Getenv("FLY_ORGANIZATION_ID"), "Organization ID to deploy the app under") | |
orgSlug = flag.String("organization_slug", os.Getenv("FLY_ORGANIZATION_SLUG"), "Organization slug to deploy the app under") | |
appConfigFile = flag.String("app_config", "", "Path to app config file") | |
secretsFormat = flag.String("secrets_format", "json", "Format to use when parsing secrets") | |
secretsCommand = flag.String("secrets_command", "", "Command that writes secrets to stdout") | |
) | |
func getSecretsDecoder() (secrets.Decoder, error) { | |
switch *secretsFormat { | |
case "json": | |
return secrets.DecodeFromJSON, nil | |
case "env": | |
return secrets.DecodeFromEnvEncoding, nil | |
default: | |
return nil, fmt.Errorf("invalid secrets_format: %s", *secretsFormat) | |
} | |
} | |
func readSecrets() (map[string]string, error) { | |
if *secretsCommand == "" { | |
return map[string]string{}, nil | |
} | |
parsedSecretsCommand := []string{} | |
err := json.Unmarshal([]byte(*secretsCommand), &parsedSecretsCommand) | |
if err != nil { | |
return nil, err | |
} | |
decoder, err := getSecretsDecoder() | |
if err != nil { | |
return nil, err | |
} | |
return secrets.ReadFromSubprocess(parsedSecretsCommand, decoder) | |
} | |
func run(ctx context.Context) (err error) { | |
apiClient := client.FromContext(ctx).API() | |
log.Print("Loading app config") | |
appConfig, err := appconfig.LoadAppConfig(*appConfigFile) | |
if err != nil { | |
return err | |
} | |
imageRef := appConfig.Image() | |
if imageRef == "" { | |
return fmt.Errorf("app config missing image field") | |
} | |
log.Print("Reading secrets") | |
declaredSecrets, err := readSecrets() | |
if err != nil { | |
return err | |
} | |
var app *api.App | |
if *orgID == "" { | |
log.Printf("Resolving organization ID for slug %s", *orgSlug) | |
org, err := apiClient.GetOrganizationBySlug(ctx, *orgSlug) | |
if err != nil { | |
return err | |
} | |
*orgID = org.ID | |
} | |
log.Print("Ensuring app") | |
app, err = apiext.EnsureApp(ctx, apiClient, *orgID, *appName) | |
if err != nil { | |
return err | |
} | |
log.Print("Validating app configuration") | |
parsedCfg, err := apiClient.ParseConfig(ctx, *appName, appConfig.Definition) | |
if err != nil { | |
if parsedCfg == nil { | |
// No error data has been returned | |
return fmt.Errorf("not possible to validate configuration: server returned %s", err) | |
} | |
for _, error := range parsedCfg.Errors { | |
log.Print("deploy ", aurora.Red("✘").String(), error) | |
} | |
return err | |
} | |
appConfig.Definition = parsedCfg.Definition | |
if parsedCfg.Valid && len(parsedCfg.Services) > 0 { | |
log.Print(aurora.Bold("Services")) | |
for _, svc := range parsedCfg.Services { | |
log.Print(svc.Description) | |
} | |
} | |
log.Print("Validating app configuration done") | |
_, err = apiext.EnsureSecrets(ctx, apiClient, *appName, declaredSecrets) | |
if err != nil { | |
return err | |
} | |
deployInput := api.DeployImageInput{ | |
AppID: *appName, | |
Image: imageRef, | |
} | |
if appConfig != nil && len(appConfig.Definition) > 0 { | |
deployInput.Definition = api.DefinitionPtr(appConfig.Definition) | |
} | |
fmt.Fprintf(os.Stderr, "Deploy %#v\n", appConfig) | |
release, releaseCommand, err := apiClient.DeployImage(ctx, deployInput) | |
if err != nil { | |
return err | |
} | |
fmt.Fprintf(os.Stderr, "Release v%d created\n", release.Version) | |
if releaseCommand != nil { | |
log.Print("Release command detected: this new release will not be available until the command succeeds.") | |
} | |
if err == nil { | |
return render.JSON(os.Stdout, app) | |
} | |
return err | |
} | |
func main() { | |
flag.Parse() | |
ctx := context.Background() | |
api.SetBaseURL("https://api.fly.io") | |
apiClient := client.New() | |
ctx = client.NewContext(ctx, apiClient) | |
err := run(ctx) | |
if err != nil { | |
log.Fatal(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment