Skip to content

Commit

Permalink
APP-930 Add OpenAPI generation script (#17)
Browse files Browse the repository at this point in the history
* add generation script

* add generation script

* improve OpenApi spec

---------

Co-authored-by: yrizhkov <[email protected]>
  • Loading branch information
korotkov-aerospike and reugn authored Oct 10, 2023
1 parent 817948a commit 0831c47
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 7 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The objective of this project is to provide a REST API service for the Aerospike
The service is written in Go and wraps the [asbackup/asrestore](https://github.com/aerospike/aerospike-tools-backup)
tools, built as shared libraries.

Use the [OpenApi generation script](./scripts/generate_OpenApi.sh) to generate OpenApi Specification for the service.

## C Library known issues
* Not thread-safe
* Uncaptured stdout logs
Expand Down
49 changes: 49 additions & 0 deletions internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ type HTTPServer struct {
backupBackends map[string]service.BackupBackend
}

// Annotations to generate OpenAPI description (https://github.com/swaggo/swag)
// @title Backup Service REST API Specification
// @version 0.1.0
// @description Aerospike Backup Service
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
//
// @externalDocs.description OpenAPI
// @externalDocs.url https://swagger.io/resources/open-api/
//
// NewHTTPServer returns a new instance of HTTPServer.
func NewHTTPServer(host string, port int, backends []service.BackupBackend,
config *model.Config) *HTTPServer {
Expand Down Expand Up @@ -113,13 +124,19 @@ func (ws *HTTPServer) Shutdown() error {
return ws.server.Shutdown(context.Background())
}

// @Summary Root endpoint
// @Router / [get]
// @Success 200 ""
func rootActionHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
w.WriteHeader(http.StatusNotFound)
}
fmt.Fprintf(w, "")
}

// @Summary Returns the configuration the service started with in the JSON format.
// @Router /config [get]
// @Success 200 {array} model.Config
func (ws *HTTPServer) configActionHandler(w http.ResponseWriter, _ *http.Request) {
configuration, err := json.MarshalIndent(ws.config, "", " ") // pretty print
if err != nil {
Expand All @@ -128,18 +145,33 @@ func (ws *HTTPServer) configActionHandler(w http.ResponseWriter, _ *http.Request
fmt.Fprint(w, string(configuration))
}

// @Summary Health endpoint.
// @Router /health [get]
// @Success 200 "Ok"
func healthActionHandler(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintf(w, "Ok")
}

// @Summary Readiness endpoint.
// @Router /ready [get]
// @Success 200 "Ok"
func readyActionHandler(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintf(w, "Ok")
}

// @Summary Returns application version.
// @Router /version [get]
// @Success 200 {string} string "version"
func versionActionHandler(w http.ResponseWriter, _ *http.Request) {
fmt.Fprint(w, util.Version)
}

// @Summary Trigger an asynchronous restore operation.
// @Description Specify the directory parameter for the full backup restore.
// @Description Use the file parameter to restore from an incremental backup file.
// @Router /restore [post]
// @Param request body model.RestoreRequest true "query params"
// @Success 200 {integer} int "Job ID (int64)"
func (ws *HTTPServer) restoreHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
var request model.RestoreRequest
Expand All @@ -161,6 +193,11 @@ func (ws *HTTPServer) restoreHandler(w http.ResponseWriter, r *http.Request) {
}
}

// @Summary Retrieve status for a restore job.
// @Produce plain
// @Param jobId query int true "Job ID to retrieve the status"
// @Router /restore/status [get]
// @Success 200 {string} string "Job status"
func (ws *HTTPServer) restoreStatusHandler(w http.ResponseWriter, r *http.Request) {
jobIDParam := r.URL.Query().Get("jobId")
jobID, err := strconv.Atoi(jobIDParam)
Expand All @@ -171,6 +208,12 @@ func (ws *HTTPServer) restoreStatusHandler(w http.ResponseWriter, r *http.Reques
}
}

// @Summary Get available full backups.
// @Produce plain
// @Param name query string true "Backup policy name"
// @Router /backup/full/list [get]
// @Success 200 {array} model.BackupDetails "Full backups"
// @Failure 404 {string} string ""
func (ws *HTTPServer) getAvailableFullBackups(w http.ResponseWriter, r *http.Request) {
policyName := r.URL.Query().Get("name")
if policyName == "" {
Expand All @@ -192,6 +235,12 @@ func (ws *HTTPServer) getAvailableFullBackups(w http.ResponseWriter, r *http.Req
}
}

// @Summary Get available incremental backups.
// @Produce plain
// @Param name query string true "Backup policy name"
// @Router /backup/incremental/list [get]
// @Success 200 {array} model.BackupDetails "Incremental backups"
// @Failure 404 {string} string ""
func (ws *HTTPServer) getAvailableIncrBackups(w http.ResponseWriter, r *http.Request) {
policyName := r.URL.Query().Get("name")
if policyName == "" {
Expand Down
21 changes: 14 additions & 7 deletions pkg/service/backup_backend_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,28 @@ var _ BackupBackend = (*BackupBackendLocal)(nil)

// NewBackupBackendLocal returns a new BackupBackendLocal instance.
func NewBackupBackendLocal(path, backupPolicyName string) *BackupBackendLocal {
if err := os.Chmod(path, 0744); err != nil {
slog.Warn("Failed to Chmod backup directory", "path", path, "err", err)
}
prepareDirectory(path)
incrDirectoryPath := path + "/" + incremenalBackupDirectory
if err := os.Mkdir(incrDirectoryPath, 0744); err != nil {
slog.Debug("Failed to Mkdir incremental backup directory",
"path", incrDirectoryPath, "err", err)
}
prepareDirectory(incrDirectoryPath)
return &BackupBackendLocal{
path: path,
stateFilePath: path + "/" + stateFileName,
backupPolicyName: backupPolicyName,
}
}

func prepareDirectory(path string) {
_, err := os.Stat(path)
if os.IsNotExist(err) {
if err = os.Mkdir(path, 0744); err != nil {
slog.Warn("Error creating backup directory", "path", path, "err", err)
}
}
if err = os.Chmod(path, 0744); err != nil {
slog.Warn("Failed to Chmod backup directory", "path", path, "err", err)
}
}

func (local *BackupBackendLocal) readState() *model.BackupState {
bytes, err := os.ReadFile(local.stateFilePath)
state := model.NewBackupState()
Expand Down
24 changes: 24 additions & 0 deletions scripts/generate_OpenApi.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash

# Check if the "swag" command exists
if ! command -v swag &> /dev/null
then
echo "swag is not installed. Installing..."

# Install swag
go install github.com/swaggo/swag/cmd/swag@latest

# Check if the installation was successful
if [ $? -eq 0 ]
then
echo "swag installed successfully."
else
echo "Error: Failed to install swag. Please install it manually."
exit 1
fi
fi

ROOT_PATH=$(cd `dirname $0` && pwd)/..
swag init -d $ROOT_PATH/internal/server,$ROOT_PATH/pkg/model \
-g server.go \
-o $ROOT_PATH/docs

0 comments on commit 0831c47

Please sign in to comment.