github.com/m3db/m3@v1.5.0/src/query/api/v1/handler/namespace/delete.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package namespace 22 23 import ( 24 "encoding/json" 25 "errors" 26 "fmt" 27 "net/http" 28 "path" 29 "strings" 30 31 clusterclient "github.com/m3db/m3/src/cluster/client" 32 "github.com/m3db/m3/src/cluster/placementhandler/handleroptions" 33 "github.com/m3db/m3/src/dbnode/namespace" 34 "github.com/m3db/m3/src/query/api/v1/route" 35 "github.com/m3db/m3/src/query/util/logging" 36 xerrors "github.com/m3db/m3/src/x/errors" 37 "github.com/m3db/m3/src/x/instrument" 38 xhttp "github.com/m3db/m3/src/x/net/http" 39 40 "github.com/gorilla/mux" 41 "go.uber.org/zap" 42 ) 43 44 const ( 45 namespaceIDVar = "id" 46 47 // DeleteHTTPMethod is the HTTP method used with this resource. 48 DeleteHTTPMethod = http.MethodDelete 49 ) 50 51 var ( 52 // M3DBDeleteURL is the url for the M3DB namespace delete handler. 53 M3DBDeleteURL = path.Join( 54 route.Prefix, 55 M3DBServiceNamespacePathName, 56 fmt.Sprintf("{%s}", namespaceIDVar), 57 ) 58 ) 59 60 var ( 61 errEmptyID = xerrors.NewInvalidParamsError(errors.New("must specify namespace ID to delete")) 62 ) 63 64 // DeleteHandler is the handler for namespace deletes. 65 type DeleteHandler Handler 66 67 // NewDeleteHandler returns a new instance of DeleteHandler. 68 func NewDeleteHandler( 69 client clusterclient.Client, 70 instrumentOpts instrument.Options, 71 ) *DeleteHandler { 72 return &DeleteHandler{ 73 client: client, 74 instrumentOpts: instrumentOpts, 75 } 76 } 77 78 func (h *DeleteHandler) ServeHTTP( 79 svc handleroptions.ServiceNameAndDefaults, 80 w http.ResponseWriter, 81 r *http.Request, 82 ) { 83 ctx := r.Context() 84 logger := logging.WithContext(ctx, h.instrumentOpts) 85 id := strings.TrimSpace(mux.Vars(r)[namespaceIDVar]) 86 if id == "" { 87 logger.Error("no namespace ID to delete", zap.Error(errEmptyID)) 88 xhttp.WriteError(w, errEmptyID) 89 return 90 } 91 92 opts := handleroptions.NewServiceOptions(svc, r.Header, nil) 93 err := h.Delete(id, opts) 94 if err != nil { 95 logger.Error("unable to delete namespace", zap.Error(err)) 96 xhttp.WriteError(w, err) 97 return 98 } 99 100 json.NewEncoder(w).Encode(struct { 101 Deleted bool `json:"deleted"` 102 }{ 103 Deleted: true, 104 }) 105 } 106 107 // Delete deletes a namespace. 108 func (h *DeleteHandler) Delete(id string, opts handleroptions.ServiceOptions) error { 109 store, err := h.client.Store(opts.KVOverrideOptions()) 110 if err != nil { 111 return err 112 } 113 114 metadatas, version, err := Metadata(store) 115 if err != nil { 116 return err 117 } 118 119 mdIdx := -1 120 for idx, md := range metadatas { 121 if md.ID().String() == id { 122 mdIdx = idx 123 break 124 } 125 } 126 127 if mdIdx == -1 { 128 return errNamespaceNotFound 129 } 130 131 // If metadatas are empty, remove the key 132 if len(metadatas) == 1 { 133 if _, err = store.Delete(M3DBNodeNamespacesKey); err != nil { 134 return fmt.Errorf("unable to delete kv key: %v", err) 135 } 136 137 return nil 138 } 139 140 // Replace the index where we found the metadata with the last element, then truncate 141 metadatas[mdIdx] = metadatas[len(metadatas)-1] 142 metadatas = metadatas[:len(metadatas)-1] 143 144 // Update namespace map and set kv 145 nsMap, err := namespace.NewMap(metadatas) 146 if err != nil { 147 return fmt.Errorf("failed to delete namespace: %v", err) 148 } 149 150 protoRegistry, err := namespace.ToProto(nsMap) 151 if err != nil { 152 return fmt.Errorf("failed to delete namespace: %v", err) 153 } 154 155 _, err = store.CheckAndSet(M3DBNodeNamespacesKey, version, protoRegistry) 156 if err != nil { 157 return fmt.Errorf("failed to delete namespace: %v", err) 158 } 159 160 return nil 161 }