Skip to content

Commit

Permalink
add basic structure and containerize service
Browse files Browse the repository at this point in the history
  • Loading branch information
mgoetzegb committed Apr 26, 2024
1 parent fa32117 commit 1b25011
Show file tree
Hide file tree
Showing 13 changed files with 348 additions and 29 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@

# common editors config files
.vscode

# docker compose env file, might be used to store secrets -> must not be comitted
.env
35 changes: 35 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM golang:1.22.2-alpine AS builder
RUN apk add --no-cache make

# swagger docs generation will fail if cgo is used
ENV CGO_ENABLED=0

WORKDIR /src/

# preinstall dependencies for better build caching
COPY go.mod .
COPY go.sum .
RUN go mod download

COPY Makefile .

# preinstall code generation tools for better build caching
RUN make install-code-generation-tools

# copy api related source files and generate api docs
COPY pkg/web pkg/web
COPY pkg/models pkg/models
RUN make api-docs

# copy rest of the source files and build
COPY cmd cmd
COPY pkg pkg
RUN make test
RUN make build

FROM busybox
# service files
COPY --from=builder /src/api /api
COPY --from=builder /src/bin/notification-service /bin/

ENTRYPOINT ["./bin/notification-service"]
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
all: api-docs build test

.PHONY: install-code-generation-tools api-docs generate-code build test
.PHONY: install-code-generation-tools api-docs generate-code build test start-services

SWAG = github.com/swaggo/swag/cmd/[email protected]

Expand All @@ -16,3 +16,9 @@ build:

test: # run unit tests
go test ./... -cover

start-services: ## start service and dependencies with docker
docker compose -f docker-compose.yml -f docker-compose.service.yml up --build --abort-on-container-exit

cleanup-services: # delete service, dependencies and all persistent data
docker compose -f docker-compose.yml -f docker-compose.service.yml down -v
59 changes: 56 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,75 @@

# OpenSight Notification Service <!-- omit in toc -->

The Notification Service allows to display all notifications in a central place in the frontend.
The Notification Service allows to display all notifications in a central place in the frontend. All OpenSight backend services can use it to send notifications to the user.

## Table of Contents <!-- omit in toc -->

