github.com/rakutentech/cli@v6.12.5-0.20151006231303-24468b65536e+incompatible/cf/commands/service/update_service.go (about)

     1  package service
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/cloudfoundry/cli/cf/actors/plan_builder"
     9  	"github.com/cloudfoundry/cli/cf/api"
    10  	"github.com/cloudfoundry/cli/cf/command_registry"
    11  	"github.com/cloudfoundry/cli/cf/configuration/core_config"
    12  	. "github.com/cloudfoundry/cli/cf/i18n"
    13  	"github.com/cloudfoundry/cli/cf/models"
    14  	"github.com/cloudfoundry/cli/cf/requirements"
    15  	"github.com/cloudfoundry/cli/cf/terminal"
    16  	"github.com/cloudfoundry/cli/cf/ui_helpers"
    17  	"github.com/cloudfoundry/cli/flags"
    18  	"github.com/cloudfoundry/cli/flags/flag"
    19  	"github.com/cloudfoundry/cli/json"
    20  )
    21  
    22  type UpdateService struct {
    23  	ui          terminal.UI
    24  	config      core_config.Reader
    25  	serviceRepo api.ServiceRepository
    26  	planBuilder plan_builder.PlanBuilder
    27  }
    28  
    29  func init() {
    30  	command_registry.Register(&UpdateService{})
    31  }
    32  
    33  func (cmd *UpdateService) MetaData() command_registry.CommandMetadata {
    34  	baseUsage := T("CF_NAME update-service SERVICE_INSTANCE [-p NEW_PLAN] [-c PARAMETERS_AS_JSON] [-t TAGS]")
    35  	paramsUsage := T(`   Optionally provide service-specific configuration parameters in a valid JSON object in-line.
    36     CF_NAME update-service -c '{"name":"value","name":"value"}'
    37  
    38     Optionally provide a file containing service-specific configuration parameters in a valid JSON object. 
    39     The path to the parameters file can be an absolute or relative path to a file.
    40     CF_NAME update-service -c PATH_TO_FILE
    41  
    42     Example of valid JSON object:
    43     {
    44        "cluster_nodes": {
    45           "count": 5,
    46           "memory_mb": 1024
    47        }
    48     }`)
    49  	tagsUsage := T(`   Optionally provide a list of comma-delimited tags that will be written to the VCAP_SERVICES environment variable for any bound applications.`)
    50  	exampleUsage := T(`EXAMPLE:
    51     CF_NAME update-service mydb -p gold
    52     CF_NAME update-service mydb -c '{"ram_gb":4}'
    53     CF_NAME update-service mydb -c ~/workspace/tmp/instance_config.json
    54     CF_NAME update-service mydb -t "list,of, tags"`)
    55  
    56  	fs := make(map[string]flags.FlagSet)
    57  	fs["p"] = &cliFlags.StringFlag{Name: "p", Usage: T("Change service plan for a service instance")}
    58  	fs["c"] = &cliFlags.StringFlag{Name: "c", Usage: T("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.")}
    59  	fs["t"] = &cliFlags.StringFlag{Name: "t", Usage: T("User provided tags")}
    60  
    61  	return command_registry.CommandMetadata{
    62  		Name:        "update-service",
    63  		Description: T("Update a service instance"),
    64  		Usage:       T(strings.Join([]string{baseUsage, paramsUsage, tagsUsage, exampleUsage}, "\n\n")),
    65  		Flags:       fs,
    66  	}
    67  }
    68  
    69  func (cmd *UpdateService) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) (reqs []requirements.Requirement, err error) {
    70  	if len(fc.Args()) != 1 {
    71  		cmd.ui.Failed(T("Incorrect Usage. Requires an argument\n\n") + command_registry.Commands.CommandUsage("update-service"))
    72  	}
    73  
    74  	reqs = []requirements.Requirement{
    75  		requirementsFactory.NewLoginRequirement(),
    76  		requirementsFactory.NewTargetedSpaceRequirement(),
    77  	}
    78  
    79  	return
    80  }
    81  
    82  func (cmd *UpdateService) SetDependency(deps command_registry.Dependency, pluginCall bool) command_registry.Command {
    83  	cmd.ui = deps.Ui
    84  	cmd.config = deps.Config
    85  	cmd.serviceRepo = deps.RepoLocator.GetServiceRepository()
    86  	cmd.planBuilder = deps.PlanBuilder
    87  	return cmd
    88  }
    89  
    90  func (cmd *UpdateService) Execute(c flags.FlagContext) {
    91  	planName := c.String("p")
    92  	params := c.String("c")
    93  
    94  	tagsSet := c.IsSet("t")
    95  	tagsList := c.String("t")
    96  
    97  	if planName == "" && params == "" && tagsSet == false {
    98  		cmd.ui.Ok()
    99  		cmd.ui.Say(T("No changes were made"))
   100  		return
   101  	}
   102  
   103  	serviceInstanceName := c.Args()[0]
   104  	serviceInstance, err := cmd.serviceRepo.FindInstanceByName(serviceInstanceName)
   105  	if err != nil {
   106  		cmd.ui.Failed(err.Error())
   107  	}
   108  
   109  	paramsMap, err := json.ParseJsonFromFileOrString(params)
   110  	if err != nil {
   111  		cmd.ui.Failed(T("Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object."))
   112  	}
   113  
   114  	tags := ui_helpers.ParseTags(tagsList)
   115  
   116  	var plan models.ServicePlanFields
   117  	if planName != "" {
   118  		cmd.checkUpdateServicePlanApiVersion()
   119  		err, plan = cmd.findPlan(serviceInstance, planName)
   120  		if err != nil {
   121  			cmd.ui.Failed(err.Error())
   122  		}
   123  	}
   124  
   125  	cmd.printUpdatingServiceInstanceMessage(serviceInstanceName)
   126  
   127  	err = cmd.serviceRepo.UpdateServiceInstance(serviceInstance.Guid, plan.Guid, paramsMap, tags)
   128  	if err != nil {
   129  		cmd.ui.Failed(err.Error())
   130  	}
   131  	err = printSuccessMessageForServiceInstance(serviceInstanceName, cmd.serviceRepo, cmd.ui)
   132  	if err != nil {
   133  		cmd.ui.Failed(err.Error())
   134  	}
   135  }
   136  
   137  func (cmd *UpdateService) findPlan(serviceInstance models.ServiceInstance, planName string) (err error, plan models.ServicePlanFields) {
   138  	plans, err := cmd.planBuilder.GetPlansForServiceForOrg(serviceInstance.ServiceOffering.Guid, cmd.config.OrganizationFields().Name)
   139  	if err != nil {
   140  		return
   141  	}
   142  
   143  	for _, p := range plans {
   144  		if p.Name == planName {
   145  			plan = p
   146  			return
   147  		}
   148  	}
   149  	err = errors.New(T("Plan does not exist for the {{.ServiceName}} service",
   150  		map[string]interface{}{"ServiceName": serviceInstance.ServiceOffering.Label}))
   151  	return
   152  }
   153  
   154  func (cmd *UpdateService) checkUpdateServicePlanApiVersion() {
   155  	if !cmd.config.IsMinApiVersion("2.16.0") {
   156  		cmd.ui.Failed(T("Updating a plan requires API v{{.RequiredCCAPIVersion}} or newer. Your current target is v{{.CurrentCCAPIVersion}}.",
   157  			map[string]interface{}{
   158  				"RequiredCCAPIVersion": "2.16.0",
   159  				"CurrentCCAPIVersion":  cmd.config.ApiVersion(),
   160  			}))
   161  	}
   162  }
   163  
   164  func (cmd *UpdateService) printUpdatingServiceInstanceMessage(serviceInstanceName string) {
   165  	cmd.ui.Say(T("Updating service instance {{.ServiceName}} as {{.UserName}}...",
   166  		map[string]interface{}{
   167  			"ServiceName": terminal.EntityNameColor(serviceInstanceName),
   168  			"UserName":    terminal.EntityNameColor(cmd.config.Username()),
   169  		}))
   170  }
   171  
   172  func printSuccessMessageForServiceInstance(serviceInstanceName string, serviceRepo api.ServiceRepository, ui terminal.UI) error {
   173  	instance, apiErr := serviceRepo.FindInstanceByName(serviceInstanceName)
   174  	if apiErr != nil {
   175  		return apiErr
   176  	}
   177  
   178  	if instance.ServiceInstanceFields.LastOperation.State == "in progress" {
   179  		ui.Ok()
   180  		ui.Say("")
   181  		ui.Say(T("{{.State}} in progress. Use '{{.ServicesCommand}}' or '{{.ServiceCommand}}' to check operation status.",
   182  			map[string]interface{}{
   183  				"State":           strings.Title(instance.ServiceInstanceFields.LastOperation.Type),
   184  				"ServicesCommand": terminal.CommandColor("cf services"),
   185  				"ServiceCommand":  terminal.CommandColor(fmt.Sprintf("cf service %s", serviceInstanceName)),
   186  			}))
   187  	} else {
   188  		ui.Ok()
   189  	}
   190  
   191  	return nil
   192  }