Skip to content
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
78 changes: 78 additions & 0 deletions internal/seed/application_seeder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package seed

import (
"context"
"fmt"
"net/url"
"os"
"strconv"
"strings"
)

func (s *Seeder) ensureApplication(ctx context.Context, accountID, planID int, app ApplicationFixture, authMode string, result *Result) error {
if s.opts.DryRun {
return nil
}
path := fmt.Sprintf("/accounts/%d/applications", accountID)
form := url.Values{
"plan_id": {strconv.Itoa(planID)},
"name": {app.Name},
"application[plan_id]": {strconv.Itoa(planID)},
"application[name]": {app.Name},
}
if authMode == "oidc" && app.RedirectURL != "" {
form.Set("application[redirect_url]", app.RedirectURL)
}
var resp struct {
Application struct {
ID int `json:"id"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
UserKey string `json:"user_key"`
} `json:"application"`
}
if err := s.client.PostForm(ctx, path, form, &resp); err != nil {
if isDuplicateError(err) || strings.Contains(strings.ToLower(err.Error()), "404") {
result.Applications = append(result.Applications, app.Name)
return nil
}
return err
}
if authMode == "oidc" && resp.Application.ClientID == "" && resp.Application.UserKey != "" {
return fmt.Errorf("application %q created with user_key instead of OIDC client credentials", app.Name)
}
result.Applications = append(result.Applications, app.Name)
return nil
}

func (s *Seeder) refreshOIDCApplications(ctx context.Context, accountID, serviceID int) error {
if s.opts.DryRun {
return nil
}
var resp struct {
Applications []struct {
Application struct {
ID int `json:"id"`
Name string `json:"name"`
UserKey string `json:"user_key"`
ClientID string `json:"client_id"`
ServiceID int `json:"service_id"`
} `json:"application"`
} `json:"applications"`
}
path := fmt.Sprintf("/accounts/%d/applications", accountID)
if err := s.client.Get(ctx, path, &resp); err != nil {
return err
}
for _, item := range resp.Applications {
app := item.Application
if app.ServiceID != serviceID {
continue
}
delPath := fmt.Sprintf("/accounts/%d/applications/%d", accountID, app.ID)
if err := s.client.Delete(ctx, delPath); err != nil {
fmt.Fprintf(os.Stderr, "warn: delete app %q (%d): %v\n", app.Name, app.ID, err)
}
}
return nil
}
115 changes: 115 additions & 0 deletions internal/seed/backend_seeder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package seed

import (
"context"
"net/url"
"strings"
)

func (s *Seeder) ensureBackend(ctx context.Context, b BackendFixture) (int, error) {
if s.opts.DryRun {
return 0, nil
}
if id, ok := s.findBackend(ctx, b.SystemName); ok {
if s.opts.SkipExisting {
s.resultSkip("backend:" + b.SystemName)
return id, nil
}
}
if s.opts.DryRun {
return 0, nil
}
form := url.Values{
"name": {b.Name},
"system_name": {b.SystemName},
"private_endpoint": {b.PrivateEndpoint},
"description": {b.Description},
}
var resp struct {
Backend struct {
ID int `json:"id"`
} `json:"backend_api"`
}
if err := s.client.PostForm(ctx, "/backend_apis", form, &resp); err != nil {
if isDuplicateError(err) {
if id, ok := s.findBackend(ctx, b.SystemName); ok {
s.resultSkip("backend:" + b.SystemName)
return id, nil
}
}
return 0, err
}
return resp.Backend.ID, nil
}

func (s *Seeder) findBackend(ctx context.Context, systemName string) (int, bool) {
var resp struct {
BackendAPIs []struct {
BackendAPI struct {
ID int `json:"id"`
SystemName string `json:"system_name"`
} `json:"backend_api"`
} `json:"backend_apis"`
}
if err := s.client.Get(ctx, "/backend_apis", &resp); err != nil {
return 0, false
}
for _, entry := range resp.BackendAPIs {
if entry.BackendAPI.SystemName == systemName {
return entry.BackendAPI.ID, true
}
}
return 0, false
}

func (s *Seeder) ensureAccount(ctx context.Context, a AccountFixture) (int, error) {
if s.opts.DryRun {
return 0, nil
}
if id, ok := s.findAccountByUsername(ctx, a.Username); ok {
if s.opts.SkipExisting {
s.resultSkip("account:" + a.Username)
return id, nil
}
}
form := url.Values{
"org_name": {a.OrgName},
"username": {a.Username},
"email": {a.Email},
"password": {a.Password},
}
var resp struct {
Account struct {
ID int `json:"id"`
} `json:"account"`
}
// Developer accounts are created via signup, not POST /accounts (404 on many tenants).
if err := s.client.PostForm(ctx, "/signup", form, &resp); err != nil {
return 0, err
}
return resp.Account.ID, nil
}

func (s *Seeder) findAccountByUsername(ctx context.Context, username string) (int, bool) {
var resp struct {
Accounts []struct {
Account struct {
ID int `json:"id"`
Username string `json:"username"`
OrgName string `json:"org_name"`
} `json:"account"`
} `json:"accounts"`
}
if err := s.client.Get(ctx, "/accounts", &resp); err != nil {
return 0, false
}
for _, item := range resp.Accounts {
if strings.EqualFold(item.Account.Username, username) {
return item.Account.ID, true
}
if strings.EqualFold(item.Account.OrgName, "Seed Demo Organization") {
return item.Account.ID, true
}
}
return 0, false
}
Loading
Loading