/* POST /services/{service}/{action} */ func ServiceHandler(w http.ResponseWriter, request *http.Request) { vars := mux.Vars(request) log.Trace(fmt.Sprintf("%s /services/%s/%s", request.Method, vars["service"], vars["action"])) switch request.Method { case "PUT": service, err := NewService(vars["service"]) if err != nil { log.Error(fmt.Sprintf("ServiceHandler(): NewService(%s)")) http.Error(w, `{"status": %d, "description": "%s"}`, http.StatusInternalServerError) return } switch vars["action"] { case "configure": err := service.Configure() if err != nil { msg := fmt.Sprintf(`{"status": %d, "description": "%s"}`, http.StatusInternalServerError, err) log.Error(msg) http.Error(w, msg, http.StatusInternalServerError) } msg := fmt.Sprintf(`{"status": %d, "description": "%s %s"}`, http.StatusOK, vars["service"], vars["action"]) log.Trace(msg) w.WriteHeader(http.StatusOK) fmt.Fprintf(w, msg) default: msg := fmt.Sprintf(`{"status": %d, "description": "Invalid Action %s for %s"}`, http.StatusBadRequest, vars["action"], vars["service"]) log.Error(msg) http.Error(w, msg, http.StatusBadRequest) } default: msg := fmt.Sprintf(`{"status": %d, "description": "Method not allowed %s"}`, http.StatusMethodNotAllowed, request.Method) log.Error(msg) http.Error(w, msg, http.StatusMethodNotAllowed) } }
func (n *Node) CreateDatabase(dbname, owner string) (err error) { n.Database = "postgres" db, err := n.Connect() if err != nil { log.Error(fmt.Sprintf("Node#CreateDatabase(%s) %s ! %s", dbname, n.Host, err)) return } defer db.Close() sq := fmt.Sprintf(`CREATE DATABASE %s WITH OWNER %s TEMPLATE template0 ENCODING 'UTF8'`, dbname, owner) log.Trace(fmt.Sprintf(`Node#CreateDatabase(%s) %s > %s`, dbname, n.Host, sq)) _, err = db.Query(sq) if err != nil { log.Error(fmt.Sprintf("Node#CreateDatabase(%s) %s ! %s", dbname, n.Host, err)) return } sq = fmt.Sprintf(`REVOKE ALL ON DATABASE "%s" FROM public`, dbname) log.Trace(fmt.Sprintf(`Node#CreateDatabase(%s) %s > %s`, dbname, n.Host, sq)) _, err = db.Exec(sq) if err != nil { log.Error(fmt.Sprintf("Node#CreateDatabase(%s) %s ! %s", dbname, n.Host, err)) } sq = fmt.Sprintf(`GRANT ALL PRIVILEGES ON DATABASE %s TO %s`, dbname, owner) log.Trace(fmt.Sprintf(`Node#CreateDatabase(%s) %s > %s`, dbname, n.Host, sq)) _, err = db.Query(sq) if err != nil { log.Error(fmt.Sprintf(`Node#CreateDatabase(%s) %s ! %s`, dbname, n.Host, err)) return } return nil }
func (r *RDPG) CreateUser(username, password string) (err error) { for _, node := range r.Nodes() { node.Database = `postgres` db, err := node.Connect() if err != nil { log.Error(fmt.Sprintf(`RDPG#CreateUser(%s) %s ! %s`, username, node.Host, err)) return err } // TODO: Check if user exists first sq := fmt.Sprintf(`CREATE USER %s;`, username) log.Trace(fmt.Sprintf(`RDPG#CreateUser(%s) %s > %s`, username, node.Host, sq)) _, err = db.Exec(sq) if err != nil { log.Error(fmt.Sprintf("RDPG#CreateUser(%s) %s ! %s", username, node.Host, err)) db.Close() return err } sq = fmt.Sprintf(`ALTER USER %s ENCRYPTED PASSWORD '%s'`, username, password) log.Trace(fmt.Sprintf(`RDPG#CreateUser(%s) %s > %s`, username, node.Host, sq)) _, err = db.Exec(sq) if err != nil { log.Error(fmt.Sprintf("RDPG#CreateUser(%s) %s ! %s", username, node.Host, err)) } db.Close() } return nil }
func httpAuth(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, request *http.Request) { if len(request.Header["Authorization"]) == 0 { log.Trace(fmt.Sprintf("httpAuth(): Authorization Required")) http.Error(w, "Authorization Required", http.StatusUnauthorized) return } auth := strings.SplitN(request.Header["Authorization"][0], " ", 2) if len(auth) != 2 || auth[0] != "Basic" { log.Error(fmt.Sprintf("httpAuth(): Unhandled Authorization Type, Expected Basic")) http.Error(w, "Unhandled Authroization Type, Expected Basic\n", http.StatusBadRequest) return } payload, err := base64.StdEncoding.DecodeString(auth[1]) if err != nil { log.Error(fmt.Sprintf("httpAuth(): Authorization Failed")) http.Error(w, "Authorization Failed\n", http.StatusUnauthorized) return } nv := strings.SplitN(string(payload), ":", 2) if (len(nv) != 2) || !isAuthorized(nv[0], nv[1]) { log.Error(fmt.Sprintf("httpAuth(): Authorization Failed")) http.Error(w, "Authorization Failed\n", http.StatusUnauthorized) return } h(w, request) } }
func (r *RDPG) DropDatabase(dbname string) (err error) { nodes := r.Nodes() for i := len(nodes) - 1; i >= 0; i-- { node := nodes[i] node.Database = "postgres" db, err := node.Connect() if err != nil { log.Error(fmt.Sprintf("RDPG#DropDatabase(%s) %s ! %s", dbname, node.Host, err)) return err } // sq := fmt.Sprintf(SELECT slot_name FROM pg_replication_slots WHERE database='%s',dbname); // pg_recvlogical --drop-slot // TODO: How do we drop a database in bdr properly? sq := fmt.Sprintf(`DROP DATABASE IF EXISTS %s`, dbname) log.Trace(fmt.Sprintf(`RDPG#DropDatabase(%s) %s DROP > %s`, dbname, node.Host, sq)) _, err = db.Exec(sq) if err != nil { log.Error(fmt.Sprintf("RDPG#DropDatabase(%s) DROP %s ! %s", dbname, node.Host, err)) } db.Close() } return nil }
/* (FC) GET /v2/catalog */ func CatalogHandler(w http.ResponseWriter, request *http.Request) { log.Trace(fmt.Sprintf("%s /v2/catalog", request.Method)) switch request.Method { case "GET": c := Catalog{} err := c.Fetch() if err != nil { msg := fmt.Sprintf(`{"status": %d, "description": "%s"}`, http.StatusInternalServerError, err) log.Error(msg) http.Error(w, msg, http.StatusInternalServerError) return } jsonCatalog, err := json.Marshal(c) if err != nil { msg := fmt.Sprintf(`{"status": %d, "description": "%s"}`, http.StatusInternalServerError, err) log.Error(msg) http.Error(w, msg, http.StatusInternalServerError) } else { w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.WriteHeader(http.StatusOK) w.Write(jsonCatalog) } default: msg := fmt.Sprintf(`{"status": %d, "description": "Allowed Methods: GET"}`, http.StatusMethodNotAllowed) log.Error(msg) http.Error(w, msg, http.StatusMethodNotAllowed) } return }
func (r *RDPG) CreateReplicationGroup(dbname string) (err error) { nodes := r.Nodes() // TODO: Drop Database on all nodes if err != nil for any operation below for index, node := range nodes { node.Database = dbname db, err := node.Connect() if err != nil { break } sq := "" name := fmt.Sprintf("%s", node.Host) if index == 0 { sq = fmt.Sprintf(`SELECT bdr.bdr_group_create( local_node_name := '%s', node_external_dsn := 'host=%s port=%s user=%s dbname=%s' ); `, name, node.Host, node.Port, node.User, dbname) } else { sq = fmt.Sprintf(`SELECT bdr.bdr_group_join( local_node_name := '%s', node_external_dsn := 'host=%s port=%s user=%s dbname=%s', join_using_dsn := 'host=%s port=%s user=%s dbname=%s' ); `, name, node.Host, node.Port, node.User, node.Database, nodes[0].Host, nodes[0].Port, nodes[0].User, dbname, ) } log.Trace(fmt.Sprintf(`RDPG#CreateReplicationGroup(%s) %s > %s`, dbname, node.Host, sq)) _, err = db.Exec(sq) if err == nil { sq = `SELECT bdr.bdr_node_join_wait_for_ready();` log.Trace(fmt.Sprintf(`RDPG#CreateReplicationGroup(%s) %s > %s`, dbname, node.Host, sq)) _, err = db.Exec(sq) } db.Close() } if err != nil { // Cleanup in BDR currently requires droping the database and trying again... log.Error(fmt.Sprintf("CreateReplicationGroup(%s) ! %s", dbname, err)) } return err }
func (n *Node) AdminAPI(method, path string) (err error) { url := fmt.Sprintf("http://%s:%s/%s", n.Host, os.Getenv("RDPG_ADMIN_PORT"), path) req, err := http.NewRequest(method, url, bytes.NewBuffer([]byte(`{}`))) // req.Header.Set("Content-Type", "application/json") req.SetBasicAuth(os.Getenv("RDPG_ADMIN_USER"), os.Getenv("RDPG_ADMIN_PASS")) client := &http.Client{} log.Trace(fmt.Sprintf(`Node#AdminAPI(%s,%s) %s`, method, path, url)) resp, err := client.Do(req) if err != nil { log.Error(fmt.Sprintf(`Node#AdminAPI(%s,%s) ! %s`, method, url, err)) } resp.Body.Close() return }
func FindBinding(bindingId string) (binding *Binding, err error) { r := rdpg.New() b := Binding{} sq := `SELECT id,instance_id, binding_id FROM cfsb.bindings WHERE binding_id=lower($1) LIMIT 1;` log.Trace(fmt.Sprintf(`cfsb.FindBinding(%s) > %s`, bindingId, sq)) r.OpenDB("rdpg") err = r.DB.Get(&b, sq, bindingId) if err != nil { // TODO: Change messaging if err is sql.NoRows then say couldn't find binding with bindingId log.Error(fmt.Sprintf("cfsb.FindBinding(%s) ! %s", bindingId, err)) } r.DB.Close() binding = &b return }
func RemoveBinding(bindingId string) (binding *Binding, err error) { binding, err = FindBinding(bindingId) if err != nil { log.Error(fmt.Sprintf(`cfsb.CreateBinding(%s) ! %s`, bindingId, err)) return } r := rdpg.New() sq := `UPDATE cfsb.bindings SET ineffective_at = CURRENT_TIMESTAMP WHERE binding_id = $1;` log.Trace(fmt.Sprintf(`cfsb.RemoveBinding(%s) > %s`, bindingId, sq)) r.OpenDB("rdpg") _, err = r.DB.Query(sq, bindingId) if err != nil { log.Error(fmt.Sprintf(`cfsb.CreateBinding(%s) ! %s`, bindingId, err)) } r.DB.Close() return }
func (r *RDPG) DropUser(name string) (err error) { nodes := r.Nodes() for i := len(nodes) - 1; i >= 0; i-- { node := nodes[i] node.Database = "postgres" db, err := node.Connect() if err != nil { log.Error(fmt.Sprintf("RDPG#DropUser(%s) %s ! %s", name, node.Host, err)) return err } sq := fmt.Sprintf(`DROP USER %s`, name) log.Trace(fmt.Sprintf(`RDPG#DropUser(%s) %s > %s`, name, node.Host, sq)) _, err = db.Exec(sq) if err != nil { log.Error(fmt.Sprintf("RDPG#DropUser(%s) %s ! %s", name, node.Host, err)) } db.Close() } return nil }
func (r *RDPG) DisableDatabase(dbname string) (err error) { nodes := r.Nodes() for i := len(nodes) - 1; i >= 0; i-- { node := nodes[i] node.Database = "postgres" db, err := node.Connect() if err != nil { log.Error(fmt.Sprintf("RDPG#DisableDatabase(%s) %s ! %s", dbname, node.Host, err)) return err } sq := fmt.Sprintf(`SELECT rdpg.bdr_disable_database('%s');`, dbname) log.Trace(fmt.Sprintf(`RDPG#DisableDatabase(%s) DISABLE %s > %s`, dbname, node.Host, sq)) _, err = db.Exec(sq) if err != nil { log.Error(fmt.Sprintf("RDPG#DisableDatabase(%s) DISABLE %s ! %s", dbname, node.Host, err)) } db.Close() } return nil }
/* (CB) PUT /v2/service_instances/:instance_id/service_bindings/:binding_id (RB) DELETE /v2/service_instances/:instance_id/service_bindings/:binding_id */ func BindingHandler(w http.ResponseWriter, request *http.Request) { vars := mux.Vars(request) body, err := ioutil.ReadAll(request.Body) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": %d,"description": %s}`, http.StatusInternalServerError, err) return } log.Trace(fmt.Sprintf("%s /v2/service_instances/:instance_id/service_bindings/:binding_id :: %+v :: %s", request.Method, vars, body)) switch request.Method { case "PUT": binding, err := CreateBinding(vars["instance_id"], vars["binding_id"]) if err != nil { log.Error(fmt.Sprintf("%s /v2/service_instances/:instance_id/service_bindings/:binding_id %s", request.Method, err)) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": %d,"description": %s}`, http.StatusInternalServerError, err) return } j, err := json.Marshal(binding) if err != nil { log.Error(fmt.Sprintf("%s /v2/service_instances/:instance_id/service_bindings/:binding_id %s", request.Method, err)) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": %d,"description": %s}`, http.StatusInternalServerError, err) } else { w.WriteHeader(http.StatusOK) w.Write(j) return } case "DELETE": // Question, do we need to do anything else? w.WriteHeader(http.StatusOK) fmt.Fprintf(w, `{"status": %d,"description": "Binding Removed"}`, http.StatusOK) default: w.WriteHeader(http.StatusMethodNotAllowed) fmt.Fprintf(w, `{"status": %d,"description": "Allowed Methods: PUT, DELETE"}`, http.StatusMethodNotAllowed) return } }
func (s *Service) Configure() (err error) { log.Trace(fmt.Sprintf(`Service#Configure(%s)`, s.Name)) switch s.Name { case "consul": return errors.New(`Service#Configure("consul") is not yet implemented`) case "haproxy": header, err := ioutil.ReadFile(`/var/vcap/jobs/rdpg-agent/config/haproxy/haproxy.cfg.header`) if err != nil { log.Error(fmt.Sprintf("cfsb#Service.Configure(%s) ! %s", s.Name, err)) return err } r := rdpg.New() nodes := r.Nodes() // TODO: 5432 & 6432 from environmental configuration. // TODO: Should this list come from active Consul registered nodes instead? footer := fmt.Sprintf(` frontend pgbdr_write_port bind 0.0.0.0:5432 mode tcp default_backend pgbdr_write_master backend pgbdr_write_master mode tcp server master %s:6432 check `, nodes[0].Host) hc := []string{string(header), footer} err = ioutil.WriteFile(`/var/vcap/jobs/haproxy/config/haproxy.cfg`, []byte(strings.Join(hc, "\n")), 0640) if err != nil { log.Error(fmt.Sprintf("cfsb#Service.Configure(%s) ! %s", s.Name, err)) return err } cmd := exec.Command("/var/vcap/jobs/haproxy/bin/control", "reload") err = cmd.Run() if err != nil { log.Error(fmt.Sprintf("cfsb#Service.Configure(%s) ! %s", s.Name, err)) return err } return errors.New(`Service#Configure("haproxy") is not yet implemented`) case "pgbouncer": instances, err := cfsb.Instances() if err != nil { log.Error(fmt.Sprintf("cfsb#Service.Configure(%s) ! %s", s.Name, err)) return err } pgbConf, err := ioutil.ReadFile(`/var/vcap/jobs/rdpg-agent/config/pgbouncer/pgbouncer.ini`) if err != nil { log.Error(fmt.Sprintf("cfsb#Service.Configure(%s) ! %s", s.Name, err)) return err } pgbUsers, err := ioutil.ReadFile(`/var/vcap/jobs/rdpg-agent/config/pgbouncer/users`) if err != nil { log.Error(fmt.Sprintf("cfsb#Service.Configure(%s) ! %s", s.Name, err)) return err } pc := []string{string(pgbConf)} pu := []string{string(pgbUsers)} for _, i := range instances { // TODO: Fetch port from something like os.Getenv("PG_PORT") instead of hardcoding here. c := fmt.Sprintf(`%s = host=%s port=%s dbname=%s`, i.Database, "127.0.0.1", "7432", i.Database) pc = append(pc, c) u := fmt.Sprintf(`"%s" "%s"`, i.User, i.Pass) pu = append(pu, u) } pc = append(pc, "") pu = append(pu, "") err = ioutil.WriteFile(`/var/vcap/store/pgbouncer/config/pgbouncer.ini`, []byte(strings.Join(pc, "\n")), 0640) if err != nil { log.Error(fmt.Sprintf("cfsb#Service.Configure(%s) ! %s", s.Name, err)) return err } err = ioutil.WriteFile(`/var/vcap/store/pgbouncer/config/users`, []byte(strings.Join(pu, "\n")), 0640) if err != nil { log.Error(fmt.Sprintf("cfsb#Service.Configure(%s) ! %s", s.Name, err)) return err } cmd := exec.Command("/var/vcap/jobs/pgbouncer/bin/control", "reload") err = cmd.Run() if err != nil { log.Error(fmt.Sprintf("cfsb#Service.Configure(%s) ! %s", s.Name, err)) return err } case "pgbdr": return errors.New(`Service#Configure("pgbdr") is not yet implemented`) default: return errors.New(fmt.Sprintf(`Service#Configure("%s") is unknown.`, s.Name)) } return }
// TODO: This should only be run on one node... func (r *RDPG) InitSchema() (err error) { // TODO: if 'rdpg' database DNE, // For each node connect to pgbdr and: // CreatDatabase('rdpg','postgres') // "ALTER USER postgres SUPERUSER CREATEDB CREATEROLE INHERIT" // CreateReplicationGroup('rdpg') log.Trace(fmt.Sprintf("RDPG#initSchema() CONNECT > %s", rdpgURI)) var name string r.OpenDB("rdpg") db := r.DB _, err = db.Exec(`SELECT bdr.bdr_node_join_wait_for_ready();`) if err != nil { log.Error(fmt.Sprintf("RDPG#initSchema() bdr.bdr_node_join_wait_for_ready ! %s", err)) } keys := []string{ "rdpg_extensions", "rdpg_schemas", } for _, key := range keys { log.Trace(fmt.Sprintf("RDPG#initSchema() SQL[%s]", key)) _, err = db.Exec(SQL[key]) if err != nil { log.Error(fmt.Sprintf("RDPG#initSchema() ! %s", err)) } } keys = []string{ "create_table_cfsb_services", "create_table_cfsb_plans", "create_table_cfsb_instances", "create_table_cfsb_bindings", "create_table_cfsb_credentials", "create_table_rdpg_consul_watch_notifications", "create_table_rdpg_events", } for _, key := range keys { k := strings.Split(strings.Replace(strings.Replace(key, "create_table_", "", 1), "_", ".", 1), ".") sq := fmt.Sprintf(`SELECT table_name FROM information_schema.tables where table_schema='%s' AND table_name='%s';`, k[0], k[1]) log.Trace(fmt.Sprintf("RDPG#initSchema() %s", sq)) if err := db.QueryRow(sq).Scan(&name); err != nil { if err == sql.ErrNoRows { log.Trace(fmt.Sprintf("RDPG#initSchema() SQL[%s]", key)) _, err = db.Exec(SQL[key]) if err != nil { log.Error(fmt.Sprintf("RDPG#initSchema() ! %s", err)) } } else { log.Error(fmt.Sprintf("rdpg.initSchema() ! %s", err)) return err } } } // TODO: Move initial population of services out of rdpg-agent to Admin API. if err := db.QueryRow("SELECT name FROM cfsb.services WHERE name='rdpg' LIMIT 1;").Scan(&name); err != nil { if err == sql.ErrNoRows { if _, err = db.Exec(SQL["insert_default_cfsb_services"]); err != nil { log.Error(fmt.Sprintf("rdpg.initSchema(insert_default_cfsb_services) %s", err)) return err } } else { log.Error(fmt.Sprintf("rdpg.initSchema() ! %s", err)) return err } } // TODO: Move initial population of services out of rdpg-agent to Admin API. if err = db.QueryRow("SELECT name FROM cfsb.plans WHERE name='shared' LIMIT 1;").Scan(&name); err != nil { if err == sql.ErrNoRows { if _, err = db.Exec(SQL["insert_default_cfsb_plans"]); err != nil { log.Error(fmt.Sprintf("rdpg.initSchema(insert_default_cfsb_plans) %s", err)) return err } } else { log.Error(fmt.Sprintf("rdpg.initSchema() ! %s", err)) return err } } db.Close() for _, node := range r.Nodes() { node.Database = "postgres" db, err := node.Connect() if err != nil { log.Error(fmt.Sprintf("RDPG#DropUser(%s) %s ! %s", name, node.Host, err)) return err } log.Trace(fmt.Sprintf("RDPG#initSchema() SQL[%s]", "postgres_schemas")) _, err = db.Exec(SQL["postgres_schemas"]) if err != nil { log.Error(fmt.Sprintf("RDPG#initSchema() ! %s", err)) } keys = []string{ // These are for the postgres database only "create_function_rdpg_disable_database", } for _, key := range keys { k := strings.Split(strings.Replace(strings.Replace(key, "create_function_", "", 1), "_", ".", 1), ".") sq := fmt.Sprintf(`SELECT routine_name FROM information_schema.routines WHERE routine_type='FUNCTION' AND routine_schema='%s' AND routine_name='%s';`, k[0], k[1]) log.Trace(fmt.Sprintf("RDPG#initSchema() %s", sq)) if err := db.QueryRow(sq).Scan(&name); err != nil { if err == sql.ErrNoRows { log.Trace(fmt.Sprintf("RDPG#initSchema() SQL[%s]", key)) _, err = db.Exec(SQL[key]) if err != nil { log.Error(fmt.Sprintf("RDPG#initSchema() %s", err)) } } else { log.Error(fmt.Sprintf("rdpg.initSchema() %s", err)) return err } } } db.Close() } return nil }
/* (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)) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": %d,"description": %s}`, http.StatusInternalServerError, err) return } err = json.Unmarshal(body, &ir) if err != nil { log.Error(fmt.Sprintf("%s /v2/service_instances/:instance_id %s", request.Method, err)) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": %d,"description": %s}`, http.StatusInternalServerError, err) return } instance, err := NewInstance( 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)) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": %d,"description": %s}`, http.StatusInternalServerError, err) return } err = instance.Provision() if err != nil { log.Error(fmt.Sprintf("%s /v2/service_instances/:instance_id %s", request.Method, err)) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": %d,"description": %s}`, http.StatusInternalServerError, err) return } w.WriteHeader(http.StatusOK) fmt.Fprintf(w, `{"status": %d,"description": "Instance Provisioned Successfully"}`, http.StatusOK) return case "DELETE": instance, err := FindInstance(vars["instance_id"]) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": %d,"description": %s}`, http.StatusInternalServerError, err) return } err = instance.Remove() if err != nil { log.Error(fmt.Sprintf("%s /v2/service_instances/:instance_id %s", request.Method, err)) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, `{"status": %d,"description": %s}`, http.StatusInternalServerError, err) return } w.WriteHeader(http.StatusOK) fmt.Fprintf(w, `{"status": %d,"description": "Successfully Deprovisioned %s"}`, http.StatusOK, instance.InstanceId) default: w.WriteHeader(http.StatusMethodNotAllowed) fmt.Fprintf(w, `{"status": %d,"description": "Allowed Methods: PUT, DELETE"}`, http.StatusMethodNotAllowed) return } }