mirror of
https://gitlab.com/psuapp/psu.git
synced 2024-08-30 18:12:34 +00:00
Merge branch 'refactoring'
This commit is contained in:
commit
854db31543
32
client/auth.go
Normal file
32
client/auth.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *portainerClientImp) AuthenticateUser() (token string, err error) {
|
||||||
|
reqBody := AuthenticateUserRequest{
|
||||||
|
Username: n.user,
|
||||||
|
Password: n.password,
|
||||||
|
}
|
||||||
|
|
||||||
|
respBody := AuthenticateUserResponse{}
|
||||||
|
|
||||||
|
err = n.doJSON("auth", http.MethodPost, http.Header{}, &reqBody, &respBody)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token = respBody.Jwt
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
48
client/auth_test.go
Normal file
48
client/auth_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
assert.Equal(t, req.Method, http.MethodPost)
|
||||||
|
assert.Equal(t, req.RequestURI, "/api/auth")
|
||||||
|
assert.NotNil(t, req.Header["Content-Type"])
|
||||||
|
assert.NotNil(t, req.Header["Content-Type"][0])
|
||||||
|
assert.Equal(t, req.Header["Content-Type"][0], "application/json")
|
||||||
|
assert.NotNil(t, req.Header["User-Agent"])
|
||||||
|
assert.NotNil(t, req.Header["User-Agent"][0])
|
||||||
|
assert.Equal(t, req.Header["User-Agent"][0], "GE007")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotNil(t, body["Username"])
|
||||||
|
assert.Equal(t, body["Username"], "admin")
|
||||||
|
assert.NotNil(t, body["Password"])
|
||||||
|
assert.Equal(t, body["Password"], "a")
|
||||||
|
|
||||||
|
writeResponseBodyAsJSON(w, map[string]interface{}{
|
||||||
|
"jwt": "somerandomtoken",
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
apiURL, _ := url.Parse(ts.URL + "/api/")
|
||||||
|
|
||||||
|
customClient := NewClient(ts.Client(), Config{
|
||||||
|
URL: apiURL,
|
||||||
|
User: "admin",
|
||||||
|
Password: "a",
|
||||||
|
UserAgent: "GE007",
|
||||||
|
})
|
||||||
|
token, err := customClient.AuthenticateUser()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, token, "somerandomtoken")
|
||||||
|
}
|
159
client/client.go
159
client/client.go
@ -3,22 +3,13 @@ package client
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StackListFilter represents a filter for a stack list
|
|
||||||
type StackListFilter struct {
|
|
||||||
SwarmID string `json:"SwarmId,omitempty"`
|
|
||||||
EndpointID portainer.EndpointID `json:"EndpointId,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config represents a Portainer client configuration
|
// Config represents a Portainer client configuration
|
||||||
type Config struct {
|
type Config struct {
|
||||||
URL *url.URL
|
URL *url.URL
|
||||||
@ -31,38 +22,38 @@ type Config struct {
|
|||||||
|
|
||||||
// PortainerClient represents a Portainer API client
|
// PortainerClient represents a Portainer API client
|
||||||
type PortainerClient interface {
|
type PortainerClient interface {
|
||||||
// Authenticate a user to get an auth token
|
// AuthenticateUser a user to get an auth token
|
||||||
Authenticate() (token string, err error)
|
AuthenticateUser() (token string, err error)
|
||||||
|
|
||||||
// Get endpoints
|
// Get endpoints
|
||||||
GetEndpoints() ([]portainer.Endpoint, error)
|
EndpointList() ([]portainer.Endpoint, error)
|
||||||
|
|
||||||
// Get endpoint groups
|
// Get endpoint groups
|
||||||
GetEndpointGroups() ([]portainer.EndpointGroup, error)
|
EndpointGroupList() ([]portainer.EndpointGroup, error)
|
||||||
|
|
||||||
// Get stacks, optionally filtered by swarmId and endpointId
|
// Get stacks, optionally filtered by swarmId and endpointId
|
||||||
GetStacks(swarmID string, endpointID portainer.EndpointID) ([]portainer.Stack, error)
|
StackList(options StackListOptions) ([]portainer.Stack, error)
|
||||||
|
|
||||||
// Create swarm stack
|
// Create swarm stack
|
||||||
CreateSwarmStack(stackName string, environmentVariables []portainer.Pair, stackFileContent string, swarmClusterID string, endpointID portainer.EndpointID) (stack portainer.Stack, err error)
|
StackCreateSwarm(options StackCreateSwarmOptions) (stack portainer.Stack, err error)
|
||||||
|
|
||||||
// Create compose stack
|
// Create compose stack
|
||||||
CreateComposeStack(stackName string, environmentVariables []portainer.Pair, stackFileContent string, endpointID portainer.EndpointID) (stack portainer.Stack, err error)
|
StackCreateCompose(options StackCreateComposeOptions) (stack portainer.Stack, err error)
|
||||||
|
|
||||||
// Update stack
|
// Update stack
|
||||||
UpdateStack(stack portainer.Stack, environmentVariables []portainer.Pair, stackFileContent string, prune bool, endpointID portainer.EndpointID) error
|
StackUpdate(options StackUpdateOptions) error
|
||||||
|
|
||||||
// Delete stack
|
// Delete stack
|
||||||
DeleteStack(stackID portainer.StackID) error
|
StackDelete(stackID portainer.StackID) error
|
||||||
|
|
||||||
// Get stack file content
|
// Get stack file content
|
||||||
GetStackFileContent(stackID portainer.StackID) (content string, err error)
|
StackFileInspect(stackID portainer.StackID) (content string, err error)
|
||||||
|
|
||||||
// Get endpoint Docker info
|
// Get endpoint Docker info
|
||||||
GetEndpointDockerInfo(endpointID portainer.EndpointID) (info map[string]interface{}, err error)
|
EndpointDockerInfo(endpointID portainer.EndpointID) (info map[string]interface{}, err error)
|
||||||
|
|
||||||
// Get Portainer status info
|
// Get Portainer status info
|
||||||
GetStatus() (portainer.Status, error)
|
Status() (portainer.Status, error)
|
||||||
|
|
||||||
// Run a function before sending a request to Portainer
|
// Run a function before sending a request to Portainer
|
||||||
BeforeRequest(hook func(req *http.Request) (err error))
|
BeforeRequest(hook func(req *http.Request) (err error))
|
||||||
@ -82,27 +73,6 @@ type portainerClientImp struct {
|
|||||||
afterResponseHooks []func(resp *http.Response) (err error)
|
afterResponseHooks []func(resp *http.Response) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if an http.Response object has errors
|
|
||||||
func checkResponseForErrors(resp *http.Response) error {
|
|
||||||
if 300 <= resp.StatusCode {
|
|
||||||
// Guess it's a GenericError
|
|
||||||
respBody := GenericError{}
|
|
||||||
err := json.NewDecoder(resp.Body).Decode(&respBody)
|
|
||||||
if err != nil {
|
|
||||||
// It's not a GenericError
|
|
||||||
bodyBytes, err := ioutil.ReadAll(resp.Body)
|
|
||||||
defer resp.Body.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
resp.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))
|
|
||||||
return errors.New(string(bodyBytes))
|
|
||||||
}
|
|
||||||
return &respBody
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do an http request
|
// Do an http request
|
||||||
func (n *portainerClientImp) do(uri, method string, requestBody io.Reader, headers http.Header) (resp *http.Response, err error) {
|
func (n *portainerClientImp) do(uri, method string, requestBody io.Reader, headers http.Header) (resp *http.Response, err error) {
|
||||||
requestURL, err := n.url.Parse(uri)
|
requestURL, err := n.url.Parse(uri)
|
||||||
@ -185,7 +155,7 @@ func (n *portainerClientImp) doJSON(uri, method string, headers http.Header, req
|
|||||||
func (n *portainerClientImp) doJSONWithToken(uri, method string, headers http.Header, request interface{}, response interface{}) (err error) {
|
func (n *portainerClientImp) doJSONWithToken(uri, method string, headers http.Header, request interface{}, response interface{}) (err error) {
|
||||||
// Ensure there is an auth token
|
// Ensure there is an auth token
|
||||||
if n.token == "" {
|
if n.token == "" {
|
||||||
n.token, err = n.Authenticate()
|
n.token, err = n.AuthenticateUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -203,109 +173,6 @@ func (n *portainerClientImp) AfterResponse(hook func(resp *http.Response) (err e
|
|||||||
n.afterResponseHooks = append(n.afterResponseHooks, hook)
|
n.afterResponseHooks = append(n.afterResponseHooks, hook)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *portainerClientImp) Authenticate() (token string, err error) {
|
|
||||||
reqBody := AuthenticateUserRequest{
|
|
||||||
Username: n.user,
|
|
||||||
Password: n.password,
|
|
||||||
}
|
|
||||||
|
|
||||||
respBody := AuthenticateUserResponse{}
|
|
||||||
|
|
||||||
err = n.doJSON("auth", http.MethodPost, http.Header{}, &reqBody, &respBody)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
token = respBody.Jwt
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *portainerClientImp) GetEndpoints() (endpoints []portainer.Endpoint, err error) {
|
|
||||||
err = n.doJSONWithToken("endpoints", http.MethodGet, http.Header{}, nil, &endpoints)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *portainerClientImp) GetEndpointGroups() (endpointGroups []portainer.EndpointGroup, err error) {
|
|
||||||
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) {
|
|
||||||
filter := StackListFilter{
|
|
||||||
SwarmID: swarmID,
|
|
||||||
EndpointID: endpointID,
|
|
||||||
}
|
|
||||||
|
|
||||||
filterJSONBytes, _ := json.Marshal(filter)
|
|
||||||
filterJSONString := string(filterJSONBytes)
|
|
||||||
|
|
||||||
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) {
|
|
||||||
reqBody := StackCreateRequest{
|
|
||||||
Name: stackName,
|
|
||||||
Env: environmentVariables,
|
|
||||||
SwarmID: swarmClusterID,
|
|
||||||
StackFileContent: stackFileContent,
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
reqBody := StackCreateRequest{
|
|
||||||
Name: stackName,
|
|
||||||
Env: environmentVariables,
|
|
||||||
StackFileContent: stackFileContent,
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
reqBody := StackUpdateRequest{
|
|
||||||
Env: environmentVariables,
|
|
||||||
StackFileContent: stackFileContent,
|
|
||||||
Prune: prune,
|
|
||||||
}
|
|
||||||
|
|
||||||
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.doJSONWithToken(fmt.Sprintf("stacks/%d", stackID), http.MethodDelete, http.Header{}, nil, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *portainerClientImp) GetStackFileContent(stackID portainer.StackID) (content string, err error) {
|
|
||||||
var respBody StackFileInspectResponse
|
|
||||||
|
|
||||||
err = n.doJSONWithToken(fmt.Sprintf("stacks/%v/file", stackID), http.MethodGet, http.Header{}, nil, &respBody)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
content = respBody.StackFileContent
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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.doJSONWithToken("status", http.MethodGet, http.Header{}, nil, &status)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClient creates a new Portainer API client
|
// NewClient creates a new Portainer API client
|
||||||
func NewClient(httpClient *http.Client, config Config) PortainerClient {
|
func NewClient(httpClient *http.Client, config Config) PortainerClient {
|
||||||
return &portainerClientImp{
|
return &portainerClientImp{
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -36,44 +35,6 @@ func TestNewClient(t *testing.T) {
|
|||||||
assert.NotNil(t, validClient)
|
assert.NotNil(t, validClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
assert.Equal(t, req.Method, http.MethodPost)
|
|
||||||
assert.Equal(t, req.RequestURI, "/api/auth")
|
|
||||||
assert.NotNil(t, req.Header["Content-Type"])
|
|
||||||
assert.NotNil(t, req.Header["Content-Type"][0])
|
|
||||||
assert.Equal(t, req.Header["Content-Type"][0], "application/json")
|
|
||||||
assert.NotNil(t, req.Header["User-Agent"])
|
|
||||||
assert.NotNil(t, req.Header["User-Agent"][0])
|
|
||||||
assert.Equal(t, req.Header["User-Agent"][0], "GE007")
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.NotNil(t, body["Username"])
|
|
||||||
assert.Equal(t, body["Username"], "admin")
|
|
||||||
assert.NotNil(t, body["Password"])
|
|
||||||
assert.Equal(t, body["Password"], "a")
|
|
||||||
|
|
||||||
writeResponseBodyAsJSON(w, map[string]interface{}{
|
|
||||||
"jwt": "somerandomtoken",
|
|
||||||
})
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
apiURL, _ := url.Parse(ts.URL + "/api/")
|
|
||||||
|
|
||||||
customClient := NewClient(ts.Client(), Config{
|
|
||||||
URL: apiURL,
|
|
||||||
User: "admin",
|
|
||||||
Password: "a",
|
|
||||||
UserAgent: "GE007",
|
|
||||||
})
|
|
||||||
token, err := customClient.Authenticate()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, token, "somerandomtoken")
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_portainerClientImp_do(t *testing.T) {
|
func Test_portainerClientImp_do(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
user string
|
user string
|
||||||
@ -184,50 +145,3 @@ func Test_portainerClientImp_do(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
12
client/endpointGroup_list.go
Normal file
12
client/endpointGroup_list.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *portainerClientImp) EndpointGroupList() (endpointGroups []portainer.EndpointGroup, err error) {
|
||||||
|
err = n.doJSONWithToken("endpoint_groups", http.MethodGet, http.Header{}, nil, &endpointGroups)
|
||||||
|
return
|
||||||
|
}
|
13
client/endpoint_docker_info.go
Normal file
13
client/endpoint_docker_info.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *portainerClientImp) EndpointDockerInfo(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
|
||||||
|
}
|
12
client/endpoint_list.go
Normal file
12
client/endpoint_list.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *portainerClientImp) EndpointList() (endpoints []portainer.Endpoint, err error) {
|
||||||
|
err = n.doJSONWithToken("endpoints", http.MethodGet, http.Header{}, nil, &endpoints)
|
||||||
|
return
|
||||||
|
}
|
16
client/errors.go
Normal file
16
client/errors.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// GenericError represents the body of a generic error returned by the Portainer API
|
||||||
|
type GenericError struct {
|
||||||
|
Err string
|
||||||
|
Details string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *GenericError) Error() string {
|
||||||
|
if e.Details != "" {
|
||||||
|
return fmt.Sprintf("%s: %s", e.Err, e.Details)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s", e.Err)
|
||||||
|
}
|
@ -3,48 +3,9 @@ package client
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"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) {
|
func TestGenericError_Error(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
Err string
|
Err string
|
@ -1,63 +0,0 @@
|
|||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 portainer.DockerComposeStack:
|
|
||||||
return "compose"
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StackCreateRequest represents the body of a request to POST /stacks
|
|
||||||
type StackCreateRequest struct {
|
|
||||||
Name string
|
|
||||||
SwarmID string
|
|
||||||
StackFileContent string
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *GenericError) Error() string {
|
|
||||||
if e.Details != "" {
|
|
||||||
return fmt.Sprintf("%s: %s", e.Err, e.Details)
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
26
client/stackFile_inspect.go
Normal file
26
client/stackFile_inspect.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StackFileInspectResponse represents the body of a response for a request to GET /stack/{id}/file
|
||||||
|
type StackFileInspectResponse struct {
|
||||||
|
StackFileContent string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *portainerClientImp) StackFileInspect(stackID portainer.StackID) (content string, err error) {
|
||||||
|
var respBody StackFileInspectResponse
|
||||||
|
|
||||||
|
err = n.doJSONWithToken(fmt.Sprintf("stacks/%v/file", stackID), http.MethodGet, http.Header{}, nil, &respBody)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content = respBody.StackFileContent
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
56
client/stack_create.go
Normal file
56
client/stack_create.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StackCreateComposeOptions represents options passed to PortainerClient.StackCreateCompose()
|
||||||
|
type StackCreateComposeOptions struct {
|
||||||
|
StackName string
|
||||||
|
EnvironmentVariables []portainer.Pair
|
||||||
|
StackFileContent string
|
||||||
|
EndpointID portainer.EndpointID
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackCreateRequest represents the body of a request to POST /stacks
|
||||||
|
type StackCreateRequest struct {
|
||||||
|
Name string
|
||||||
|
SwarmID string
|
||||||
|
StackFileContent string
|
||||||
|
Env []portainer.Pair `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackCreateSwarmOptions represents options passed to PortainerClient.StackCreateSwarm()
|
||||||
|
type StackCreateSwarmOptions struct {
|
||||||
|
StackName string
|
||||||
|
EnvironmentVariables []portainer.Pair
|
||||||
|
StackFileContent string
|
||||||
|
SwarmClusterID string
|
||||||
|
EndpointID portainer.EndpointID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *portainerClientImp) StackCreateCompose(options StackCreateComposeOptions) (stack portainer.Stack, err error) {
|
||||||
|
reqBody := StackCreateRequest{
|
||||||
|
Name: options.StackName,
|
||||||
|
Env: options.EnvironmentVariables,
|
||||||
|
StackFileContent: options.StackFileContent,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = n.doJSONWithToken(fmt.Sprintf("stacks?type=%v&method=%s&endpointId=%v", 2, "string", options.EndpointID), http.MethodPost, http.Header{}, &reqBody, &stack)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *portainerClientImp) StackCreateSwarm(options StackCreateSwarmOptions) (stack portainer.Stack, err error) {
|
||||||
|
reqBody := StackCreateRequest{
|
||||||
|
Name: options.StackName,
|
||||||
|
Env: options.EnvironmentVariables,
|
||||||
|
SwarmID: options.SwarmClusterID,
|
||||||
|
StackFileContent: options.StackFileContent,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = n.doJSONWithToken(fmt.Sprintf("stacks?type=%v&method=%s&endpointId=%v", 1, "string", options.EndpointID), http.MethodPost, http.Header{}, &reqBody, &stack)
|
||||||
|
return
|
||||||
|
}
|
13
client/stack_delete.go
Normal file
13
client/stack_delete.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *portainerClientImp) StackDelete(stackID portainer.StackID) (err error) {
|
||||||
|
err = n.doJSONWithToken(fmt.Sprintf("stacks/%d", stackID), http.MethodDelete, http.Header{}, nil, nil)
|
||||||
|
return
|
||||||
|
}
|
28
client/stack_list.go
Normal file
28
client/stack_list.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StackListFilter represents a filter for a stack list
|
||||||
|
type StackListFilter struct {
|
||||||
|
SwarmID string `json:"SwarmId,omitempty"`
|
||||||
|
EndpointID portainer.EndpointID `json:"EndpointId,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackListOptions represents options passed to PortainerClient.StackList()
|
||||||
|
type StackListOptions struct {
|
||||||
|
Filter StackListFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *portainerClientImp) StackList(options StackListOptions) (stacks []portainer.Stack, err error) {
|
||||||
|
filterJSONBytes, _ := json.Marshal(options.Filter)
|
||||||
|
filterJSONString := string(filterJSONBytes)
|
||||||
|
|
||||||
|
err = n.doJSONWithToken(fmt.Sprintf("stacks?filters=%s", filterJSONString), http.MethodGet, http.Header{}, nil, &stacks)
|
||||||
|
return
|
||||||
|
}
|
35
client/stack_update.go
Normal file
35
client/stack_update.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StackUpdateOptions represents options passed to PortainerClient.StackUpdate()
|
||||||
|
type StackUpdateOptions struct {
|
||||||
|
Stack portainer.Stack
|
||||||
|
EnvironmentVariables []portainer.Pair
|
||||||
|
StackFileContent string
|
||||||
|
Prune bool
|
||||||
|
EndpointID portainer.EndpointID
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackUpdateRequest represents the body of a request to PUT /stacks/{id}
|
||||||
|
type StackUpdateRequest struct {
|
||||||
|
StackFileContent string
|
||||||
|
Env []portainer.Pair `json:",omitempty"`
|
||||||
|
Prune bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *portainerClientImp) StackUpdate(options StackUpdateOptions) (err error) {
|
||||||
|
reqBody := StackUpdateRequest{
|
||||||
|
Env: options.EnvironmentVariables,
|
||||||
|
StackFileContent: options.StackFileContent,
|
||||||
|
Prune: options.Prune,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = n.doJSONWithToken(fmt.Sprintf("stacks/%v?endpointId=%v", options.Stack.ID, options.EndpointID), http.MethodPut, http.Header{}, &reqBody, nil)
|
||||||
|
return
|
||||||
|
}
|
12
client/status.go
Normal file
12
client/status.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *portainerClientImp) Status() (status portainer.Status, err error) {
|
||||||
|
err = n.doJSONWithToken("status", http.MethodGet, http.Header{}, nil, &status)
|
||||||
|
return
|
||||||
|
}
|
44
client/utils.go
Normal file
44
client/utils.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 portainer.DockerComposeStack:
|
||||||
|
return "compose"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if an http.Response object has errors
|
||||||
|
func checkResponseForErrors(resp *http.Response) error {
|
||||||
|
if 300 <= resp.StatusCode {
|
||||||
|
// Guess it's a GenericError
|
||||||
|
respBody := GenericError{}
|
||||||
|
err := json.NewDecoder(resp.Body).Decode(&respBody)
|
||||||
|
if err != nil {
|
||||||
|
// It's not a GenericError
|
||||||
|
bodyBytes, err := ioutil.ReadAll(resp.Body)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))
|
||||||
|
return errors.New(string(bodyBytes))
|
||||||
|
}
|
||||||
|
return &respBody
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
97
client/utils_test.go
Normal file
97
client/utils_test.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"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 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,7 @@ var endpointGroupListCmd = &cobra.Command{
|
|||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
|
|
||||||
logrus.Debug("Getting endpoint groups")
|
logrus.Debug("Getting endpoint groups")
|
||||||
endpointGroups, err := client.GetEndpointGroups()
|
endpointGroups, err := client.EndpointGroupList()
|
||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
|
|
||||||
switch viper.GetString("endpoint.group.list.format") {
|
switch viper.GetString("endpoint.group.list.format") {
|
||||||
|
@ -30,7 +30,7 @@ var endpointListCmd = &cobra.Command{
|
|||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
|
|
||||||
logrus.Debug("Getting endpoints")
|
logrus.Debug("Getting endpoints")
|
||||||
endpoints, err := client.GetEndpoints()
|
endpoints, err := client.EndpointList()
|
||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
|
|
||||||
switch viper.GetString("endpoint.list.format") {
|
switch viper.GetString("endpoint.list.format") {
|
||||||
|
@ -22,7 +22,7 @@ var loginCmd = &cobra.Command{
|
|||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"user": user,
|
"user": user,
|
||||||
}).Debug("Getting auth token")
|
}).Debug("Getting auth token")
|
||||||
authToken, err := client.Authenticate()
|
authToken, err := client.AuthenticateUser()
|
||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
|
|
||||||
if viper.GetBool("login.print") {
|
if viper.GetBool("login.print") {
|
||||||
|
@ -3,6 +3,8 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/greenled/portainer-stack-utils/client"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -87,7 +89,7 @@ var stackDeployCmd = &cobra.Command{
|
|||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"stack": retrievedStack.Name,
|
"stack": retrievedStack.Name,
|
||||||
}).Debug("Getting stack file content")
|
}).Debug("Getting stack file content")
|
||||||
stackFileContent, stackFileContentRetrievalErr = portainerClient.GetStackFileContent(retrievedStack.ID)
|
stackFileContent, stackFileContentRetrievalErr = portainerClient.StackFileInspect(retrievedStack.ID)
|
||||||
common.CheckError(stackFileContentRetrievalErr)
|
common.CheckError(stackFileContentRetrievalErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +117,13 @@ var stackDeployCmd = &cobra.Command{
|
|||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"stack": retrievedStack.Name,
|
"stack": retrievedStack.Name,
|
||||||
}).Info("Updating stack")
|
}).Info("Updating stack")
|
||||||
err := portainerClient.UpdateStack(retrievedStack, newEnvironmentVariables, stackFileContent, viper.GetBool("stack.deploy.prune"), endpoint.ID)
|
err := portainerClient.StackUpdate(client.StackUpdateOptions{
|
||||||
|
Stack: retrievedStack,
|
||||||
|
EnvironmentVariables: newEnvironmentVariables,
|
||||||
|
StackFileContent: stackFileContent,
|
||||||
|
Prune: viper.GetBool("stack.deploy.prune"),
|
||||||
|
EndpointID: endpoint.ID,
|
||||||
|
})
|
||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
} else if stackRetrievalErr == common.ErrStackNotFound {
|
} else if stackRetrievalErr == common.ErrStackNotFound {
|
||||||
// We are deploying a new stack
|
// We are deploying a new stack
|
||||||
@ -135,7 +143,13 @@ var stackDeployCmd = &cobra.Command{
|
|||||||
"stack": stackName,
|
"stack": stackName,
|
||||||
"endpoint": endpoint.Name,
|
"endpoint": endpoint.Name,
|
||||||
}).Info("Creating stack")
|
}).Info("Creating stack")
|
||||||
stack, deploymentErr := portainerClient.CreateSwarmStack(stackName, loadedEnvironmentVariables, stackFileContent, endpointSwarmClusterID, endpoint.ID)
|
stack, deploymentErr := portainerClient.StackCreateSwarm(client.StackCreateSwarmOptions{
|
||||||
|
StackName: stackName,
|
||||||
|
EnvironmentVariables: loadedEnvironmentVariables,
|
||||||
|
StackFileContent: stackFileContent,
|
||||||
|
SwarmClusterID: endpointSwarmClusterID,
|
||||||
|
EndpointID: endpoint.ID,
|
||||||
|
})
|
||||||
common.CheckError(deploymentErr)
|
common.CheckError(deploymentErr)
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"stack": stack.Name,
|
"stack": stack.Name,
|
||||||
@ -148,7 +162,12 @@ var stackDeployCmd = &cobra.Command{
|
|||||||
"stack": stackName,
|
"stack": stackName,
|
||||||
"endpoint": endpoint.Name,
|
"endpoint": endpoint.Name,
|
||||||
}).Info("Creating stack")
|
}).Info("Creating stack")
|
||||||
stack, deploymentErr := portainerClient.CreateComposeStack(stackName, loadedEnvironmentVariables, stackFileContent, endpoint.ID)
|
stack, deploymentErr := portainerClient.StackCreateCompose(client.StackCreateComposeOptions{
|
||||||
|
StackName: stackName,
|
||||||
|
EnvironmentVariables: loadedEnvironmentVariables,
|
||||||
|
StackFileContent: stackFileContent,
|
||||||
|
EndpointID: endpoint.ID,
|
||||||
|
})
|
||||||
common.CheckError(deploymentErr)
|
common.CheckError(deploymentErr)
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"stack": stack.Name,
|
"stack": stack.Name,
|
||||||
|
@ -33,7 +33,7 @@ var stackListCmd = &cobra.Command{
|
|||||||
portainerClient, err := common.GetClient()
|
portainerClient, err := common.GetClient()
|
||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
|
|
||||||
endpoints, endpointsRetrievalErr := portainerClient.GetEndpoints()
|
endpoints, endpointsRetrievalErr := portainerClient.EndpointList()
|
||||||
common.CheckError(endpointsRetrievalErr)
|
common.CheckError(endpointsRetrievalErr)
|
||||||
|
|
||||||
var endpointSwarmClusterID string
|
var endpointSwarmClusterID string
|
||||||
@ -53,14 +53,23 @@ var stackListCmd = &cobra.Command{
|
|||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"endpoint": endpoint.Name,
|
"endpoint": endpoint.Name,
|
||||||
}).Debug("Getting stacks")
|
}).Debug("Getting stacks")
|
||||||
stacks, err = portainerClient.GetStacks(endpointSwarmClusterID, endpoint.ID)
|
stacks, err = portainerClient.StackList(client.StackListOptions{
|
||||||
|
Filter: client.StackListFilter{
|
||||||
|
SwarmID: endpointSwarmClusterID,
|
||||||
|
EndpointID: endpoint.ID,
|
||||||
|
},
|
||||||
|
})
|
||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
} else if selectionErr == common.ErrStackClusterNotFound {
|
} else if selectionErr == common.ErrStackClusterNotFound {
|
||||||
// It's not a swarm cluster
|
// It's not a swarm cluster
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"endpoint": endpoint.Name,
|
"endpoint": endpoint.Name,
|
||||||
}).Debug("Getting stacks")
|
}).Debug("Getting stacks")
|
||||||
stacks, err = portainerClient.GetStacks("", endpoint.ID)
|
stacks, err = portainerClient.StackList(client.StackListOptions{
|
||||||
|
Filter: client.StackListFilter{
|
||||||
|
EndpointID: endpoint.ID,
|
||||||
|
},
|
||||||
|
})
|
||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
} else {
|
} else {
|
||||||
// Something else happened
|
// Something else happened
|
||||||
@ -68,7 +77,7 @@ var stackListCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logrus.Debug("Getting stacks")
|
logrus.Debug("Getting stacks")
|
||||||
stacks, err = portainerClient.GetStacks("", 0)
|
stacks, err = portainerClient.StackList(client.StackListOptions{})
|
||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ var stackRemoveCmd = &cobra.Command{
|
|||||||
"stack": stackName,
|
"stack": stackName,
|
||||||
"endpoint": endpoint.Name,
|
"endpoint": endpoint.Name,
|
||||||
}).Info("Removing stack")
|
}).Info("Removing stack")
|
||||||
err := portainerClient.DeleteStack(stackID)
|
err := portainerClient.StackDelete(stackID)
|
||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"stack": stack.Name,
|
"stack": stack.Name,
|
||||||
|
@ -26,7 +26,7 @@ var statusCmd = &cobra.Command{
|
|||||||
client, err := common.GetClient()
|
client, err := common.GetClient()
|
||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
|
|
||||||
respBody, err := client.GetStatus()
|
respBody, err := client.Status()
|
||||||
common.CheckError(err)
|
common.CheckError(err)
|
||||||
|
|
||||||
switch viper.GetString("status.format") {
|
switch viper.GetString("status.format") {
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/greenled/portainer-stack-utils/client"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -38,7 +40,7 @@ func GetDefaultEndpoint() (endpoint portainer.Endpoint, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debug("Getting endpoints")
|
logrus.Debug("Getting endpoints")
|
||||||
endpoints, err := portainerClient.GetEndpoints()
|
endpoints, err := portainerClient.EndpointList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -63,7 +65,12 @@ func GetStackByName(name string, swarmID string, endpointID portainer.EndpointID
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
stacks, err := portainerClient.GetStacks(swarmID, endpointID)
|
stacks, err := portainerClient.StackList(client.StackListOptions{
|
||||||
|
Filter: client.StackListFilter{
|
||||||
|
SwarmID: swarmID,
|
||||||
|
EndpointID: endpointID,
|
||||||
|
},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -85,7 +92,7 @@ func GetEndpointByName(name string) (endpoint portainer.Endpoint, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoints, err := portainerClient.GetEndpoints()
|
endpoints, err := portainerClient.EndpointList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -107,7 +114,7 @@ func GetEndpointGroupByName(name string) (endpointGroup portainer.EndpointGroup,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
endpointGroups, err := portainerClient.GetEndpointGroups()
|
endpointGroups, err := portainerClient.EndpointGroupList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -151,7 +158,7 @@ func GetEndpointSwarmClusterID(endpointID portainer.EndpointID) (endpointSwarmCl
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := portainerClient.GetEndpointDockerInfo(endpointID)
|
result, err := portainerClient.EndpointDockerInfo(endpointID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user