github.com/cloudfoundry-attic/cli-with-i18n@v6.32.1-0.20171002233121-7401370d3b85+incompatible/actor/v3action/application.go (about) 1 package v3action 2 3 import ( 4 "fmt" 5 "net/url" 6 "time" 7 8 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 10 ) 11 12 // Application represents a V3 actor application. 13 type Application struct { 14 Name string 15 GUID string 16 State string 17 Lifecycle AppLifecycle 18 } 19 20 type AppLifecycle struct { 21 Type AppLifecycleType 22 Data AppLifecycleData 23 } 24 25 type AppLifecycleType ccv3.AppLifecycleType 26 type AppLifecycleData ccv3.AppLifecycleData 27 28 const ( 29 BuildpackAppLifecycleType AppLifecycleType = AppLifecycleType(ccv3.BuildpackAppLifecycleType) 30 DockerAppLifecycleType AppLifecycleType = AppLifecycleType(ccv3.DockerAppLifecycleType) 31 ) 32 33 func (app Application) Started() bool { 34 return app.State == "STARTED" 35 } 36 37 // ApplicationNotFoundError represents the error that occurs when the 38 // application is not found. 39 type ApplicationNotFoundError struct { 40 Name string 41 } 42 43 func (e ApplicationNotFoundError) Error() string { 44 return fmt.Sprintf("Application '%s' not found.", e.Name) 45 } 46 47 // ApplicationAlreadyExistsError represents the error that occurs when the 48 // application already exists. 49 type ApplicationAlreadyExistsError struct { 50 Name string 51 } 52 53 func (e ApplicationAlreadyExistsError) Error() string { 54 return fmt.Sprintf("Application '%s' already exists.", e.Name) 55 } 56 57 func (actor Actor) DeleteApplicationByNameAndSpace(name string, spaceGUID string) (Warnings, error) { 58 var allWarnings Warnings 59 60 app, getAppWarnings, err := actor.GetApplicationByNameAndSpace(name, spaceGUID) 61 allWarnings = append(allWarnings, getAppWarnings...) 62 if err != nil { 63 return allWarnings, err 64 } 65 66 jobURL, deleteAppWarnings, err := actor.CloudControllerClient.DeleteApplication(app.GUID) 67 allWarnings = append(allWarnings, deleteAppWarnings...) 68 if err != nil { 69 return allWarnings, err 70 } 71 72 pollWarnings, err := actor.CloudControllerClient.PollJob(jobURL) 73 allWarnings = append(allWarnings, pollWarnings...) 74 return allWarnings, err 75 } 76 77 // GetApplicationByNameAndSpace returns the application with the given 78 // name in the given space. 79 func (actor Actor) GetApplicationByNameAndSpace(appName string, spaceGUID string) (Application, Warnings, error) { 80 apps, warnings, err := actor.CloudControllerClient.GetApplications(url.Values{ 81 "space_guids": []string{spaceGUID}, 82 "names": []string{appName}, 83 }) 84 if err != nil { 85 return Application{}, Warnings(warnings), err 86 } 87 88 if len(apps) == 0 { 89 return Application{}, Warnings(warnings), ApplicationNotFoundError{Name: appName} 90 } 91 92 return Application{ 93 Name: apps[0].Name, 94 GUID: apps[0].GUID, 95 State: apps[0].State, 96 Lifecycle: AppLifecycle{ 97 Type: AppLifecycleType(apps[0].Lifecycle.Type), 98 Data: AppLifecycleData(apps[0].Lifecycle.Data), 99 }, 100 }, Warnings(warnings), nil 101 } 102 103 // GetApplicationsBySpace returns all applications in a space. 104 func (actor Actor) GetApplicationsBySpace(spaceGUID string) ([]Application, Warnings, error) { 105 ccv3Apps, warnings, err := actor.CloudControllerClient.GetApplications(url.Values{ 106 "space_guids": []string{spaceGUID}, 107 }) 108 109 if err != nil { 110 return []Application{}, Warnings(warnings), err 111 } 112 113 apps := make([]Application, len(ccv3Apps)) 114 for i, ccv3App := range ccv3Apps { 115 apps[i] = Application{ 116 Name: ccv3App.Name, 117 GUID: ccv3App.GUID, 118 State: ccv3App.State, 119 Lifecycle: AppLifecycle{ 120 Type: AppLifecycleType(ccv3App.Lifecycle.Type), 121 Data: AppLifecycleData(ccv3App.Lifecycle.Data), 122 }, 123 } 124 } 125 return apps, Warnings(warnings), nil 126 } 127 128 // CreateApplicationInSpace creates and returns the application with the given 129 // name in the given space. 130 func (actor Actor) CreateApplicationInSpace(app Application, spaceGUID string) (Application, Warnings, error) { 131 createdApp, warnings, err := actor.CloudControllerClient.CreateApplication( 132 ccv3.Application{ 133 Name: app.Name, 134 Relationships: ccv3.Relationships{ 135 ccv3.SpaceRelationship: ccv3.Relationship{GUID: spaceGUID}, 136 }, 137 Lifecycle: ccv3.AppLifecycle{ 138 Type: ccv3.AppLifecycleType(app.Lifecycle.Type), 139 Data: ccv3.AppLifecycleData{ 140 Buildpacks: app.Lifecycle.Data.Buildpacks, 141 }, 142 }, 143 }) 144 145 if err != nil { 146 if _, ok := err.(ccerror.NameNotUniqueInSpaceError); ok { 147 return Application{}, Warnings(warnings), ApplicationAlreadyExistsError{Name: app.Name} 148 } 149 return Application{}, Warnings(warnings), err 150 } 151 152 return Application{ 153 Name: createdApp.Name, 154 GUID: createdApp.GUID, 155 State: createdApp.State, 156 Lifecycle: AppLifecycle{ 157 Type: AppLifecycleType(createdApp.Lifecycle.Type), 158 Data: AppLifecycleData(createdApp.Lifecycle.Data), 159 }, 160 }, Warnings(warnings), nil 161 } 162 163 // StopApplication stops an application. 164 func (actor Actor) StopApplication(appGUID string) (Warnings, error) { 165 warnings, err := actor.CloudControllerClient.StopApplication(appGUID) 166 167 return Warnings(warnings), err 168 } 169 170 // StartApplication starts an application. 171 func (actor Actor) StartApplication(appGUID string) (Application, Warnings, error) { 172 updatedApp, warnings, err := actor.CloudControllerClient.StartApplication(appGUID) 173 if err != nil { 174 return Application{}, Warnings(warnings), err 175 } 176 177 return Application{ 178 Name: updatedApp.Name, 179 GUID: updatedApp.GUID, 180 State: updatedApp.State, 181 Lifecycle: AppLifecycle{ 182 Type: AppLifecycleType(updatedApp.Lifecycle.Type), 183 Data: AppLifecycleData(updatedApp.Lifecycle.Data), 184 }, 185 }, Warnings(warnings), nil 186 } 187 188 func (actor Actor) PollStart(appGUID string, warningsChannel chan<- Warnings) error { 189 processes, warnings, err := actor.CloudControllerClient.GetApplicationProcesses(appGUID) 190 warningsChannel <- Warnings(warnings) 191 if err != nil { 192 return err 193 } 194 195 timeout := time.Now().Add(actor.Config.StartupTimeout()) 196 for time.Now().Before(timeout) { 197 readyProcs := 0 198 for _, process := range processes { 199 ready, err := actor.processStatus(process, warningsChannel) 200 if err != nil { 201 return err 202 } 203 204 if ready { 205 readyProcs++ 206 } 207 } 208 209 if readyProcs == len(processes) { 210 return nil 211 } 212 time.Sleep(actor.Config.PollingInterval()) 213 } 214 215 return StartupTimeoutError{} 216 } 217 218 // UpdateApplication updates the buildpacks on an application 219 func (actor Actor) UpdateApplication(app Application) (Application, Warnings, error) { 220 ccApp := ccv3.Application{ 221 GUID: app.GUID, 222 Lifecycle: ccv3.AppLifecycle{ 223 Type: ccv3.AppLifecycleType(app.Lifecycle.Type), 224 Data: ccv3.AppLifecycleData(app.Lifecycle.Data), 225 }, 226 } 227 228 updatedApp, warnings, err := actor.CloudControllerClient.UpdateApplication(ccApp) 229 if err != nil { 230 return Application{}, Warnings(warnings), err 231 } 232 233 return Application{ 234 Name: updatedApp.Name, 235 GUID: updatedApp.GUID, 236 State: updatedApp.State, 237 Lifecycle: AppLifecycle{ 238 Type: AppLifecycleType(updatedApp.Lifecycle.Type), 239 Data: AppLifecycleData(updatedApp.Lifecycle.Data), 240 }, 241 }, Warnings(warnings), nil 242 } 243 244 // StartupTimeoutError is returned when startup timeout is reached waiting for 245 // an application to start. 246 type StartupTimeoutError struct { 247 } 248 249 func (e StartupTimeoutError) Error() string { 250 return fmt.Sprintf("Timed out waiting for application to start") 251 } 252 253 func (actor Actor) processStatus(process ccv3.Process, warningsChannel chan<- Warnings) (bool, error) { 254 instances, warnings, err := actor.CloudControllerClient.GetProcessInstances(process.GUID) 255 warningsChannel <- Warnings(warnings) 256 if err != nil { 257 return false, err 258 } 259 if len(instances) == 0 { 260 return true, nil 261 } 262 263 for _, instance := range instances { 264 if instance.State == "RUNNING" { 265 return true, nil 266 } 267 } 268 269 for _, instance := range instances { 270 if instance.State != "CRASHED" { 271 return false, nil 272 } 273 } 274 275 // all of the instances are crashed at this point 276 return true, nil 277 }