mirror of
https://gitlab.com/psuapp/psu.git
synced 2024-08-30 18:12:34 +00:00
Merge branch 'refactoring-and-tests'
This commit is contained in:
commit
5c9de76d5f
129
client/client.go
129
client/client.go
@ -13,13 +13,15 @@ import (
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
)
|
||||
|
||||
// StackListFilter represents a filter for a stack list
|
||||
type StackListFilter struct {
|
||||
SwarmId string `json:",omitempty"`
|
||||
EndpointId portainer.EndpointID `json:",omitempty"`
|
||||
SwarmID string `json:"SwarmId,omitempty"`
|
||||
EndpointID portainer.EndpointID `json:"EndpointId,omitempty"`
|
||||
}
|
||||
|
||||
// Config represents a Portainer client configuration
|
||||
type Config struct {
|
||||
Url *url.URL
|
||||
URL *url.URL
|
||||
User string
|
||||
Password string
|
||||
Token string
|
||||
@ -27,6 +29,7 @@ type Config struct {
|
||||
DoNotUseToken bool
|
||||
}
|
||||
|
||||
// PortainerClient represents a Portainer API client
|
||||
type PortainerClient interface {
|
||||
// Authenticate a user to get an auth token
|
||||
Authenticate() (token string, err error)
|
||||
@ -38,25 +41,25 @@ type PortainerClient interface {
|
||||
GetEndpointGroups() ([]portainer.EndpointGroup, error)
|
||||
|
||||
// Get stacks, optionally filtered by swarmId and endpointId
|
||||
GetStacks(swarmId string, endpointId portainer.EndpointID) ([]portainer.Stack, error)
|
||||
GetStacks(swarmID string, endpointID portainer.EndpointID) ([]portainer.Stack, error)
|
||||
|
||||
// Create swarm stack
|
||||
CreateSwarmStack(stackName string, environmentVariables []portainer.Pair, stackFileContent string, swarmClusterId string, endpointId portainer.EndpointID) (stack portainer.Stack, err error)
|
||||
CreateSwarmStack(stackName string, environmentVariables []portainer.Pair, stackFileContent string, swarmClusterID string, endpointID portainer.EndpointID) (stack portainer.Stack, err error)
|
||||
|
||||
// Create compose stack
|
||||
CreateComposeStack(stackName string, environmentVariables []portainer.Pair, stackFileContent string, endpointId portainer.EndpointID) (stack portainer.Stack, err error)
|
||||
CreateComposeStack(stackName string, environmentVariables []portainer.Pair, stackFileContent string, endpointID portainer.EndpointID) (stack portainer.Stack, err error)
|
||||
|
||||
// Update stack
|
||||
UpdateStack(stack portainer.Stack, environmentVariables []portainer.Pair, stackFileContent string, prune bool, endpointId portainer.EndpointID) error
|
||||
UpdateStack(stack portainer.Stack, environmentVariables []portainer.Pair, stackFileContent string, prune bool, endpointID portainer.EndpointID) error
|
||||
|
||||
// Delete stack
|
||||
DeleteStack(stackId portainer.StackID) error
|
||||
DeleteStack(stackID portainer.StackID) error
|
||||
|
||||
// Get stack file content
|
||||
GetStackFileContent(stackId portainer.StackID) (content string, err error)
|
||||
GetStackFileContent(stackID portainer.StackID) (content string, err error)
|
||||
|
||||
// Get endpoint Docker info
|
||||
GetEndpointDockerInfo(endpointId portainer.EndpointID) (info map[string]interface{}, err error)
|
||||
GetEndpointDockerInfo(endpointID portainer.EndpointID) (info map[string]interface{}, err error)
|
||||
|
||||
// Get Portainer status info
|
||||
GetStatus() (portainer.Status, error)
|
||||
@ -75,7 +78,6 @@ type portainerClientImp struct {
|
||||
password string
|
||||
token string
|
||||
userAgent string
|
||||
doNotUseToken bool
|
||||
beforeRequestHooks []func(req *http.Request) (err error)
|
||||
afterResponseHooks []func(resp *http.Response) (err error)
|
||||
}
|
||||
@ -102,13 +104,13 @@ func checkResponseForErrors(resp *http.Response) error {
|
||||
}
|
||||
|
||||
// Do an http request
|
||||
func (n *portainerClientImp) do(uri, method string, request io.Reader, requestType string, headers http.Header) (resp *http.Response, err error) {
|
||||
requestUrl, err := n.url.Parse(uri)
|
||||
func (n *portainerClientImp) do(uri, method string, requestBody io.Reader, headers http.Header) (resp *http.Response, err error) {
|
||||
requestURL, err := n.url.Parse(uri)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, requestUrl.String(), request)
|
||||
req, err := http.NewRequest(method, requestURL.String(), requestBody)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -117,20 +119,8 @@ func (n *portainerClientImp) do(uri, method string, request io.Reader, requestTy
|
||||
req.Header = headers
|
||||
}
|
||||
|
||||
if request != nil {
|
||||
req.Header.Set("Content-Type", requestType)
|
||||
req.Header.Set("User-Agent", n.userAgent)
|
||||
}
|
||||
|
||||
if !n.doNotUseToken {
|
||||
if n.token == "" {
|
||||
n.token, err = n.Authenticate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+n.token)
|
||||
}
|
||||
// Set user agent header
|
||||
req.Header.Set("User-Agent", n.userAgent)
|
||||
|
||||
// Run all "before request" hooks
|
||||
for i := 0; i < len(n.beforeRequestHooks); i++ {
|
||||
@ -162,25 +152,27 @@ func (n *portainerClientImp) do(uri, method string, request io.Reader, requestTy
|
||||
}
|
||||
|
||||
// Do a JSON http request
|
||||
func (n *portainerClientImp) doJSON(uri, method string, request interface{}, response interface{}) error {
|
||||
func (n *portainerClientImp) doJSON(uri, method string, headers http.Header, requestBody interface{}, responseBody interface{}) error {
|
||||
var body io.Reader
|
||||
|
||||
if request != nil {
|
||||
reqBodyBytes, err := json.Marshal(request)
|
||||
if requestBody != nil {
|
||||
reqBodyBytes, err := json.Marshal(requestBody)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body = bytes.NewReader(reqBodyBytes)
|
||||
}
|
||||
|
||||
resp, err := n.do(uri, method, body, "application/json", nil)
|
||||
headers.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := n.do(uri, method, body, headers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if response != nil {
|
||||
if responseBody != nil {
|
||||
d := json.NewDecoder(resp.Body)
|
||||
err := d.Decode(response)
|
||||
err := d.Decode(responseBody)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -189,6 +181,20 @@ func (n *portainerClientImp) doJSON(uri, method string, request interface{}, res
|
||||
return nil
|
||||
}
|
||||
|
||||
// Do a JSON http request with an auth token
|
||||
func (n *portainerClientImp) doJSONWithToken(uri, method string, headers http.Header, request interface{}, response interface{}) (err error) {
|
||||
// Ensure there is an auth token
|
||||
if n.token == "" {
|
||||
n.token, err = n.Authenticate()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
headers.Set("Authorization", "Bearer "+n.token)
|
||||
|
||||
return n.doJSON(uri, method, headers, request, response)
|
||||
}
|
||||
|
||||
func (n *portainerClientImp) BeforeRequest(hook func(req *http.Request) (err error)) {
|
||||
n.beforeRequestHooks = append(n.beforeRequestHooks, hook)
|
||||
}
|
||||
@ -205,87 +211,82 @@ func (n *portainerClientImp) Authenticate() (token string, err error) {
|
||||
|
||||
respBody := AuthenticateUserResponse{}
|
||||
|
||||
previousDoNotUseTokenValue := n.doNotUseToken
|
||||
n.doNotUseToken = true
|
||||
|
||||
err = n.doJSON("auth", http.MethodPost, &reqBody, &respBody)
|
||||
err = n.doJSON("auth", http.MethodPost, http.Header{}, &reqBody, &respBody)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
n.doNotUseToken = previousDoNotUseTokenValue
|
||||
|
||||
token = respBody.Jwt
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (n *portainerClientImp) GetEndpoints() (endpoints []portainer.Endpoint, err error) {
|
||||
err = n.doJSON("endpoints", http.MethodGet, nil, &endpoints)
|
||||
err = n.doJSONWithToken("endpoints", http.MethodGet, http.Header{}, nil, &endpoints)
|
||||
return
|
||||
}
|
||||
|
||||
func (n *portainerClientImp) GetEndpointGroups() (endpointGroups []portainer.EndpointGroup, err error) {
|
||||
err = n.doJSON("endpoint_groups", http.MethodGet, nil, &endpointGroups)
|
||||
err = n.doJSONWithToken("endpoint_groups", http.MethodGet, http.Header{}, nil, &endpointGroups)
|
||||
return
|
||||
}
|
||||
|
||||
func (n *portainerClientImp) GetStacks(swarmId string, endpointId portainer.EndpointID) (stacks []portainer.Stack, err error) {
|
||||
func (n *portainerClientImp) GetStacks(swarmID string, endpointID portainer.EndpointID) (stacks []portainer.Stack, err error) {
|
||||
filter := StackListFilter{
|
||||
SwarmId: swarmId,
|
||||
EndpointId: endpointId,
|
||||
SwarmID: swarmID,
|
||||
EndpointID: endpointID,
|
||||
}
|
||||
|
||||
filterJsonBytes, _ := json.Marshal(filter)
|
||||
filterJsonString := string(filterJsonBytes)
|
||||
filterJSONBytes, _ := json.Marshal(filter)
|
||||
filterJSONString := string(filterJSONBytes)
|
||||
|
||||
err = n.doJSON(fmt.Sprintf("stacks?filters=%s", filterJsonString), http.MethodGet, nil, &stacks)
|
||||
err = n.doJSONWithToken(fmt.Sprintf("stacks?filters=%s", filterJSONString), http.MethodGet, http.Header{}, nil, &stacks)
|
||||
return
|
||||
}
|
||||
|
||||
func (n *portainerClientImp) CreateSwarmStack(stackName string, environmentVariables []portainer.Pair, stackFileContent string, swarmClusterId string, endpointId portainer.EndpointID) (stack portainer.Stack, err error) {
|
||||
func (n *portainerClientImp) CreateSwarmStack(stackName string, environmentVariables []portainer.Pair, stackFileContent string, swarmClusterID string, endpointID portainer.EndpointID) (stack portainer.Stack, err error) {
|
||||
reqBody := StackCreateRequest{
|
||||
Name: stackName,
|
||||
Env: environmentVariables,
|
||||
SwarmID: swarmClusterId,
|
||||
SwarmID: swarmClusterID,
|
||||
StackFileContent: stackFileContent,
|
||||
}
|
||||
|
||||
err = n.doJSON(fmt.Sprintf("stacks?type=%v&method=%s&endpointId=%v", 1, "string", endpointId), http.MethodPost, &reqBody, &stack)
|
||||
err = n.doJSONWithToken(fmt.Sprintf("stacks?type=%v&method=%s&endpointId=%v", 1, "string", endpointID), http.MethodPost, http.Header{}, &reqBody, &stack)
|
||||
return
|
||||
}
|
||||
|
||||
func (n *portainerClientImp) CreateComposeStack(stackName string, environmentVariables []portainer.Pair, stackFileContent string, endpointId portainer.EndpointID) (stack portainer.Stack, err error) {
|
||||
func (n *portainerClientImp) CreateComposeStack(stackName string, environmentVariables []portainer.Pair, stackFileContent string, endpointID portainer.EndpointID) (stack portainer.Stack, err error) {
|
||||
reqBody := StackCreateRequest{
|
||||
Name: stackName,
|
||||
Env: environmentVariables,
|
||||
StackFileContent: stackFileContent,
|
||||
}
|
||||
|
||||
err = n.doJSON(fmt.Sprintf("stacks?type=%v&method=%s&endpointId=%v", 2, "string", endpointId), http.MethodPost, &reqBody, &stack)
|
||||
err = n.doJSONWithToken(fmt.Sprintf("stacks?type=%v&method=%s&endpointId=%v", 2, "string", endpointID), http.MethodPost, http.Header{}, &reqBody, &stack)
|
||||
return
|
||||
}
|
||||
|
||||
func (n *portainerClientImp) UpdateStack(stack portainer.Stack, environmentVariables []portainer.Pair, stackFileContent string, prune bool, endpointId portainer.EndpointID) (err error) {
|
||||
func (n *portainerClientImp) UpdateStack(stack portainer.Stack, environmentVariables []portainer.Pair, stackFileContent string, prune bool, endpointID portainer.EndpointID) (err error) {
|
||||
reqBody := StackUpdateRequest{
|
||||
Env: environmentVariables,
|
||||
StackFileContent: stackFileContent,
|
||||
Prune: prune,
|
||||
}
|
||||
|
||||
err = n.doJSON(fmt.Sprintf("stacks/%v?endpointId=%v", stack.ID, endpointId), http.MethodPut, &reqBody, nil)
|
||||
err = n.doJSONWithToken(fmt.Sprintf("stacks/%v?endpointId=%v", stack.ID, endpointID), http.MethodPut, http.Header{}, &reqBody, nil)
|
||||
return
|
||||
}
|
||||
|
||||
func (n *portainerClientImp) DeleteStack(stackId portainer.StackID) (err error) {
|
||||
err = n.doJSON(fmt.Sprintf("stacks/%d", stackId), http.MethodDelete, nil, nil)
|
||||
func (n *portainerClientImp) DeleteStack(stackID portainer.StackID) (err error) {
|
||||
err = n.doJSONWithToken(fmt.Sprintf("stacks/%d", stackID), http.MethodDelete, http.Header{}, nil, nil)
|
||||
return
|
||||
}
|
||||
|
||||
func (n *portainerClientImp) GetStackFileContent(stackId portainer.StackID) (content string, err error) {
|
||||
func (n *portainerClientImp) GetStackFileContent(stackID portainer.StackID) (content string, err error) {
|
||||
var respBody StackFileInspectResponse
|
||||
|
||||
err = n.doJSON(fmt.Sprintf("stacks/%v/file", stackId), http.MethodGet, nil, &respBody)
|
||||
err = n.doJSONWithToken(fmt.Sprintf("stacks/%v/file", stackID), http.MethodGet, http.Header{}, nil, &respBody)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -295,21 +296,21 @@ func (n *portainerClientImp) GetStackFileContent(stackId portainer.StackID) (con
|
||||
return
|
||||
}
|
||||
|
||||
func (n *portainerClientImp) GetEndpointDockerInfo(endpointId portainer.EndpointID) (info map[string]interface{}, err error) {
|
||||
err = n.doJSON(fmt.Sprintf("endpoints/%v/docker/info", endpointId), http.MethodGet, nil, &info)
|
||||
func (n *portainerClientImp) GetEndpointDockerInfo(endpointID portainer.EndpointID) (info map[string]interface{}, err error) {
|
||||
err = n.doJSONWithToken(fmt.Sprintf("endpoints/%v/docker/info", endpointID), http.MethodGet, http.Header{}, nil, &info)
|
||||
return
|
||||
}
|
||||
|
||||
func (n *portainerClientImp) GetStatus() (status portainer.Status, err error) {
|
||||
err = n.doJSON("status", http.MethodGet, nil, &status)
|
||||
err = n.doJSONWithToken("status", http.MethodGet, http.Header{}, nil, &status)
|
||||
return
|
||||
}
|
||||
|
||||
// Create a new client
|
||||
// NewClient creates a new Portainer API client
|
||||
func NewClient(httpClient *http.Client, config Config) PortainerClient {
|
||||
return &portainerClientImp{
|
||||
httpClient: httpClient,
|
||||
url: config.Url,
|
||||
url: config.URL,
|
||||
user: config.User,
|
||||
password: config.Password,
|
||||
token: config.Token,
|
||||
|
@ -1,8 +1,10 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@ -12,24 +14,24 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func readRequestBodyAsJson(req *http.Request, body *map[string]interface{}) (err error) {
|
||||
func readRequestBodyAsJSON(req *http.Request, body *map[string]interface{}) (err error) {
|
||||
bodyBytes, err := ioutil.ReadAll(req.Body)
|
||||
defer req.Body.Close()
|
||||
err = json.Unmarshal(bodyBytes, body)
|
||||
return
|
||||
}
|
||||
|
||||
func writeResponseBodyAsJson(w http.ResponseWriter, body map[string]interface{}) (err error) {
|
||||
func writeResponseBodyAsJSON(w http.ResponseWriter, body map[string]interface{}) (err error) {
|
||||
bodyBytes, err := json.Marshal(body)
|
||||
fmt.Fprintln(w, string(bodyBytes))
|
||||
return
|
||||
}
|
||||
|
||||
func TestNewClient(t *testing.T) {
|
||||
apiUrl, _ := url.Parse("http://validurl.com/api")
|
||||
apiURL, _ := url.Parse("http://validurl.com/api")
|
||||
|
||||
validClient := NewClient(http.DefaultClient, Config{
|
||||
Url: apiUrl,
|
||||
URL: apiURL,
|
||||
})
|
||||
assert.NotNil(t, validClient)
|
||||
}
|
||||
@ -37,7 +39,7 @@ func TestNewClient(t *testing.T) {
|
||||
func TestClientAuthenticates(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
var body map[string]interface{}
|
||||
err := readRequestBodyAsJson(req, &body)
|
||||
err := readRequestBodyAsJSON(req, &body)
|
||||
|
||||
assert.Equal(t, req.Method, http.MethodPost)
|
||||
assert.Equal(t, req.RequestURI, "/api/auth")
|
||||
@ -53,16 +55,16 @@ func TestClientAuthenticates(t *testing.T) {
|
||||
assert.NotNil(t, body["Password"])
|
||||
assert.Equal(t, body["Password"], "a")
|
||||
|
||||
writeResponseBodyAsJson(w, map[string]interface{}{
|
||||
writeResponseBodyAsJSON(w, map[string]interface{}{
|
||||
"jwt": "somerandomtoken",
|
||||
})
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
apiUrl, _ := url.Parse(ts.URL + "/api/")
|
||||
apiURL, _ := url.Parse(ts.URL + "/api/")
|
||||
|
||||
customClient := NewClient(ts.Client(), Config{
|
||||
Url: apiUrl,
|
||||
URL: apiURL,
|
||||
User: "admin",
|
||||
Password: "a",
|
||||
UserAgent: "GE007",
|
||||
@ -71,3 +73,161 @@ func TestClientAuthenticates(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, token, "somerandomtoken")
|
||||
}
|
||||
|
||||
func Test_portainerClientImp_do(t *testing.T) {
|
||||
type fields struct {
|
||||
user string
|
||||
password string
|
||||
token string
|
||||
userAgent string
|
||||
beforeRequestHooks []func(req *http.Request) (err error)
|
||||
afterResponseHooks []func(resp *http.Response) (err error)
|
||||
server *httptest.Server
|
||||
beforeFunctionCall func(t *testing.T, tt *fields)
|
||||
}
|
||||
type args struct {
|
||||
uri string
|
||||
method string
|
||||
requestBody io.Reader
|
||||
headers http.Header
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantRespCheck func(resp *http.Response) bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "error on bad URI",
|
||||
fields: fields{
|
||||
server: httptest.NewUnstartedServer(nil),
|
||||
},
|
||||
args: args{
|
||||
uri: string(0x7f),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "error on bad method",
|
||||
fields: fields{
|
||||
server: httptest.NewUnstartedServer(nil),
|
||||
},
|
||||
args: args{
|
||||
method: "WOLOLO?",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "extra headers are added",
|
||||
fields: fields{
|
||||
server: httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
assert.Equal(t, req.Header.Get("Some-Header"), "value")
|
||||
})),
|
||||
},
|
||||
args: args{
|
||||
headers: http.Header{
|
||||
"Some-Header": []string{
|
||||
"value",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "returns error on http error",
|
||||
fields: fields{
|
||||
token: "token",
|
||||
server: httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {})),
|
||||
beforeFunctionCall: func(t *testing.T, tt *fields) {
|
||||
tt.server.Close()
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "returns error on response error",
|
||||
fields: fields{
|
||||
server: httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
})),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.fields.server.Start()
|
||||
defer tt.fields.server.Close()
|
||||
|
||||
apiURL, _ := url.Parse(tt.fields.server.URL + "/api/")
|
||||
|
||||
n := &portainerClientImp{
|
||||
httpClient: tt.fields.server.Client(),
|
||||
url: apiURL,
|
||||
user: tt.fields.user,
|
||||
password: tt.fields.password,
|
||||
token: tt.fields.token,
|
||||
userAgent: tt.fields.userAgent,
|
||||
beforeRequestHooks: tt.fields.beforeRequestHooks,
|
||||
afterResponseHooks: tt.fields.afterResponseHooks,
|
||||
}
|
||||
|
||||
if tt.fields.beforeFunctionCall != nil {
|
||||
tt.fields.beforeFunctionCall(t, &tt.fields)
|
||||
}
|
||||
gotResp, err := n.do(tt.args.uri, tt.args.method, tt.args.requestBody, tt.args.headers)
|
||||
|
||||
assert.Equal(t, tt.wantErr, err != nil)
|
||||
if tt.wantRespCheck != nil {
|
||||
assert.True(t, tt.wantRespCheck(gotResp))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_checkResponseForErrors(t *testing.T) {
|
||||
type args struct {
|
||||
resp *http.Response
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "generic error",
|
||||
args: args{
|
||||
resp: func() (resp *http.Response) {
|
||||
resp = &http.Response{
|
||||
StatusCode: http.StatusNotFound,
|
||||
}
|
||||
bodyBytes, _ := json.Marshal(map[string]interface{}{
|
||||
"Err": "Error",
|
||||
"Details": "Not found",
|
||||
})
|
||||
resp.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))
|
||||
return
|
||||
}(),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "non generic error",
|
||||
args: args{
|
||||
resp: func() (resp *http.Response) {
|
||||
resp = &http.Response{
|
||||
StatusCode: http.StatusNotFound,
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte("Err"))),
|
||||
}
|
||||
return
|
||||
}(),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.wantErr, checkResponseForErrors(tt.args.resp) != nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -6,17 +6,19 @@ import (
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
)
|
||||
|
||||
func GetTranslatedStackType(s portainer.Stack) string {
|
||||
switch s.Type {
|
||||
case 1:
|
||||
// GetTranslatedStackType returns a stack's Type field (int) translated to it's human readable form (string)
|
||||
func GetTranslatedStackType(t portainer.StackType) string {
|
||||
switch t {
|
||||
case portainer.DockerSwarmStack:
|
||||
return "swarm"
|
||||
case 2:
|
||||
case portainer.DockerComposeStack:
|
||||
return "compose"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// StackCreateRequest represents the body of a request to POST /stacks
|
||||
type StackCreateRequest struct {
|
||||
Name string
|
||||
SwarmID string
|
||||
@ -24,16 +26,19 @@ type StackCreateRequest struct {
|
||||
Env []portainer.Pair `json:",omitempty"`
|
||||
}
|
||||
|
||||
// StackUpdateRequest represents the body of a request to PUT /stacks/{id}
|
||||
type StackUpdateRequest struct {
|
||||
StackFileContent string
|
||||
Env []portainer.Pair `json:",omitempty"`
|
||||
Prune bool
|
||||
}
|
||||
|
||||
// StackFileInspectResponse represents the body of a response for a request to GET /stack/{id}/file
|
||||
type StackFileInspectResponse struct {
|
||||
StackFileContent string
|
||||
}
|
||||
|
||||
// GenericError represents the body of a generic error returned by the Portainer API
|
||||
type GenericError struct {
|
||||
Err string
|
||||
Details string
|
||||
@ -42,16 +47,17 @@ type GenericError struct {
|
||||
func (e *GenericError) Error() string {
|
||||
if e.Details != "" {
|
||||
return fmt.Sprintf("%s: %s", e.Err, e.Details)
|
||||
} else {
|
||||
return fmt.Sprintf("%s", e.Err)
|
||||
}
|
||||
return fmt.Sprintf("%s", e.Err)
|
||||
}
|
||||
|
||||
// AuthenticateUserRequest represents the body of a request to POST /auth
|
||||
type AuthenticateUserRequest struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// AuthenticateUserResponse represents the body of a response for a request to POST /auth
|
||||
type AuthenticateUserResponse struct {
|
||||
Jwt string
|
||||
}
|
||||
|
95
client/portainerTypes_test.go
Normal file
95
client/portainerTypes_test.go
Normal file
@ -0,0 +1,95 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetTranslatedStackType(t *testing.T) {
|
||||
type args struct {
|
||||
t portainer.StackType
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "swarm stack type",
|
||||
args: args{
|
||||
t: portainer.DockerSwarmStack,
|
||||
},
|
||||
want: "swarm",
|
||||
},
|
||||
{
|
||||
name: "compose stack type",
|
||||
args: args{
|
||||
t: portainer.DockerComposeStack,
|
||||
},
|
||||
want: "compose",
|
||||
},
|
||||
{
|
||||
name: "unknown stack type",
|
||||
args: args{
|
||||
t: 100,
|
||||
},
|
||||
want: "",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.want, GetTranslatedStackType(tt.args.t))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenericError_Error(t *testing.T) {
|
||||
type fields struct {
|
||||
Err string
|
||||
Details string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "error with message and details",
|
||||
fields: fields{
|
||||
Err: "error",
|
||||
Details: "details",
|
||||
},
|
||||
want: "error: details",
|
||||
},
|
||||
{
|
||||
name: "error with message and no details",
|
||||
fields: fields{
|
||||
Err: "error",
|
||||
},
|
||||
want: "error",
|
||||
},
|
||||
{
|
||||
name: "error with no error message and details",
|
||||
fields: fields{
|
||||
Details: "details",
|
||||
},
|
||||
want: ": details",
|
||||
},
|
||||
{
|
||||
name: "error with no error message and no details",
|
||||
fields: fields{},
|
||||
want: "",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
e := &GenericError{
|
||||
Err: tt.fields.Err,
|
||||
Details: tt.fields.Details,
|
||||
}
|
||||
assert.Equal(t, tt.want, e.Error())
|
||||
})
|
||||
}
|
||||
}
|
@ -77,9 +77,9 @@ var configListCmd = &cobra.Command{
|
||||
common.CheckError(flushErr)
|
||||
case "json":
|
||||
// Print configs in a json format
|
||||
statusJsonBytes, err := json.Marshal(configs)
|
||||
statusJSONBytes, err := json.Marshal(configs)
|
||||
common.CheckError(err)
|
||||
fmt.Println(string(statusJsonBytes))
|
||||
fmt.Println(string(statusJSONBytes))
|
||||
default:
|
||||
// Print configs in a custom format
|
||||
template, templateParsingErr := template.New("configTpl").Parse(viper.GetString("config.list.format"))
|
||||
|
@ -44,9 +44,9 @@ var endpointGroupInspectCmd = &cobra.Command{
|
||||
common.CheckError(err)
|
||||
case "json":
|
||||
// Print endpoint group in a json format
|
||||
endpointJsonBytes, err := json.Marshal(endpointGroup)
|
||||
endpointJSONBytes, err := json.Marshal(endpointGroup)
|
||||
common.CheckError(err)
|
||||
fmt.Println(string(endpointJsonBytes))
|
||||
fmt.Println(string(endpointJSONBytes))
|
||||
default:
|
||||
// Print endpoint group in a custom format
|
||||
template, err := template.New("endpointGroupTpl").Parse(viper.GetString("endpoint.group.inspect.format"))
|
||||
|
@ -55,9 +55,9 @@ var endpointGroupListCmd = &cobra.Command{
|
||||
common.CheckError(flushErr)
|
||||
case "json":
|
||||
// Print endpoint groups in a json format
|
||||
statusJsonBytes, err := json.Marshal(endpointGroups)
|
||||
statusJSONBytes, err := json.Marshal(endpointGroups)
|
||||
common.CheckError(err)
|
||||
fmt.Println(string(statusJsonBytes))
|
||||
fmt.Println(string(statusJSONBytes))
|
||||
default:
|
||||
// Print endpoint groups in a custom format
|
||||
template, templateParsingErr := template.New("endpointGroupTpl").Parse(viper.GetString("endpoint.group.list.format"))
|
||||
|
@ -74,9 +74,9 @@ var endpointInspectCmd = &cobra.Command{
|
||||
common.CheckError(err)
|
||||
case "json":
|
||||
// Print endpoint in a json format
|
||||
endpointJsonBytes, err := json.Marshal(endpoint)
|
||||
endpointJSONBytes, err := json.Marshal(endpoint)
|
||||
common.CheckError(err)
|
||||
fmt.Println(string(endpointJsonBytes))
|
||||
fmt.Println(string(endpointJSONBytes))
|
||||
default:
|
||||
// Print endpoint in a custom format
|
||||
template, err := template.New("endpointTpl").Parse(viper.GetString("endpoint.inspect.format"))
|
||||
|
@ -71,9 +71,9 @@ var endpointListCmd = &cobra.Command{
|
||||
common.CheckError(flushErr)
|
||||
case "json":
|
||||
// Print endpoints in a json format
|
||||
statusJsonBytes, err := json.Marshal(endpoints)
|
||||
statusJSONBytes, err := json.Marshal(endpoints)
|
||||
common.CheckError(err)
|
||||
fmt.Println(string(statusJsonBytes))
|
||||
fmt.Println(string(statusJSONBytes))
|
||||
default:
|
||||
// Print endpoints in a custom format
|
||||
template, templateParsingErr := template.New("endpointTpl").Parse(viper.GetString("endpoint.list.format"))
|
||||
|
@ -56,7 +56,7 @@ var stackDeployCmd = &cobra.Command{
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"endpoint": endpoint.Name,
|
||||
}).Debug("Getting endpoint's Docker info")
|
||||
endpointSwarmClusterId, selectionErr := common.GetEndpointSwarmClusterId(endpoint.ID)
|
||||
endpointSwarmClusterID, selectionErr := common.GetEndpointSwarmClusterID(endpoint.ID)
|
||||
if selectionErr == nil {
|
||||
// It's a swarm cluster
|
||||
} else if selectionErr == common.ErrStackClusterNotFound {
|
||||
@ -70,7 +70,7 @@ var stackDeployCmd = &cobra.Command{
|
||||
"stack": stackName,
|
||||
"endpoint": endpoint.Name,
|
||||
}).Debug("Getting stack")
|
||||
retrievedStack, stackRetrievalErr := common.GetStackByName(stackName, endpointSwarmClusterId, endpoint.ID)
|
||||
retrievedStack, stackRetrievalErr := common.GetStackByName(stackName, endpointSwarmClusterID, endpoint.ID)
|
||||
if stackRetrievalErr == nil {
|
||||
// We are updating an existing stack
|
||||
logrus.WithFields(logrus.Fields{
|
||||
@ -129,13 +129,13 @@ var stackDeployCmd = &cobra.Command{
|
||||
stackFileContent, loadingErr := loadStackFile(viper.GetString("stack.deploy.stack-file"))
|
||||
common.CheckError(loadingErr)
|
||||
|
||||
if endpointSwarmClusterId != "" {
|
||||
if endpointSwarmClusterID != "" {
|
||||
// It's a swarm cluster
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"stack": stackName,
|
||||
"endpoint": endpoint.Name,
|
||||
}).Info("Creating stack")
|
||||
stack, deploymentErr := portainerClient.CreateSwarmStack(stackName, loadedEnvironmentVariables, stackFileContent, endpointSwarmClusterId, endpoint.ID)
|
||||
stack, deploymentErr := portainerClient.CreateSwarmStack(stackName, loadedEnvironmentVariables, stackFileContent, endpointSwarmClusterID, endpoint.ID)
|
||||
common.CheckError(deploymentErr)
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"stack": stack.Name,
|
||||
|
@ -24,7 +24,7 @@ var stackInspectCmd = &cobra.Command{
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
stackName := args[0]
|
||||
var endpointSwarmClusterId string
|
||||
var endpointSwarmClusterID string
|
||||
var stack portainer.Stack
|
||||
|
||||
var endpoint portainer.Endpoint
|
||||
@ -51,14 +51,14 @@ var stackInspectCmd = &cobra.Command{
|
||||
"endpoint": endpoint.Name,
|
||||
}).Debug("Getting endpoint's Docker info")
|
||||
var selectionErr, stackRetrievalErr error
|
||||
endpointSwarmClusterId, selectionErr = common.GetEndpointSwarmClusterId(endpoint.ID)
|
||||
endpointSwarmClusterID, selectionErr = common.GetEndpointSwarmClusterID(endpoint.ID)
|
||||
if selectionErr == nil {
|
||||
// It's a swarm cluster
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"stack": stackName,
|
||||
"endpoint": endpoint.Name,
|
||||
}).Debug("Getting stack")
|
||||
stack, stackRetrievalErr = common.GetStackByName(stackName, endpointSwarmClusterId, endpoint.ID)
|
||||
stack, stackRetrievalErr = common.GetStackByName(stackName, endpointSwarmClusterID, endpoint.ID)
|
||||
} else if selectionErr == common.ErrStackClusterNotFound {
|
||||
// It's not a swarm cluster
|
||||
logrus.WithFields(logrus.Fields{
|
||||
@ -87,7 +87,7 @@ var stackInspectCmd = &cobra.Command{
|
||||
"%v\t%s\t%v\t%s",
|
||||
stack.ID,
|
||||
stack.Name,
|
||||
client.GetTranslatedStackType(stack),
|
||||
client.GetTranslatedStackType(stack.Type),
|
||||
endpoint.Name,
|
||||
))
|
||||
common.CheckError(err)
|
||||
@ -95,9 +95,9 @@ var stackInspectCmd = &cobra.Command{
|
||||
common.CheckError(flushErr)
|
||||
case "json":
|
||||
// Print stack in a json format
|
||||
stackJsonBytes, err := json.Marshal(stack)
|
||||
stackJSONBytes, err := json.Marshal(stack)
|
||||
common.CheckError(err)
|
||||
fmt.Println(string(stackJsonBytes))
|
||||
fmt.Println(string(stackJSONBytes))
|
||||
default:
|
||||
// Print stack in a custom format
|
||||
template, templateParsingErr := template.New("stackTpl").Parse(viper.GetString("stack.inspect.format"))
|
||||
|
@ -36,7 +36,7 @@ var stackListCmd = &cobra.Command{
|
||||
endpoints, endpointsRetrievalErr := portainerClient.GetEndpoints()
|
||||
common.CheckError(endpointsRetrievalErr)
|
||||
|
||||
var endpointSwarmClusterId string
|
||||
var endpointSwarmClusterID string
|
||||
var stacks []portainer.Stack
|
||||
if endpointName := viper.GetString("stack.list.endpoint"); endpointName != "" {
|
||||
// Get endpoint by name
|
||||
@ -47,13 +47,13 @@ var stackListCmd = &cobra.Command{
|
||||
"endpoint": endpoint.Name,
|
||||
}).Debug("Getting endpoint's Docker info")
|
||||
var selectionErr error
|
||||
endpointSwarmClusterId, selectionErr = common.GetEndpointSwarmClusterId(endpoint.ID)
|
||||
endpointSwarmClusterID, selectionErr = common.GetEndpointSwarmClusterID(endpoint.ID)
|
||||
if selectionErr == nil {
|
||||
// It's a swarm cluster
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"endpoint": endpoint.Name,
|
||||
}).Debug("Getting stacks")
|
||||
stacks, err = portainerClient.GetStacks(endpointSwarmClusterId, endpoint.ID)
|
||||
stacks, err = portainerClient.GetStacks(endpointSwarmClusterID, endpoint.ID)
|
||||
common.CheckError(err)
|
||||
} else if selectionErr == common.ErrStackClusterNotFound {
|
||||
// It's not a swarm cluster
|
||||
@ -83,13 +83,13 @@ var stackListCmd = &cobra.Command{
|
||||
})
|
||||
common.CheckError(err)
|
||||
for _, s := range stacks {
|
||||
stackEndpoint, err := common.GetEndpointFromListById(endpoints, s.EndpointID)
|
||||
stackEndpoint, err := common.GetEndpointFromListByID(endpoints, s.EndpointID)
|
||||
common.CheckError(err)
|
||||
_, err = fmt.Fprintln(writer, fmt.Sprintf(
|
||||
"%v\t%s\t%v\t%s",
|
||||
s.ID,
|
||||
s.Name,
|
||||
client.GetTranslatedStackType(s),
|
||||
client.GetTranslatedStackType(s.Type),
|
||||
stackEndpoint.Name,
|
||||
))
|
||||
common.CheckError(err)
|
||||
@ -98,9 +98,9 @@ var stackListCmd = &cobra.Command{
|
||||
common.CheckError(flushErr)
|
||||
case "json":
|
||||
// Print stacks in a json format
|
||||
stacksJsonBytes, err := json.Marshal(stacks)
|
||||
stacksJSONBytes, err := json.Marshal(stacks)
|
||||
common.CheckError(err)
|
||||
fmt.Println(string(stacksJsonBytes))
|
||||
fmt.Println(string(stacksJSONBytes))
|
||||
default:
|
||||
// Print stacks in a custom format
|
||||
template, templateParsingErr := template.New("stackTpl").Parse(viper.GetString("stack.list.format"))
|
||||
|
@ -22,7 +22,7 @@ var stackRemoveCmd = &cobra.Command{
|
||||
common.CheckError(clientRetrievalErr)
|
||||
|
||||
stackName := args[0]
|
||||
var endpointSwarmClusterId string
|
||||
var endpointSwarmClusterID string
|
||||
var stack portainer.Stack
|
||||
|
||||
var endpoint portainer.Endpoint
|
||||
@ -49,14 +49,14 @@ var stackRemoveCmd = &cobra.Command{
|
||||
"endpoint": endpoint.Name,
|
||||
}).Debug("Getting endpoint's Docker info")
|
||||
var selectionErr, stackRetrievalErr error
|
||||
endpointSwarmClusterId, selectionErr = common.GetEndpointSwarmClusterId(endpoint.ID)
|
||||
endpointSwarmClusterID, selectionErr = common.GetEndpointSwarmClusterID(endpoint.ID)
|
||||
if selectionErr == nil {
|
||||
// It's a swarm cluster
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"stack": stackName,
|
||||
"endpoint": endpoint.Name,
|
||||
}).Debug("Getting stack")
|
||||
stack, stackRetrievalErr = common.GetStackByName(stackName, endpointSwarmClusterId, endpoint.ID)
|
||||
stack, stackRetrievalErr = common.GetStackByName(stackName, endpointSwarmClusterID, endpoint.ID)
|
||||
} else if selectionErr == common.ErrStackClusterNotFound {
|
||||
// It's not a swarm cluster
|
||||
logrus.WithFields(logrus.Fields{
|
||||
@ -71,13 +71,13 @@ var stackRemoveCmd = &cobra.Command{
|
||||
|
||||
if stackRetrievalErr == nil {
|
||||
// The stack exists
|
||||
stackId := stack.ID
|
||||
stackID := stack.ID
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"stack": stackName,
|
||||
"endpoint": endpoint.Name,
|
||||
}).Info("Removing stack")
|
||||
err := portainerClient.DeleteStack(stackId)
|
||||
err := portainerClient.DeleteStack(stackID)
|
||||
common.CheckError(err)
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"stack": stack.Name,
|
||||
|
@ -53,9 +53,9 @@ var statusCmd = &cobra.Command{
|
||||
common.CheckError(flushErr)
|
||||
case "json":
|
||||
// Print status in a json format
|
||||
statusJsonBytes, err := json.Marshal(respBody)
|
||||
statusJSONBytes, err := json.Marshal(respBody)
|
||||
common.CheckError(err)
|
||||
fmt.Println(string(statusJsonBytes))
|
||||
fmt.Println(string(statusJSONBytes))
|
||||
default:
|
||||
// Print status in a custom format
|
||||
template, templateParsingErr := template.New("statusTpl").Parse(viper.GetString("status.format"))
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
|
||||
var cachedClient client.PortainerClient
|
||||
|
||||
// Get the cached client or a new one
|
||||
// GetClient returns the cached Portainer API client. If none is present, creates and returns a new one).
|
||||
func GetClient() (c client.PortainerClient, err error) {
|
||||
if cachedClient == nil {
|
||||
cachedClient, err = GetDefaultClient()
|
||||
@ -29,14 +29,14 @@ func GetClient() (c client.PortainerClient, err error) {
|
||||
return cachedClient, nil
|
||||
}
|
||||
|
||||
// Get the default client
|
||||
// GetDefaultClient returns a new Portainer API client with the default configuration
|
||||
func GetDefaultClient() (c client.PortainerClient, err error) {
|
||||
config, err := GetDefaultClientConfig()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c = client.NewClient(GetDefaultHttpClient(), config)
|
||||
c = client.NewClient(GetDefaultHTTPClient(), config)
|
||||
|
||||
c.BeforeRequest(func(req *http.Request) (err error) {
|
||||
var bodyString string
|
||||
@ -82,15 +82,15 @@ func GetDefaultClient() (c client.PortainerClient, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Get the default config for a client
|
||||
// GetDefaultClientConfig returns the default configuration for a Portainer API client
|
||||
func GetDefaultClientConfig() (config client.Config, err error) {
|
||||
apiUrl, err := url.Parse(strings.TrimRight(viper.GetString("url"), "/") + "/api/")
|
||||
apiURL, err := url.Parse(strings.TrimRight(viper.GetString("url"), "/") + "/api/")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
config = client.Config{
|
||||
Url: apiUrl,
|
||||
URL: apiURL,
|
||||
User: viper.GetString("user"),
|
||||
Password: viper.GetString("password"),
|
||||
Token: viper.GetString("auth-token"),
|
||||
@ -101,8 +101,8 @@ func GetDefaultClientConfig() (config client.Config, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Get the default http client for a Portainer client
|
||||
func GetDefaultHttpClient() *http.Client {
|
||||
// GetDefaultHTTPClient returns the default HTTP client for a Portainer API client
|
||||
func GetDefaultHTTPClient() *http.Client {
|
||||
return &http.Client{
|
||||
Timeout: viper.GetDuration("timeout"),
|
||||
Transport: &http.Transport{
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// LoadCofig loads the configuration file currently used by viper into a new viper instance
|
||||
func LoadCofig() (v *viper.Viper, err error) {
|
||||
// Set config file name
|
||||
var configFile string
|
||||
@ -34,6 +35,7 @@ func LoadCofig() (v *viper.Viper, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// CheckConfigKeyExists checks a given configuration key exists in the default viper
|
||||
func CheckConfigKeyExists(key string) (keyExists bool) {
|
||||
for _, k := range viper.AllKeys() {
|
||||
if k == key {
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
// NewTabWriter returns a new tabwriter.Writer
|
||||
func NewTabWriter(headers []string) (*tabwriter.Writer, error) {
|
||||
writer := tabwriter.NewWriter(os.Stdout, 20, 2, 3, ' ', 0)
|
||||
_, err := fmt.Fprintln(writer, strings.Join(headers, "\t"))
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Common errors
|
||||
const (
|
||||
ErrStackNotFound = Error("Stack not found")
|
||||
ErrStackClusterNotFound = Error("Stack cluster not found")
|
||||
@ -29,6 +30,7 @@ func (e Error) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
// GetDefaultEndpoint returns the default endpoint (if only one endpoint exists)
|
||||
func GetDefaultEndpoint() (endpoint portainer.Endpoint, err error) {
|
||||
portainerClient, err := GetClient()
|
||||
if err != nil {
|
||||
@ -53,13 +55,15 @@ func GetDefaultEndpoint() (endpoint portainer.Endpoint, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func GetStackByName(name string, swarmId string, endpointId portainer.EndpointID) (stack portainer.Stack, err error) {
|
||||
// GetStackByName returns a stack by its name from the (endpoint filtered) list
|
||||
// of all stacks
|
||||
func GetStackByName(name string, swarmID string, endpointID portainer.EndpointID) (stack portainer.Stack, err error) {
|
||||
portainerClient, err := GetClient()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stacks, err := portainerClient.GetStacks(swarmId, endpointId)
|
||||
stacks, err := portainerClient.GetStacks(swarmID, endpointID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -73,6 +77,8 @@ func GetStackByName(name string, swarmId string, endpointId portainer.EndpointID
|
||||
return
|
||||
}
|
||||
|
||||
// GetEndpointByName returns an endpoint by its name from the list of all
|
||||
// endpoints
|
||||
func GetEndpointByName(name string) (endpoint portainer.Endpoint, err error) {
|
||||
portainerClient, err := GetClient()
|
||||
if err != nil {
|
||||
@ -93,6 +99,8 @@ func GetEndpointByName(name string) (endpoint portainer.Endpoint, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// GetEndpointGroupByName returns an endpoint group by its name from the list
|
||||
// of all endpoint groups
|
||||
func GetEndpointGroupByName(name string) (endpointGroup portainer.EndpointGroup, err error) {
|
||||
portainerClient, err := GetClient()
|
||||
if err != nil {
|
||||
@ -113,7 +121,9 @@ func GetEndpointGroupByName(name string) (endpointGroup portainer.EndpointGroup,
|
||||
return
|
||||
}
|
||||
|
||||
func GetEndpointFromListById(endpoints []portainer.Endpoint, id portainer.EndpointID) (endpoint portainer.Endpoint, err error) {
|
||||
// GetEndpointFromListByID returns an endpoint by its id from a list of
|
||||
// endpoints
|
||||
func GetEndpointFromListByID(endpoints []portainer.Endpoint, id portainer.EndpointID) (endpoint portainer.Endpoint, err error) {
|
||||
for i := range endpoints {
|
||||
if endpoints[i].ID == id {
|
||||
return endpoints[i], err
|
||||
@ -122,6 +132,8 @@ func GetEndpointFromListById(endpoints []portainer.Endpoint, id portainer.Endpoi
|
||||
return endpoint, ErrEndpointNotFound
|
||||
}
|
||||
|
||||
// GetEndpointFromListByName returns an endpoint by its name from a list of
|
||||
// endpoints
|
||||
func GetEndpointFromListByName(endpoints []portainer.Endpoint, name string) (endpoint portainer.Endpoint, err error) {
|
||||
for i := range endpoints {
|
||||
if endpoints[i].Name == name {
|
||||
@ -131,14 +143,15 @@ func GetEndpointFromListByName(endpoints []portainer.Endpoint, name string) (end
|
||||
return endpoint, ErrEndpointNotFound
|
||||
}
|
||||
|
||||
func GetEndpointSwarmClusterId(endpointId portainer.EndpointID) (endpointSwarmClusterId string, err error) {
|
||||
// GetEndpointSwarmClusterID returns an endpoint's swarm cluster id
|
||||
func GetEndpointSwarmClusterID(endpointID portainer.EndpointID) (endpointSwarmClusterID string, err error) {
|
||||
// Get docker information for endpoint
|
||||
portainerClient, err := GetClient()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := portainerClient.GetEndpointDockerInfo(endpointId)
|
||||
result, err := portainerClient.GetEndpointDockerInfo(endpointID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -146,7 +159,7 @@ func GetEndpointSwarmClusterId(endpointId portainer.EndpointID) (endpointSwarmCl
|
||||
// Get swarm (if any) information for endpoint
|
||||
id, selectionErr := selectValue(result, []string{"Swarm", "Cluster", "ID"})
|
||||
if selectionErr == nil {
|
||||
endpointSwarmClusterId = id.(string)
|
||||
endpointSwarmClusterID = id.(string)
|
||||
} else if selectionErr == valueNotFoundError {
|
||||
err = ErrStackClusterNotFound
|
||||
} else {
|
||||
@ -167,6 +180,7 @@ func selectValue(jsonMap map[string]interface{}, jsonPath []string) (interface{}
|
||||
}
|
||||
}
|
||||
|
||||
// GetFormatHelp returns the help string for --format flags
|
||||
func GetFormatHelp(v interface{}) (r string) {
|
||||
typeOfV := reflect.TypeOf(v)
|
||||
r = fmt.Sprintf(`
|
||||
|
@ -19,6 +19,7 @@ var (
|
||||
buildDate string
|
||||
)
|
||||
|
||||
// BuildVersionString returns the tool's version
|
||||
func BuildVersionString() string {
|
||||
osArch := runtime.GOOS + "/" + runtime.GOARCH
|
||||
|
||||
@ -33,6 +34,8 @@ func BuildVersionString() string {
|
||||
return fmt.Sprintf("%s %s %s BuildDate: %s", programName, version, osArch, buildDate)
|
||||
}
|
||||
|
||||
// BuildUseAgentString returns the tool's User-Agent in requests to the
|
||||
// Portainer API
|
||||
func BuildUseAgentString() string {
|
||||
var theVersion = version
|
||||
if theVersion == "" {
|
||||
|
Loading…
Reference in New Issue
Block a user