Skip to content

Commit

Permalink
Write apps to mongo (#32)
Browse files Browse the repository at this point in the history
* chore: update dependencies

* feat: lambda boilerplate for migration

* chore: update dependencies

* infra: add deployment files

* feat: add mongo functions to get collections

* feat: add postgres client

* feat: get mongo and postgres apps

* feat: add bson tag to structs

* feat: insert collections

* refactor: postgres client name

* feat: get both db documents and compare them

* refactor: method identifier

* feat: add convertions from repository to mongo model

* feat: add Collection type

* fix: model types

* feat: migrate postgres apps to mongo

* fix: change default collections to write

* feat: add field to write

* fix: only write documents if there's any to write

* infra: disable vpc lambda creation
  • Loading branch information
rem1niscence authored Sep 21, 2022
1 parent 12251e2 commit 0c750b7
Show file tree
Hide file tree
Showing 10 changed files with 560 additions and 179 deletions.
42 changes: 23 additions & 19 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,49 @@ module github.com/Pocket/global-services
go 1.18

require (
github.com/aws/aws-lambda-go v1.32.0
github.com/aws/aws-sdk-go v1.44.40
github.com/aws/aws-lambda-go v1.34.1
github.com/aws/aws-sdk-go v1.44.102
github.com/go-redis/redis/v8 v8.11.5
github.com/gojektech/heimdall v5.0.2+incompatible
github.com/jackc/pgx/v4 v4.16.1
github.com/jackc/pgx/v4 v4.17.2
github.com/pkg/errors v0.9.1
github.com/pokt-foundation/pocket-go v0.10.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
go.mongodb.org/mongo-driver v1.9.1
golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
github.com/pokt-foundation/pocket-go v0.10.6
github.com/pokt-foundation/utils-go v0.2.4
github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.8.0
go.mongodb.org/mongo-driver v1.10.2
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b
golang.org/x/sync v0.0.0-20220907140024-f12130a52804
)

require github.com/google/uuid v1.3.0 // indirect

require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/gojektech/valkyrie v0.0.0-20190210220504-8f62c1e7ba45 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.12.1 // indirect
github.com/jackc/pgconn v1.13.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.11.0 // indirect
github.com/jackc/puddle v1.2.1 // indirect
github.com/jackc/pgtype v1.12.0 // indirect
github.com/jackc/puddle v1.3.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/klauspost/compress v1.15.6 // indirect
github.com/joho/godotenv v1.4.0 // indirect
github.com/klauspost/compress v1.15.10 // indirect
github.com/montanaflynn/stats v0.6.6 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pokt-foundation/portal-api-go v0.3.7
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.1 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 // indirect
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
134 changes: 53 additions & 81 deletions go.sum

Large diffs are not rendered by default.

156 changes: 156 additions & 0 deletions mongo-migration/cmd/migrate-postgres-to-mongo/lambda/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package main

import (
"context"
"errors"
"net/http"

postgresgateway "github.com/Pocket/global-services/mongo-migration/postgres_client"
"github.com/Pocket/global-services/shared/apigateway"
"github.com/Pocket/global-services/shared/database"
"github.com/Pocket/global-services/shared/gateway/models"
logger "github.com/Pocket/global-services/shared/logger"
"github.com/Pocket/global-services/shared/utils"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
log "github.com/sirupsen/logrus"

"github.com/pokt-foundation/portal-api-go/repository"
"github.com/pokt-foundation/utils-go/environment"
)

var (
postgresClientUrl = environment.MustGetString("POSTGRES_CLIENT_URL")
authenticationToken = environment.MustGetString("AUTHENTICATION_TOKEN")
mongoConnectionString = environment.MustGetString("MONGO_CONNECTION_STRING")
mongoDatabase = environment.GetString("MONGO_DATABASE", "gateway")
)

// LambdaHandler manages the process of getting the postgres apps migrated to mongo
func LambdaHandler(ctx context.Context) (events.APIGatewayProxyResponse, error) {
appsCount, lbsCount, err := migrateToMongo(ctx)

if err != nil {
return *apigateway.NewJSONResponse(http.StatusOK, map[string]any{
"err": err.Error(),
}), nil
}
return *apigateway.NewJSONResponse(http.StatusOK, map[string]any{
"newApps": appsCount,
"newLbs": lbsCount,
}), nil
}

func main() {
lambda.Start(LambdaHandler)
}

func migrateToMongo(ctx context.Context) (int, int, error) {
mongo, err := database.ClientFromURI(ctx, mongoConnectionString, mongoDatabase)
if err != nil {
return 0, 0, errors.New("error connecting to mongo: " + err.Error())
}

postgres := postgresgateway.NewPostgresClient(postgresClientUrl, authenticationToken)

mongoApps, postgresApps, err := getApplications(ctx, mongo, postgres)
if err != nil {
return 0, 0, err
}
mongoLBs, postgresLBs, err := getLoadBalancers(ctx, mongo, postgres)
if err != nil {
return 0, 0, err
}

appsToWrite := convertRepositoryToMongo(getItemsNotInMongo(postgresApps, mongoApps), models.RepositoryToModelApp)
lbsToWrite := convertRepositoryToMongo(getItemsNotInMongo(postgresLBs, mongoLBs), models.RepositoryToModelLoadBalancer)

if len(appsToWrite) > 0 {
err = mongo.InsertMany(ctx, database.ApplicationCollection, appsToWrite)
if err != nil {
return 0, 0, err
}
}

if len(lbsToWrite) > 0 {
err = mongo.InsertMany(ctx, database.LoadBalancersCollection, lbsToWrite)
if err != nil {
return 0, 0, err
}
}

return len(appsToWrite), len(lbsToWrite), nil
}

func getApplications(ctx context.Context, mongo *database.Mongo, postgres *postgresgateway.Client) (map[string]*models.Application, map[string]*repository.Application, error) {
mongoAppsArr, err := mongo.GetApplications(ctx)
if err != nil {
return nil, nil, err
}

postgresAppsArr, err := postgres.GetAllApplications()
if err != nil {
return nil, nil, err
}

mongoApps := utils.SliceToMappedStruct(mongoAppsArr, func(app *models.Application) string {
return app.ID.Hex()
})

postgresApps := utils.SliceToMappedStruct(postgresAppsArr, func(app *repository.Application) string {
return app.ID
})

return mongoApps, postgresApps, nil
}

func getLoadBalancers(ctx context.Context, mongo *database.Mongo, postgres *postgresgateway.Client) (map[string]*models.LoadBalancer, map[string]*repository.LoadBalancer, error) {
mongoLBsArr, err := mongo.GetLoadBalancers(ctx)
if err != nil {
return nil, nil, err
}

postgresLBsArr, err := postgres.GetAllLoadBalancers()
if err != nil {
return nil, nil, err
}

mongoLBs := utils.SliceToMappedStruct(mongoLBsArr, func(lb *models.LoadBalancer) string {
return lb.ID.Hex()
})

postgresLBs := utils.SliceToMappedStruct(postgresLBsArr, func(lb *repository.LoadBalancer) string {
return lb.ID
})

return mongoLBs, postgresLBs, nil
}

func getItemsNotInMongo[T any, V any](pgItems map[string]*T, mongoItems map[string]*V) []T {
items := make([]T, 0)
for key, item := range pgItems {
_, ok := mongoItems[key]
if ok {
continue
}
items = append(items, *item)
}
return items
}

func convertRepositoryToMongo[T any, V any](items []T, convertFn func(*T) (V, error)) []any {
convertedItems := make([]any, 0)
for _, item := range items {
convertedItem, err := convertFn(&item)
if err != nil {
logger.Log.WithFields(log.Fields{
"error": err.Error(),
}).Error("could not convert repository item to a mongo type")
continue
}

convertedItems = append(convertedItems, convertedItem)
}

return convertedItems
}
62 changes: 62 additions & 0 deletions mongo-migration/postgres_client/postgres.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package postgresgateway

import (
"encoding/json"
"net/http"
"time"

"github.com/pokt-foundation/portal-api-go/repository"
)

type GatewayPostgresRoutes string

const (
GetAllBlockchains GatewayPostgresRoutes = "/blockchain"
GetAllApplications GatewayPostgresRoutes = "/application"
GetAllLoadBalancers GatewayPostgresRoutes = "/load_balancer"
)

type Client struct {
client *http.Client
url string
authenticationToken string
}

func NewPostgresClient(url, authenticationToken string) *Client {
return &Client{
client: &http.Client{
Timeout: 20 * time.Second,
},
url: url,
authenticationToken: authenticationToken,
}
}

func (cl *Client) GetAllLoadBalancers() ([]*repository.LoadBalancer, error) {
return getAllItems[repository.LoadBalancer](cl.url+string(GetAllLoadBalancers), cl.client, cl.authenticationToken)
}

func (cl *Client) GetAllApplications() ([]*repository.Application, error) {
return getAllItems[repository.Application](cl.url+string(GetAllApplications), cl.client, cl.authenticationToken)
}

func (cl *Client) GetAllBlockchains() ([]*repository.Blockchain, error) {
return getAllItems[repository.Blockchain](cl.url+string(GetAllBlockchains), cl.client, cl.authenticationToken)
}

func getAllItems[T any](path string, client *http.Client, authToken string) ([]*T, error) {
var items []*T

req, err := http.NewRequest(http.MethodGet, path, nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", authToken)

res, err := client.Do(req)
if err != nil {
return nil, err
}

return items, json.NewDecoder(res.Body).Decode(&items)
}
14 changes: 13 additions & 1 deletion serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ provider:
name: aws
runtime: go1.x
region: us-west-2
vpc: ${file(.env.global.yml):vpc}
# vpc: ${file(.env.global.yml):vpc}

iam:
role:
Expand Down Expand Up @@ -120,3 +120,15 @@ functions:
environment: ${file(.env.flush-cache.yml)}
memorySize: 128
timeout: 20

migrate-postgres-to-mongo:
vpc: ~
handler: bin/migrate-postgres-to-mongo
environment: ${file(.env.migrate-postgres-to-mongo.yml)}
memorySize: 1256
timeout: 360
maximumRetryAttempts: 2
events:
- schedule:
rate: rate(5 minutes)
enabled: true
Loading

0 comments on commit 0c750b7

Please sign in to comment.