github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+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 uint64 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 // MarshalJSON converts an application into a Cloud Controller Application. 89 func (application Application) MarshalJSON() ([]byte, error) { 90 ccApp := struct { 91 Buildpack *string `json:"buildpack,omitempty"` 92 Command *string `json:"command,omitempty"` 93 DiskQuota *uint64 `json:"disk_quota,omitempty"` 94 DockerCredentials *DockerCredentials `json:"docker_credentials,omitempty"` 95 DockerImage string `json:"docker_image,omitempty"` 96 EnvironmentVariables map[string]string `json:"environment_json,omitempty"` 97 HealthCheckHTTPEndpoint *string `json:"health_check_http_endpoint,omitempty"` 98 HealthCheckTimeout uint64 `json:"health_check_timeout,omitempty"` 99 HealthCheckType constant.ApplicationHealthCheckType `json:"health_check_type,omitempty"` 100 Instances *int `json:"instances,omitempty"` 101 Memory *uint64 `json:"memory,omitempty"` 102 Name string `json:"name,omitempty"` 103 SpaceGUID string `json:"space_guid,omitempty"` 104 StackGUID string `json:"stack_guid,omitempty"` 105 State constant.ApplicationState `json:"state,omitempty"` 106 }{ 107 DockerImage: application.DockerImage, 108 EnvironmentVariables: application.EnvironmentVariables, 109 HealthCheckTimeout: application.HealthCheckTimeout, 110 HealthCheckType: application.HealthCheckType, 111 Name: application.Name, 112 SpaceGUID: application.SpaceGUID, 113 StackGUID: application.StackGUID, 114 State: application.State, 115 } 116 117 if application.Buildpack.IsSet { 118 ccApp.Buildpack = &application.Buildpack.Value 119 } 120 121 if application.Command.IsSet { 122 ccApp.Command = &application.Command.Value 123 } 124 125 if application.DiskQuota.IsSet { 126 ccApp.DiskQuota = &application.DiskQuota.Value 127 } 128 129 if application.DockerCredentials.Username != "" || application.DockerCredentials.Password != "" { 130 ccApp.DockerCredentials = &DockerCredentials{ 131 Username: application.DockerCredentials.Username, 132 Password: application.DockerCredentials.Password, 133 } 134 } 135 136 if application.Instances.IsSet { 137 ccApp.Instances = &application.Instances.Value 138 } 139 140 if application.HealthCheckType != "" { 141 ccApp.HealthCheckHTTPEndpoint = &application.HealthCheckHTTPEndpoint 142 } 143 144 if application.Memory.IsSet { 145 ccApp.Memory = &application.Memory.Value 146 } 147 148 return json.Marshal(ccApp) 149 } 150 151 // UnmarshalJSON helps unmarshal a Cloud Controller Application response. 152 func (application *Application) UnmarshalJSON(data []byte) error { 153 var ccApp struct { 154 Metadata internal.Metadata `json:"metadata"` 155 Entity struct { 156 Buildpack string `json:"buildpack"` 157 Command string `json:"command"` 158 DetectedBuildpack string `json:"detected_buildpack"` 159 DetectedStartCommand string `json:"detected_start_command"` 160 DiskQuota *uint64 `json:"disk_quota"` 161 DockerImage string `json:"docker_image"` 162 DockerCredentials DockerCredentials `json:"docker_credentials"` 163 // EnvironmentVariables' values can be any type, so we must accept 164 // interface{}, but we convert to string. 165 EnvironmentVariables map[string]interface{} `json:"environment_json"` 166 HealthCheckHTTPEndpoint string `json:"health_check_http_endpoint"` 167 HealthCheckTimeout uint64 `json:"health_check_timeout"` 168 HealthCheckType string `json:"health_check_type"` 169 Instances json.Number `json:"instances"` 170 Memory *uint64 `json:"memory"` 171 Name string `json:"name"` 172 PackageState string `json:"package_state"` 173 PackageUpdatedAt *time.Time `json:"package_updated_at"` 174 SpaceGUID string `json:"space_guid"` 175 StackGUID string `json:"stack_guid"` 176 StagingFailedDescription string `json:"staging_failed_description"` 177 StagingFailedReason string `json:"staging_failed_reason"` 178 State string `json:"state"` 179 } `json:"entity"` 180 } 181 err := cloudcontroller.DecodeJSON(data, &ccApp) 182 if err != nil { 183 return err 184 } 185 186 application.Buildpack.ParseValue(ccApp.Entity.Buildpack) 187 application.Command.ParseValue(ccApp.Entity.Command) 188 application.DetectedBuildpack.ParseValue(ccApp.Entity.DetectedBuildpack) 189 application.DetectedStartCommand.ParseValue(ccApp.Entity.DetectedStartCommand) 190 application.DiskQuota.ParseUint64Value(ccApp.Entity.DiskQuota) 191 application.DockerCredentials = ccApp.Entity.DockerCredentials 192 application.DockerImage = ccApp.Entity.DockerImage 193 application.GUID = ccApp.Metadata.GUID 194 application.HealthCheckHTTPEndpoint = ccApp.Entity.HealthCheckHTTPEndpoint 195 application.HealthCheckTimeout = ccApp.Entity.HealthCheckTimeout 196 application.HealthCheckType = constant.ApplicationHealthCheckType(ccApp.Entity.HealthCheckType) 197 application.Memory.ParseUint64Value(ccApp.Entity.Memory) 198 application.Name = ccApp.Entity.Name 199 application.PackageState = constant.ApplicationPackageState(ccApp.Entity.PackageState) 200 application.SpaceGUID = ccApp.Entity.SpaceGUID 201 application.StackGUID = ccApp.Entity.StackGUID 202 application.StagingFailedDescription = ccApp.Entity.StagingFailedDescription 203 application.StagingFailedReason = ccApp.Entity.StagingFailedReason 204 application.State = constant.ApplicationState(ccApp.Entity.State) 205 206 if len(ccApp.Entity.EnvironmentVariables) > 0 { 207 envVariableValues := map[string]string{} 208 for key, value := range ccApp.Entity.EnvironmentVariables { 209 envVariableValues[key] = fmt.Sprint(value) 210 } 211 application.EnvironmentVariables = envVariableValues 212 } 213 214 err = application.Instances.ParseStringValue(ccApp.Entity.Instances.String()) 215 if err != nil { 216 return err 217 } 218 219 if ccApp.Entity.PackageUpdatedAt != nil { 220 application.PackageUpdatedAt = *ccApp.Entity.PackageUpdatedAt 221 } 222 return nil 223 } 224 225 // CreateApplication creates a cloud controller application in with the given 226 // settings. SpaceGUID and Name are the only required fields. 227 func (client *Client) CreateApplication(app Application) (Application, Warnings, error) { 228 body, err := json.Marshal(app) 229 if err != nil { 230 return Application{}, nil, err 231 } 232 233 request, err := client.newHTTPRequest(requestOptions{ 234 RequestName: internal.PostAppRequest, 235 Body: bytes.NewReader(body), 236 }) 237 if err != nil { 238 return Application{}, nil, err 239 } 240 241 var updatedApp Application 242 response := cloudcontroller.Response{ 243 DecodeJSONResponseInto: &updatedApp, 244 } 245 246 err = client.connection.Make(request, &response) 247 return updatedApp, response.Warnings, err 248 } 249 250 // GetApplication returns back an Application. 251 func (client *Client) GetApplication(guid string) (Application, Warnings, error) { 252 request, err := client.newHTTPRequest(requestOptions{ 253 RequestName: internal.GetAppRequest, 254 URIParams: Params{"app_guid": guid}, 255 }) 256 if err != nil { 257 return Application{}, nil, err 258 } 259 260 var app Application 261 response := cloudcontroller.Response{ 262 DecodeJSONResponseInto: &app, 263 } 264 265 err = client.connection.Make(request, &response) 266 return app, response.Warnings, err 267 } 268 269 // GetApplications returns back a list of Applications based off of the 270 // provided filters. 271 func (client *Client) GetApplications(filters ...Filter) ([]Application, Warnings, error) { 272 request, err := client.newHTTPRequest(requestOptions{ 273 RequestName: internal.GetAppsRequest, 274 Query: ConvertFilterParameters(filters), 275 }) 276 if err != nil { 277 return nil, nil, err 278 } 279 280 var fullAppsList []Application 281 warnings, err := client.paginate(request, Application{}, func(item interface{}) error { 282 if app, ok := item.(Application); ok { 283 fullAppsList = append(fullAppsList, app) 284 } else { 285 return ccerror.UnknownObjectInListError{ 286 Expected: Application{}, 287 Unexpected: item, 288 } 289 } 290 return nil 291 }) 292 293 return fullAppsList, warnings, err 294 } 295 296 // GetRouteApplications returns a list of Applications based off a route 297 // GUID and the provided filters. 298 func (client *Client) GetRouteApplications(routeGUID string, filters ...Filter) ([]Application, Warnings, error) { 299 request, err := client.newHTTPRequest(requestOptions{ 300 RequestName: internal.GetRouteAppsRequest, 301 URIParams: map[string]string{"route_guid": routeGUID}, 302 Query: ConvertFilterParameters(filters), 303 }) 304 if err != nil { 305 return nil, nil, err 306 } 307 308 var fullAppsList []Application 309 warnings, err := client.paginate(request, Application{}, func(item interface{}) error { 310 if app, ok := item.(Application); ok { 311 fullAppsList = append(fullAppsList, app) 312 } else { 313 return ccerror.UnknownObjectInListError{ 314 Expected: Application{}, 315 Unexpected: item, 316 } 317 } 318 return nil 319 }) 320 321 return fullAppsList, warnings, err 322 } 323 324 // RestageApplication restages the application with the given GUID. 325 func (client *Client) RestageApplication(app Application) (Application, Warnings, error) { 326 request, err := client.newHTTPRequest(requestOptions{ 327 RequestName: internal.PostAppRestageRequest, 328 URIParams: Params{"app_guid": app.GUID}, 329 }) 330 if err != nil { 331 return Application{}, nil, err 332 } 333 334 var restagedApp Application 335 response := cloudcontroller.Response{ 336 DecodeJSONResponseInto: &restagedApp, 337 } 338 339 err = client.connection.Make(request, &response) 340 return restagedApp, response.Warnings, err 341 } 342 343 // UpdateApplication updates the application with the given GUID. Note: Sending 344 // DockerImage and StackGUID at the same time will result in an API error. 345 func (client *Client) UpdateApplication(app Application) (Application, Warnings, error) { 346 body, err := json.Marshal(app) 347 if err != nil { 348 return Application{}, nil, err 349 } 350 351 request, err := client.newHTTPRequest(requestOptions{ 352 RequestName: internal.PutAppRequest, 353 URIParams: Params{"app_guid": app.GUID}, 354 Body: bytes.NewReader(body), 355 }) 356 if err != nil { 357 return Application{}, nil, err 358 } 359 360 var updatedApp Application 361 response := cloudcontroller.Response{ 362 DecodeJSONResponseInto: &updatedApp, 363 } 364 365 err = client.connection.Make(request, &response) 366 return updatedApp, response.Warnings, err 367 }