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
}