// Create Binding in the data store func (b *Binding) Create() (err error) { log.Trace(fmt.Sprintf(`cfsb.Binding#Create(%s,%s) ... `, b.InstanceID, b.BindingID)) instance, err := instances.FindByInstanceID(b.InstanceID) if err != nil { log.Error(fmt.Sprintf(`cfsb.Binding#Create(%s) instances.FindByInstanceID(%s) ! %s`, b.BindingID, b.InstanceID, err)) return } dns, err := instance.ExternalDNS() if err != nil { log.Error(fmt.Sprintf(`cfsb.Binding#Create(%s) instance.ExternalDNS(%s) ! %s`, b.BindingID, b.InstanceID, err)) return } // For now the crednetials are fixed, future feature is that we will be able to // create new users/credentials for each binding later on. Currently only // one set of credentials exists for each Instance. s := strings.Split(dns, ":") uri, err := instance.URI() if err != nil { log.Error(fmt.Sprintf(`cfsb.Binding#Create(%s) instance.URI(%s) ! %s`, b.BindingID, b.InstanceID, err)) return } dsn, err := instance.DSN() if err != nil { log.Error(fmt.Sprintf(`cfsb.Binding#Create(%s) instance.DSN(%s) ! %s`, b.BindingID, b.InstanceID, err)) return } jdbc, err := instance.JDBCURI() if err != nil { log.Error(fmt.Sprintf(`cfsb.Binding#Create(%s) instance.JDBCURI(%s) ! %s`, b.BindingID, b.InstanceID, err)) return } b.Creds = &Credentials{ InstanceID: b.InstanceID, BindingID: b.BindingID, URI: uri, DSN: dsn, JDBCURI: jdbc, Host: s[0], Port: s[1], UserName: instance.User, Password: instance.Pass, Database: instance.Database, } p := pg.NewPG(`127.0.0.1`, pbPort, `rdpg`, `rdpg`, pgPass) db, err := p.Connect() if err != nil { log.Error(fmt.Sprintf("cfsb.Binding#Create(%s) ! %s", b.BindingID, err)) return } defer db.Close() err = b.Find() if err != nil { if err == sql.ErrNoRows { // Does not yet exist, insert the binding and it's credentials. sq := fmt.Sprintf(`INSERT INTO cfsb.bindings (instance_id,binding_id) VALUES (lower('%s'),lower('%s'));`, b.InstanceID, b.BindingID) log.Trace(fmt.Sprintf(`cfsb.Binding#Create() > %s`, sq)) _, err = db.Exec(sq) if err != nil { log.Error(fmt.Sprintf(`cfsb.Binding#Create(%s) %s ! %s`, b.BindingID, sq, err)) } err := b.Creds.Create() if err != nil { log.Error(fmt.Sprintf(`cfsb.Binding#Create(%s) b.Creds.Create() ! %s`, b.BindingID, err)) } } } else { // Binding already exists, return existing binding and credentials. return } return }
// InstanceHandler handles put and delete // (PI) PUT /v2/service_instances/:id // (RI) DELETE /v2/service_instances/:id func InstanceHandler(w http.ResponseWriter, request *http.Request) { vars := mux.Vars(request) log.Trace(fmt.Sprintf("%s /v2/service_instances/:instance_id :: %+v", request.Method, vars)) w.Header().Set("Content-Type", "application/json; charset=UTF-8") switch request.Method { case "PUT": type instanceRequest struct { ServiceID string `json:"service_id"` Plan string `json:"plan_id"` OrganizationID string `json:"organization_guid"` SpaceID string `json:"space_guid"` } ir := instanceRequest{} body, err := ioutil.ReadAll(request.Body) if err != nil { log.Error(fmt.Sprintf("%s /v2/service_instances/:instance_id %s", request.Method, err)) writeJSONResponse(w, http.StatusInternalServerError, err.Error()) return } err = json.Unmarshal(body, &ir) if err != nil { log.Error(fmt.Sprintf("%s /v2/service_instances/:instance_id ! %s", request.Method, err)) writeJSONResponse(w, http.StatusInternalServerError, err.Error()) return } instance, err := NewServiceInstance( vars["instance_id"], ir.ServiceID, ir.Plan, ir.OrganizationID, ir.SpaceID, ) if err != nil { log.Error(fmt.Sprintf("%s /v2/service_instances/:instance_id ! %s", request.Method, err)) writeJSONResponse(w, http.StatusInternalServerError, err.Error()) return } err = instance.Provision() if err != nil { log.Error(fmt.Sprintf("%s /v2/service_instances/:instance_id ! %s", request.Method, err)) writeJSONResponse(w, http.StatusInternalServerError, err.Error()) return } msg := fmt.Sprintf("Provisioned Instance %s", instance.InstanceID) writeJSONResponse(w, http.StatusOK, msg) return case "DELETE": instance, err := instances.FindByInstanceID(vars["instance_id"]) if err != nil { log.Error(fmt.Sprintf("%s /v2/service_instances/:instance_id ! %s", request.Method, err)) msg := fmt.Sprintf("Could not find instance %s, perhaps it was already deleted?", vars["instance_id"]) writeJSONResponse(w, http.StatusInternalServerError, msg) return } err = instance.Decommission() if err != nil { log.Error(fmt.Sprintf("%s /v2/service_instances/:instance_id %s", request.Method, err)) writeJSONResponse(w, http.StatusInternalServerError, "There was an error decommissioning instance "+instance.InstanceID) return } writeJSONResponse(w, http.StatusOK, "Successfully Deprovisioned Instance "+instance.InstanceID) default: writeJSONResponse(w, http.StatusMethodNotAllowed, "Allowed Methods: PUT, DELETE") } }
// TODO: This should be remove database func (t *Task) RemoveDatabase(workRole string) (err error) { // For now we assume data is simply the database name. key := fmt.Sprintf("rdpg/%s/work/databases/remove", os.Getenv(`RDPGD_CLUSTER`)) client, _ := consulapi.NewClient(consulapi.DefaultConfig()) lock, err := client.LockKey(key) if err != nil { log.Error(fmt.Sprintf("tasks.Task#RemoveDatabase() Error aquiring lock ! %s", err)) return } leaderCh, err := lock.Lock(nil) if err != nil { log.Error(fmt.Sprintf("tasks.Task#RemoveDatabase() Error aquiring lock ! %s", err)) return } if leaderCh == nil { log.Trace(fmt.Sprintf("tasks.Task#RemoveDatabase() > Not Leader.")) return } log.Trace(fmt.Sprintf("tasks.Task#RemoveDatabase() > Leader.")) p := pg.NewPG(`127.0.0.1`, pbPort, `rdpg`, `rdpg`, pgPass) db, err := p.Connect() if err != nil { log.Error(fmt.Sprintf("tasks.Task#RemoveDatabase() p.Connect() ! %s", err)) return } ids := []string{} sq := fmt.Sprintf(`SELECT instance_id from cfsb.instances WHERE ineffective_at IS NOT NULL AND ineffective_at < CURRENT_TIMESTAMP AND decommissioned_at IS NULL`) err = db.Select(&ids, sq) if err != nil { log.Error(fmt.Sprintf("tasks.Task#RemoveDatabase() Querying for Databases to Cleanup ! %s", err)) } db.Close() for _, id := range ids { db, err := p.Connect() if err != nil { log.Error(fmt.Sprintf("tasks.Task#RemoveDatabase() p.Connect() ! %s", err)) return err } uri := "postgres://" b := bdr.NewBDR(uri, client) i, err := instances.FindByInstanceID(id) if err != nil { log.Error(fmt.Sprintf("tasks.Task#RemoveDatabase(%s) FindingInstance(%s) ! %s", i.Database, i.InstanceID, err)) db.Close() continue } err = b.DisableDatabase(i.Database) if err != nil { log.Error(fmt.Sprintf("tasks.Task#RemoveDatabase() DisableDatabase(%s) for %s ! %s", i.Database, i.InstanceID, err)) db.Close() continue } err = b.BackupDatabase(i.Database) if err != nil { log.Error(fmt.Sprintf("tasks.Task#RemoveDatabase() BackupDatabase(%s) ! %s", i.Database, err)) db.Close() continue } // Question, How do we "stop" the replication group before dropping the database? err = b.DropDatabase(i.Database) if err != nil { log.Error(fmt.Sprintf("tasks.Task#RemoveDatabase() DropDatabase(%s) for %s ! %s", i.Database, i.InstanceID, err)) db.Close() continue } err = b.DropUser(i.User) if err != nil { log.Error(fmt.Sprintf("tasks.Task#RemoveDatabase() DropUser(%s) for %s ! %s", i.User, i.InstanceID, err)) db.Close() continue } err = b.DropDatabase(i.Database) if err != nil { log.Error(fmt.Sprintf("tasks.Task#RemoveDatabase() DropDatabase(%s) for %s ! %s", i.Database, i.InstanceID, err)) db.Close() continue } } db.Close() return }