diff --git a/scripts/portainer/client/client.go b/scripts/portainer/client/client.go index cdf6d25..e50228b 100644 --- a/scripts/portainer/client/client.go +++ b/scripts/portainer/client/client.go @@ -12,29 +12,96 @@ const ( applicationJson = "application/json" ) +// api docs +// https://app.swaggerhub.com/apis/portainer/portainer-ce/2.9.3 + type PortainerClient struct { authToken string baseUrl string } -func NewPortainerClient(baseUrl string) *PortainerClient { - return &PortainerClient{ - baseUrl: baseUrl, +type Credentials struct { + Username string `json:"username"` + Password string `json:"password"` + BaseUrl string `json:"baseUrl"` +} + +func NewPortainerClient(creds Credentials) (*PortainerClient, error) { + c := &PortainerClient{ + baseUrl: creds.BaseUrl, } + return c, c.Login(creds.Username, creds.Password) } func (c *PortainerClient) IsLoggedIn() bool { return c.authToken != "" } +func (c *PortainerClient) Login(username, password string) error { + payload := map[string]string{"Username": username, "Password": password} + body, err := c.post("api/auth", payload) + if err != nil { + return err + } + type JwtToken struct { + Token string `json:"jwt"` + } + token := JwtToken{} + if err := json.Unmarshal(body, &token); err != nil { + return err + } + c.authToken = token.Token + return nil +} + +func (c *PortainerClient) GetAllStacks() ([]Stack, error) { + b, err := c.get("stacks") + if err != nil { + return nil, err + } + var stacks []Stack + if err := json.Unmarshal(b, &stacks); err != nil { + return nil, err + } + return stacks, nil +} + +func (c *PortainerClient) GetStackByName(name string) (*Stack, error) { + stacks, err := c.GetAllStacks() + if err != nil { + return nil, err + } + for _, s := range stacks { + if s.Name == name { + return &s, nil + } + } + return nil, nil +} + +func (c *PortainerClient) StartStack(stackId int) error { + url := fmt.Sprintf("api/stacks/%d/start", stackId) + b, err := c.post(url, nil) + fmt.Println(string(b)) + return err +} func (c *PortainerClient) post(path string, payload interface{}) ([]byte, error) { jsonBytes, err := json.Marshal(payload) if err != nil { return nil, err } - url := fmt.Sprintf("%s/%s", c.baseUrl, path) - resp, err := http.Post(url, applicationJson, bytes.NewBuffer(jsonBytes)) + // Create a Bearer string by appending string access token + var bearer = "Bearer " + c.authToken + // Create a new request using http + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes)) + + // add authorization header to the req + req.Header.Add("Authorization", bearer) + + // Send req using http Client + client := &http.Client{} + resp, err := client.Do(req) if err != nil { return nil, err } @@ -46,19 +113,28 @@ func (c *PortainerClient) post(path string, payload interface{}) ([]byte, error) return body, nil } -func (c *PortainerClient) Login(username, password string) error { - payload := map[string]string{"Username": username, "Password": password} - body, err := c.post("api/auth", payload) +func (c *PortainerClient) get(path string) ([]byte, error) { + url := fmt.Sprintf("%s/api/%s", c.baseUrl, path) + + // Create a Bearer string by appending string access token + var bearer = "Bearer " + c.authToken + // Create a new request using http + req, err := http.NewRequest("GET", url, nil) + + // add authorization header to the req + req.Header.Add("Authorization", bearer) + + // Send req using http Client + client := &http.Client{} + resp, err := client.Do(req) if err != nil { - return err - } - type JwtToken struct { - Token string `json:"jwt"` + return nil, err } - token := JwtToken{} - if err := json.Unmarshal(body, &token); err != nil { - return err + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err } - c.authToken = token.Token - return nil + return body, nil } diff --git a/scripts/portainer/client/types.go b/scripts/portainer/client/types.go new file mode 100644 index 0000000..3848c5e --- /dev/null +++ b/scripts/portainer/client/types.go @@ -0,0 +1,34 @@ +package client + +type Stack struct { + ID int `json:"Id"` + Name string `json:"Name"` + Type int `json:"Type"` + EndpointID int `json:"EndpointId"` + SwarmID string `json:"SwarmId"` + EntryPoint string `json:"EntryPoint"` + Env []interface{} `json:"Env"` + ResourceControl struct { + ID int `json:"Id"` + ResourceID string `json:"ResourceId"` + SubResourceIds []interface{} `json:"SubResourceIds"` + Type int `json:"Type"` + UserAccesses []interface{} `json:"UserAccesses"` + TeamAccesses []interface{} `json:"TeamAccesses"` + Public bool `json:"Public"` + AdministratorsOnly bool `json:"AdministratorsOnly"` + System bool `json:"System"` + } `json:"ResourceControl"` + Status int `json:"Status"` + ProjectPath string `json:"ProjectPath"` + CreationDate int `json:"CreationDate"` + CreatedBy string `json:"CreatedBy"` + UpdateDate int `json:"UpdateDate"` + UpdatedBy string `json:"UpdatedBy"` + AdditionalFiles interface{} `json:"AdditionalFiles"` + AutoUpdate interface{} `json:"AutoUpdate"` + GitConfig interface{} `json:"GitConfig"` + FromAppTemplate bool `json:"FromAppTemplate"` + Namespace string `json:"Namespace"` + IsComposeFormat bool `json:"IsComposeFormat"` +} diff --git a/scripts/portainer/main.go b/scripts/portainer/main.go index 60e2f02..5df689b 100644 --- a/scripts/portainer/main.go +++ b/scripts/portainer/main.go @@ -7,21 +7,12 @@ import ( "log" "os" "os/user" + "strings" "github.com/chatton/portainer/client" ) -const ( - applicationJson = "application/json" - baseUrl = "http://qnap:9000" -) - -type PortainerCredentials struct { - Username string `json:"username"` - Password string `json:"password"` -} - -func loadCreds() PortainerCredentials { +func loadCreds() client.Credentials { usr, _ := user.Current() credPath := fmt.Sprintf("%s/.homelab/portainer-creds.json", usr.HomeDir) @@ -34,7 +25,7 @@ func loadCreds() PortainerCredentials { log.Fatal(err) } - creds := PortainerCredentials{} + creds := client.Credentials{} if err := json.Unmarshal(fileBytes, &creds); err != nil { log.Fatal(err) } @@ -42,10 +33,25 @@ func loadCreds() PortainerCredentials { } func main() { - c := client.NewPortainerClient(baseUrl) + args := os.Args + if len(args) != 2 { + fmt.Println("must specify name of stack to start!") + os.Exit(1) + } + + stackName := args[1] creds := loadCreds() - err := c.Login(creds.Username, creds.Password) + c, err := client.NewPortainerClient(creds) if err != nil { - log.Fatalln(err) + log.Fatal(err) + } + s, err := c.GetStackByName(stackName) + if err != nil { + log.Fatal(err) + } + + err = c.StartStack(s.ID) + if err != nil && strings.Contains(err.Error(), "is already running") { + log.Fatal(err) } }