github.com/Thanhphan1147/cloudfoundry-cli@v7.1.0+incompatible/actor/pushaction/application.go (about) 1 package pushaction 2 3 import ( 4 "fmt" 5 6 "code.cloudfoundry.org/cli/actor/actionerror" 7 "code.cloudfoundry.org/cli/actor/v2action" 8 "code.cloudfoundry.org/cli/actor/v3action" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 11 "code.cloudfoundry.org/cli/types" 12 log "github.com/sirupsen/logrus" 13 ) 14 15 type Application struct { 16 v2action.Application 17 Buildpacks []string 18 Stack v2action.Stack 19 } 20 21 // CalculatedBuildpacks will return back the buildpacks for the application. 22 func (app Application) CalculatedBuildpacks() []string { 23 buildpack := app.CalculatedBuildpack() 24 switch { 25 case app.Buildpacks != nil: 26 return app.Buildpacks 27 case len(buildpack) > 0: 28 return []string{buildpack} 29 default: 30 return nil 31 } 32 } 33 34 func (app Application) String() string { 35 return fmt.Sprintf("%s, Stack Name: '%s', Buildpacks: %s", app.Application, app.Stack.Name, app.Buildpacks) 36 } 37 38 func (app *Application) SetStack(stack v2action.Stack) { 39 app.Stack = stack 40 app.StackGUID = stack.GUID 41 } 42 43 func (actor Actor) CreateApplication(config ApplicationConfig) (ApplicationConfig, Event, Warnings, error) { 44 log.Debug("creating application") 45 v2App := config.DesiredApplication.Application 46 v2App.Buildpack = actor.setBuildpack(config) 47 48 log.WithField("application", v2App).Debug("creating application with these settings") 49 var warnings Warnings 50 newApp, v2warnings, err := actor.V2Actor.CreateApplication(v2App) 51 warnings = append(warnings, v2warnings...) 52 if err != nil { 53 log.Errorln("creating application:", err) 54 return ApplicationConfig{}, "", Warnings(warnings), err 55 } 56 57 if config.HasMultipleBuildpacks() { 58 v3Warnings, v3Err := actor.updateBuildpacks(config, newApp) 59 warnings = append(warnings, v3Warnings...) 60 if v3Err != nil { 61 return ApplicationConfig{}, "", warnings, v3Err 62 } 63 } 64 65 config.DesiredApplication.Application = newApp 66 config.CurrentApplication = config.DesiredApplication 67 68 return config, CreatedApplication, Warnings(warnings), nil 69 } 70 71 func (actor Actor) UpdateApplication(config ApplicationConfig) (ApplicationConfig, Event, Warnings, error) { 72 log.Debug("updating application") 73 v2App := config.DesiredApplication.Application 74 v2App.Buildpack = actor.setBuildpack(config) 75 76 v2App = actor.ignoreSameState(config, v2App) 77 v2App = actor.ignoreSameStackGUID(config, v2App) 78 79 log.WithField("application", v2App).Debug("updating application with these settings") 80 var warnings Warnings 81 updatedApp, v2Warnings, err := actor.V2Actor.UpdateApplication(v2App) 82 warnings = append(warnings, v2Warnings...) 83 if err != nil { 84 log.Errorln("updating application:", err) 85 return ApplicationConfig{}, "", Warnings(warnings), err 86 } 87 88 if config.HasMultipleBuildpacks() { 89 v3Warnings, v3Err := actor.updateBuildpacks(config, updatedApp) 90 warnings = append(warnings, v3Warnings...) 91 if v3Err != nil { 92 return ApplicationConfig{}, "", warnings, v3Err 93 } 94 } 95 96 config.DesiredApplication.Application = updatedApp 97 config.CurrentApplication = config.DesiredApplication 98 99 return config, UpdatedApplication, Warnings(warnings), err 100 } 101 102 func (actor Actor) FindOrReturnPartialApp(appName string, spaceGUID string) (bool, Application, v2action.Warnings, error) { 103 foundApp, appWarnings, err := actor.V2Actor.GetApplicationByNameAndSpace(appName, spaceGUID) 104 if _, ok := err.(actionerror.ApplicationNotFoundError); ok { 105 log.Warnf("unable to find app %s in current space (GUID: %s)", appName, spaceGUID) 106 return false, Application{ 107 Application: v2action.Application{ 108 Name: appName, 109 SpaceGUID: spaceGUID, 110 }, 111 }, appWarnings, nil 112 } else if err != nil { 113 log.WithField("appName", appName).Error("error retrieving app") 114 return false, Application{}, appWarnings, err 115 } 116 117 stack, stackWarnings, err := actor.V2Actor.GetStack(foundApp.StackGUID) 118 warnings := append(appWarnings, stackWarnings...) 119 if err != nil { 120 log.Warnf("unable to find app's stack (GUID: %s)", foundApp.StackGUID) 121 return false, Application{}, warnings, err 122 } 123 124 v3App, v3AppWarnings, err := actor.V3Actor.GetApplicationByNameAndSpace(appName, spaceGUID) 125 warnings = append(warnings, v3AppWarnings...) 126 if err != nil { 127 if _, ok := err.(ccerror.APINotFoundError); !ok { 128 return false, Application{}, warnings, err 129 } 130 } 131 132 // if err api don't exist - ignore, else return error 133 app := Application{ 134 Application: foundApp, 135 Stack: stack, 136 Buildpacks: v3App.LifecycleBuildpacks, 137 } 138 return true, app, warnings, nil 139 } 140 141 // For some versions of CC, sending state will always result in CC 142 // attempting to do perform that request (i.e. started -> start/restart). 143 // In order to prevent repeated unintended restarts in the middle of a 144 // push, don't send state. This will be fixed in capi-release 1.48.0. 145 func (actor Actor) ignoreSameState(config ApplicationConfig, v2App v2action.Application) v2action.Application { 146 if config.CurrentApplication.State == config.DesiredApplication.State { 147 v2App.State = "" 148 } 149 150 return v2App 151 } 152 153 // Apps updates with both docker image and stack guids fail. So do not send 154 // StackGUID unless it is necessary. 155 func (actor Actor) ignoreSameStackGUID(config ApplicationConfig, v2App v2action.Application) v2action.Application { 156 if config.CurrentApplication.StackGUID == config.DesiredApplication.StackGUID { 157 v2App.StackGUID = "" 158 } 159 160 return v2App 161 } 162 163 // If 'buildpacks' is set with only one buildpack, set `buildpack` (singular) 164 // on the application. 165 func (Actor) setBuildpack(config ApplicationConfig) types.FilteredString { 166 buildpacks := config.DesiredApplication.Buildpacks 167 168 if len(buildpacks) >= 1 { 169 var filtered types.FilteredString 170 filtered.ParseValue(buildpacks[0]) 171 return filtered 172 } 173 174 if buildpacks != nil && len(buildpacks) == 0 { 175 return types.FilteredString{IsSet: true} 176 } 177 178 return config.DesiredApplication.Buildpack 179 } 180 181 func (actor Actor) updateBuildpacks(config ApplicationConfig, v2App v2action.Application) (Warnings, error) { 182 log.WithField("buildpacks", config.DesiredApplication.Buildpacks).Debug("updating with multiple buildpacks") 183 v3App := v3action.Application{ 184 Name: v2App.Name, 185 GUID: v2App.GUID, 186 StackName: config.DesiredApplication.Stack.Name, 187 LifecycleBuildpacks: config.DesiredApplication.Buildpacks, 188 LifecycleType: constant.AppLifecycleTypeBuildpack, 189 } 190 191 _, warnings, err := actor.V3Actor.UpdateApplication(v3App) 192 return Warnings(warnings), err 193 }