github.com/arunkumar7540/cli@v6.45.0+incompatible/api/cloudcontroller/ccv3/buildpack.go (about) 1 package ccv3 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "io" 7 8 "code.cloudfoundry.org/cli/api/cloudcontroller" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal" 11 "code.cloudfoundry.org/cli/api/cloudcontroller/uploads" 12 "code.cloudfoundry.org/cli/types" 13 ) 14 15 // Buildpack represents a Cloud Controller V3 buildpack. 16 type Buildpack struct { 17 // Enabled is true when the buildpack can be used for staging. 18 Enabled types.NullBool 19 // Filename is the uploaded filename of the buildpack. 20 Filename string 21 // GUID is the unique identifier for the buildpack. 22 GUID string 23 // Locked is true when the buildpack cannot be updated. 24 Locked types.NullBool 25 // Name is the name of the buildpack. To be used by app buildpack field. 26 // (only alphanumeric characters) 27 Name string 28 // Position is the order in which the buildpacks are checked during buildpack 29 // auto-detection. 30 Position types.NullInt 31 // Stack is the name of the stack that the buildpack will use. 32 Stack string 33 // State is the current state of the buildpack. 34 State string 35 // Links are links to related resources. 36 Links APILinks 37 } 38 39 // MarshalJSON converts a Package into a Cloud Controller Package. 40 func (buildpack Buildpack) MarshalJSON() ([]byte, error) { 41 ccBuildpack := struct { 42 Name string `json:"name,omitempty"` 43 Stack string `json:"stack,omitempty"` 44 Position *int `json:"position,omitempty"` 45 Enabled *bool `json:"enabled,omitempty"` 46 Locked *bool `json:"locked,omitempty"` 47 }{ 48 Name: buildpack.Name, 49 Stack: buildpack.Stack, 50 } 51 52 if buildpack.Position.IsSet { 53 ccBuildpack.Position = &buildpack.Position.Value 54 } 55 if buildpack.Enabled.IsSet { 56 ccBuildpack.Enabled = &buildpack.Enabled.Value 57 } 58 if buildpack.Locked.IsSet { 59 ccBuildpack.Locked = &buildpack.Locked.Value 60 } 61 62 return json.Marshal(ccBuildpack) 63 } 64 65 func (buildpack *Buildpack) UnmarshalJSON(data []byte) error { 66 var ccBuildpack struct { 67 GUID string `json:"guid,omitempty"` 68 Links APILinks `json:"links,omitempty"` 69 Name string `json:"name,omitempty"` 70 Filename string `json:"filename,omitempty"` 71 Stack string `json:"stack,omitempty"` 72 State string `json:"state,omitempty"` 73 Enabled types.NullBool `json:"enabled"` 74 Locked types.NullBool `json:"locked"` 75 Position types.NullInt `json:"position"` 76 } 77 78 err := cloudcontroller.DecodeJSON(data, &ccBuildpack) 79 if err != nil { 80 return err 81 } 82 83 buildpack.Enabled = ccBuildpack.Enabled 84 buildpack.Filename = ccBuildpack.Filename 85 buildpack.GUID = ccBuildpack.GUID 86 buildpack.Locked = ccBuildpack.Locked 87 buildpack.Name = ccBuildpack.Name 88 buildpack.Position = ccBuildpack.Position 89 buildpack.Stack = ccBuildpack.Stack 90 buildpack.State = ccBuildpack.State 91 buildpack.Links = ccBuildpack.Links 92 93 return nil 94 } 95 96 // CreateBuildpack creates a buildpack with the given settings, Type and the 97 // ApplicationRelationship must be set. 98 func (client *Client) CreateBuildpack(bp Buildpack) (Buildpack, Warnings, error) { 99 bodyBytes, err := json.Marshal(bp) 100 if err != nil { 101 return Buildpack{}, nil, err 102 } 103 104 request, err := client.newHTTPRequest(requestOptions{ 105 RequestName: internal.PostBuildpackRequest, 106 Body: bytes.NewReader(bodyBytes), 107 }) 108 if err != nil { 109 return Buildpack{}, nil, err 110 } 111 112 var responseBuildpack Buildpack 113 response := cloudcontroller.Response{ 114 DecodeJSONResponseInto: &responseBuildpack, 115 } 116 err = client.connection.Make(request, &response) 117 118 return responseBuildpack, response.Warnings, err 119 } 120 121 // DeleteBuildpack deletes the buildpack with the provided guid. 122 func (client Client) DeleteBuildpack(buildpackGUID string) (JobURL, Warnings, error) { 123 request, err := client.newHTTPRequest(requestOptions{ 124 RequestName: internal.DeleteBuildpackRequest, 125 URIParams: map[string]string{ 126 "buildpack_guid": buildpackGUID, 127 }, 128 }) 129 if err != nil { 130 return "", nil, err 131 } 132 133 response := cloudcontroller.Response{} 134 err = client.connection.Make(request, &response) 135 136 return JobURL(response.ResourceLocationURL), response.Warnings, err 137 } 138 139 // GetBuildpacks lists buildpacks with optional filters. 140 func (client *Client) GetBuildpacks(query ...Query) ([]Buildpack, Warnings, error) { 141 request, err := client.newHTTPRequest(requestOptions{ 142 RequestName: internal.GetBuildpacksRequest, 143 Query: query, 144 }) 145 if err != nil { 146 return nil, nil, err 147 } 148 149 var fullBuildpacksList []Buildpack 150 warnings, err := client.paginate(request, Buildpack{}, func(item interface{}) error { 151 if buildpack, ok := item.(Buildpack); ok { 152 fullBuildpacksList = append(fullBuildpacksList, buildpack) 153 } else { 154 return ccerror.UnknownObjectInListError{ 155 Expected: Buildpack{}, 156 Unexpected: item, 157 } 158 } 159 return nil 160 }) 161 162 return fullBuildpacksList, warnings, err 163 } 164 165 func (client Client) UpdateBuildpack(buildpack Buildpack) (Buildpack, Warnings, error) { 166 bodyBytes, err := json.Marshal(buildpack) 167 if err != nil { 168 return Buildpack{}, nil, err 169 } 170 171 request, err := client.newHTTPRequest(requestOptions{ 172 RequestName: internal.PatchBuildpackRequest, 173 Body: bytes.NewReader(bodyBytes), 174 URIParams: map[string]string{"buildpack_guid": buildpack.GUID}, 175 }) 176 if err != nil { 177 return Buildpack{}, nil, err 178 } 179 180 var responseBuildpack Buildpack 181 response := cloudcontroller.Response{ 182 DecodeJSONResponseInto: &responseBuildpack, 183 } 184 err = client.connection.Make(request, &response) 185 186 return responseBuildpack, response.Warnings, err 187 } 188 189 // UploadBuildpack uploads the contents of a buildpack zip to the server. 190 func (client *Client) UploadBuildpack(buildpackGUID string, buildpackPath string, buildpack io.Reader, buildpackLength int64) (JobURL, Warnings, error) { 191 192 contentLength, err := uploads.CalculateRequestSize(buildpackLength, buildpackPath, "bits") 193 if err != nil { 194 return "", nil, err 195 } 196 197 contentType, body, writeErrors := uploads.CreateMultipartBodyAndHeader(buildpack, buildpackPath, "bits") 198 199 request, err := client.newHTTPRequest(requestOptions{ 200 RequestName: internal.PostBuildpackBitsRequest, 201 URIParams: internal.Params{"buildpack_guid": buildpackGUID}, 202 Body: body, 203 }) 204 205 if err != nil { 206 return "", nil, err 207 } 208 209 request.ContentLength = contentLength 210 request.Header.Set("Content-Type", contentType) 211 212 jobURL, warnings, err := client.uploadBuildpackAsynchronously(request, writeErrors) 213 if err != nil { 214 return "", warnings, err 215 } 216 return jobURL, warnings, nil 217 } 218 219 func (client *Client) uploadBuildpackAsynchronously(request *cloudcontroller.Request, writeErrors <-chan error) (JobURL, Warnings, error) { 220 221 var buildpack Buildpack 222 response := cloudcontroller.Response{ 223 DecodeJSONResponseInto: &buildpack, 224 } 225 226 httpErrors := make(chan error) 227 228 go func() { 229 defer close(httpErrors) 230 231 err := client.connection.Make(request, &response) 232 if err != nil { 233 httpErrors <- err 234 } 235 }() 236 237 // The following section makes the following assumptions: 238 // 1) If an error occurs during file reading, an EOF is sent to the request 239 // object. Thus ending the request transfer. 240 // 2) If an error occurs during request transfer, an EOF is sent to the pipe. 241 // Thus ending the writing routine. 242 var firstError error 243 var writeClosed, httpClosed bool 244 245 for { 246 select { 247 case writeErr, ok := <-writeErrors: 248 if !ok { 249 writeClosed = true 250 break // for select 251 } 252 if firstError == nil { 253 firstError = writeErr 254 } 255 case httpErr, ok := <-httpErrors: 256 if !ok { 257 httpClosed = true 258 break // for select 259 } 260 if firstError == nil { 261 firstError = httpErr 262 } 263 } 264 265 if writeClosed && httpClosed { 266 break // for for 267 } 268 } 269 return JobURL(response.ResourceLocationURL), response.Warnings, firstError 270 }