Jiri Simsa | d7616c9 | 2015-03-24 23:44:30 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Vanadium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
Todd Wang | 4ac9e65 | 2015-03-27 14:50:47 -0700 | [diff] [blame] | 5 | package main |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 6 | |
| 7 | import ( |
Robert Kroeger | c66b387 | 2015-04-22 14:24:32 -0700 | [diff] [blame] | 8 | "sort" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 9 | "strings" |
| 10 | |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 11 | "v.io/v23/context" |
Robin Thellend | f15f295 | 2015-07-17 21:49:58 -0700 | [diff] [blame] | 12 | "v.io/v23/glob" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 13 | "v.io/v23/naming" |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 14 | "v.io/v23/rpc" |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 15 | "v.io/v23/security" |
Todd Wang | 387d8a4 | 2015-03-30 17:09:05 -0700 | [diff] [blame] | 16 | "v.io/v23/security/access" |
Todd Wang | 94c9d0b | 2015-04-01 14:27:00 -0700 | [diff] [blame] | 17 | "v.io/v23/services/application" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 18 | "v.io/v23/verror" |
Jiri Simsa | 87d884d | 2015-06-18 10:25:54 -0700 | [diff] [blame] | 19 | "v.io/x/lib/set" |
Jiri Simsa | 87d884d | 2015-06-18 10:25:54 -0700 | [diff] [blame] | 20 | "v.io/x/ref/services/internal/fs" |
| 21 | "v.io/x/ref/services/internal/pathperms" |
| 22 | "v.io/x/ref/services/repository" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 23 | ) |
| 24 | |
Robin Thellend | 9bc8fcb | 2014-11-17 10:23:04 -0800 | [diff] [blame] | 25 | // appRepoService implements the Application repository interface. |
| 26 | type appRepoService struct { |
Robert Kroeger | d9c3488 | 2014-08-22 11:16:38 -0700 | [diff] [blame] | 27 | // store is the storage server used for storing application |
| 28 | // metadata. |
Robin Thellend | 9bc8fcb | 2014-11-17 10:23:04 -0800 | [diff] [blame] | 29 | // All objects share the same Memstore. |
Robert Kroeger | d9c3488 | 2014-08-22 11:16:38 -0700 | [diff] [blame] | 30 | store *fs.Memstore |
Robin Thellend | 9bc8fcb | 2014-11-17 10:23:04 -0800 | [diff] [blame] | 31 | // storeRoot is a name in the directory under which all data will be |
| 32 | // stored. |
Adam Sadovsky | ffac12c | 2014-08-20 14:23:16 -0700 | [diff] [blame] | 33 | storeRoot string |
Robin Thellend | 9bc8fcb | 2014-11-17 10:23:04 -0800 | [diff] [blame] | 34 | // suffix is the name of the application object. |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 35 | suffix string |
| 36 | } |
| 37 | |
Todd Wang | 159f6ee | 2015-04-02 18:57:46 -0700 | [diff] [blame] | 38 | const pkgPath = "v.io/x/ref/services/application/applicationd/" |
Todd Wang | 34ed4c6 | 2014-11-26 15:15:52 -0800 | [diff] [blame] | 39 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 40 | var ( |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 41 | ErrInvalidSuffix = verror.Register(pkgPath+".InvalidSuffix", verror.NoRetry, "{1:}{2:} invalid suffix{:_}") |
| 42 | ErrOperationFailed = verror.Register(pkgPath+".OperationFailed", verror.NoRetry, "{1:}{2:} operation failed{:_}") |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 43 | ErrNotAuthorized = verror.Register(pkgPath+".errNotAuthorized", verror.NoRetry, "{1:}{2:} none of the client's blessings are valid {:_}") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 44 | ) |
| 45 | |
Robin Thellend | 9bc8fcb | 2014-11-17 10:23:04 -0800 | [diff] [blame] | 46 | // NewApplicationService returns a new Application service implementation. |
Bogdan Caprita | e96cd04 | 2015-02-03 17:32:57 -0800 | [diff] [blame] | 47 | func NewApplicationService(store *fs.Memstore, storeRoot, suffix string) repository.ApplicationServerMethods { |
Robin Thellend | 9bc8fcb | 2014-11-17 10:23:04 -0800 | [diff] [blame] | 48 | return &appRepoService{store: store, storeRoot: storeRoot, suffix: suffix} |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 49 | } |
| 50 | |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 51 | func parse(ctx *context.T, suffix string) (string, string, error) { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 52 | tokens := strings.Split(suffix, "/") |
| 53 | switch len(tokens) { |
| 54 | case 2: |
| 55 | return tokens[0], tokens[1], nil |
| 56 | case 1: |
| 57 | return tokens[0], "", nil |
| 58 | default: |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 59 | return "", "", verror.New(ErrInvalidSuffix, ctx) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 60 | } |
| 61 | } |
| 62 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 63 | func (i *appRepoService) Match(ctx *context.T, call rpc.ServerCall, profiles []string) (application.Envelope, error) { |
Cosmos Nicolaou | 1c33b7d | 2015-06-24 15:15:54 -0700 | [diff] [blame] | 64 | ctx.VI(0).Infof("%v.Match(%v)", i.suffix, profiles) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 65 | empty := application.Envelope{} |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 66 | name, version, err := parse(ctx, i.suffix) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 67 | if err != nil { |
| 68 | return empty, err |
| 69 | } |
Robert Kroeger | d9c3488 | 2014-08-22 11:16:38 -0700 | [diff] [blame] | 70 | |
| 71 | i.store.Lock() |
| 72 | defer i.store.Unlock() |
| 73 | |
Robert Kroeger | c66b387 | 2015-04-22 14:24:32 -0700 | [diff] [blame] | 74 | if version == "" { |
Robert Kroeger | 7894732 | 2015-06-24 14:12:17 -0700 | [diff] [blame] | 75 | versions, err := i.allAppVersionsForProfiles(name, profiles) |
Robert Kroeger | c66b387 | 2015-04-22 14:24:32 -0700 | [diff] [blame] | 76 | if err != nil { |
| 77 | return empty, err |
| 78 | } |
| 79 | if len(versions) < 1 { |
| 80 | return empty, verror.New(ErrInvalidSuffix, ctx) |
| 81 | } |
| 82 | sort.Strings(versions) |
| 83 | version = versions[len(versions)-1] |
| 84 | } |
| 85 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 86 | for _, profile := range profiles { |
Ken Ashcraft | 7ca37d9 | 2014-08-12 17:46:43 -0700 | [diff] [blame] | 87 | path := naming.Join("/applications", name, profile, version) |
Matt Rosencrantz | 9dce9b2 | 2015-03-02 10:48:37 -0800 | [diff] [blame] | 88 | entry, err := i.store.BindObject(path).Get(call) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 89 | if err != nil { |
| 90 | continue |
| 91 | } |
| 92 | envelope, ok := entry.Value.(application.Envelope) |
| 93 | if !ok { |
| 94 | continue |
| 95 | } |
| 96 | return envelope, nil |
| 97 | } |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 98 | return empty, verror.New(verror.ErrNoExist, ctx) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 99 | } |
| 100 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 101 | func (i *appRepoService) Put(ctx *context.T, call rpc.ServerCall, profiles []string, envelope application.Envelope) error { |
Cosmos Nicolaou | 1c33b7d | 2015-06-24 15:15:54 -0700 | [diff] [blame] | 102 | ctx.VI(0).Infof("%v.Put(%v, %v)", i.suffix, profiles, envelope) |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 103 | name, version, err := parse(ctx, i.suffix) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 104 | if err != nil { |
| 105 | return err |
| 106 | } |
| 107 | if version == "" { |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 108 | return verror.New(ErrInvalidSuffix, ctx) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 109 | } |
Robert Kroeger | d9c3488 | 2014-08-22 11:16:38 -0700 | [diff] [blame] | 110 | i.store.Lock() |
| 111 | defer i.store.Unlock() |
| 112 | // Transaction is rooted at "", so tname == tid. |
Matt Rosencrantz | 9dce9b2 | 2015-03-02 10:48:37 -0800 | [diff] [blame] | 113 | tname, err := i.store.BindTransactionRoot("").CreateTransaction(call) |
Robert Kroeger | d9c3488 | 2014-08-22 11:16:38 -0700 | [diff] [blame] | 114 | if err != nil { |
| 115 | return err |
| 116 | } |
| 117 | |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 118 | // Only add a Permissions value if there is not already one present. |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 119 | apath := naming.Join("/acls", name, "data") |
| 120 | aobj := i.store.BindObject(apath) |
| 121 | if _, err := aobj.Get(call); verror.ErrorID(err) == fs.ErrNotInMemStore.ID { |
Todd Wang | 4264e4b | 2015-04-16 22:43:40 -0700 | [diff] [blame] | 122 | rb, _ := security.RemoteBlessingNames(ctx, call.Security()) |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 123 | if len(rb) == 0 { |
| 124 | // None of the client's blessings are valid. |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 125 | return verror.New(ErrNotAuthorized, ctx) |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 126 | } |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 127 | newperms := pathperms.PermissionsForBlessings(rb) |
| 128 | if _, err := aobj.Put(nil, newperms); err != nil { |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 129 | return err |
| 130 | } |
| 131 | } |
| 132 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 133 | for _, profile := range profiles { |
Robert Kroeger | d9c3488 | 2014-08-22 11:16:38 -0700 | [diff] [blame] | 134 | path := naming.Join(tname, "/applications", name, profile, version) |
| 135 | |
| 136 | object := i.store.BindObject(path) |
Matt Rosencrantz | 9dce9b2 | 2015-03-02 10:48:37 -0800 | [diff] [blame] | 137 | _, err := object.Put(call, envelope) |
Robert Kroeger | d9c3488 | 2014-08-22 11:16:38 -0700 | [diff] [blame] | 138 | if err != nil { |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 139 | return verror.New(ErrOperationFailed, ctx) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 140 | } |
| 141 | } |
Matt Rosencrantz | 9dce9b2 | 2015-03-02 10:48:37 -0800 | [diff] [blame] | 142 | if err := i.store.BindTransaction(tname).Commit(call); err != nil { |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 143 | return verror.New(ErrOperationFailed, ctx) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 144 | } |
| 145 | return nil |
| 146 | } |
| 147 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 148 | func (i *appRepoService) Remove(ctx *context.T, call rpc.ServerCall, profile string) error { |
Cosmos Nicolaou | 1c33b7d | 2015-06-24 15:15:54 -0700 | [diff] [blame] | 149 | ctx.VI(0).Infof("%v.Remove(%v)", i.suffix, profile) |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 150 | name, version, err := parse(ctx, i.suffix) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 151 | if err != nil { |
| 152 | return err |
| 153 | } |
Robert Kroeger | d9c3488 | 2014-08-22 11:16:38 -0700 | [diff] [blame] | 154 | i.store.Lock() |
| 155 | defer i.store.Unlock() |
| 156 | // Transaction is rooted at "", so tname == tid. |
Matt Rosencrantz | 9dce9b2 | 2015-03-02 10:48:37 -0800 | [diff] [blame] | 157 | tname, err := i.store.BindTransactionRoot("").CreateTransaction(call) |
Robert Kroeger | d9c3488 | 2014-08-22 11:16:38 -0700 | [diff] [blame] | 158 | if err != nil { |
| 159 | return err |
| 160 | } |
| 161 | path := naming.Join(tname, "/applications", name, profile) |
| 162 | if version != "" { |
| 163 | path += "/" + version |
| 164 | } |
| 165 | object := i.store.BindObject(path) |
Matt Rosencrantz | 9dce9b2 | 2015-03-02 10:48:37 -0800 | [diff] [blame] | 166 | found, err := object.Exists(call) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 167 | if err != nil { |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 168 | return verror.New(ErrOperationFailed, ctx) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 169 | } |
| 170 | if !found { |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 171 | return verror.New(verror.ErrNoExist, ctx) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 172 | } |
Matt Rosencrantz | 9dce9b2 | 2015-03-02 10:48:37 -0800 | [diff] [blame] | 173 | if err := object.Remove(call); err != nil { |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 174 | return verror.New(ErrOperationFailed, ctx) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 175 | } |
Matt Rosencrantz | 9dce9b2 | 2015-03-02 10:48:37 -0800 | [diff] [blame] | 176 | if err := i.store.BindTransaction(tname).Commit(call); err != nil { |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 177 | return verror.New(ErrOperationFailed, ctx) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 178 | } |
| 179 | return nil |
| 180 | } |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 181 | |
Robin Thellend | 9bc8fcb | 2014-11-17 10:23:04 -0800 | [diff] [blame] | 182 | func (i *appRepoService) allApplications() ([]string, error) { |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 183 | apps, err := i.store.BindObject("/applications").Children() |
| 184 | if err != nil { |
| 185 | return nil, err |
| 186 | } |
| 187 | return apps, nil |
| 188 | } |
| 189 | |
Robert Kroeger | 7894732 | 2015-06-24 14:12:17 -0700 | [diff] [blame] | 190 | func (i *appRepoService) allAppVersionsForProfiles(appName string, profiles []string) ([]string, error) { |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 191 | uniqueVersions := make(map[string]struct{}) |
| 192 | for _, profile := range profiles { |
| 193 | versions, err := i.store.BindObject(naming.Join("/applications", appName, profile)).Children() |
Robert Kroeger | 7894732 | 2015-06-24 14:12:17 -0700 | [diff] [blame] | 194 | if verror.ErrorID(err) == verror.ErrNoExist.ID { |
| 195 | continue |
| 196 | } else if err != nil { |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 197 | return nil, err |
| 198 | } |
Jiri Simsa | 87d884d | 2015-06-18 10:25:54 -0700 | [diff] [blame] | 199 | set.String.Union(uniqueVersions, set.String.FromSlice(versions)) |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 200 | } |
Jiri Simsa | 87d884d | 2015-06-18 10:25:54 -0700 | [diff] [blame] | 201 | return set.String.ToSlice(uniqueVersions), nil |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 202 | } |
| 203 | |
Robert Kroeger | 7894732 | 2015-06-24 14:12:17 -0700 | [diff] [blame] | 204 | func (i *appRepoService) allAppVersions(appName string) ([]string, error) { |
| 205 | profiles, err := i.store.BindObject(naming.Join("/applications", appName)).Children() |
| 206 | if err != nil { |
| 207 | return nil, err |
| 208 | } |
| 209 | return i.allAppVersionsForProfiles(appName, profiles) |
| 210 | } |
| 211 | |
Robin Thellend | f15f295 | 2015-07-17 21:49:58 -0700 | [diff] [blame] | 212 | func (i *appRepoService) GlobChildren__(ctx *context.T, call rpc.GlobChildrenServerCall, m *glob.Element) error { |
Cosmos Nicolaou | 1c33b7d | 2015-06-24 15:15:54 -0700 | [diff] [blame] | 213 | ctx.VI(0).Infof("%v.GlobChildren__()", i.suffix) |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 214 | i.store.Lock() |
| 215 | defer i.store.Unlock() |
| 216 | |
| 217 | var elems []string |
| 218 | if i.suffix != "" { |
| 219 | elems = strings.Split(i.suffix, "/") |
| 220 | } |
| 221 | |
Robin Thellend | 8e9cc24 | 2014-11-26 09:43:10 -0800 | [diff] [blame] | 222 | var results []string |
| 223 | var err error |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 224 | switch len(elems) { |
| 225 | case 0: |
Robin Thellend | 8e9cc24 | 2014-11-26 09:43:10 -0800 | [diff] [blame] | 226 | results, err = i.allApplications() |
| 227 | if err != nil { |
Robin Thellend | f15f295 | 2015-07-17 21:49:58 -0700 | [diff] [blame] | 228 | return err |
Robin Thellend | 8e9cc24 | 2014-11-26 09:43:10 -0800 | [diff] [blame] | 229 | } |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 230 | case 1: |
Robin Thellend | 8e9cc24 | 2014-11-26 09:43:10 -0800 | [diff] [blame] | 231 | results, err = i.allAppVersions(elems[0]) |
| 232 | if err != nil { |
Robin Thellend | f15f295 | 2015-07-17 21:49:58 -0700 | [diff] [blame] | 233 | return err |
Robin Thellend | 8e9cc24 | 2014-11-26 09:43:10 -0800 | [diff] [blame] | 234 | } |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 235 | case 2: |
| 236 | versions, err := i.allAppVersions(elems[0]) |
| 237 | if err != nil { |
Robin Thellend | f15f295 | 2015-07-17 21:49:58 -0700 | [diff] [blame] | 238 | return err |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 239 | } |
| 240 | for _, v := range versions { |
| 241 | if v == elems[1] { |
Robin Thellend | f15f295 | 2015-07-17 21:49:58 -0700 | [diff] [blame] | 242 | return nil |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 243 | } |
| 244 | } |
Robin Thellend | f15f295 | 2015-07-17 21:49:58 -0700 | [diff] [blame] | 245 | return verror.New(verror.ErrNoExist, nil) |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 246 | default: |
Robin Thellend | f15f295 | 2015-07-17 21:49:58 -0700 | [diff] [blame] | 247 | return verror.New(verror.ErrNoExist, nil) |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 248 | } |
Robin Thellend | 8e9cc24 | 2014-11-26 09:43:10 -0800 | [diff] [blame] | 249 | |
Robin Thellend | 8e9cc24 | 2014-11-26 09:43:10 -0800 | [diff] [blame] | 250 | for _, r := range results { |
Robin Thellend | f15f295 | 2015-07-17 21:49:58 -0700 | [diff] [blame] | 251 | if m.Match(r) { |
Jiri Simsa | d9a7b3c | 2015-08-12 16:38:27 -0700 | [diff] [blame] | 252 | call.SendStream().Send(naming.GlobChildrenReplyName{Value: r}) |
Robin Thellend | f15f295 | 2015-07-17 21:49:58 -0700 | [diff] [blame] | 253 | } |
Robin Thellend | 8e9cc24 | 2014-11-26 09:43:10 -0800 | [diff] [blame] | 254 | } |
Robin Thellend | f15f295 | 2015-07-17 21:49:58 -0700 | [diff] [blame] | 255 | return nil |
Robin Thellend | 0155a37 | 2014-11-11 17:30:11 -0800 | [diff] [blame] | 256 | } |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 257 | |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 258 | func (i *appRepoService) GetPermissions(ctx *context.T, call rpc.ServerCall) (perms access.Permissions, version string, err error) { |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 259 | name, _, err := parse(ctx, i.suffix) |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 260 | if err != nil { |
| 261 | return nil, "", err |
| 262 | } |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 263 | i.store.Lock() |
| 264 | defer i.store.Unlock() |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 265 | path := naming.Join("/acls", name, "data") |
| 266 | |
Cosmos Nicolaou | 1c33b7d | 2015-06-24 15:15:54 -0700 | [diff] [blame] | 267 | perms, version, err = getPermissions(ctx, i.store, path) |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 268 | if verror.ErrorID(err) == verror.ErrNoExist.ID { |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 269 | return pathperms.NilAuthPermissions(ctx, call.Security()), "", nil |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 270 | } |
| 271 | |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 272 | return perms, version, err |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 273 | } |
| 274 | |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 275 | func (i *appRepoService) SetPermissions(ctx *context.T, _ rpc.ServerCall, perms access.Permissions, version string) error { |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 276 | name, _, err := parse(ctx, i.suffix) |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 277 | if err != nil { |
| 278 | return err |
| 279 | } |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 280 | i.store.Lock() |
| 281 | defer i.store.Unlock() |
Robert Kroeger | f9536ac | 2015-04-03 16:30:44 -0700 | [diff] [blame] | 282 | path := naming.Join("/acls", name, "data") |
Cosmos Nicolaou | 1c33b7d | 2015-06-24 15:15:54 -0700 | [diff] [blame] | 283 | return setPermissions(ctx, i.store, path, perms, version) |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 284 | } |
| 285 | |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 286 | // getPermissions fetches a Permissions out of the Memstore at the provided path. |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 287 | // path is expected to already have been cleaned by naming.Join or its ilk. |
Cosmos Nicolaou | 1c33b7d | 2015-06-24 15:15:54 -0700 | [diff] [blame] | 288 | func getPermissions(ctx *context.T, store *fs.Memstore, path string) (access.Permissions, string, error) { |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 289 | entry, err := store.BindObject(path).Get(nil) |
| 290 | |
Todd Wang | 8fa3876 | 2015-03-25 14:04:59 -0700 | [diff] [blame] | 291 | if verror.ErrorID(err) == fs.ErrNotInMemStore.ID { |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 292 | // No Permissions exists |
Todd Wang | 4ac9e65 | 2015-03-27 14:50:47 -0700 | [diff] [blame] | 293 | return nil, "", verror.New(verror.ErrNoExist, nil) |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 294 | } else if err != nil { |
Cosmos Nicolaou | 1c33b7d | 2015-06-24 15:15:54 -0700 | [diff] [blame] | 295 | ctx.Errorf("getPermissions: internal failure in fs.Memstore") |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 296 | return nil, "", err |
| 297 | } |
| 298 | |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 299 | perms, ok := entry.Value.(access.Permissions) |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 300 | if !ok { |
| 301 | return nil, "", err |
| 302 | } |
| 303 | |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 304 | version, err := pathperms.ComputeVersion(perms) |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 305 | if err != nil { |
| 306 | return nil, "", err |
| 307 | } |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 308 | return perms, version, nil |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 309 | } |
| 310 | |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 311 | // setPermissions writes a Permissions into the Memstore at the provided path. |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 312 | // where path is expected to have already been cleaned by naming.Join. |
Cosmos Nicolaou | 1c33b7d | 2015-06-24 15:15:54 -0700 | [diff] [blame] | 313 | func setPermissions(ctx *context.T, store *fs.Memstore, path string, perms access.Permissions, version string) error { |
Robin Thellend | 4da2d8f | 2015-04-16 17:28:45 -0700 | [diff] [blame] | 314 | if version != "" { |
Cosmos Nicolaou | 1c33b7d | 2015-06-24 15:15:54 -0700 | [diff] [blame] | 315 | _, oversion, err := getPermissions(ctx, store, path) |
Robin Thellend | 4da2d8f | 2015-04-16 17:28:45 -0700 | [diff] [blame] | 316 | if verror.ErrorID(err) == verror.ErrNoExist.ID { |
| 317 | oversion = version |
| 318 | } else if err != nil { |
| 319 | return err |
| 320 | } |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 321 | |
Robin Thellend | 4da2d8f | 2015-04-16 17:28:45 -0700 | [diff] [blame] | 322 | if oversion != version { |
| 323 | return verror.NewErrBadVersion(nil) |
| 324 | } |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 325 | } |
| 326 | |
| 327 | tname, err := store.BindTransactionRoot("").CreateTransaction(nil) |
| 328 | if err != nil { |
| 329 | return err |
| 330 | } |
| 331 | |
| 332 | object := store.BindObject(path) |
| 333 | |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 334 | if _, err := object.Put(nil, perms); err != nil { |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 335 | return err |
| 336 | } |
| 337 | if err := store.BindTransaction(tname).Commit(nil); err != nil { |
Todd Wang | ff73e1f | 2015-02-10 21:45:52 -0800 | [diff] [blame] | 338 | return verror.New(ErrOperationFailed, nil) |
Robert Kroeger | d6e1d1a | 2014-12-10 15:08:45 -0800 | [diff] [blame] | 339 | } |
| 340 | return nil |
| 341 | } |
Robert Kroeger | 3cd5ed5 | 2015-06-23 14:44:47 -0700 | [diff] [blame] | 342 | |
Robert Kroeger | 7894732 | 2015-06-24 14:12:17 -0700 | [diff] [blame] | 343 | func (i *appRepoService) tidyRemoveVersions(call rpc.ServerCall, tname, appName, profile string, versions []string) error { |
| 344 | for _, v := range versions { |
| 345 | path := naming.Join(tname, "/applications", appName, profile, v) |
| 346 | object := i.store.BindObject(path) |
| 347 | if err := object.Remove(call); err != nil { |
| 348 | return err |
| 349 | } |
| 350 | } |
| 351 | return nil |
| 352 | } |
| 353 | |
| 354 | // numberOfVersionsToKeep can be set for tests. |
| 355 | var numberOfVersionsToKeep = 5 |
| 356 | |
Robert Kroeger | 3cd5ed5 | 2015-06-23 14:44:47 -0700 | [diff] [blame] | 357 | func (i *appRepoService) TidyNow(ctx *context.T, call rpc.ServerCall) error { |
Robert Kroeger | 7894732 | 2015-06-24 14:12:17 -0700 | [diff] [blame] | 358 | ctx.VI(2).Infof("%v.TidyNow()", i.suffix) |
| 359 | i.store.Lock() |
| 360 | defer i.store.Unlock() |
| 361 | |
| 362 | tname, err := i.store.BindTransactionRoot("").CreateTransaction(call) |
| 363 | if err != nil { |
| 364 | return err |
| 365 | } |
| 366 | |
| 367 | apps, err := i.allApplications() |
| 368 | if err != nil { |
| 369 | return err |
| 370 | } |
| 371 | |
| 372 | for _, app := range apps { |
| 373 | profiles, err := i.store.BindObject(naming.Join("/applications", app)).Children() |
| 374 | if err != nil { |
| 375 | return err |
| 376 | } |
| 377 | |
| 378 | for _, profile := range profiles { |
| 379 | versions, err := i.store.BindObject(naming.Join("/applications", app, profile)).Children() |
| 380 | if err != nil { |
| 381 | return err |
| 382 | } |
| 383 | |
| 384 | lv := len(versions) |
| 385 | if lv <= numberOfVersionsToKeep { |
| 386 | continue |
| 387 | } |
| 388 | |
| 389 | // Per assumption in Match, version names should ascend. |
| 390 | sort.Strings(versions) |
| 391 | versionsToRemove := versions[0 : lv-numberOfVersionsToKeep] |
| 392 | if err := i.tidyRemoveVersions(call, tname, app, profile, versionsToRemove); err != nil { |
| 393 | return err |
| 394 | } |
| 395 | } |
| 396 | } |
| 397 | |
| 398 | if err := i.store.BindTransaction(tname).Commit(call); err != nil { |
| 399 | return verror.New(ErrOperationFailed, ctx) |
| 400 | } |
| 401 | return nil |
| 402 | |
Robert Kroeger | 3cd5ed5 | 2015-06-23 14:44:47 -0700 | [diff] [blame] | 403 | } |