add /v2/casaos/health/ports to get ports in use (#1023)
Signed-off-by: Tiger Wang <tigerwang@outlook.com>
This commit is contained in:
parent
af440eac55
commit
8e1b9b82c1
8 changed files with 191 additions and 20 deletions
|
@ -47,6 +47,19 @@ paths:
|
|||
$ref: "#/components/responses/GetHealthServicesOK"
|
||||
"500":
|
||||
$ref: "#/components/responses/ResponseInternalServerError"
|
||||
|
||||
/health/ports:
|
||||
get:
|
||||
tags:
|
||||
- Health methods
|
||||
summary: Get port in use
|
||||
operationId: getHealthPorts
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/GetHealthPortsOK"
|
||||
"500":
|
||||
$ref: "#/components/responses/ResponseInternalServerError"
|
||||
|
||||
/file/test:
|
||||
get:
|
||||
tags:
|
||||
|
@ -93,6 +106,17 @@ components:
|
|||
data:
|
||||
$ref: "#/components/schemas/HealthServices"
|
||||
|
||||
GetHealthPortsOK:
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/BaseResponse"
|
||||
- properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/HealthPorts"
|
||||
|
||||
schemas:
|
||||
BaseResponse:
|
||||
properties:
|
||||
|
@ -114,3 +138,18 @@ components:
|
|||
items:
|
||||
type: string
|
||||
example: "casaos.service"
|
||||
|
||||
HealthPorts:
|
||||
properties:
|
||||
tcp:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
example: 80
|
||||
x-go-name: TCP
|
||||
udp:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
example: 53
|
||||
x-go-name: UDP
|
||||
|
|
|
@ -26,12 +26,26 @@ type BaseResponse struct {
|
|||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// HealthPorts defines model for HealthPorts.
|
||||
type HealthPorts struct {
|
||||
TCP *[]int `json:"tcp,omitempty"`
|
||||
UDP *[]int `json:"udp,omitempty"`
|
||||
}
|
||||
|
||||
// HealthServices defines model for HealthServices.
|
||||
type HealthServices struct {
|
||||
NotRunning *[]string `json:"not_running,omitempty"`
|
||||
Running *[]string `json:"running,omitempty"`
|
||||
}
|
||||
|
||||
// GetHealthPortsOK defines model for GetHealthPortsOK.
|
||||
type GetHealthPortsOK struct {
|
||||
Data *HealthPorts `json:"data,omitempty"`
|
||||
|
||||
// Message message returned by server side if there is any
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// GetHealthServicesOK defines model for GetHealthServicesOK.
|
||||
type GetHealthServicesOK struct {
|
||||
Data *HealthServices `json:"data,omitempty"`
|
||||
|
@ -51,6 +65,9 @@ type ServerInterface interface {
|
|||
// Test file methods
|
||||
// (GET /file/test)
|
||||
GetFileTest(ctx echo.Context) error
|
||||
// Get port in use
|
||||
// (GET /health/ports)
|
||||
GetHealthPorts(ctx echo.Context) error
|
||||
// Get service status
|
||||
// (GET /health/services)
|
||||
GetHealthServices(ctx echo.Context) error
|
||||
|
@ -72,6 +89,17 @@ func (w *ServerInterfaceWrapper) GetFileTest(ctx echo.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// GetHealthPorts converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) GetHealthPorts(ctx echo.Context) error {
|
||||
var err error
|
||||
|
||||
ctx.Set(Access_tokenScopes, []string{""})
|
||||
|
||||
// Invoke the callback with all the unmarshalled arguments
|
||||
err = w.Handler.GetHealthPorts(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetHealthServices converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) GetHealthServices(ctx echo.Context) error {
|
||||
var err error
|
||||
|
@ -112,6 +140,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
|||
}
|
||||
|
||||
router.GET(baseURL+"/file/test", wrapper.GetFileTest)
|
||||
router.GET(baseURL+"/health/ports", wrapper.GetHealthPorts)
|
||||
router.GET(baseURL+"/health/services", wrapper.GetHealthServices)
|
||||
|
||||
}
|
||||
|
@ -119,22 +148,24 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
|||
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||
var swaggerSpec = []string{
|
||||
|
||||
"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",
|
||||
"BwAA///xoj5w+wwAAA==",
|
||||
}
|
||||
|
||||
// GetSwagger returns the content of the embedded swagger specification file
|
||||
|
|
7
go.mod
7
go.mod
|
@ -33,15 +33,18 @@ require (
|
|||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/samber/lo v1.38.1
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/shirou/gopsutil/v3 v3.23.2
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
go.uber.org/goleak v1.2.1
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/crypto v0.7.0
|
||||
golang.org/x/oauth2 v0.6.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/sys v0.6.0
|
||||
gorm.io/gorm v1.24.6
|
||||
gotest.tools v2.2.0+incompatible
|
||||
)
|
||||
|
@ -53,6 +56,7 @@ require (
|
|||
github.com/bytedance/sonic v1.8.5 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect
|
||||
|
@ -100,6 +104,7 @@ require (
|
|||
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.4 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
|
@ -116,9 +121,9 @@ require (
|
|||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.10.0 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
|
||||
golang.org/x/image v0.6.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
|
|
4
go.sum
4
go.sum
|
@ -255,6 +255,8 @@ github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6po
|
|||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ=
|
||||
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU=
|
||||
|
@ -324,6 +326,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
|||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
|
||||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4=
|
||||
golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0=
|
||||
|
|
|
@ -71,10 +71,10 @@ func InitV2Router() http.Handler {
|
|||
e.Use(echo_middleware.JWTWithConfig(echo_middleware.JWTConfig{
|
||||
Skipper: func(c echo.Context) bool {
|
||||
return c.RealIP() == "::1" || c.RealIP() == "127.0.0.1"
|
||||
//return true
|
||||
// return true
|
||||
},
|
||||
ParseTokenFunc: func(token string, c echo.Context) (interface{}, error) {
|
||||
claims, code := jwt.Validate(token)
|
||||
claims, code := jwt.Validate(token) // TODO - needs JWT validation
|
||||
if code != common_err.SUCCESS {
|
||||
return nil, echo.ErrUnauthorized
|
||||
}
|
||||
|
@ -137,6 +137,7 @@ func InitV2DocRouter(docHTML string, docYAML string) http.Handler {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func InitFile() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
filePath := r.URL.Query().Get("path")
|
||||
|
@ -174,7 +175,7 @@ func InitDir() http.Handler {
|
|||
// handles only single files not folders and multiple files
|
||||
// if len(list) == 1 {
|
||||
|
||||
//filePath := list[0]
|
||||
// filePath := list[0]
|
||||
// info, err := os.Stat(filePath)
|
||||
// if err != nil {
|
||||
|
||||
|
|
|
@ -24,3 +24,20 @@ func (s *CasaOS) GetHealthServices(ctx echo.Context) error {
|
|||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *CasaOS) GetHealthPorts(ctx echo.Context) error {
|
||||
tcpPorts, udpPorts, err := service.MyService.Health().Ports()
|
||||
if err != nil {
|
||||
message := err.Error()
|
||||
return ctx.JSON(http.StatusInternalServerError, codegen.ResponseInternalServerError{
|
||||
Message: &message,
|
||||
})
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, codegen.GetHealthPortsOK{
|
||||
Data: &codegen.HealthPorts{
|
||||
TCP: &tcpPorts,
|
||||
UDP: &udpPorts,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS-Common/utils/systemctl"
|
||||
)
|
||||
|
||||
type HealthService interface {
|
||||
Services() (map[bool]*[]string, error)
|
||||
Ports() ([]int, []int, error)
|
||||
}
|
||||
|
||||
type service struct{}
|
||||
|
@ -34,6 +44,52 @@ func (s *service) Services() (map[bool]*[]string, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (s *service) Ports() ([]int, []int, error) {
|
||||
usedPorts := map[string]map[int]struct{}{
|
||||
"tcp": {},
|
||||
"udp": {},
|
||||
}
|
||||
|
||||
for _, protocol := range []string{"tcp", "udp"} {
|
||||
filename := fmt.Sprintf("/proc/net/%s", protocol)
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, nil, errors.New("Failed to open " + filename)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
localAddress := fields[1]
|
||||
addressParts := strings.Split(localAddress, ":")
|
||||
if len(addressParts) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
portHex := addressParts[1]
|
||||
port, err := strconv.ParseInt(portHex, 16, 0)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
usedPorts[protocol][int(port)] = struct{}{}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, nil, errors.New("Error reading from " + filename)
|
||||
}
|
||||
}
|
||||
|
||||
return lo.Keys(usedPorts["tcp"]), lo.Keys(usedPorts["udp"]), nil
|
||||
}
|
||||
|
||||
func NewHealthService() HealthService {
|
||||
return &service{}
|
||||
}
|
||||
|
|
18
service/health_test.go
Normal file
18
service/health_test.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package service_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/IceWhaleTech/CasaOS/service"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPorts(t *testing.T) {
|
||||
service := service.NewHealthService()
|
||||
|
||||
tcpPorts, udpPorts, err := service.Ports()
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.NotEmpty(t, tcpPorts)
|
||||
assert.NotEmpty(t, udpPorts)
|
||||
}
|
Loading…
Reference in a new issue