- [Usage](#usage)
- [Requirements](#requirements)
- [Development](#development)
- [Configuration](#configuration)
- [Running](#running)
- [Running non-containerized service](#running-non-containerized-service)
- [Build and test](#build-and-test)
- [Maintainer](#maintainer)
- [License](#license)

## Usage

The Notification Service is intended to be deployed along the others openSight services on the appliance. The service provides a REST API. See the [OpenApi definition](../api/notification-service/notificationService_swagger.yaml) for details. You can view them e.g. in the [Swagger Editor](https://editor.swagger.io/).

Backend services can send notifications via the `Create Notification` endpoint. Those notifications can then be retrieved via `List Notifications` to provide them to the user.

## Requirements

To run the service and its dependencies on you local machine you need a working installation of [docker](https://docs.docker.com/engine/install/) and `make`.

For running the Notification Service outside of docker the latest version of [go](https://go.dev/doc/install) must be installed.

## Configuration

The service is configured via environment variables. Refer to the [Config](pkg/config/config.go) for the available options and their defaults.

## Running

> The following instructions are targeted at openSight developers. As end user the services should be run in orchestration with the other openSight services, which is not in the scope of this readme.
Before starting the services you need to set the environment variable `DB_PASSWORD` for the database password. This password is set (only) on the first start of the database, so make sure to use the same password on consecutive runs. All other configuration parameters are already set in the docker compose files.

Then you can start the notification service and the required dependent service [Postgres](https://www.postgresql.org/) with

```sh
# make sure the `DB_PASSWORD` environment variable is set
make start-services
```

The port of the notification service is forwarded, so you can access its API directly from the host machine at the base url http://localhost:8085/api/notification-service. A convenient way to interact with the service are the Swagger docs served by the running service at URL http://localhost:8085/docs/notification-service/notification-service/index.html.

### Running non-containerized service

If you are actively developing it might be more convenient to run the notification service directly on the host machine.

First start the containerized database with

```sh
docker compose up -d
```

Then load the configuration parameters into environment variables and start the notification service:

```sh
# make sure the `DB_PASSWORD` environment variable is set beforehand
source set_env_vars_local_setup.sh && go run ./cmd/notification-service
```
From here everything is identical to the docker compose setup.

If there are errors regarding the database, verify that it is running with `docker ps` (should show a running container for postgres).

## Development
## Build and test

> Refer to [Makefile](./Makefile) to get an overview of all commands
To build run `make build`. To run the unit tests run `make test`. The rest API docs can be generated with `make api-docs`.

## Maintainer

Expand Down
96 changes: 92 additions & 4 deletions cmd/notification-service/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,96 @@
// SPDX-FileCopyrightText: 2024 Greenbone AG <https://greenbone.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package main

import (
"context"
"fmt"
"net/http"
"os"
"os/signal"

"github.com/greenbone/opensight-notification-service/pkg/config"
"github.com/greenbone/opensight-notification-service/pkg/logging"
"github.com/greenbone/opensight-notification-service/pkg/repository"
"github.com/greenbone/opensight-notification-service/pkg/repository/notificationrepository"
"github.com/greenbone/opensight-notification-service/pkg/services/healthservice"
"github.com/greenbone/opensight-notification-service/pkg/services/notificationservice"
"github.com/greenbone/opensight-notification-service/pkg/web"
"github.com/greenbone/opensight-notification-service/pkg/web/healthcontroller"
"github.com/greenbone/opensight-notification-service/pkg/web/notificationcontroller"

"github.com/rs/zerolog/log"
)

func main() {
config, err := config.ReadConfig()
if err != nil {
log.Fatal().Err(err).Msg("failed to read config")
}

err = logging.SetupLogger(config.LogLevel)
if err != nil {
log.Fatal().Err(err).Msg("failed to set up logger")
}

check(run(config))
}

func run(config config.Config) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx, stop := signal.NotifyContext(ctx, os.Interrupt)
defer stop()

pgClient, err := repository.NewClient(config.Database)
if err != nil {
return err
}
notificationRepository, err := notificationrepository.NewNotificationRepository(pgClient)
if err != nil {
return err
}

notificationService := notificationservice.NewNotificationService(notificationRepository)
healthService := healthservice.NewHealthService(pgClient)

gin := web.NewWebEngine()
rootRouter := gin.Group("/")
notificationServiceRouter := gin.Group("/api/notification-service")
docsRouter := gin.Group("/docs/notification-service")

// rest api docs
web.RegisterSwaggerDocsRoute(docsRouter)
healthcontroller.RegisterSwaggerDocsRoute(docsRouter)

//instantiate controllers
notificationcontroller.NewNotificationController(notificationServiceRouter, notificationService)
healthcontroller.NewHealthController(rootRouter, healthService) // for health probes (not a data source)

srv := &http.Server{
Addr: fmt.Sprintf(":%d", config.Http.Port),
Handler: gin,
ReadTimeout: config.Http.ReadTimeout,
WriteTimeout: config.Http.WriteTimeout,
IdleTimeout: config.Http.IdleTimeout,
}

go func() {
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
check(err)
}
}()

<-ctx.Done()
log.Info().Msg("Received signal. Shutting down")
err = srv.Shutdown(ctx)
if err != nil {
return fmt.Errorf("failed to shut down error: %w", err)
}

return nil
}

func check(err error) {
if err != nil {
log.Fatal().Err(err).Msg("critical error")
}
}
22 changes: 22 additions & 0 deletions docker-compose.service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# only to be used in combination with `docker-compose.yml`

# version: '3' # uncomment for compatibility with old docker compose versions

services:
notification-service:
build: . # replace this line with `image: ghcr.io/greenbone/notification-service:<desired vibd docker image>` if you want to use an already built image instead of building one from the active working directory
environment:
DB_HOST: postgres
DB_PORT: 5432
DB_USERNAME: postgres
DB_PASSWORD: $DB_PASSWORD
DB_NAME: notification_service
DB_SSL_MODE: disable
LOG_LEVEL: debug
ports:
- 8085:8085
networks:
- notification-service-net
depends_on:
postgres:
condition: service_healthy
26 changes: 26 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# version: '3' # uncomment for compatibility with old docker compose versions

services:
postgres:
image: postgres:16
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: $DB_PASSWORD
POSTGRES_DB: notification_service
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- 5432:5432
networks:
- notification-service-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 1s
timeout: 5s
retries: 10

volumes:
postgres-data:

networks:
notification-service-net:
14 changes: 8 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/greenbone/opensight-notification-service
go 1.22.2

require (
github.com/gin-contrib/logger v1.1.1
github.com/gin-gonic/gin v1.9.1
github.com/golang-migrate/migrate/v4 v4.17.1
github.com/greenbone/opensight-golang-libraries v1.3.1
Expand All @@ -17,8 +18,9 @@ require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/bytedance/sonic v1.11.3 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
Expand All @@ -38,7 +40,7 @@ require (
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/magiconair/properties v1.8.7 // indirect
Expand All @@ -48,7 +50,7 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
Expand All @@ -59,10 +61,10 @@ require (
github.com/spf13/viper v1.18.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect
golang.org/x/net v0.22.0 // indirect
Expand Down
Loading

0 comments on commit 1b25011

Please sign in to comment.