func (bkr *Broker) update(instanceID structs.ClusterID, updateDetails brokerapi.UpdateDetails, acceptsIncomplete bool) (async bool, err error) { logger := bkr.newLoggingSession("update", lager.Data{"instanceID": instanceID}) defer logger.Info("done") features, err := structs.ClusterFeaturesFromParameters(updateDetails.Parameters) if err != nil { logger.Error("cluster-features", err) return false, err } if err := bkr.assertUpdatePrecondition(instanceID, features); err != nil { logger.Error("preconditions.error", err) return false, err } clusterState, err := bkr.state.LoadCluster(instanceID) if err != nil { logger.Error("load-cluster.error", err) return false, err } clusterModel := state.NewClusterModel(bkr.state, clusterState) go func() { err = bkr.scheduler.RunCluster(clusterModel, features) if err != nil { logger.Error("run-cluster", err) } }() return true, err }
func (bkr *Broker) provision(instanceID structs.ClusterID, details brokerapi.ProvisionDetails, acceptsIncomplete bool) (resp brokerapi.ProvisioningResponse, async bool, err error) { if details.ServiceID == "" && details.PlanID == "" { return bkr.Recreate(instanceID, details, acceptsIncomplete) } logger := bkr.newLoggingSession("provision", lager.Data{"instanceID": instanceID}) defer logger.Info("done") features, err := structs.ClusterFeaturesFromParameters(details.Parameters) if err != nil { logger.Error("cluster-features", err) return resp, false, err } if err = bkr.assertProvisionPrecondition(instanceID, features); err != nil { logger.Error("preconditions.error", err) return resp, false, err } port, err := bkr.router.AllocatePort() clusterState := bkr.initCluster(instanceID, port, details) clusterModel := state.NewClusterModel(bkr.state, clusterState) if bkr.callbacks.Configured() { bkr.callbacks.WriteRecreationData(clusterState.RecreationData()) data, err := bkr.callbacks.RestoreRecreationData(instanceID) if !reflect.DeepEqual(clusterState.RecreationData(), data) { logger.Error("recreation-data.failure", err) return resp, false, err } } // Continue processing in background // TODO: if error, store it into etcd; and last_operation_endpoint should look for errors first go func() { err := bkr.scheduler.RunCluster(clusterModel, features) if err != nil { logger.Error("run-cluster", err) return } err = bkr.router.AssignPortToCluster(clusterModel.InstanceID(), port) if err != nil { logger.Error("assign-port", err) } }() return resp, true, err }
// Recreate service instance; invoked via Provision endpoint func (bkr *Broker) Recreate(instanceID structs.ClusterID, details brokerapi.ProvisionDetails, acceptsIncomplete bool) (resp brokerapi.ProvisioningResponse, async bool, err error) { logger := bkr.newLoggingSession("recreate", lager.Data{}) defer logger.Info("stop") features, err := structs.ClusterFeaturesFromParameters(details.Parameters) if err != nil { logger.Error("cluster-features", err) return resp, false, err } if err = bkr.assertRecreatePrecondition(instanceID, features); err != nil { logger.Error("preconditions.error", err) return resp, false, err } recreationData, err := bkr.callbacks.RestoreRecreationData(instanceID) if err != nil { err = fmt.Errorf("Cannot recreate service from backup; unable to restore original service instance data: %s", err) return } clusterState := bkr.initClusterStateFromRecreationData(recreationData) clusterModel := state.NewClusterModel(bkr.state, clusterState) go func() { err := bkr.scheduler.RunCluster(clusterModel, features) if err != nil { logger.Error("run-cluster", err) return } err = bkr.router.AssignPortToCluster(clusterModel.InstanceID(), clusterModel.AllocatedPort()) if err != nil { logger.Error("assign-port", err) } }() return resp, true, err }
func (bkr *Broker) provision(instanceID structs.ClusterID, details brokerapi.ProvisionDetails, acceptsIncomplete bool) (resp brokerapi.ProvisioningResponse, async bool, err error) { if details.ServiceID == "" && details.PlanID == "" { return bkr.Recreate(instanceID, details, acceptsIncomplete) } logger := bkr.newLoggingSession("provision", lager.Data{"instance-id": instanceID}) defer logger.Info("done") features, err := structs.ClusterFeaturesFromParameters(details.Parameters) if err != nil { logger.Error("cluster-features", err) return resp, false, err } if err = bkr.assertProvisionPrecondition(instanceID, features); err != nil { logger.Error("preconditions.error", err) return resp, false, err } port, err := bkr.router.AllocatePort() clusterState := bkr.initCluster(instanceID, port, details) clusterModel := state.NewClusterModel(bkr.state, clusterState) clusterModel.SchedulingMessage("Initializing...") if bkr.callbacks.Configured() { logger.Info("recreation-data.writing") bkr.callbacks.WriteRecreationData(clusterState.RecreationData()) logger.Info("recreation-data.restoring") data, err := bkr.callbacks.RestoreRecreationData(instanceID) if err != nil { logger.Error("recreation-data.save-failure.error", err) return resp, false, err } if !reflect.DeepEqual(clusterState.RecreationData(), data) { err = fmt.Errorf("Cluster recreation data was not saved successfully") logger.Error("recreation-data.save-failure.deep-equal", err) return resp, false, err } logger.Info("recreation-data.success") } var existingClusterData *structs.ClusterRecreationData if features.CloneFromServiceName != "" { if bkr.backups.BaseURI == "" { return resp, false, fmt.Errorf("Broker missing configuration backups.base_uri to support 'clone-from' feature") } // Confirm that backup can be found before continuing asynchronously logger.Info("lookup-service-name.start") existingClusterData, err = bkr.lookupClusterDataBackupByServiceInstanceName(details.SpaceGUID, features.CloneFromServiceName, logger) if err != nil { logger.Error("lookup-service-name.error", err) return resp, false, err } logger.Info("lookup-service-name.success") } // Continue processing in background go func() { logger.Info("async-begin") defer logger.Info("async-complete") if existingClusterData != nil { clusterModel.SchedulingMessage(fmt.Sprintf("Cloning existing database %s", existingClusterData.ServiceInstanceName)) if err := bkr.prepopulateDatabaseFromExistingClusterData(existingClusterData, instanceID, clusterModel, logger); err != nil { logger.Error("pre-populate-cluster", err) clusterModel.SchedulingError(fmt.Errorf("Unsuccessful pre-populating database from backup. Please contact administrator: %s", err.Error())) return } } if err := bkr.scheduler.RunCluster(clusterModel, features); err != nil { logger.Error("run-cluster", err) return } if err := bkr.router.AssignPortToCluster(instanceID, port); err != nil { logger.Error("assign-port", err) clusterModel.SchedulingError(fmt.Errorf("Unsuccessful mapping database to routing mesh. Please contact administrator: %s", err.Error())) return } bkr.fetchAndBackupServiceInstanceName(instanceID, &clusterState, logger) }() return resp, true, err }