github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/api/cloudcontroller/ccv2/application.go (about) 1 package ccv2 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "time" 8 9 "code.cloudfoundry.org/cli/api/cloudcontroller" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 11 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant" 12 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/internal" 13 "code.cloudfoundry.org/cli/types" 14 ) 15 16 // Application represents a Cloud Controller Application. 17 type Application struct { 18 // Buildpack is the buildpack set by the user. 19 Buildpack types.FilteredString 20 21 // Command is the user specified start command. 22 Command types.FilteredString 23 24 // DetectedBuildpack is the buildpack automatically detected. 25 DetectedBuildpack types.FilteredString 26 27 // DetectedStartCommand is the command used to start the application. 28 DetectedStartCommand types.FilteredString 29 30 // DiskQuota is the disk given to each instance, in megabytes. 31 DiskQuota types.NullByteSizeInMb 32 33 // DockerCredentials is the authentication information for the provided 34 // DockerImage. 35 DockerCredentials DockerCredentials 36 37 // DockerImage is the docker image location. 38 DockerImage string 39 40 // EnvironmentVariables are the environment variables passed to the app. 41 EnvironmentVariables map[string]string 42 43 // GUID is the unique application identifier. 44 GUID string 45 46 // HealthCheckTimeout is the number of seconds for health checking of an 47 // staged app when starting up. 48 HealthCheckTimeout int 49 50 // HealthCheckType is the type of health check that will be done to the app. 51 HealthCheckType constant.ApplicationHealthCheckType 52 53 // HealthCheckHTTPEndpoint is the url of the http health check endpoint. 54 HealthCheckHTTPEndpoint string 55 56 // Instances is the total number of app instances. 57 Instances types.NullInt 58 59 // Memory is the memory given to each instance, in megabytes. 60 Memory types.NullByteSizeInMb 61 62 // Name is the name given to the application. 63 Name string 64 65 // PackageState represents the staging state of the application bits. 66 PackageState constant.ApplicationPackageState 67 68 // PackageUpdatedAt is the last time the app bits were updated. In RFC3339. 69 PackageUpdatedAt time.Time 70 71 // SpaceGUID is the GUID of the app's space. 72 SpaceGUID string 73 74 // StackGUID is the GUID for the Stack the application is running on. 75 StackGUID string 76 77 // StagingFailedDescription is the verbose description of why the package 78 // failed to stage. 79 StagingFailedDescription string 80 81 // StagingFailedReason is the reason why the package failed to stage. 82 StagingFailedReason string 83 84 // State is the desired state of the application. 85 State constant.ApplicationState 86 } 87 88 // DockerCredentials are the authentication credentials to pull a docker image 89 // from it's repository. 90 type DockerCredentials struct { 91 // Username is the username for a user that has access to a given docker 92 // image. 93 Username string `json:"username,omitempty"` 94 95 // Password is the password for the user. 96 Password string `json:"password,omitempty"` 97 } 98 99 // MarshalJSON converts an application into a Cloud Controller Application. 100 func (application Application) MarshalJSON() ([]byte, error) { 101 ccApp := struct { 102 Buildpack *string `json:"buildpack,omitempty"` 103 Command *string `json:"command,omitempty"` 104 DiskQuota *uint64 `json:"disk_quota,omitempty"` 105 DockerCredentials *DockerCredentials `json:"docker_credentials,omitempty"` 106 DockerImage string `json:"docker_image,omitempty"` 107 EnvironmentVariables map[string]string `json:"environment_json,omitempty"` 108 HealthCheckHTTPEndpoint *string `json:"health_check_http_endpoint,omitempty"` 109 HealthCheckTimeout int `json:"health_check_timeout,omitempty"` 110 HealthCheckType constant.ApplicationHealthCheckType `json:"health_check_type,omitempty"` 111 Instances *int `json:"instances,omitempty"` 112 Memory *uint64 `json:"memory,omitempty"` 113 Name string `json:"name,omitempty"` 114 SpaceGUID string `json:"space_guid,omitempty"` 115 StackGUID string `json:"stack_guid,omitempty"` 116 State constant.ApplicationState `json:"state,omitempty"` 117 }{ 118 DockerImage: application.DockerImage, 119 EnvironmentVariables: application.EnvironmentVariables, 120 HealthCheckTimeout: application.HealthCheckTimeout, 121 HealthCheckType: application.HealthCheckType, 122 Name: application.Name, 123 SpaceGUID: application.SpaceGUID, 124 StackGUID: application.StackGUID, 125 State: application.State, 126 } 127 128 if application.Buildpack.IsSet { 129 ccApp.Buildpack = &application.Buildpack.Value 130 } 131 132 if application.Command.IsSet { 133 ccApp.Command = &application.Command.Value 134 } 135 136 if application.DiskQuota.IsSet { 137 ccApp.DiskQuota = &application.DiskQuota.Value 138 } 139 140 if application.DockerCredentials.Username != "" || application.DockerCredentials.Password != "" { 141 ccApp.DockerCredentials = &DockerCredentials{ 142 Username: application.DockerCredentials.Username, 143 Password: application.DockerCredentials.Password, 144 } 145 } 146 147 if application.Instances.IsSet { 148 ccApp.Instances = &application.Instances.Value 149 } 150 151 if application.HealthCheckType != "" { 152 ccApp.HealthCheckHTTPEndpoint = &application.HealthCheckHTTPEndpoint 153 } 154 155 if application.Memory.IsSet { 156 ccApp.Memory = &application.Memory.Value 157 } 158 159 return json.Marshal(ccApp) 160 } 161 162 // UnmarshalJSON helps unmarshal a Cloud Controller Application response. 163 func (application *Application) UnmarshalJSON(data []byte) error { 164 var ccApp struct { 165 Metadata internal.Metadata `json:"metadata"` 166 Entity struct { 167 Buildpack string `json:"buildpack"` 168 Command string `json:"command"` 169 DetectedBuildpack string `json:"detected_buildpack"` 170 DetectedStartCommand string `json:"detected_start_command"` 171 DiskQuota *uint64 `json:"disk_quota"` 172 DockerImage string `json:"docker_image"` 173 DockerCredentials DockerCredentials `json:"docker_credentials"` 174 // EnvironmentVariables' values can be any type, so we must accept 175 // interface{}, but we convert to string. 176 EnvironmentVariables map[string]interface{} `json:"environment_json"` 177 HealthCheckHTTPEndpoint string `json:"health_check_http_endpoint"` 178 HealthCheckTimeout int `json:"health_check_timeout"` 179 HealthCheckType string `json:"health_check_type"` 180 Instances json.Number `json:"instances"` 181 Memory *uint64 `json:"memory"` 182 Name string `json:"name"` 183 PackageState string `json:"package_state"` 184 PackageUpdatedAt *time.Time `json:"package_updated_at"` 185 StackGUID string `json:"stack_guid"` 186 StagingFailedDescription string `json:"staging_failed_description"` 187 StagingFailedReason string `json:"staging_failed_reason"` 188 State string `json:"state"` 189 } `json:"entity"` 190 } 191 192 decoder := json.NewDecoder(bytes.NewBuffer(data)) 193 decoder.UseNumber() 194 err := decoder.Decode(&ccApp) 195 if err != nil { 196 return err 197 } 198 199 application.Buildpack.ParseValue(ccApp.Entity.Buildpack) 200 application.Command.ParseValue(ccApp.Entity.Command) 201 application.DetectedBuildpack.ParseValue(ccApp.Entity.DetectedBuildpack) 202 application.DetectedStartCommand.ParseValue(ccApp.Entity.DetectedStartCommand) 203 application.DiskQuota.ParseUint64Value(ccApp.Entity.DiskQuota) 204 application.DockerCredentials = ccApp.Entity.DockerCredentials 205 application.DockerImage = ccApp.Entity.DockerImage 206 application.GUID = ccApp.Metadata.GUID 207 application.HealthCheckHTTPEndpoint = ccApp.Entity.HealthCheckHTTPEndpoint 208 application.HealthCheckTimeout = ccApp.Entity.HealthCheckTimeout 209 application.HealthCheckType = constant.ApplicationHealthCheckType(ccApp.Entity.HealthCheckType) 210 application.Memory.ParseUint64Value(ccApp.Entity.Memory) 211 application.Name = ccApp.Entity.Name 212 application.PackageState = constant.ApplicationPackageState(ccApp.Entity.PackageState) 213 application.StackGUID = ccApp.Entity.StackGUID 214 application.StagingFailedDescription = ccApp.Entity.StagingFailedDescription 215 application.StagingFailedReason = ccApp.Entity.StagingFailedReason 216 application.State = constant.ApplicationState(ccApp.Entity.State) 217 218 if len(ccApp.Entity.EnvironmentVariables) > 0 { 219 envVariableValues := map[string]string{} 220 for key, value := range ccApp.Entity.EnvironmentVariables { 221 envVariableValues[key] = fmt.Sprint(value) 222 } 223 application.EnvironmentVariables = envVariableValues 224 } 225 226 err = application.Instances.ParseStringValue(ccApp.Entity.Instances.String()) 227 if err != nil { 228 return err 229 } 230 231 if ccApp.Entity.PackageUpdatedAt != nil { 232 application.PackageUpdatedAt = *ccApp.Entity.PackageUpdatedAt 233 } 234 return nil 235 } 236 237 // CreateApplication creates a cloud controller application in with the given 238 // settings. SpaceGUID and Name are the only required fields. 239 func (client *Client) CreateApplication(app Application) (Application, Warnings, error) { 240 body, err := json.Marshal(app) 241 if err != nil { 242 return Application{}, nil, err 243 } 244 245 request, err := client.newHTTPRequest(requestOptions{ 246 RequestName: internal.PostAppRequest, 247 Body: bytes.NewReader(body), 248 }) 249 if err != nil { 250 return Application{}, nil, err 251 } 252 253 var updatedApp Application 254 response := cloudcontroller.Response{ 255 Result: &updatedApp, 256 } 257 258 err = client.connection.Make(request, &response) 259 return updatedApp, response.Warnings, err 260 } 261 262 // GetApplication returns back an Application. 263 func (client *Client) GetApplication(guid string) (Application, Warnings, error) { 264 request, err := client.newHTTPRequest(requestOptions{ 265 RequestName: internal.GetAppRequest, 266 URIParams: Params{"app_guid": guid}, 267 }) 268 if err != nil { 269 return Application{}, nil, err 270 } 271 272 var app Application 273 response := cloudcontroller.Response{ 274 Result: &app, 275 } 276 277 err = client.connection.Make(request, &response) 278 return app, response.Warnings, err 279 } 280 281 // GetApplications returns back a list of Applications based off of the 282 // provided filters. 283 func (client *Client) GetApplications(filters ...Filter) ([]Application, Warnings, error) { 284 request, err := client.newHTTPRequest(requestOptions{ 285 RequestName: internal.GetAppsRequest, 286 Query: ConvertFilterParameters(filters), 287 }) 288 if err != nil { 289 return nil, nil, err 290 } 291 292 var fullAppsList []Application 293 warnings, err := client.paginate(request, Application{}, func(item interface{}) error { 294 if app, ok := item.(Application); ok { 295 fullAppsList = append(fullAppsList, app) 296 } else { 297 return ccerror.UnknownObjectInListError{ 298 Expected: Application{}, 299 Unexpected: item, 300 } 301 } 302 return nil 303 }) 304 305 return fullAppsList, warnings, err 306 } 307 308 // UpdateApplication updates the application with the given GUID. Note: Sending 309 // DockerImage and StackGUID at the same time will result in an API error. 310 func (client *Client) UpdateApplication(app Application) (Application, Warnings, error) { 311 body, err := json.Marshal(app) 312 if err != nil { 313 return Application{}, nil, err 314 } 315 316 request, err := client.newHTTPRequest(requestOptions{ 317 RequestName: internal.PutAppRequest, 318 URIParams: Params{"app_guid": app.GUID}, 319 Body: bytes.NewReader(body), 320 }) 321 if err != nil { 322 return Application{}, nil, err 323 } 324 325 var updatedApp Application 326 response := cloudcontroller.Response{ 327 Result: &updatedApp, 328 } 329 330 err = client.connection.Make(request, &response) 331 return updatedApp, response.Warnings, err 332 } 333 334 // RestageApplication restages the application with the given GUID. 335 func (client *Client) RestageApplication(app Application) (Application, Warnings, error) { 336 request, err := client.newHTTPRequest(requestOptions{ 337 RequestName: internal.PostAppRestageRequest, 338 URIParams: Params{"app_guid": app.GUID}, 339 }) 340 if err != nil { 341 return Application{}, nil, err 342 } 343 344 var restagedApp Application 345 response := cloudcontroller.Response{ 346 Result: &restagedApp, 347 } 348 349 err = client.connection.Make(request, &response) 350 return restagedApp, response.Warnings, err 351 } 352 353 // GetRouteApplications returns a list of Applications based off a route 354 // GUID and the provided filters. 355 func (client *Client) GetRouteApplications(routeGUID string, filters ...Filter) ([]Application, Warnings, error) { 356 request, err := client.newHTTPRequest(requestOptions{ 357 RequestName: internal.GetRouteAppsRequest, 358 URIParams: map[string]string{"route_guid": routeGUID}, 359 Query: ConvertFilterParameters(filters), 360 }) 361 if err != nil { 362 return nil, nil, err 363 } 364 365 var fullAppsList []Application 366 warnings, err := client.paginate(request, Application{}, func(item interface{}) error { 367 if app, ok := item.(Application); ok { 368 fullAppsList = append(fullAppsList, app) 369 } else { 370 return ccerror.UnknownObjectInListError{ 371 Expected: Application{}, 372 Unexpected: item, 373 } 374 } 375 return nil 376 }) 377 378 return fullAppsList, warnings, err 379 }