248 lines
6.6 KiB
Go
248 lines
6.6 KiB
Go
package cfclient
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"io/ioutil"
|
|
"mime/multipart"
|
|
"os"
|
|
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"code.cloudfoundry.org/gofileutils/fileutils"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type BuildpackResponse struct {
|
|
Count int `json:"total_results"`
|
|
Pages int `json:"total_pages"`
|
|
NextUrl string `json:"next_url"`
|
|
Resources []BuildpackResource `json:"resources"`
|
|
}
|
|
|
|
type BuildpackResource struct {
|
|
Meta Meta `json:"metadata"`
|
|
Entity Buildpack `json:"entity"`
|
|
}
|
|
|
|
type Buildpack struct {
|
|
Guid string `json:"guid"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
Name string `json:"name"`
|
|
Enabled bool `json:"enabled"`
|
|
Locked bool `json:"locked"`
|
|
Position int `json:"position"`
|
|
Filename string `json:"filename"`
|
|
Stack string `json:"stack"`
|
|
c *Client
|
|
}
|
|
|
|
type BuildpackRequest struct {
|
|
// These are all pointers to the values so that we can tell
|
|
// whether people wanted position 0, or enable/unlock values,
|
|
// vs whether they didn't specify them and want them unchanged/default.
|
|
Name *string `json:"name,omitempty"`
|
|
Enabled *bool `json:"enabled,omitempty"`
|
|
Locked *bool `json:"locked,omitempty"`
|
|
Position *int `json:"position,omitempty"`
|
|
Stack *string `json:"stack,omitempty"`
|
|
}
|
|
|
|
func (c *Client) CreateBuildpack(bpr *BuildpackRequest) (*Buildpack, error) {
|
|
if bpr.Name == nil || *bpr.Name == "" {
|
|
return nil, errors.New("Unable to create a buidlpack with no name")
|
|
}
|
|
requestUrl := "/v2/buildpacks"
|
|
req := c.NewRequest("POST", requestUrl)
|
|
req.obj = bpr
|
|
resp, err := c.DoRequest(req)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Error creating buildpack:")
|
|
}
|
|
bp, err := c.handleBuildpackResp(resp)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Error creating buildpack:")
|
|
}
|
|
return &bp, nil
|
|
}
|
|
|
|
func (c *Client) ListBuildpacks() ([]Buildpack, error) {
|
|
var buildpacks []Buildpack
|
|
requestUrl := "/v2/buildpacks"
|
|
for {
|
|
buildpackResp, err := c.getBuildpackResponse(requestUrl)
|
|
if err != nil {
|
|
return []Buildpack{}, err
|
|
}
|
|
for _, buildpack := range buildpackResp.Resources {
|
|
buildpacks = append(buildpacks, c.mergeBuildpackResource(buildpack))
|
|
}
|
|
requestUrl = buildpackResp.NextUrl
|
|
if requestUrl == "" {
|
|
break
|
|
}
|
|
}
|
|
return buildpacks, nil
|
|
}
|
|
|
|
func (c *Client) DeleteBuildpack(guid string, async bool) error {
|
|
resp, err := c.DoRequest(c.NewRequest("DELETE", fmt.Sprintf("/v2/buildpacks/%s?async=%t", guid, async)))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if (async && (resp.StatusCode != http.StatusAccepted)) || (!async && (resp.StatusCode != http.StatusNoContent)) {
|
|
return errors.Wrapf(err, "Error deleting buildpack %s, response code: %d", guid, resp.StatusCode)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) getBuildpackResponse(requestUrl string) (BuildpackResponse, error) {
|
|
var buildpackResp BuildpackResponse
|
|
r := c.NewRequest("GET", requestUrl)
|
|
resp, err := c.DoRequest(r)
|
|
if err != nil {
|
|
return BuildpackResponse{}, errors.Wrap(err, "Error requesting buildpacks")
|
|
}
|
|
resBody, err := ioutil.ReadAll(resp.Body)
|
|
defer resp.Body.Close()
|
|
if err != nil {
|
|
return BuildpackResponse{}, errors.Wrap(err, "Error reading buildpack request")
|
|
}
|
|
err = json.Unmarshal(resBody, &buildpackResp)
|
|
if err != nil {
|
|
return BuildpackResponse{}, errors.Wrap(err, "Error unmarshalling buildpack")
|
|
}
|
|
return buildpackResp, nil
|
|
}
|
|
|
|
func (c *Client) mergeBuildpackResource(buildpack BuildpackResource) Buildpack {
|
|
buildpack.Entity.Guid = buildpack.Meta.Guid
|
|
buildpack.Entity.CreatedAt = buildpack.Meta.CreatedAt
|
|
buildpack.Entity.UpdatedAt = buildpack.Meta.UpdatedAt
|
|
buildpack.Entity.c = c
|
|
return buildpack.Entity
|
|
}
|
|
|
|
func (c *Client) GetBuildpackByGuid(buildpackGUID string) (Buildpack, error) {
|
|
requestUrl := fmt.Sprintf("/v2/buildpacks/%s", buildpackGUID)
|
|
r := c.NewRequest("GET", requestUrl)
|
|
resp, err := c.DoRequest(r)
|
|
if err != nil {
|
|
return Buildpack{}, errors.Wrap(err, "Error requesting buildpack info")
|
|
}
|
|
return c.handleBuildpackResp(resp)
|
|
}
|
|
|
|
func (c *Client) handleBuildpackResp(resp *http.Response) (Buildpack, error) {
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
defer resp.Body.Close()
|
|
if err != nil {
|
|
return Buildpack{}, err
|
|
}
|
|
var buildpackResource BuildpackResource
|
|
if err := json.Unmarshal(body, &buildpackResource); err != nil {
|
|
return Buildpack{}, err
|
|
}
|
|
return c.mergeBuildpackResource(buildpackResource), nil
|
|
}
|
|
|
|
func (b *Buildpack) Upload(file io.Reader, fileName string) error {
|
|
var capturedErr error
|
|
fileutils.TempFile("requests", func(requestFile *os.File, err error) {
|
|
if err != nil {
|
|
capturedErr = err
|
|
return
|
|
}
|
|
writer := multipart.NewWriter(requestFile)
|
|
part, err := writer.CreateFormFile("buildpack", fileName)
|
|
|
|
if err != nil {
|
|
_ = writer.Close()
|
|
capturedErr = err
|
|
return
|
|
}
|
|
|
|
_, err = io.Copy(part, file)
|
|
if err != nil {
|
|
capturedErr = fmt.Errorf("Error creating upload: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
err = writer.Close()
|
|
if err != nil {
|
|
capturedErr = err
|
|
return
|
|
}
|
|
|
|
requestFile.Seek(0, 0)
|
|
fileStats, err := requestFile.Stat()
|
|
if err != nil {
|
|
capturedErr = fmt.Errorf("Error getting file info: %s", err)
|
|
}
|
|
|
|
req, err := http.NewRequest("PUT", fmt.Sprintf("%s/v2/buildpacks/%s/bits", b.c.Config.ApiAddress, b.Guid), requestFile)
|
|
if err != nil {
|
|
capturedErr = err
|
|
return
|
|
}
|
|
|
|
req.ContentLength = fileStats.Size()
|
|
contentType := fmt.Sprintf("multipart/form-data; boundary=%s", writer.Boundary())
|
|
req.Header.Set("Content-Type", contentType)
|
|
resp, err := b.c.Do(req) //client.Do() handles the HTTP status code checking for us
|
|
if err != nil {
|
|
capturedErr = err
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
})
|
|
|
|
return errors.Wrap(capturedErr, "Error uploading buildpack:")
|
|
}
|
|
|
|
func (b *Buildpack) Update(bpr *BuildpackRequest) error {
|
|
requestUrl := fmt.Sprintf("/v2/buildpacks/%s", b.Guid)
|
|
req := b.c.NewRequest("PUT", requestUrl)
|
|
req.obj = bpr
|
|
resp, err := b.c.DoRequest(req)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Error updating buildpack:")
|
|
}
|
|
newBp, err := b.c.handleBuildpackResp(resp)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Error updating buildpack:")
|
|
}
|
|
b.Name = newBp.Name
|
|
b.Locked = newBp.Locked
|
|
b.Enabled = newBp.Enabled
|
|
return nil
|
|
}
|
|
|
|
func (bpr *BuildpackRequest) Lock() {
|
|
b := true
|
|
bpr.Locked = &b
|
|
}
|
|
func (bpr *BuildpackRequest) Unlock() {
|
|
b := false
|
|
bpr.Locked = &b
|
|
}
|
|
func (bpr *BuildpackRequest) Enable() {
|
|
b := true
|
|
bpr.Enabled = &b
|
|
}
|
|
func (bpr *BuildpackRequest) Disable() {
|
|
b := false
|
|
bpr.Enabled = &b
|
|
}
|
|
func (bpr *BuildpackRequest) SetPosition(i int) {
|
|
bpr.Position = &i
|
|
}
|
|
func (bpr *BuildpackRequest) SetName(s string) {
|
|
bpr.Name = &s
|
|
}
|
|
func (bpr *BuildpackRequest) SetStack(s string) {
|
|
bpr.Stack = &s
|
|
}
|