Replace manual request creation and marshaling with new client

This commit is contained in:
Juan Carlos Mejías Rodríguez 2019-08-02 12:03:43 -04:00
parent 1b1c2bc1d1
commit fa666db1b8
5 changed files with 84 additions and 279 deletions

View File

@ -2,6 +2,7 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/greenled/portainer-stack-utils/common" "github.com/greenled/portainer-stack-utils/common"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -13,8 +14,11 @@ var loginCmd = &cobra.Command{
Short: "Log in to a Portainer instance", Short: "Log in to a Portainer instance",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
// Get auth token // Get auth token
authToken, authenticationTokenRetrievalError := common.GetNewAuthenticationToken() client, err := common.GetClient()
common.CheckError(authenticationTokenRetrievalError) common.CheckError(err)
authToken, err := client.Authenticate(viper.GetString("url"), viper.GetString("password"))
common.CheckError(err)
if viper.GetBool("login.print") { if viper.GetBool("login.print") {
fmt.Println(authToken) fmt.Println(authToken)

View File

@ -1,17 +1,15 @@
package cmd package cmd
import ( import (
"bytes"
"encoding/json"
"fmt" "fmt"
"io/ioutil"
"log"
"net/http"
"github.com/greenled/portainer-stack-utils/common" "github.com/greenled/portainer-stack-utils/common"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"io/ioutil"
"log"
"net/http"
"net/url"
) )
// stackDeployCmd represents the undeploy command // stackDeployCmd represents the undeploy command
@ -118,7 +116,12 @@ func init() {
viper.BindPFlag("stack.deploy.prune", stackDeployCmd.Flags().Lookup("prune")) viper.BindPFlag("stack.deploy.prune", stackDeployCmd.Flags().Lookup("prune"))
} }
func deploySwarmStack(stackName string, environmentVariables []common.StackEnv, dockerComposeFileContent string, swarmClusterId string) error { func deploySwarmStack(stackName string, environmentVariables []common.StackEnv, dockerComposeFileContent string, swarmClusterId string) (err error) {
client, err := common.GetClient()
if err != nil {
return
}
reqBody := common.StackCreateRequest{ reqBody := common.StackCreateRequest{
Name: stackName, Name: stackName,
Env: environmentVariables, Env: environmentVariables,
@ -126,174 +129,67 @@ func deploySwarmStack(stackName string, environmentVariables []common.StackEnv,
StackFileContent: dockerComposeFileContent, StackFileContent: dockerComposeFileContent,
} }
reqBodyBytes, marshalingErr := json.Marshal(reqBody) err = client.DoJSON(fmt.Sprintf("stacks?type=%v&method=%s&endpointId=%s", 1, "string", viper.GetString("stack.deploy.endpoint")), http.MethodPost, &reqBody, nil)
if marshalingErr != nil {
return marshalingErr
}
reqUrl, parsingErr := url.Parse(fmt.Sprintf("%s/api/stacks?type=%v&method=%s&endpointId=%s", viper.GetString("url"), 1, "string", viper.GetString("stack.deploy.endpoint"))) return
if parsingErr != nil {
return parsingErr
}
req, newRequestErr := http.NewRequest(http.MethodPost, reqUrl.String(), bytes.NewBuffer(reqBodyBytes))
if newRequestErr != nil {
return newRequestErr
}
headerErr := common.AddAuthorizationHeader(req)
req.Header.Add("Content-Type", "application/json")
if headerErr != nil {
return headerErr
}
common.PrintDebugRequest("Deploy stack request", req)
client := common.NewHttpClient()
resp, requestExecutionErr := client.Do(req)
if requestExecutionErr != nil {
return requestExecutionErr
}
common.PrintDebugResponse("Deploy stack response", resp)
responseErr := common.CheckResponseForErrors(resp)
if responseErr != nil {
return responseErr
}
return nil
} }
func deployComposeStack(stackName string, environmentVariables []common.StackEnv, stackFileContent string) error { func deployComposeStack(stackName string, environmentVariables []common.StackEnv, stackFileContent string) (err error) {
client, err := common.GetClient()
if err != nil {
return
}
reqBody := common.StackCreateRequest{ reqBody := common.StackCreateRequest{
Name: stackName, Name: stackName,
Env: environmentVariables, Env: environmentVariables,
StackFileContent: stackFileContent, StackFileContent: stackFileContent,
} }
reqBodyBytes, marshalingErr := json.Marshal(reqBody) err = client.DoJSON(fmt.Sprintf("stacks?type=%v&method=%s&endpointId=%s", 2, "string", viper.GetString("stack.deploy.endpoint")), http.MethodPost, &reqBody, nil)
if marshalingErr != nil {
return marshalingErr
}
reqUrl, parsingErr := url.Parse(fmt.Sprintf("%s/api/stacks?type=%v&method=%s&endpointId=%s", viper.GetString("url"), 2, "string", viper.GetString("stack.deploy.endpoint"))) return
if parsingErr != nil {
return parsingErr
}
req, newRequestErr := http.NewRequest(http.MethodPost, reqUrl.String(), bytes.NewBuffer(reqBodyBytes))
if newRequestErr != nil {
return newRequestErr
}
headerErr := common.AddAuthorizationHeader(req)
req.Header.Add("Content-Type", "application/json")
if headerErr != nil {
return headerErr
}
common.PrintDebugRequest("Deploy stack request", req)
client := common.NewHttpClient()
resp, requestExecutionErr := client.Do(req)
if requestExecutionErr != nil {
return requestExecutionErr
}
common.PrintDebugResponse("Deploy stack response", resp)
responseErr := common.CheckResponseForErrors(resp)
if responseErr != nil {
return responseErr
}
return nil
} }
func updateStack(stack common.Stack, environmentVariables []common.StackEnv, stackFileContent string, prune bool) error { func updateStack(stack common.Stack, environmentVariables []common.StackEnv, stackFileContent string, prune bool) (err error) {
client, err := common.GetClient()
if err != nil {
return
}
reqBody := common.StackUpdateRequest{ reqBody := common.StackUpdateRequest{
Env: environmentVariables, Env: environmentVariables,
StackFileContent: stackFileContent, StackFileContent: stackFileContent,
Prune: prune, Prune: prune,
} }
reqBodyBytes, marshalingErr := json.Marshal(reqBody) err = client.DoJSON(fmt.Sprintf("stacks/%v?endpointId=%s", stack.Id, viper.GetString("stack.deploy.endpoint")), http.MethodPut, &reqBody, nil)
if marshalingErr != nil {
return marshalingErr
}
reqUrl, parsingErr := url.Parse(fmt.Sprintf("%s/api/stacks/%v?endpointId=%s", viper.GetString("url"), stack.Id, viper.GetString("stack.deploy.endpoint"))) return
if parsingErr != nil {
return parsingErr
}
req, newRequestErr := http.NewRequest(http.MethodPut, reqUrl.String(), bytes.NewBuffer(reqBodyBytes))
if newRequestErr != nil {
return newRequestErr
}
headerErr := common.AddAuthorizationHeader(req)
req.Header.Add("Content-Type", "application/json")
if headerErr != nil {
return headerErr
}
common.PrintDebugRequest("Update stack request", req)
client := common.NewHttpClient()
resp, requestExecutionErr := client.Do(req)
if requestExecutionErr != nil {
return requestExecutionErr
}
common.PrintDebugResponse("Update stack response", resp)
responseErr := common.CheckResponseForErrors(resp)
if responseErr != nil {
return responseErr
}
return nil
} }
func getSwarmClusterId() (string, error) { func getSwarmClusterId() (id string, err error) {
// Get docker information for endpoint // Get docker information for endpoint
reqUrl, parsingErr := url.Parse(fmt.Sprintf("%s/api/endpoints/%v/docker/info", viper.GetString("url"), viper.GetString("stack.deploy.endpoint"))) client, err := common.GetClient()
if parsingErr != nil { if err != nil {
return "", parsingErr return
} }
req, newRequestErr := http.NewRequest(http.MethodGet, reqUrl.String(), nil) var result map[string]interface{}
if newRequestErr != nil {
return "", newRequestErr
}
headerErr := common.AddAuthorizationHeader(req)
if headerErr != nil {
return "", headerErr
}
common.PrintDebugRequest("Get docker info request", req)
client := common.NewHttpClient() err = client.DoJSON(fmt.Sprintf("endpoints/%v/docker/info", viper.GetString("stack.deploy.endpoint")), http.MethodGet, nil, &result)
if err != nil {
resp, requestExecutionErr := client.Do(req) return
if requestExecutionErr != nil {
return "", requestExecutionErr
}
common.PrintDebugResponse("Get docker info response", resp)
responseErr := common.CheckResponseForErrors(resp)
if responseErr != nil {
return "", responseErr
} }
// Get swarm (if any) information for endpoint // Get swarm (if any) information for endpoint
var result map[string]interface{} swarmClusterId, err := selectValue(result, []string{"Swarm", "Cluster", "ID"})
decodingError := json.NewDecoder(resp.Body).Decode(&result) if err != nil {
if decodingError != nil { return
return "", decodingError
} }
id = swarmClusterId.(string)
swarmClusterId, selectionErr := selectValue(result, []string{"Swarm", "Cluster", "ID"}) return
if selectionErr != nil {
return "", selectionErr
}
return swarmClusterId.(string), nil
} }
func selectValue(jsonMap map[string]interface{}, jsonPath []string) (interface{}, error) { func selectValue(jsonMap map[string]interface{}, jsonPath []string) (interface{}, error) {
@ -333,42 +229,22 @@ func loadEnvironmentVariablesFile(path string) ([]common.StackEnv, error) {
return variables, nil return variables, nil
} }
func getStackFileContent(stackId uint32) (string, error) { func getStackFileContent(stackId uint32) (content string, err error) {
reqUrl, parsingErr := url.Parse(fmt.Sprintf("%s/api/stacks/%v/file", viper.GetString("url"), stackId)) client, err := common.GetClient()
if parsingErr != nil { if err != nil {
return "", parsingErr return
}
req, newRequestErr := http.NewRequest(http.MethodGet, reqUrl.String(), nil)
if newRequestErr != nil {
return "", newRequestErr
}
headerErr := common.AddAuthorizationHeader(req)
if headerErr != nil {
return "", headerErr
}
common.PrintDebugRequest("Get stack file content request", req)
client := common.NewHttpClient()
resp, requestExecutionErr := client.Do(req)
if requestExecutionErr != nil {
return "", requestExecutionErr
}
common.PrintDebugResponse("Get stack file content response", resp)
responseErr := common.CheckResponseForErrors(resp)
if responseErr != nil {
return "", responseErr
} }
var respBody common.StackFileInspectResponse var respBody common.StackFileInspectResponse
decodingErr := json.NewDecoder(resp.Body).Decode(&respBody)
if decodingErr != nil { err = client.DoJSON(fmt.Sprintf("stacks/%v/file", stackId), http.MethodGet, nil, respBody)
return "", decodingErr if err != nil {
return
} }
return respBody.StackFileContent, nil content = respBody.StackFileContent
return
} }
type valueNotFoundError struct{} type valueNotFoundError struct{}

View File

@ -2,13 +2,12 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/greenled/portainer-stack-utils/common"
"github.com/spf13/viper"
"log" "log"
"net/http" "net/http"
"net/url"
"github.com/greenled/portainer-stack-utils/common"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper"
) )
// stackRemoveCmd represents the remove command // stackRemoveCmd represents the remove command
@ -30,22 +29,12 @@ var stackRemoveCmd = &cobra.Command{
stackId := stack.Id stackId := stack.Id
common.PrintVerbose(fmt.Sprintf("Removing stack %s...", stackName)) common.PrintVerbose(fmt.Sprintf("Removing stack %s...", stackName))
reqUrl, err := url.Parse(fmt.Sprintf("%s/api/stacks/%d", viper.GetString("url"), stackId))
client, err := common.GetClient()
common.CheckError(err) common.CheckError(err)
req, err := http.NewRequest(http.MethodDelete, reqUrl.String(), nil) err = client.DoJSON(fmt.Sprintf("stacks/%d", stackId), http.MethodDelete, nil, nil)
common.CheckError(err) common.CheckError(err)
headerErr := common.AddAuthorizationHeader(req)
common.CheckError(headerErr)
common.PrintDebugRequest("Remove stack request", req)
client := common.NewHttpClient()
resp, err := client.Do(req)
common.PrintDebugResponse("Remove stack response", resp)
common.CheckError(err)
common.CheckError(common.CheckResponseForErrors(resp))
case *common.StackNotFoundError: case *common.StackNotFoundError:
// The stack does not exist // The stack does not exist
common.PrintVerbose(fmt.Sprintf("Stack %s does not exist.", stackName)) common.PrintVerbose(fmt.Sprintf("Stack %s does not exist.", stackName))

View File

@ -1,15 +1,14 @@
package cmd package cmd
import ( import (
"encoding/json"
"fmt" "fmt"
"net/http"
"os"
"text/template"
"github.com/greenled/portainer-stack-utils/common" "github.com/greenled/portainer-stack-utils/common"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"net/http"
"net/url"
"os"
"text/template"
) )
// statusCmd represents the status command // statusCmd represents the status command
@ -17,27 +16,12 @@ var statusCmd = &cobra.Command{
Use: "status", Use: "status",
Short: "Check Portainer status", Short: "Check Portainer status",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
reqUrl, parsingErr := url.Parse(fmt.Sprintf("%s/api/status", viper.GetString("url"))) client, err := common.GetClient()
common.CheckError(parsingErr) common.CheckError(err)
req, newRequestErr := http.NewRequest(http.MethodGet, reqUrl.String(), nil)
common.CheckError(newRequestErr)
headerErr := common.AddAuthorizationHeader(req)
common.CheckError(headerErr)
common.PrintDebugRequest("Get status request", req)
client := common.NewHttpClient()
resp, requestExecutionErr := client.Do(req)
common.CheckError(requestExecutionErr)
common.PrintDebugResponse("Get status response", resp)
responseErr := common.CheckResponseForErrors(resp)
common.CheckError(responseErr)
var respBody common.Status var respBody common.Status
decodingErr := json.NewDecoder(resp.Body).Decode(&respBody) err = client.DoJSON("status", http.MethodGet, nil, &respBody)
common.CheckError(decodingErr) common.CheckError(err)
if viper.GetString("status.format") != "" { if viper.GetString("status.format") != "" {
// Print stack fields formatted // Print stack fields formatted

View File

@ -3,51 +3,26 @@ package common
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/spf13/viper"
"net/http" "net/http"
"net/url"
) )
func GetAllStacks() ([]Stack, error) { func GetAllStacks() ([]Stack, error) {
return GetAllStacksFiltered(StackListFilter{}) return GetAllStacksFiltered(StackListFilter{})
} }
func GetAllStacksFiltered(filter StackListFilter) ([]Stack, error) { func GetAllStacksFiltered(filter StackListFilter) (stacks []Stack, err error) {
PrintVerbose("Getting all stacks...") PrintVerbose("Getting all stacks...")
client, err := GetClient()
if err != nil {
return
}
filterJsonBytes, _ := json.Marshal(filter) filterJsonBytes, _ := json.Marshal(filter)
filterJsonString := string(filterJsonBytes) filterJsonString := string(filterJsonBytes)
reqUrl, err := url.Parse(fmt.Sprintf("%s/api/stacks?filters=%s", viper.GetString("url"), filterJsonString)) err = client.DoJSON(fmt.Sprintf("stacks?filters=%s", filterJsonString), http.MethodGet, nil, &stacks)
if err != nil { return
return nil, err
}
req, err := http.NewRequest(http.MethodGet, reqUrl.String(), nil)
if err != nil {
return nil, err
}
headerErr := AddAuthorizationHeader(req)
if headerErr != nil {
return nil, err
}
PrintDebugRequest("Get stacks request", req)
client := NewHttpClient()
resp, err := client.Do(req)
if err != nil {
return nil, err
}
PrintDebugResponse("Get stacks response", resp)
CheckError(CheckResponseForErrors(resp))
var respBody []Stack
decodingErr := json.NewDecoder(resp.Body).Decode(&respBody)
CheckError(decodingErr)
return respBody, nil
} }
func GetStackByName(name string) (Stack, error) { func GetStackByName(name string) (Stack, error) {
@ -81,37 +56,14 @@ func (e *StackNotFoundError) Error() string {
return fmt.Sprintf("Stack %s not found", e.StackName) return fmt.Sprintf("Stack %s not found", e.StackName)
} }
func GetAllEndpoints() ([]EndpointSubset, error) { func GetAllEndpoints() (endpoints []EndpointSubset, err error) {
PrintVerbose("Getting all endpoints...") PrintVerbose("Getting all endpoints...")
reqUrl, err := url.Parse(fmt.Sprintf("%s/api/endpoints", viper.GetString("url"))) client, err := GetClient()
if err != nil { if err != nil {
return nil, err return
} }
req, err := http.NewRequest(http.MethodGet, reqUrl.String(), nil) err = client.DoJSON("endpoints", http.MethodGet, nil, &endpoints)
if err != nil { return
return nil, err
}
headerErr := AddAuthorizationHeader(req)
if headerErr != nil {
return nil, err
}
PrintDebugRequest("Get endpoints request", req)
client := NewHttpClient()
resp, err := client.Do(req)
if err != nil {
return nil, err
}
PrintDebugResponse("Get endpoints response", resp)
CheckError(CheckResponseForErrors(resp))
var respBody []EndpointSubset
decodingErr := json.NewDecoder(resp.Body).Decode(&respBody)
CheckError(decodingErr)
return respBody, nil
} }