open-vault/vendor/github.com/cloudfoundry-community/go-cfclient/buildpacks.go
2019-06-06 12:26:04 -07:00

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
}