github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/command/v6/update_service_command.go (about)

     1  package v6
     2  
     3  import (
     4  	"code.cloudfoundry.org/cli/actor/actionerror"
     5  	"code.cloudfoundry.org/cli/actor/sharedaction"
     6  	"code.cloudfoundry.org/cli/actor/v2action"
     7  	"code.cloudfoundry.org/cli/actor/v2action/composite"
     8  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
     9  	"code.cloudfoundry.org/cli/command"
    10  	"code.cloudfoundry.org/cli/command/flag"
    11  	"code.cloudfoundry.org/cli/command/translatableerror"
    12  	"code.cloudfoundry.org/cli/command/v6/shared"
    13  )
    14  
    15  //go:generate counterfeiter . UpdateServiceActor
    16  
    17  type UpdateServiceActor interface {
    18  	CloudControllerAPIVersion() string
    19  	GetServiceInstanceByNameAndSpace(name string, spaceGUID string) (v2action.ServiceInstance, v2action.Warnings, error)
    20  	UpgradeServiceInstance(serviceInstance v2action.ServiceInstance) (v2action.Warnings, error)
    21  }
    22  
    23  type textData map[string]interface{}
    24  
    25  type UpdateServiceCommand struct {
    26  	RequiredArgs     flag.ServiceInstance `positional-args:"yes"`
    27  	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."`
    28  	Plan             string               `short:"p" description:"Change service plan for a service instance"`
    29  	Tags             string               `short:"t" description:"User provided tags"`
    30  	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"`
    31  	relatedCommands  interface{}          `related_commands:"rename-service, services, update-user-provided-service"`
    32  	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."`
    33  	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."`
    34  
    35  	UI          command.UI
    36  	Actor       UpdateServiceActor
    37  	SharedActor command.SharedActor
    38  	Config      command.Config
    39  }
    40  
    41  func (cmd *UpdateServiceCommand) Setup(config command.Config, ui command.UI) error {
    42  	cmd.UI = ui
    43  	cmd.Config = config
    44  
    45  	cmd.SharedActor = sharedaction.NewActor(config)
    46  
    47  	ccClient, uaaClient, err := shared.GetNewClientsAndConnectToCF(config, ui)
    48  	if err != nil {
    49  		return err
    50  	}
    51  
    52  	baseActor := v2action.NewActor(ccClient, uaaClient, config)
    53  	cmd.Actor = &composite.UpdateServiceInstanceCompositeActor{
    54  		GetAPIVersionActor:                        baseActor,
    55  		GetServicePlanActor:                       baseActor,
    56  		GetServiceInstanceActor:                   baseActor,
    57  		UpdateServiceInstanceMaintenanceInfoActor: baseActor,
    58  	}
    59  
    60  	return nil
    61  }
    62  
    63  func (cmd *UpdateServiceCommand) Execute(args []string) error {
    64  	if !cmd.Upgrade {
    65  		return translatableerror.UnrefactoredCommandError{}
    66  	}
    67  
    68  	if len(args) > 0 {
    69  		return translatableerror.TooManyArgumentsError{
    70  			ExtraArgument: args[0],
    71  		}
    72  	}
    73  
    74  	if err := cmd.validateArgumentCombination(); err != nil {
    75  		return err
    76  	}
    77  
    78  	if err := command.MinimumCCAPIVersionCheck(cmd.Actor.CloudControllerAPIVersion(), ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2, "Option '--upgrade'"); err != nil {
    79  		return err
    80  	}
    81  
    82  	if err := cmd.SharedActor.CheckTarget(true, true); err != nil {
    83  		return err
    84  	}
    85  
    86  	instance, warnings, err := cmd.Actor.GetServiceInstanceByNameAndSpace(cmd.RequiredArgs.ServiceInstance, cmd.Config.TargetedSpace().GUID)
    87  	cmd.UI.DisplayWarnings(warnings)
    88  	if err != nil {
    89  		return err
    90  	}
    91  
    92  	proceed, err := cmd.promptForUpgrade()
    93  	if err != nil {
    94  		return err
    95  	}
    96  
    97  	if !proceed {
    98  		cmd.UI.DisplayText("Update cancelled")
    99  		return nil
   100  	}
   101  
   102  	return cmd.performUpgrade(instance)
   103  }
   104  
   105  func (cmd *UpdateServiceCommand) promptForUpgrade() (bool, error) {
   106  	if cmd.ForceUpgrade {
   107  		return true, nil
   108  	}
   109  
   110  	var serviceName = textData{"ServiceName": cmd.RequiredArgs.ServiceInstance}
   111  
   112  	cmd.UI.DisplayTextWithFlavor("You are about to update {{.ServiceName}}.", serviceName)
   113  	cmd.UI.DisplayText("Warning: This operation may be long running and will block further operations on the service until complete.")
   114  
   115  	return cmd.UI.DisplayBoolPrompt(false, "Really update service {{.ServiceName}}?", serviceName)
   116  }
   117  
   118  func (cmd *UpdateServiceCommand) performUpgrade(instance v2action.ServiceInstance) error {
   119  	currentUserName, err := cmd.Config.CurrentUserName()
   120  	if err != nil {
   121  		return err
   122  	}
   123  
   124  	cmd.printUpdatingServiceInstanceMessage(instance.Name, currentUserName)
   125  
   126  	warnings, err := cmd.Actor.UpgradeServiceInstance(instance)
   127  	cmd.UI.DisplayWarnings(warnings)
   128  	if err != nil {
   129  		if castedErr, ok := err.(actionerror.ServiceUpgradeNotAvailableError); ok {
   130  			return decorateUpgradeNotAvailableErrorWithTip(castedErr, instance)
   131  		}
   132  		return err
   133  	}
   134  
   135  	cmd.UI.DisplayOK()
   136  	return nil
   137  }
   138  
   139  func decorateUpgradeNotAvailableErrorWithTip(castedErr actionerror.ServiceUpgradeNotAvailableError, instance v2action.ServiceInstance) error {
   140  	return translatableerror.TipDecoratorError{
   141  		BaseError: castedErr,
   142  		Tip:       "To find out if upgrade is available run `cf service {{.ServiceName}}`.",
   143  		TipKeys: map[string]interface{}{
   144  			"ServiceName": instance.Name,
   145  		},
   146  	}
   147  }
   148  
   149  func (cmd *UpdateServiceCommand) printUpdatingServiceInstanceMessage(serviceInstanceName, currentUserName string) {
   150  	cmd.UI.DisplayTextWithFlavor("Updating service instance {{.ServiceName}} as {{.UserName}}...",
   151  		map[string]interface{}{
   152  			"ServiceName": serviceInstanceName,
   153  			"UserName":    currentUserName,
   154  		})
   155  }
   156  
   157  func (cmd *UpdateServiceCommand) validateArgumentCombination() error {
   158  	if cmd.Tags != "" || cmd.ParametersAsJSON != "" || cmd.Plan != "" {
   159  		return translatableerror.ArgumentCombinationError{
   160  			Args: []string{"--upgrade", "-t", "-c", "-p"},
   161  		}
   162  	}
   163  
   164  	return nil
   165  }