github.com/franc20/ayesa_sap@v7.0.0-beta.28.0.20200124003224-302d4d52fa6c+incompatible/cf/commands/service/update_service.go (about)

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