httpd: add an API to get data provider status

This commit is contained in:
Nicola Murino 2019-11-14 18:48:01 +01:00
parent f3de83707f
commit 206799ff1c
9 changed files with 111 additions and 3 deletions

View file

@ -315,6 +315,11 @@ func GetUserByID(p Provider, ID int64) (User, error) {
return p.getUserByID(ID)
}
// GetProviderStatus returns an error if the provider is not available
func GetProviderStatus(p Provider) error {
return p.checkAvailability()
}
// Close releases all provider resources.
// This method is used in test cases.
// Closing an uninitialized provider is not supported

View file

@ -287,6 +287,24 @@ func GetVersion(expectedStatusCode int) (utils.VersionInfo, []byte, error) {
return version, body, err
}
// GetProviderStatus returns provider status
func GetProviderStatus(expectedStatusCode int) (map[string]interface{}, []byte, error) {
var response map[string]interface{}
var body []byte
resp, err := getHTTPClient().Get(buildURLRelativeToBase(providerStatusPath))
if err != nil {
return response, body, err
}
defer resp.Body.Close()
err = checkResponse(resp.StatusCode, expectedStatusCode)
if err == nil && (expectedStatusCode == http.StatusOK || expectedStatusCode == http.StatusInternalServerError) {
err = render.DecodeJSON(resp.Body, &response)
} else {
body, _ = getResponseBody(resp)
}
return response, body, err
}
func checkResponse(actual int, expected int) error {
if expected != actual {
return fmt.Errorf("wrong status code: got %v want %v", actual, expected)

View file

@ -23,6 +23,7 @@ const (
quotaScanPath = "/api/v1/quota_scan"
userPath = "/api/v1/user"
versionPath = "/api/v1/version"
providerStatusPath = "/api/v1/providerstatus"
metricsPath = "/metrics"
webBasePath = "/web"
webUsersPath = "/web/users"
@ -77,7 +78,7 @@ func (c Conf) Initialize(configDir string) error {
Handler: router,
ReadTimeout: 300 * time.Second,
WriteTimeout: 300 * time.Second,
MaxHeaderBytes: 1 << 20, // 1MB
MaxHeaderBytes: 1 << 16, // 64KB
}
return httpServer.ListenAndServe()
}

View file

@ -39,6 +39,7 @@ const (
activeConnectionsPath = "/api/v1/connection"
quotaScanPath = "/api/v1/quota_scan"
versionPath = "/api/v1/version"
providerStatusPath = "/api/v1/providerstatus"
metricsPath = "/metrics"
webBasePath = "/web"
webUsersPath = "/web/users"
@ -429,7 +430,7 @@ func TestStartQuotaScan(t *testing.T) {
func TestGetVersion(t *testing.T) {
_, _, err := httpd.GetVersion(http.StatusOK)
if err != nil {
t.Errorf("unable to get sftp version: %v", err)
t.Errorf("unable to get version: %v", err)
}
_, _, err = httpd.GetVersion(http.StatusInternalServerError)
if err == nil {
@ -437,6 +438,17 @@ func TestGetVersion(t *testing.T) {
}
}
func TestGetProviderStatus(t *testing.T) {
_, _, err := httpd.GetProviderStatus(http.StatusOK)
if err != nil {
t.Errorf("unable to get provider status: %v", err)
}
_, _, err = httpd.GetProviderStatus(http.StatusBadRequest)
if err == nil {
t.Errorf("get provider status request must succeed, we requested to check a wrong status code")
}
}
func TestGetConnections(t *testing.T) {
_, _, err := httpd.GetConnections(http.StatusOK)
if err != nil {
@ -513,6 +525,10 @@ func TestProviderErrors(t *testing.T) {
if err != nil {
t.Errorf("delete user with provider closed must fail: %v", err)
}
_, _, err = httpd.GetProviderStatus(http.StatusInternalServerError)
if err != nil {
t.Errorf("get provider status with provider closed must fail: %v", err)
}
config.LoadConfig(configDir, "")
providerConf := config.GetProviderConf()
err = dataprovider.Initialize(providerConf, configDir)

View file

@ -225,6 +225,10 @@ func TestApiCallToNotListeningServer(t *testing.T) {
if err == nil {
t.Errorf("request to an inactive URL must fail")
}
_, _, err = GetProviderStatus(http.StatusOK)
if err == nil {
t.Errorf("request to an inactive URL must fail")
}
SetBaseURL(oldBaseURL)
}

View file

@ -3,6 +3,7 @@ package httpd
import (
"net/http"
"github.com/drakkan/sftpgo/dataprovider"
"github.com/drakkan/sftpgo/logger"
"github.com/drakkan/sftpgo/sftpd"
"github.com/drakkan/sftpgo/utils"
@ -46,6 +47,15 @@ func initializeRouter(staticFilesPath string) {
render.JSON(w, r, utils.GetAppVersion())
})
router.Get(providerStatusPath, func(w http.ResponseWriter, r *http.Request) {
err := dataprovider.GetProviderStatus(dataProvider)
if err != nil {
sendAPIResponse(w, r, err, "", http.StatusInternalServerError)
} else {
sendAPIResponse(w, r, err, "Alive", http.StatusOK)
}
})
router.Get(activeConnectionsPath, func(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, sftpd.GetConnectionsStats())
})

View file

@ -2,7 +2,7 @@ openapi: 3.0.1
info:
title: SFTPGo
description: 'SFTPGo REST API'
version: 1.1.0
version: 1.2.0
servers:
- url: /api/v1
@ -22,6 +22,33 @@ paths:
type: array
items:
$ref : '#/components/schemas/VersionInfo'
/providerstatus:
get:
tags:
- providerstatus
summary: Get data provider status
operationId: get_provider_status
responses:
200:
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
example:
status: 200
message: "Alive"
error: ""
500:
description: Provider Error
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
example:
status: 500
message: ""
error: "Error description if any"
/connection:
get:
tags:

View file

@ -277,6 +277,24 @@ Output:
}
```
### Get provider status
Command:
```
python sftpgo_api_cli.py get-provider-status
```
Output:
```json
{
"error": "",
"message": "Alive",
"status": 200
}
```
### Colors highlight for Windows command prompt
If your Windows command prompt does not recognize ANSI/VT100 escape sequences you can download [ANSICON](https://github.com/adoxa/ansicon "ANSICON") extract proper files depending on your Windows OS, and install them using `ansicon -i`.

View file

@ -25,6 +25,7 @@ class SFTPGoApiRequests:
self.quotaScanPath = urlparse.urljoin(baseUrl, '/api/v1/quota_scan')
self.activeConnectionsPath = urlparse.urljoin(baseUrl, '/api/v1/connection')
self.versionPath = urlparse.urljoin(baseUrl, '/api/v1/version')
self.providerStatusPath = urlparse.urljoin(baseUrl, '/api/v1/providerstatus')
self.debug = debug
if authType == 'basic':
self.auth = requests.auth.HTTPBasicAuth(authUser, authPassword)
@ -125,6 +126,10 @@ class SFTPGoApiRequests:
r = requests.get(self.versionPath, auth=self.auth, verify=self.verify)
self.printResponse(r)
def getProviderStatus(self):
r = requests.get(self.providerStatusPath, auth=self.auth, verify=self.verify)
self.printResponse(r)
def validDate(s):
if not s:
@ -222,6 +227,8 @@ if __name__ == '__main__':
parserGetVersion = subparsers.add_parser('get-version', help='Get version details')
parserGetProviderStatus = subparsers.add_parser('get-provider-status', help='Get data provider status')
args = parser.parse_args()
api = SFTPGoApiRequests(args.debug, args.base_url, args.auth_type, args.auth_user, args.auth_password, args.secure,
@ -251,4 +258,6 @@ if __name__ == '__main__':
api.startQuotaScan(args.username)
elif args.command == 'get-version':
api.getVersion()
elif args.command == 'get-provider-status':
api.getProviderStatus()