1// Copyright (c) 2016 Couchbase, Inc. 2// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 3// except in compliance with the License. You may obtain a copy of the License at 4// http://www.apache.org/licenses/LICENSE-2.0 5// Unless required by applicable law or agreed to in writing, software distributed under the 6// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 7// either express or implied. See the License for the specific language governing permissions 8// and limitations under the License. 9 10package system 11 12import ( 13 "fmt" 14 15 "github.com/couchbase/query/auth" 16 "github.com/couchbase/query/datastore" 17 "github.com/couchbase/query/errors" 18 "github.com/couchbase/query/expression" 19 "github.com/couchbase/query/timestamp" 20 "github.com/couchbase/query/value" 21) 22 23type userInfoKeyspace struct { 24 keyspaceBase 25 name string 26 indexer datastore.Indexer 27} 28 29func (b *userInfoKeyspace) Release() { 30} 31 32func (b *userInfoKeyspace) NamespaceId() string { 33 return b.namespace.Id() 34} 35 36func (b *userInfoKeyspace) Id() string { 37 return b.Name() 38} 39 40func (b *userInfoKeyspace) Name() string { 41 return b.name 42} 43 44func getUserInfoList(s *store) ([]interface{}, errors.Error) { 45 val, err := s.UserInfo() 46 if err != nil { 47 return nil, err 48 } 49 // Expected data format: 50 // [{"id":"ivanivanov","name":"Ivan Ivanov","roles":[{"role":"cluster_admin"},{"bucket_name":"default","role":"bucket_admin"}]}, 51 // {"id":"petrpetrov","name":"Petr Petrov","roles":[{"role":"replication_admin"}]}] 52 data := val.Actual() 53 sliceOfUsers, ok := data.([]interface{}) 54 if !ok { 55 return nil, errors.NewInvalidValueError(fmt.Sprintf("Unexpected format for user_info received from server: %v", data)) 56 } 57 58 return sliceOfUsers, nil 59} 60 61func (b *userInfoKeyspace) Count(context datastore.QueryContext) (int64, errors.Error) { 62 uil, err := getUserInfoList(b.namespace.store) 63 if err != nil { 64 return 0, err 65 } 66 return int64(len(uil)), nil 67} 68 69func (b *userInfoKeyspace) Indexer(name datastore.IndexType) (datastore.Indexer, errors.Error) { 70 return b.indexer, nil 71} 72 73func (b *userInfoKeyspace) Indexers() ([]datastore.Indexer, errors.Error) { 74 return []datastore.Indexer{b.indexer}, nil 75} 76 77func (b *userInfoKeyspace) Fetch(keys []string, keysMap map[string]value.AnnotatedValue, 78 context datastore.QueryContext, subPaths []string) (errs []errors.Error) { 79 sliceOfUsers, err := getUserInfoList(b.namespace.store) 80 if err != nil { 81 return []errors.Error{err} 82 } 83 newMap, err := userInfoListToMap(sliceOfUsers) 84 if err != nil { 85 return []errors.Error{err} 86 } 87 88 for _, k := range keys { 89 val := newMap[k] 90 if val == nil { 91 continue 92 } 93 94 item := value.NewAnnotatedValue(val) 95 item.SetAttachment("meta", map[string]interface{}{ 96 "id": k, 97 }) 98 keysMap[k] = item 99 } 100 101 return 102} 103 104func (b *userInfoKeyspace) Insert(inserts []value.Pair) ([]value.Pair, errors.Error) { 105 return nil, errors.NewSystemNotImplementedError(nil, "") 106} 107 108func (b *userInfoKeyspace) Update(updates []value.Pair) ([]value.Pair, errors.Error) { 109 return nil, errors.NewSystemNotImplementedError(nil, "") 110} 111 112func (b *userInfoKeyspace) Upsert(upserts []value.Pair) ([]value.Pair, errors.Error) { 113 return nil, errors.NewSystemNotImplementedError(nil, "") 114} 115 116func (b *userInfoKeyspace) Delete(deletes []string, context datastore.QueryContext) ([]string, errors.Error) { 117 return nil, errors.NewSystemNotImplementedError(nil, "") 118} 119 120func newUserInfoKeyspace(p *namespace) (*userInfoKeyspace, errors.Error) { 121 b := new(userInfoKeyspace) 122 setKeyspaceBase(&b.keyspaceBase, p) 123 b.name = KEYSPACE_NAME_USER_INFO 124 125 primary := &userInfoIndex{name: "#primary", keyspace: b} 126 b.indexer = newSystemIndexer(b, primary) 127 setIndexBase(&primary.indexBase, b.indexer) 128 129 return b, nil 130} 131 132type userInfoIndex struct { 133 indexBase 134 name string 135 keyspace *userInfoKeyspace 136} 137 138func (pi *userInfoIndex) KeyspaceId() string { 139 return pi.keyspace.Id() 140} 141 142func (pi *userInfoIndex) Id() string { 143 return pi.Name() 144} 145 146func (pi *userInfoIndex) Name() string { 147 return pi.name 148} 149 150func (pi *userInfoIndex) Type() datastore.IndexType { 151 return datastore.SYSTEM 152} 153 154func (pi *userInfoIndex) SeekKey() expression.Expressions { 155 return nil 156} 157 158func (pi *userInfoIndex) RangeKey() expression.Expressions { 159 return nil 160} 161 162func (pi *userInfoIndex) Condition() expression.Expression { 163 return nil 164} 165 166func (pi *userInfoIndex) IsPrimary() bool { 167 return true 168} 169 170func (pi *userInfoIndex) State() (state datastore.IndexState, msg string, err errors.Error) { 171 return datastore.ONLINE, "", nil 172} 173 174func (pi *userInfoIndex) Statistics(requestId string, span *datastore.Span) ( 175 datastore.Statistics, errors.Error) { 176 return nil, nil 177} 178 179func (pi *userInfoIndex) Drop(requestId string) errors.Error { 180 return errors.NewSystemIdxNoDropError(nil, "") 181} 182 183func (pi *userInfoIndex) Scan(requestId string, span *datastore.Span, distinct bool, limit int64, 184 cons datastore.ScanConsistency, vector timestamp.Vector, conn *datastore.IndexConnection) { 185 186 pi.ScanEntries(requestId, limit, cons, vector, conn) 187} 188 189func userInfoListToMap(sliceOfUsers []interface{}) (map[string]value.Value, errors.Error) { 190 newMap := make(map[string]value.Value, len(sliceOfUsers)) 191 for i, u := range sliceOfUsers { 192 userAsMap, ok := u.(map[string]interface{}) 193 if !ok { 194 return nil, errors.NewInvalidValueError(fmt.Sprintf("Unexpected format for user_info at position %d: %v", i, u)) 195 } 196 auth.ConvertRolesToAliases(userAsMap) 197 id, present := userAsMap["id"] 198 if !present { 199 return nil, errors.NewInvalidValueError(fmt.Sprintf("Could not find id in user_info data at position %d: %v", i, u)) 200 } 201 idAsString, ok := id.(string) 202 if !ok { 203 return nil, errors.NewInvalidValueError(fmt.Sprintf("Field id of unexpected type in user_info data at position %d: %v", i, u)) 204 } 205 domain, present := userAsMap["domain"] 206 if !present { 207 return nil, errors.NewInvalidValueError(fmt.Sprintf("Could not find domain in user_info data at position %d: %v", i, u)) 208 } 209 domainAsString, ok := domain.(string) 210 if !ok { 211 return nil, errors.NewInvalidValueError( 212 fmt.Sprintf("Field domain of unexpected type in user_info data at position %d: %v", i, u)) 213 } 214 userKey := fmt.Sprintf("%s:%s", domainAsString, idAsString) 215 newMap[userKey] = value.NewValue(u) 216 } 217 return newMap, nil 218} 219 220func (pi *userInfoIndex) ScanEntries(requestId string, limit int64, cons datastore.ScanConsistency, 221 vector timestamp.Vector, conn *datastore.IndexConnection) { 222 defer close(conn.EntryChannel()) 223 224 sliceOfUsers, err := getUserInfoList(pi.keyspace.namespace.store) 225 if err != nil { 226 conn.Fatal(err) 227 return 228 } 229 mapOfUsers, err := userInfoListToMap(sliceOfUsers) 230 if err != nil { 231 conn.Fatal(err) 232 return 233 } 234 235 var numProduced int64 236 for k, _ := range mapOfUsers { 237 if limit > 0 && numProduced > limit { 238 break 239 } 240 241 entry := datastore.IndexEntry{PrimaryKey: k} 242 if !sendSystemKey(conn, &entry) { 243 return 244 } 245 numProduced++ 246 } 247} 248