func()

in pkg/broker/api.go [559:661]


func (b *AwsBroker) Update(request *osb.UpdateInstanceRequest, c *broker.RequestContext) (*broker.UpdateInstanceResponse, error) {
	glog.V(10).Infof("request=%+v", *request)

	if !request.AcceptsIncomplete {
		return nil, newAsyncError()
	}

	// Get the service instance
	instance, err := b.db.DataStorePort.GetServiceInstance(request.InstanceID)
	if err != nil {
		desc := fmt.Sprintf("Failed to get the service instance %q: %v", request.InstanceID, err)
		return nil, newHTTPStatusCodeError(http.StatusInternalServerError, "", desc)
	} else if instance == nil {
		desc := fmt.Sprintf("The service instance %q was not found.", request.InstanceID)
		return nil, newHTTPStatusCodeError(http.StatusBadRequest, "", desc)
	}

	// Verify that we're not changing the plan (this should never happen since
	// we're setting `plan_updateable: false`, but better safe than sorry)
	if request.PlanID != nil && *request.PlanID != instance.PlanID {
		desc := fmt.Sprintf("The service plan cannot be changed from %q to %q.", instance.PlanID, *request.PlanID)
		return nil, newHTTPStatusCodeError(http.StatusBadRequest, "", desc)
	}

	// Get the service
	service, err := b.db.DataStorePort.GetServiceDefinition(request.ServiceID)
	if err != nil {
		desc := fmt.Sprintf("Failed to get the service %q: %v", request.ServiceID, err)
		return nil, newHTTPStatusCodeError(http.StatusInternalServerError, "", desc)
	} else if service == nil {
		desc := fmt.Sprintf("The service %q was not found.", request.ServiceID)
		return nil, newHTTPStatusCodeError(http.StatusBadRequest, "", desc)
	}

	// Get the plan
	plan := getPlan(service, instance.PlanID)
	if plan == nil {
		desc := fmt.Sprintf("The service plan %q was not found.", instance.PlanID)
		return nil, newHTTPStatusCodeError(http.StatusBadRequest, "", desc)
	}

	// Get the parameters
	params := getPlanDefaults(plan)
	paramsUpdated := false
	updatableParams := getUpdatableParams(plan)
	for k, v := range instance.Params {
		params[k] = v
	}
	for k, v := range request.Parameters {
		newValue := paramValue(v)
		if params[k] != newValue {
			if !stringInSlice(k, updatableParams) {
				desc := fmt.Sprintf("The parameter %q is not updatable.", k)
				return nil, newHTTPStatusCodeError(http.StatusBadRequest, "", desc)
			}
			params[k] = newValue
			paramsUpdated = true
		}
	}
	if !paramsUpdated {
		// Nothing to do, so return success (if we try a CFN update, it'll fail)
		return &broker.UpdateInstanceResponse{}, nil
	}
	glog.V(10).Infof("params=%v", params)

	// Update the CFN stack
	cfnSvc := b.Clients.NewCfn(b.GetSession(b.keyid, b.secretkey, b.region, b.accountId, b.profile, params))
	_, err = cfnSvc.Client.UpdateStack(&cloudformation.UpdateStackInput{
		Capabilities: aws.StringSlice([]string{cloudformation.CapabilityCapabilityNamedIam}),
		Parameters:   toCFNParams(params),
		StackName:    aws.String(instance.StackID),
		TemplateURL:  b.generateS3HTTPUrl(service.Name),
	})
	if err != nil {
		desc := fmt.Sprintf("Failed to update the CloudFormation stack %q: %v", instance.StackID, err)
		return nil, newHTTPStatusCodeError(http.StatusInternalServerError, "", desc)
	}

	// Update the params in the DB
	instance.Params = params
	err = b.db.DataStorePort.PutServiceInstance(*instance)
	if err != nil {
		// Try to cancel the update
		if _, err := cfnSvc.Client.CancelUpdateStack(&cloudformation.CancelUpdateStackInput{StackName: aws.String(instance.StackID)}); err != nil {
			glog.Errorf("Failed to cancel updating the CloudFormation stack %q: %v", instance.StackID, err)
			glog.Errorf("Service instance %q and CloudFormation stack %q may be out of sync!", instance.ID, instance.StackID)
		}

		desc := fmt.Sprintf("Failed to update the service instance %q: %v", instance.ID, err)
		return nil, newHTTPStatusCodeError(http.StatusInternalServerError, "", desc)
	}

	b.metrics.Actions.With(
		prom.Labels{
			"action":  "update",
			"service": service.Name,
			"plan":    plan.Name,
		}).Inc()

	response := broker.UpdateInstanceResponse{}
	response.Async = true
	return &response, nil
}