diff --git a/.env b/.env deleted file mode 100644 index 7742721..0000000 --- a/.env +++ /dev/null @@ -1,5 +0,0 @@ -# Postgres -DB_HOST=db-postgres:5432 -DB_USER=postgres -DB_PASSWORD=postgres -DB_NAME=ms_gin_go \ No newline at end of file diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml deleted file mode 100644 index 8b10116..0000000 --- a/.github/workflows/aws.yml +++ /dev/null @@ -1,81 +0,0 @@ -# This workflow will build and push a new container image to Amazon ECR, -# and then will deploy a new task definition to Amazon ECS, when a release is created -# -# To use this workflow, you will need to complete the following set-up steps: -# -# 1. Create an ECR repository to store your images. -# For example: `aws ecr create-repository --repository-name my-ecr-repo --region us-east-2`. -# Replace the value of `ECR_REPOSITORY` in the workflow below with your repository's name. -# Replace the value of `aws-region` in the workflow below with your repository's region. -# -# 2. Create an ECS task definition, an ECS cluster, and an ECS service. -# For example, follow the Getting Started guide on the ECS console: -# https://us-east-2.console.aws.amazon.com/ecs/home?region=us-east-2#/firstRun -# Replace the values for `service` and `cluster` in the workflow below with your service and cluster names. -# -# 3. Store your ECS task definition as a JSON file in your repository. -# The format should follow the output of `aws ecs register-task-definition --generate-cli-skeleton`. -# Replace the value of `task-definition` in the workflow below with your JSON file's name. -# Replace the value of `container-name` in the workflow below with the name of the container -# in the `containerDefinitions` section of the task definition. -# -# 4. Store an IAM user access key in GitHub Actions secrets named `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`. -# See the documentation for each action used below for the recommended IAM policies for this IAM user, -# and best practices on handling the access key credentials. - -on: - release: - types: [created] - -name: Deploy to Amazon ECS - -jobs: - deploy: - name: Deploy - runs-on: ubuntu-latest - environment: production - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-2 - - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 - - - name: Build, tag, and push image to Amazon ECR - id: build-image - env: - ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} - ECR_REPOSITORY: my-ecr-repo - IMAGE_TAG: ${{ github.sha }} - run: | - # Build a docker container and - # push it to ECR so that it can - # be deployed to ECS. - docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . - docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG - echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" - - - name: Fill in the new image ID in the Amazon ECS task definition - id: task-def - uses: aws-actions/amazon-ecs-render-task-definition@v1 - with: - task-definition: task-definition.json - container-name: sample-app - image: ${{ steps.build-image.outputs.image }} - - - name: Deploy Amazon ECS task definition - uses: aws-actions/amazon-ecs-deploy-task-definition@v1 - with: - task-definition: ${{ steps.task-def.outputs.task-definition }} - service: sample-app-service - cluster: default - wait-for-service-stability: true diff --git a/Dockerfile b/Dockerfile index 877fb47..9638d61 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,7 +34,6 @@ COPY ./migrations ./migrations # Copy the Pre-built binary file from the previous stage. Observe we also copied the .env file COPY --from=builder /app/main . -COPY --from=builder /app/.env . # Expose port 8080 to the outside world EXPOSE 8080 diff --git a/README.md b/README.md index 53e06c0..43c99aa 100644 --- a/README.md +++ b/README.md @@ -1 +1,75 @@ -# ms-gin-go \ No newline at end of file +# Microservice: Gin Framework Example +This project shows the use of Gin Framework in Golang. + +This repository runs a simple main daemon (main) that implements a REST API for users. The daemon uses a postgres database to persist data and after creation uses migrations to create the user schema. + +## Table of Contents + +- [Running](#running) + - [Dependencies](#dependencies) + - [Environment Variables](#environment-variables) + - [Make Rule](#make-rule) +- [Testing](#testing) + - Coming soon + +## Running + +### Dependencies + +The only dependencies to run the services in this repository are: + +- `docker` +- `docker-compose` + +### Environment Variables + +The program looks for the following environment variables: + +- `DB_USER`: The postgres database username that gets used within the postgres connection +string (Default: `root`). +- `DB_PASS`: The postgres database password that gets used within the postgres connection +string (Default: `root`). +- `DB_NAME`: The postgres database name that gets used within the postgres connection string +(Default: `user`). +- `DB_HOST`: The postgres database host name that gets used within the postgres connection +string (Default `db`). +- `DB_PORT`: The postgres database port that gets used within the postgres connection string +(Default: `5432`). + +If the environment variable has a supplied default and none are set within the context of the host +machine, then the default will be used. + +To set any given environment variable, simply execute the following +pattern, replacing `[ENV_NAME]` with the name of the environment variable and `[ENV_VALUE]` with the +desired value of the environment variable: `export [ENV_NAME]=[ENV_VALUE]`. To unset any set environment +variable, simply execute the following pattern, replacing `[ENV_NAME]` with the name of the environment +variable: `unset [ENV_NAME]`. + +### Make Rule + +To run the services simply execute the following command: + +```shell +make run +``` + +This will stop any containers defined by the compose file if already running +and then rebuild the containers using the compose file. The main daemon (`main`) +will be available at `localhost:8080` and the postgres instance will be available +at `localhost:5432`. + +To stop the services simply execute the following command: + +```shell +make stop +``` + +To down the services simply execute the following command: + +```shell +make down +``` + +## Testing + +Coming soon \ No newline at end of file diff --git a/database/database.go b/database/database.go new file mode 100644 index 0000000..8ddd0f1 --- /dev/null +++ b/database/database.go @@ -0,0 +1,45 @@ +package database + +import ( + "context" + "github.com/go-pg/pg/v10" + log "github.com/sirupsen/logrus" + "sync" + "time" +) + +var ( + instance *pg.DB + once sync.Once +) + +func NewPgDB(pgOptions *pg.Options) *pg.DB { + once.Do(func() { + instance = Connect(pgOptions) + }) + + return instance +} + +func Connect(pgOptions *pg.Options) *pg.DB { + log.Info("connecting to postgres database...") + ctx := context.Background() + db := pg.Connect(pgOptions) + + log.Info("verifying postgres connection...") + if err := db.Ping(ctx); err != nil { + log.Errorln(err) + time.Sleep(2 * time.Second) + + db = pg.Connect(pgOptions) + if err := db.Ping(ctx); err == nil { + log.Info("successfully connected to postgres database...") + return db + } + + log.Panicf("Postgres connection error %+v\n", err) + } + + log.Info("Connection to postgres verified...") + return db +} diff --git a/docker-compose.yml b/docker-compose.yml index a52e2bc..9ec5f91 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,36 +1,31 @@ version: '3' + networks: ms-go-network: driver: bridge + services: - db-postgres: - image: postgres:latest - container_name: full_db_postgres - environment: - - POSTGRES_USER=${DB_USER} - - POSTGRES_PASSWORD=${DB_PASSWORD} - - POSTGRES_DB=${DB_NAME} + app: + build: + context: . + dockerfile: ./Dockerfile ports: - - '5432:5432' + - "8080:8080" + depends_on: + - db restart: on-failure - volumes: - - database_postgres:/var/lib/postgresql/data networks: - ms-go-network - app: - container_name: full_app - build: . + db: + image: postgres:13.2 ports: - - 8080:8080 + - "5432:5432" + expose: + - "5432" + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: user restart: on-failure - volumes: - - api:/usr/src/app/ - env_file: - - .env - depends_on: - - db-postgres networks: - - ms-go-network -volumes: - api: - database_postgres: \ No newline at end of file + - ms-go-network \ No newline at end of file diff --git a/go.mod b/go.mod index 95ac1e2..500469a 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,21 @@ module github.com/laironacosta/ms-gin-go go 1.16 require ( - github.com/Lairon/db-go v0.0.0-20210328034946-ed191835cebb github.com/gin-gonic/gin v1.6.3 github.com/go-pg/migrations/v8 v8.1.0 github.com/go-pg/pg/v10 v10.9.0 github.com/go-playground/validator/v10 v10.4.1 // indirect github.com/golang/protobuf v1.5.1 // indirect github.com/json-iterator/go v1.1.10 // indirect + github.com/kelseyhightower/envconfig v1.4.0 github.com/leodido/go-urn v1.2.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/onsi/ginkgo v1.15.0 // indirect + github.com/onsi/gomega v1.10.5 // indirect + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.8.1 github.com/ugorji/go v1.2.4 // indirect - golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 // indirect + golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 8ac1a29..9e600ac 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,10 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Lairon/db-go v0.0.0-20210328034946-ed191835cebb h1:TymkFrVlntF+wIx2ocKei4jHKn8+8tlDnpoSTDNp2MA= -github.com/Lairon/db-go v0.0.0-20210328034946-ed191835cebb/go.mod h1:FZoBm6eGMtnp2kxzbrWqhzizi+4D41GJMJsYOtKHqis= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -34,7 +30,6 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-redis/redis/v8 v8.8.0/go.mod h1:F7resOH5Kdug49Otu24RjHWwgK7u9AmtqWMnCV1iP5Y= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -68,6 +63,8 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= @@ -97,10 +94,15 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -177,6 +179,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -187,8 +190,8 @@ golang.org/x/sys v0.0.0-20201017003518-b09fb700fbb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 h1:64ChN/hjER/taL4YJuA+gpLfIMT+/NFherRZixbxOhg= -golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54 h1:rF3Ohx8DRyl8h2zw9qojyLHLhrJpEMgyPOImREEryf0= +golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/main.go b/main.go index 247f3f4..2e64633 100644 --- a/main.go +++ b/main.go @@ -1,25 +1,42 @@ package main import ( - "github.com/Lairon/db-go/pgdb" + "fmt" "github.com/gin-gonic/gin" "github.com/go-pg/pg/v10" + "github.com/kelseyhightower/envconfig" "github.com/laironacosta/ms-gin-go/controllers" + "github.com/laironacosta/ms-gin-go/database" "github.com/laironacosta/ms-gin-go/migrations" repo "github.com/laironacosta/ms-gin-go/repository" "github.com/laironacosta/ms-gin-go/router" "github.com/laironacosta/ms-gin-go/services" - "os" + "github.com/pkg/errors" ) +// cfg is the struct type that contains fields that stores the necessary configuration +// gathered from the environment. +var cfg struct { + DBUser string `envconfig:"DB_USER" default:"root"` + DBPass string `envconfig:"DB_PASS" default:"root"` + DBName string `envconfig:"DB_NAME" default:"user"` + DBHost string `envconfig:"DB_HOST" default:"db"` + DBPort int `envconfig:"DB_PORT" default:"5432"` +} + func main() { gin := gin.Default() - db := pgdb.NewPgDB(&pg.Options{ - Addr: os.Getenv("DB_HOST"), - User: os.Getenv("DB_USER"), - Password: os.Getenv("DB_PASSWORD"), - Database: os.Getenv("DB_NAME"), + if err := envconfig.Process("LIST", &cfg); err != nil { + err = errors.Wrap(err, "parse environment variables") + return + } + + db := database.NewPgDB(&pg.Options{ + Addr: fmt.Sprintf("%s:%d", cfg.DBHost, cfg.DBPort), + User: cfg.DBUser, + Password: cfg.DBPass, + Database: cfg.DBName, }) migrations.Init(db) diff --git a/makefile b/makefile new file mode 100644 index 0000000..4dcc905 --- /dev/null +++ b/makefile @@ -0,0 +1,15 @@ +run: stop up + +mod: + # This make rule requires Go 1.11+ + GO111MODULE=on go mod tidy + GO111MODULE=on go mod vendor + +up: + docker-compose -f docker-compose.yml up -d --build + +stop: + docker-compose -f docker-compose.yml stop + +down: + docker-compose -f docker-compose.yml down