github.com/cloudfoundry-community/cloudfoundry-cli@v6.44.1-0.20240130060226-cda5ed8e89a5+incompatible/actor/v7action/application.go (about) 1 package v7action 2 3 import ( 4 "code.cloudfoundry.org/cli/resources" 5 "time" 6 7 "code.cloudfoundry.org/cli/actor/actionerror" 8 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 11 ) 12 13 // Application represents a V3 actor application. 14 type Application struct { 15 Name string 16 GUID string 17 StackName string 18 State constant.ApplicationState 19 LifecycleType constant.AppLifecycleType 20 LifecycleBuildpacks []string 21 Metadata *Metadata 22 } 23 24 func (app Application) Started() bool { 25 return app.State == constant.ApplicationStarted 26 } 27 28 func (app Application) Stopped() bool { 29 return app.State == constant.ApplicationStopped 30 } 31 32 func (actor Actor) DeleteApplicationByNameAndSpace(name string, spaceGUID string) (Warnings, error) { 33 var allWarnings Warnings 34 35 app, getAppWarnings, err := actor.GetApplicationByNameAndSpace(name, spaceGUID) 36 allWarnings = append(allWarnings, getAppWarnings...) 37 if err != nil { 38 return allWarnings, err 39 } 40 41 jobURL, deleteAppWarnings, err := actor.CloudControllerClient.DeleteApplication(app.GUID) 42 allWarnings = append(allWarnings, deleteAppWarnings...) 43 if err != nil { 44 return allWarnings, err 45 } 46 47 pollWarnings, err := actor.CloudControllerClient.PollJob(jobURL) 48 allWarnings = append(allWarnings, pollWarnings...) 49 return allWarnings, err 50 } 51 52 func (actor Actor) GetApplicationsByNamesAndSpace(appNames []string, spaceGUID string) ([]Application, Warnings, error) { 53 apps, warnings, err := actor.CloudControllerClient.GetApplications( 54 ccv3.Query{Key: ccv3.NameFilter, Values: appNames}, 55 ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{spaceGUID}}, 56 ) 57 58 if err != nil { 59 return nil, Warnings(warnings), err 60 } 61 62 if len(apps) < len(appNames) { 63 return nil, Warnings(warnings), actionerror.ApplicationsNotFoundError{} 64 } 65 66 actorApps := []Application{} 67 for _, a := range apps { 68 actorApps = append(actorApps, actor.convertCCToActorApplication(a)) 69 } 70 return actorApps, Warnings(warnings), nil 71 } 72 73 // GetApplicationByNameAndSpace returns the application with the given 74 // name in the given space. 75 func (actor Actor) GetApplicationByNameAndSpace(appName string, spaceGUID string) (Application, Warnings, error) { 76 apps, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{appName}, spaceGUID) 77 78 if err != nil { 79 if _, ok := err.(actionerror.ApplicationsNotFoundError); ok { 80 return Application{}, warnings, actionerror.ApplicationNotFoundError{Name: appName} 81 } 82 return Application{}, warnings, err 83 } 84 85 return apps[0], warnings, nil 86 } 87 88 // GetApplicationsBySpace returns all applications in a space. 89 func (actor Actor) GetApplicationsBySpace(spaceGUID string) ([]Application, Warnings, error) { 90 ccApps, warnings, err := actor.CloudControllerClient.GetApplications( 91 ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{spaceGUID}}, 92 ) 93 94 if err != nil { 95 return []Application{}, Warnings(warnings), err 96 } 97 98 var apps []Application 99 for _, ccApp := range ccApps { 100 apps = append(apps, actor.convertCCToActorApplication(ccApp)) 101 } 102 return apps, Warnings(warnings), nil 103 } 104 105 // CreateApplicationInSpace creates and returns the application with the given 106 // name in the given space. 107 func (actor Actor) CreateApplicationInSpace(app Application, spaceGUID string) (Application, Warnings, error) { 108 createdApp, warnings, err := actor.CloudControllerClient.CreateApplication( 109 resources.Application{ 110 LifecycleType: app.LifecycleType, 111 LifecycleBuildpacks: app.LifecycleBuildpacks, 112 StackName: app.StackName, 113 Name: app.Name, 114 SpaceGUID: spaceGUID, 115 }) 116 117 if err != nil { 118 if _, ok := err.(ccerror.NameNotUniqueInSpaceError); ok { 119 return Application{}, Warnings(warnings), actionerror.ApplicationAlreadyExistsError{Name: app.Name} 120 } 121 return Application{}, Warnings(warnings), err 122 } 123 124 return actor.convertCCToActorApplication(createdApp), Warnings(warnings), nil 125 } 126 127 // SetApplicationProcessHealthCheckTypeByNameAndSpace sets the health check 128 // information of the provided processType for an application with the given 129 // name and space GUID. 130 func (actor Actor) SetApplicationProcessHealthCheckTypeByNameAndSpace( 131 appName string, 132 spaceGUID string, 133 healthCheckType constant.HealthCheckType, 134 httpEndpoint string, 135 processType string, 136 invocationTimeout int64, 137 ) (Application, Warnings, error) { 138 139 app, getWarnings, err := actor.GetApplicationByNameAndSpace(appName, spaceGUID) 140 if err != nil { 141 return Application{}, getWarnings, err 142 } 143 144 setWarnings, err := actor.UpdateProcessByTypeAndApplication( 145 processType, 146 app.GUID, 147 Process{ 148 HealthCheckType: healthCheckType, 149 HealthCheckEndpoint: httpEndpoint, 150 HealthCheckInvocationTimeout: invocationTimeout, 151 }) 152 return app, append(getWarnings, setWarnings...), err 153 } 154 155 // StopApplication stops an application. 156 func (actor Actor) StopApplication(appGUID string) (Warnings, error) { 157 _, warnings, err := actor.CloudControllerClient.UpdateApplicationStop(appGUID) 158 159 return Warnings(warnings), err 160 } 161 162 // StartApplication starts an application. 163 func (actor Actor) StartApplication(appGUID string) (Application, Warnings, error) { 164 updatedApp, warnings, err := actor.CloudControllerClient.UpdateApplicationStart(appGUID) 165 if err != nil { 166 return Application{}, Warnings(warnings), err 167 } 168 169 return actor.convertCCToActorApplication(updatedApp), Warnings(warnings), nil 170 } 171 172 // RestartApplication restarts an application and waits for it to start. 173 func (actor Actor) RestartApplication(appGUID string) (Warnings, error) { 174 var allWarnings Warnings 175 _, warnings, err := actor.CloudControllerClient.UpdateApplicationRestart(appGUID) 176 allWarnings = append(allWarnings, warnings...) 177 if err != nil { 178 return allWarnings, err 179 } 180 181 pollingWarnings, err := actor.PollStart(appGUID) 182 allWarnings = append(allWarnings, pollingWarnings...) 183 return allWarnings, err 184 } 185 186 func (actor Actor) PollStart(appGUID string) (Warnings, error) { 187 var allWarnings Warnings 188 processes, warnings, err := actor.CloudControllerClient.GetApplicationProcesses(appGUID) 189 allWarnings = append(allWarnings, warnings...) 190 if err != nil { 191 return allWarnings, err 192 } 193 194 timeout := time.Now().Add(actor.Config.StartupTimeout()) 195 for time.Now().Before(timeout) { 196 allProcessesDone := true 197 for _, process := range processes { 198 shouldContinuePolling, warnings, err := actor.shouldContinuePollingProcessStatus(process) 199 allWarnings = append(allWarnings, warnings...) 200 if err != nil { 201 return allWarnings, err 202 } 203 204 if shouldContinuePolling { 205 allProcessesDone = false 206 break 207 } 208 } 209 210 if allProcessesDone { 211 return allWarnings, nil 212 } 213 time.Sleep(actor.Config.PollingInterval()) 214 } 215 216 return allWarnings, actionerror.StartupTimeoutError{} 217 } 218 219 // UpdateApplication updates the buildpacks on an application 220 func (actor Actor) UpdateApplication(app Application) (Application, Warnings, error) { 221 ccApp := resources.Application{ 222 GUID: app.GUID, 223 StackName: app.StackName, 224 LifecycleType: app.LifecycleType, 225 LifecycleBuildpacks: app.LifecycleBuildpacks, 226 Metadata: (*resources.Metadata)(app.Metadata), 227 } 228 229 updatedApp, warnings, err := actor.CloudControllerClient.UpdateApplication(ccApp) 230 if err != nil { 231 return Application{}, Warnings(warnings), err 232 } 233 234 return actor.convertCCToActorApplication(updatedApp), Warnings(warnings), nil 235 } 236 237 func (Actor) convertCCToActorApplication(app resources.Application) Application { 238 return Application{ 239 GUID: app.GUID, 240 StackName: app.StackName, 241 LifecycleType: app.LifecycleType, 242 LifecycleBuildpacks: app.LifecycleBuildpacks, 243 Name: app.Name, 244 State: app.State, 245 Metadata: (*Metadata)(app.Metadata), 246 } 247 } 248 249 func (actor Actor) shouldContinuePollingProcessStatus(process resources.Process) (bool, Warnings, error) { 250 ccInstances, ccWarnings, err := actor.CloudControllerClient.GetProcessInstances(process.GUID) 251 instances := ProcessInstances(ccInstances) 252 warnings := Warnings(ccWarnings) 253 if err != nil { 254 return true, warnings, err 255 } 256 257 if instances.Empty() || instances.AnyRunning() { 258 return false, warnings, nil 259 } else if instances.AllCrashed() { 260 return false, warnings, actionerror.AllInstancesCrashedError{} 261 } 262 263 return true, warnings, nil 264 }