Code cleanup for remote client
This commit is contained in:
parent
e3b0b91912
commit
065da77afa
|
@ -137,11 +137,12 @@ func rootCmdRun(cmd *cobra.Command, _ []string) {
|
|||
"gid": config.Get().System.User.Gid,
|
||||
}).Info("configured system user successfully")
|
||||
|
||||
pclient := remote.CreateClient(
|
||||
pclient := remote.New(
|
||||
config.Get().PanelLocation,
|
||||
config.Get().AuthenticationTokenId,
|
||||
config.Get().AuthenticationToken,
|
||||
remote.WithTimeout(time.Second*time.Duration(config.Get().RemoteQuery.Timeout)),
|
||||
remote.WithCredentials(config.Get().AuthenticationTokenId, config.Get().AuthenticationToken),
|
||||
remote.WithHttpClient(&http.Client{
|
||||
Timeout: time.Second * time.Duration(config.Get().RemoteQuery.Timeout),
|
||||
}),
|
||||
)
|
||||
|
||||
manager, err := server.NewManager(cmd.Context(), pclient)
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
package remote
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (c *client) GetBackupRemoteUploadURLs(ctx context.Context, backup string, size int64) (BackupRemoteUploadResponse, error) {
|
||||
var data BackupRemoteUploadResponse
|
||||
res, err := c.get(ctx, fmt.Sprintf("/backups/%s", backup), q{"size": strconv.FormatInt(size, 10)})
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.HasError() {
|
||||
return data, res.Error()
|
||||
}
|
||||
|
||||
err = res.BindJSON(&data)
|
||||
return data, err
|
||||
}
|
||||
|
||||
func (c *client) SetBackupStatus(ctx context.Context, backup string, data BackupRequest) error {
|
||||
resp, err := c.post(ctx, fmt.Sprintf("/backups/%s", backup), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return resp.Error()
|
||||
}
|
||||
|
||||
|
||||
// SendRestorationStatus triggers a request to the Panel to notify it that a
|
||||
// restoration has been completed and the server should be marked as being
|
||||
// activated again.
|
||||
func (c *client) SendRestorationStatus(ctx context.Context, backup string, successful bool) error {
|
||||
resp, err := c.post(ctx, fmt.Sprintf("/backups/%s/restore", backup), d{"successful": successful})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return resp.Error()
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package remote
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
GetBackupRemoteUploadURLs(ctx context.Context, backup string, size int64) (BackupRemoteUploadResponse, error)
|
||||
GetInstallationScript(ctx context.Context, uuid string) (InstallationScript, error)
|
||||
GetServerConfiguration(ctx context.Context, uuid string) (ServerConfigurationResponse, error)
|
||||
GetServers(context context.Context, perPage int) ([]RawServerData, error)
|
||||
SetArchiveStatus(ctx context.Context, uuid string, successful bool) error
|
||||
SetBackupStatus(ctx context.Context, backup string, data BackupRequest) error
|
||||
SendRestorationStatus(ctx context.Context, backup string, successful bool) error
|
||||
SetInstallationStatus(ctx context.Context, uuid string, successful bool) error
|
||||
SetTransferStatus(ctx context.Context, uuid string, successful bool) error
|
||||
ValidateSftpCredentials(ctx context.Context, request SftpAuthRequest) (SftpAuthResponse, error)
|
||||
}
|
||||
|
||||
type client struct {
|
||||
httpClient *http.Client
|
||||
baseUrl string
|
||||
tokenId string
|
||||
token string
|
||||
retries int
|
||||
}
|
||||
|
||||
type ClientOption func(c *client)
|
||||
|
||||
func CreateClient(base, tokenId, token string, opts ...ClientOption) Client {
|
||||
httpClient := &http.Client{
|
||||
Timeout: time.Second * 15,
|
||||
}
|
||||
base = strings.TrimSuffix(base, "/")
|
||||
c := &client{
|
||||
baseUrl: base + "/api/remote",
|
||||
tokenId: tokenId,
|
||||
token: token,
|
||||
httpClient: httpClient,
|
||||
retries: 3,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(c)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func WithTimeout(timeout time.Duration) ClientOption {
|
||||
return func(c *client) {
|
||||
c.httpClient.Timeout = timeout
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package remote
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
)
|
||||
|
||||
func createTestClient(h http.HandlerFunc) (*client, *httptest.Server) {
|
||||
s := httptest.NewServer(h)
|
||||
c := &client{
|
||||
httpClient: s.Client(),
|
||||
baseUrl: s.URL,
|
||||
|
||||
retries: 1,
|
||||
tokenId: "testid",
|
||||
token: "testtoken",
|
||||
}
|
||||
return c, s
|
||||
}
|
105
remote/http.go
105
remote/http.go
|
@ -9,34 +9,65 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/pterodactyl/wings/system"
|
||||
)
|
||||
|
||||
// A generic type allowing for easy binding use when making requests to API
|
||||
// endpoints that only expect a singular argument or something that would not
|
||||
// benefit from being a typed struct.
|
||||
//
|
||||
// Inspired by gin.H, same concept.
|
||||
type d map[string]interface{}
|
||||
|
||||
// Same concept as d, but a map of strings, used for querying GET requests.
|
||||
type q map[string]string
|
||||
|
||||
// Response is a custom response type that allows for commonly used error
|
||||
// handling and response parsing from the Panel API. This just embeds the normal
|
||||
// HTTP response from Go and we attach a few helper functions to it.
|
||||
type Response struct {
|
||||
*http.Response
|
||||
type Client interface {
|
||||
GetBackupRemoteUploadURLs(ctx context.Context, backup string, size int64) (BackupRemoteUploadResponse, error)
|
||||
GetInstallationScript(ctx context.Context, uuid string) (InstallationScript, error)
|
||||
GetServerConfiguration(ctx context.Context, uuid string) (ServerConfigurationResponse, error)
|
||||
GetServers(context context.Context, perPage int) ([]RawServerData, error)
|
||||
SetArchiveStatus(ctx context.Context, uuid string, successful bool) error
|
||||
SetBackupStatus(ctx context.Context, backup string, data BackupRequest) error
|
||||
SendRestorationStatus(ctx context.Context, backup string, successful bool) error
|
||||
SetInstallationStatus(ctx context.Context, uuid string, successful bool) error
|
||||
SetTransferStatus(ctx context.Context, uuid string, successful bool) error
|
||||
ValidateSftpCredentials(ctx context.Context, request SftpAuthRequest) (SftpAuthResponse, error)
|
||||
}
|
||||
|
||||
type Pagination struct {
|
||||
CurrentPage uint `json:"current_page"`
|
||||
From uint `json:"from"`
|
||||
LastPage uint `json:"last_page"`
|
||||
PerPage uint `json:"per_page"`
|
||||
To uint `json:"to"`
|
||||
Total uint `json:"total"`
|
||||
type client struct {
|
||||
httpClient *http.Client
|
||||
baseUrl string
|
||||
tokenId string
|
||||
token string
|
||||
retries int
|
||||
}
|
||||
|
||||
// New returns a new HTTP request client that is used for making authenticated
|
||||
// requests to the Panel that this instance is running under.
|
||||
func New(base string, opts ...ClientOption) Client {
|
||||
c := client{
|
||||
baseUrl: strings.TrimSuffix(base, "/") + "/api/remote",
|
||||
httpClient: &http.Client{
|
||||
Timeout: time.Second * 15,
|
||||
},
|
||||
retries: 3,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(&c)
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
||||
// WithCredentials sets the credentials to use when making request to the remote
|
||||
// API endpoint.
|
||||
func WithCredentials(id, token string) ClientOption {
|
||||
return func(c *client) {
|
||||
c.tokenId = id
|
||||
c.token = token
|
||||
}
|
||||
}
|
||||
|
||||
// WithHttpClient sets the underlying HTTP client instance to use when making
|
||||
// requests to the Panel API.
|
||||
func WithHttpClient(httpClient *http.Client) ClientOption {
|
||||
return func(c *client) {
|
||||
c.httpClient = httpClient
|
||||
}
|
||||
}
|
||||
|
||||
// requestOnce creates a http request and executes it once. Prefer request()
|
||||
|
@ -103,6 +134,13 @@ func (c *client) post(ctx context.Context, path string, data interface{}) (*Resp
|
|||
return c.request(ctx, http.MethodPost, path, bytes.NewBuffer(b))
|
||||
}
|
||||
|
||||
// Response is a custom response type that allows for commonly used error
|
||||
// handling and response parsing from the Panel API. This just embeds the normal
|
||||
// HTTP response from Go and we attach a few helper functions to it.
|
||||
type Response struct {
|
||||
*http.Response
|
||||
}
|
||||
|
||||
// HasError determines if the API call encountered an error. If no request has
|
||||
// been made the response will be false. This function will evaluate to true if
|
||||
// the response code is anything 300 or higher.
|
||||
|
@ -165,3 +203,26 @@ func (r *Response) Error() error {
|
|||
|
||||
return e
|
||||
}
|
||||
|
||||
// Logs the request into the debug log with all of the important request bits.
|
||||
// The authorization key will be cleaned up before being output.
|
||||
func debugLogRequest(req *http.Request) {
|
||||
if l, ok := log.Log.(*log.Logger); ok && l.Level != log.DebugLevel {
|
||||
return
|
||||
}
|
||||
headers := make(map[string][]string)
|
||||
for k, v := range req.Header {
|
||||
if k != "Authorization" || len(v) == 0 || len(v[0]) == 0 {
|
||||
headers[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
headers[k] = []string{"(redacted)"}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"method": req.Method,
|
||||
"endpoint": req.URL.String(),
|
||||
"headers": headers,
|
||||
}).Debug("making request to external HTTP endpoint")
|
||||
}
|
||||
|
|
|
@ -3,11 +3,25 @@ package remote
|
|||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func createTestClient(h http.HandlerFunc) (*client, *httptest.Server) {
|
||||
s := httptest.NewServer(h)
|
||||
c := &client{
|
||||
httpClient: s.Client(),
|
||||
baseUrl: s.URL,
|
||||
|
||||
retries: 1,
|
||||
tokenId: "testid",
|
||||
token: "testtoken",
|
||||
}
|
||||
return c, s
|
||||
}
|
||||
|
||||
func TestRequest(t *testing.T) {
|
||||
c, _ := createTestClient(func(rw http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "application/vnd.pterodactyl.v1+json", r.Header.Get("Accept"))
|
||||
|
|
|
@ -144,6 +144,44 @@ func (c *client) ValidateSftpCredentials(ctx context.Context, request SftpAuthRe
|
|||
return auth, err
|
||||
}
|
||||
|
||||
func (c *client) GetBackupRemoteUploadURLs(ctx context.Context, backup string, size int64) (BackupRemoteUploadResponse, error) {
|
||||
var data BackupRemoteUploadResponse
|
||||
res, err := c.get(ctx, fmt.Sprintf("/backups/%s", backup), q{"size": strconv.FormatInt(size, 10)})
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.HasError() {
|
||||
return data, res.Error()
|
||||
}
|
||||
|
||||
err = res.BindJSON(&data)
|
||||
return data, err
|
||||
}
|
||||
|
||||
func (c *client) SetBackupStatus(ctx context.Context, backup string, data BackupRequest) error {
|
||||
resp, err := c.post(ctx, fmt.Sprintf("/backups/%s", backup), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return resp.Error()
|
||||
}
|
||||
|
||||
|
||||
// SendRestorationStatus triggers a request to the Panel to notify it that a
|
||||
// restoration has been completed and the server should be marked as being
|
||||
// activated again.
|
||||
func (c *client) SendRestorationStatus(ctx context.Context, backup string, successful bool) error {
|
||||
resp, err := c.post(ctx, fmt.Sprintf("/backups/%s/restore", backup), d{"successful": successful})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
return resp.Error()
|
||||
}
|
||||
|
||||
// getServersPaged returns a subset of servers from the Panel API using the
|
||||
// pagination query parameters.
|
||||
func (c *client) getServersPaged(ctx context.Context, page, limit int) ([]RawServerData, Pagination, error) {
|
||||
|
|
|
@ -9,6 +9,27 @@ import (
|
|||
"github.com/pterodactyl/wings/parser"
|
||||
)
|
||||
|
||||
// A generic type allowing for easy binding use when making requests to API
|
||||
// endpoints that only expect a singular argument or something that would not
|
||||
// benefit from being a typed struct.
|
||||
//
|
||||
// Inspired by gin.H, same concept.
|
||||
type d map[string]interface{}
|
||||
|
||||
// Same concept as d, but a map of strings, used for querying GET requests.
|
||||
type q map[string]string
|
||||
|
||||
type ClientOption func(c *client)
|
||||
|
||||
type Pagination struct {
|
||||
CurrentPage uint `json:"current_page"`
|
||||
From uint `json:"from"`
|
||||
LastPage uint `json:"last_page"`
|
||||
PerPage uint `json:"per_page"`
|
||||
To uint `json:"to"`
|
||||
Total uint `json:"total"`
|
||||
}
|
||||
|
||||
// ServerConfigurationResponse holds the server configuration data returned from
|
||||
// the Panel. When a server process is started, Wings communicates with the
|
||||
// Panel to fetch the latest build information as well as get all of the details
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
package remote
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/apex/log"
|
||||
)
|
||||
|
||||
// Logs the request into the debug log with all of the important request bits.
|
||||
// The authorization key will be cleaned up before being output.
|
||||
func debugLogRequest(req *http.Request) {
|
||||
if l, ok := log.Log.(*log.Logger); ok && l.Level != log.DebugLevel {
|
||||
return
|
||||
}
|
||||
headers := make(map[string][]string)
|
||||
for k, v := range req.Header {
|
||||
if k != "Authorization" || len(v) == 0 || len(v[0]) == 0 {
|
||||
headers[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
headers[k] = []string{"(redacted)"}
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"method": req.Method,
|
||||
"endpoint": req.URL.String(),
|
||||
"headers": headers,
|
||||
}).Debug("making request to external HTTP endpoint")
|
||||
}
|
Loading…
Reference in New Issue
Block a user