-
Notifications
You must be signed in to change notification settings - Fork 929
/
update_service_command.go
166 lines (133 loc) · 6.76 KB
/
update_service_command.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package v6
import (
"code.cloudfoundry.org/cli/actor/actionerror"
"code.cloudfoundry.org/cli/actor/sharedaction"
"code.cloudfoundry.org/cli/actor/v2action"
"code.cloudfoundry.org/cli/actor/v2action/composite"
"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
"code.cloudfoundry.org/cli/command"
"code.cloudfoundry.org/cli/command/flag"
"code.cloudfoundry.org/cli/command/translatableerror"
"code.cloudfoundry.org/cli/command/v6/shared"
)
//go:generate counterfeiter . UpdateServiceActor
type UpdateServiceActor interface {
CloudControllerAPIVersion() string
GetServiceInstanceByNameAndSpace(name string, spaceGUID string) (v2action.ServiceInstance, v2action.Warnings, error)
UpgradeServiceInstance(serviceInstance v2action.ServiceInstance) (v2action.Warnings, error)
}
type textData map[string]interface{}
type UpdateServiceCommand struct {
RequiredArgs flag.ServiceInstance `positional-args:"yes"`
ParametersAsJSON flag.Path `short:"c" description:"Valid JSON object containing service-specific configuration parameters, provided either in-line or in a file. For a list of supported configuration parameters, see documentation for the particular service offering."`
Plan string `short:"p" description:"Change service plan for a service instance"`
Tags string `short:"t" description:"User provided tags"`
usage interface{} `usage:"CF_NAME update-service SERVICE_INSTANCE [-p NEW_PLAN] [-c PARAMETERS_AS_JSON] [-t TAGS] [--upgrade]\n\n Optionally provide service-specific configuration parameters in a valid JSON object in-line:\n CF_NAME update-service SERVICE_INSTANCE -c '{\"name\":\"value\",\"name\":\"value\"}'\n\n Optionally provide a file containing service-specific configuration parameters in a valid JSON object. \n The path to the parameters file can be an absolute or relative path to a file:\n CF_NAME update-service SERVICE_INSTANCE -c PATH_TO_FILE\n\n Example of valid JSON object:\n {\n \"cluster_nodes\": {\n \"count\": 5,\n \"memory_mb\": 1024\n }\n }\n\n Optionally provide a list of comma-delimited tags that will be written to the VCAP_SERVICES environment variable for any bound applications.\n\nEXAMPLES:\n CF_NAME update-service mydb -p gold\n CF_NAME update-service mydb -c '{\"ram_gb\":4}'\n CF_NAME update-service mydb -c ~/workspace/tmp/instance_config.json\n CF_NAME update-service mydb -t \"list, of, tags\"\n CF_NAME update-service mydb --upgrade\n CF_NAME update-service mydb --upgrade --force"`
relatedCommands interface{} `related_commands:"rename-service, services, update-user-provided-service"`
Upgrade bool `short:"u" long:"upgrade" description:"Upgrade the service instance to the latest version of the service plan available. It cannot be combined with flags: -c, -p, -t."`
ForceUpgrade bool `short:"f" long:"force" description:"Force the upgrade to the latest available version of the service plan. It can only be used with: -u, --upgrade."`
UI command.UI
Actor UpdateServiceActor
SharedActor command.SharedActor
Config command.Config
}
func (cmd *UpdateServiceCommand) Setup(config command.Config, ui command.UI) error {
cmd.UI = ui
cmd.Config = config
cmd.SharedActor = sharedaction.NewActor(config)
ccClient, uaaClient, err := shared.GetNewClientsAndConnectToCF(config, ui)
if err != nil {
return err
}
baseActor := v2action.NewActor(ccClient, uaaClient, config)
cmd.Actor = &composite.UpdateServiceInstanceCompositeActor{
GetAPIVersionActor: baseActor,
GetServicePlanActor: baseActor,
GetServiceInstanceActor: baseActor,
UpdateServiceInstanceMaintenanceInfoActor: baseActor,
}
return nil
}
func (cmd *UpdateServiceCommand) Execute(args []string) error {
if !cmd.Upgrade {
return translatableerror.UnrefactoredCommandError{}
}
if len(args) > 0 {
return translatableerror.TooManyArgumentsError{
ExtraArgument: args[0],
}
}
if err := cmd.validateArgumentCombination(); err != nil {
return err
}
if err := command.MinimumCCAPIVersionCheck(cmd.Actor.CloudControllerAPIVersion(), ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2, "Option '--upgrade'"); err != nil {
return err
}
if err := cmd.SharedActor.CheckTarget(true, true); err != nil {
return err
}
instance, warnings, err := cmd.Actor.GetServiceInstanceByNameAndSpace(cmd.RequiredArgs.ServiceInstance, cmd.Config.TargetedSpace().GUID)
cmd.UI.DisplayWarnings(warnings)
if err != nil {
return err
}
proceed, err := cmd.promptForUpgrade()
if err != nil {
return err
}
if !proceed {
cmd.UI.DisplayText("Update cancelled")
return nil
}
return cmd.performUpgrade(instance)
}
func (cmd *UpdateServiceCommand) promptForUpgrade() (bool, error) {
if cmd.ForceUpgrade {
return true, nil
}
var serviceName = textData{"ServiceName": cmd.RequiredArgs.ServiceInstance}
cmd.UI.DisplayTextWithFlavor("You are about to update {{.ServiceName}}.", serviceName)
cmd.UI.DisplayText("Warning: This operation may be long running and will block further operations on the service until complete.")
return cmd.UI.DisplayBoolPrompt(false, "Really update service {{.ServiceName}}?", serviceName)
}
func (cmd *UpdateServiceCommand) performUpgrade(instance v2action.ServiceInstance) error {
currentUserName, err := cmd.Config.CurrentUserName()
if err != nil {
return err
}
cmd.printUpdatingServiceInstanceMessage(instance.Name, currentUserName)
warnings, err := cmd.Actor.UpgradeServiceInstance(instance)
cmd.UI.DisplayWarnings(warnings)
if err != nil {
if castedErr, ok := err.(actionerror.ServiceUpgradeNotAvailableError); ok {
return decorateUpgradeNotAvailableErrorWithTip(castedErr, instance)
}
return err
}
cmd.UI.DisplayOK()
return nil
}
func decorateUpgradeNotAvailableErrorWithTip(castedErr actionerror.ServiceUpgradeNotAvailableError, instance v2action.ServiceInstance) error {
return translatableerror.TipDecoratorError{
BaseError: castedErr,
Tip: "To find out if upgrade is available run `cf service {{.ServiceName}}`.",
TipKeys: map[string]interface{}{
"ServiceName": instance.Name,
},
}
}
func (cmd *UpdateServiceCommand) printUpdatingServiceInstanceMessage(serviceInstanceName, currentUserName string) {
cmd.UI.DisplayTextWithFlavor("Updating service instance {{.ServiceName}} as {{.UserName}}...",
map[string]interface{}{
"ServiceName": serviceInstanceName,
"UserName": currentUserName,
})
}
func (cmd *UpdateServiceCommand) validateArgumentCombination() error {
if cmd.Tags != "" || cmd.ParametersAsJSON != "" || cmd.Plan != "" {
return translatableerror.ArgumentCombinationError{
Args: []string{"--upgrade", "-t", "-c", "-p"},
}
}
return nil
}