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 | |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 5 | // Package starter provides a single function that starts up servers for a |
| 6 | // mounttable and a device manager that is mounted on it. |
| 7 | package starter |
| 8 | |
| 9 | import ( |
gauthamt | 1c6e04b | 2015-02-19 16:09:47 -0800 | [diff] [blame] | 10 | "encoding/base64" |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 11 | "net" |
Bogdan Caprita | 4e66324 | 2015-02-15 15:23:14 -0800 | [diff] [blame] | 12 | "os" |
| 13 | "path/filepath" |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 14 | "strconv" |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 15 | "time" |
| 16 | |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 17 | "v.io/v23" |
| 18 | "v.io/v23/context" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 19 | "v.io/v23/naming" |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 20 | "v.io/v23/rpc" |
Asim Shankar | 99b18a7 | 2015-04-25 23:19:28 -0700 | [diff] [blame] | 21 | "v.io/v23/security" |
Mike Burrows | 39bbaaf | 2015-03-24 11:27:32 -0700 | [diff] [blame] | 22 | "v.io/v23/verror" |
Matt Rosencrantz | e4a49f4 | 2015-09-03 17:08:51 -0700 | [diff] [blame] | 23 | displib "v.io/x/ref/lib/dispatcher" |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 24 | "v.io/x/ref/runtime/factories/roaming" |
| 25 | "v.io/x/ref/services/debug/debuglib" |
Bogdan Caprita | 1bba736 | 2015-06-30 14:03:17 -0700 | [diff] [blame] | 26 | "v.io/x/ref/services/device/deviced/internal/impl" |
Bogdan Caprita | 226d88e | 2015-06-30 17:34:57 -0700 | [diff] [blame] | 27 | "v.io/x/ref/services/device/deviced/internal/versioning" |
Robin Thellend | b01356d | 2015-08-18 10:23:14 -0700 | [diff] [blame] | 28 | "v.io/x/ref/services/device/internal/claim" |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 29 | "v.io/x/ref/services/device/internal/config" |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 30 | "v.io/x/ref/services/internal/pathperms" |
| 31 | "v.io/x/ref/services/mounttable/mounttablelib" |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 32 | ) |
| 33 | |
Bogdan Caprita | 1bba736 | 2015-06-30 14:03:17 -0700 | [diff] [blame] | 34 | const pkgPath = "v.io/x/ref/services/device/deviced/internal/starter" |
Mike Burrows | 39bbaaf | 2015-03-24 11:27:32 -0700 | [diff] [blame] | 35 | |
| 36 | var ( |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 37 | errCantSaveInfo = verror.Register(pkgPath+".errCantSaveInfo", verror.NoRetry, "{1:}{2:} failed to save info{:_}") |
| 38 | errBadPort = verror.Register(pkgPath+".errBadPort", verror.NoRetry, "{1:}{2:} invalid port{:_}") |
| 39 | errCantCreateProxy = verror.Register(pkgPath+".errCantCreateProxy", verror.NoRetry, "{1:}{2:} Failed to create proxy{:_}") |
| 40 | errNoEndpointToClaim = verror.Register(pkgPath+".errNoEndpointToClaim", verror.NoRetry, "{1:}{2:} failed to find an endpoint for claiming{:_}") |
Mike Burrows | 39bbaaf | 2015-03-24 11:27:32 -0700 | [diff] [blame] | 41 | ) |
| 42 | |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 43 | type NamespaceArgs struct { |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 44 | Name string // Name to publish the mounttable service under (after claiming). |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 45 | ListenSpec rpc.ListenSpec // ListenSpec for the server. |
| 46 | PermissionsFile string // Path to the Permissions file used by the mounttable. |
David Why Use Two When One Will Do Presotto | ba9593f | 2015-04-22 12:29:26 -0700 | [diff] [blame] | 47 | PersistenceDir string // Path to the directory holding persistent acls. |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 48 | // Name in the local neighborhood on which to make the mounttable |
| 49 | // visible. If empty, the mounttable will not be visible in the local |
| 50 | // neighborhood. |
| 51 | Neighborhood string |
| 52 | } |
| 53 | |
| 54 | type DeviceArgs struct { |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 55 | Name string // Name to publish the device service under (after claiming). |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 56 | ListenSpec rpc.ListenSpec // ListenSpec for the device server. |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 57 | ConfigState *config.State // Configuration for the device. |
| 58 | TestMode bool // Whether the device is running in test mode or not. |
| 59 | RestartCallback func() // Callback invoked when the device service is restarted. |
gauthamt | 27f38ba | 2015-02-13 13:45:01 -0800 | [diff] [blame] | 60 | PairingToken string // PairingToken that a claimer needs to provide. |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 61 | } |
| 62 | |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 63 | func (d *DeviceArgs) name(mt string) string { |
| 64 | if d.Name != "" { |
| 65 | return d.Name |
| 66 | } |
| 67 | return naming.Join(mt, "devmgr") |
| 68 | } |
| 69 | |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 70 | type ProxyArgs struct { |
| 71 | Port int |
| 72 | } |
| 73 | |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 74 | type Args struct { |
| 75 | Namespace NamespaceArgs |
| 76 | Device DeviceArgs |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 77 | Proxy ProxyArgs |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 78 | |
| 79 | // If true, the global namespace will be made available on the |
| 80 | // mounttable server under "global/". |
| 81 | MountGlobalNamespaceInLocalNamespace bool |
| 82 | } |
| 83 | |
| 84 | // Start creates servers for the mounttable and device services and links them together. |
| 85 | // |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 86 | // Returns the object name for the claimable service (empty if already claimed), |
| 87 | // a callback to be invoked to shutdown the services on success, or an error on |
| 88 | // failure. |
| 89 | func Start(ctx *context.T, args Args) (string, func(), error) { |
Arup Mukherjee | 31b77c8 | 2015-03-04 10:48:33 -0800 | [diff] [blame] | 90 | // Is this binary compatible with the state on disk? |
Bogdan Caprita | 226d88e | 2015-06-30 17:34:57 -0700 | [diff] [blame] | 91 | if err := versioning.CheckCompatibility(ctx, args.Device.ConfigState.Root); err != nil { |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 92 | return "", nil, err |
Arup Mukherjee | 31b77c8 | 2015-03-04 10:48:33 -0800 | [diff] [blame] | 93 | } |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 94 | // In test mode, we skip writing the info file to disk, and we skip |
| 95 | // attempting to start the claimable service: the device must have been |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 96 | // claimed already to enable updates anyway, and checking for perms in |
| 97 | // NewClaimableDispatcher needlessly prints a perms signature |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 98 | // verification error to the logs. |
| 99 | if args.Device.TestMode { |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 100 | cleanup, err := startClaimedDevice(ctx, args) |
| 101 | return "", cleanup, err |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 102 | } |
Arup Mukherjee | 31b77c8 | 2015-03-04 10:48:33 -0800 | [diff] [blame] | 103 | |
Bogdan Caprita | 4e66324 | 2015-02-15 15:23:14 -0800 | [diff] [blame] | 104 | // TODO(caprita): use some mechanism (a file lock or presence of entry |
| 105 | // in mounttable) to ensure only one device manager is running in an |
| 106 | // installation? |
| 107 | mi := &impl.ManagerInfo{ |
| 108 | Pid: os.Getpid(), |
| 109 | } |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 110 | if err := impl.SaveManagerInfo(filepath.Join(args.Device.ConfigState.Root, "device-manager"), mi); err != nil { |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 111 | return "", nil, verror.New(errCantSaveInfo, ctx, err) |
Bogdan Caprita | 4e66324 | 2015-02-15 15:23:14 -0800 | [diff] [blame] | 112 | } |
| 113 | |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 114 | // If the device has not yet been claimed, start the mounttable and |
| 115 | // claimable service and wait for it to be claimed. |
| 116 | // Once a device is claimed, close any previously running servers and |
| 117 | // start a new mounttable and device service. |
Robin Thellend | b01356d | 2015-08-18 10:23:14 -0700 | [diff] [blame] | 118 | claimable, claimed := claim.NewClaimableDispatcher(ctx, impl.PermsDir(args.Device.ConfigState), args.Device.PairingToken, security.AllowEveryone()) |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 119 | if claimable == nil { |
| 120 | // Device has already been claimed, bypass claimable service |
| 121 | // stage. |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 122 | cleanup, err := startClaimedDevice(ctx, args) |
| 123 | return "", cleanup, err |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 124 | } |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 125 | epName, stopClaimable, err := startClaimableDevice(ctx, claimable, args) |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 126 | if err != nil { |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 127 | return "", nil, err |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 128 | } |
| 129 | stop := make(chan struct{}) |
| 130 | stopped := make(chan struct{}) |
| 131 | go waitToBeClaimedAndStartClaimedDevice(ctx, stopClaimable, claimed, stop, stopped, args) |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 132 | return epName, func() { |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 133 | close(stop) |
| 134 | <-stopped |
| 135 | }, nil |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 136 | } |
| 137 | |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 138 | func startClaimableDevice(ctx *context.T, dispatcher rpc.Dispatcher, args Args) (string, func(), error) { |
Bogdan Caprita | 9032e74 | 2015-02-27 15:10:25 -0800 | [diff] [blame] | 139 | // TODO(caprita,ashankar): We create a context with a new stream manager |
| 140 | // that we can cancel once the device has been claimed. This gets around |
| 141 | // the following issue: if we publish the claimable server to the local |
| 142 | // mounttable, and then (following claim) we restart the mounttable |
| 143 | // server on the same port, we fail to publish the device service to the |
| 144 | // (new) mounttable server (Mount fails with "VC handshake failed: |
| 145 | // remote end closed VC(VCs not accepted)". Presumably, something to do |
| 146 | // with caching connections (following the claim, the mounttable comes |
| 147 | // back on the same port as before, and the client-side of the mount |
| 148 | // gets confused trying to reuse the old connection and doesn't attempt |
| 149 | // to create a new connection). We should get to the bottom of it. |
Bogdan Caprita | fa9341a | 2015-02-16 21:42:00 -0800 | [diff] [blame] | 150 | ctx, cancel := context.WithCancel(ctx) |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 151 | var err error |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 152 | if ctx, err = v23.WithNewStreamManager(ctx); err != nil { |
Bogdan Caprita | 9032e74 | 2015-02-27 15:10:25 -0800 | [diff] [blame] | 153 | cancel() |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 154 | return "", nil, err |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 155 | } |
Matt Rosencrantz | a9fb36d | 2015-06-22 11:44:37 -0700 | [diff] [blame] | 156 | ctx = v23.WithListenSpec(ctx, args.Device.ListenSpec) |
Matt Rosencrantz | 53ac585 | 2015-09-04 15:14:54 -0700 | [diff] [blame] | 157 | ctx, server, err := v23.WithNewDispatchingServer(ctx, "", dispatcher) |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 158 | if err != nil { |
Bogdan Caprita | fa9341a | 2015-02-16 21:42:00 -0800 | [diff] [blame] | 159 | cancel() |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 160 | return "", nil, err |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 161 | } |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 162 | shutdown := func() { |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 163 | ctx.Infof("Stopping claimable server...") |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 164 | server.Stop() |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 165 | ctx.Infof("Stopped claimable server.") |
Bogdan Caprita | fa9341a | 2015-02-16 21:42:00 -0800 | [diff] [blame] | 166 | cancel() |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 167 | } |
Matt Rosencrantz | bb6295d | 2015-06-19 15:13:58 -0700 | [diff] [blame] | 168 | endpoints := server.Status().Endpoints |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 169 | publicKey, err := v23.GetPrincipal(ctx).PublicKey().MarshalBinary() |
gauthamt | 1c6e04b | 2015-02-19 16:09:47 -0800 | [diff] [blame] | 170 | if err != nil { |
| 171 | shutdown() |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 172 | return "", nil, err |
gauthamt | 1c6e04b | 2015-02-19 16:09:47 -0800 | [diff] [blame] | 173 | } |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 174 | var epName string |
Robin Thellend | 1ec18e2 | 2015-04-09 11:11:14 -0700 | [diff] [blame] | 175 | if args.Device.ListenSpec.Proxy != "" { |
Suharsh Sivakumar | c1d9e04 | 2015-09-17 13:13:27 -0700 | [diff] [blame] | 176 | if os.Getenv("V23_RPC_TRANSITION_STATE") == "xservers" { |
| 177 | for { |
| 178 | eps := server.Status().Endpoints |
| 179 | if len(eps) > 0 && len(eps[0].Addr().Network()) > 0 { |
| 180 | epName = eps[0].Name() |
| 181 | ctx.Infof("Proxied address: %s", epName) |
| 182 | break |
| 183 | } |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 184 | ctx.Infof("Waiting for proxy address to appear...") |
Robin Thellend | 1ec18e2 | 2015-04-09 11:11:14 -0700 | [diff] [blame] | 185 | time.Sleep(time.Second) |
Robin Thellend | 1ec18e2 | 2015-04-09 11:11:14 -0700 | [diff] [blame] | 186 | } |
Suharsh Sivakumar | c1d9e04 | 2015-09-17 13:13:27 -0700 | [diff] [blame] | 187 | } else { |
| 188 | // TODO(suharshs): Remove this else block once the transition is complete. |
| 189 | for { |
| 190 | p := server.Status().Proxies |
| 191 | if len(p) == 0 { |
| 192 | ctx.Infof("Waiting for proxy address to appear...") |
| 193 | time.Sleep(time.Second) |
| 194 | continue |
| 195 | } |
| 196 | epName = p[0].Endpoint.Name() |
| 197 | ctx.Infof("Proxied address: %s", epName) |
| 198 | break |
| 199 | } |
Robin Thellend | 1ec18e2 | 2015-04-09 11:11:14 -0700 | [diff] [blame] | 200 | } |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 201 | } else { |
| 202 | if len(endpoints) == 0 { |
| 203 | return "", nil, verror.New(errNoEndpointToClaim, ctx, err) |
| 204 | } |
| 205 | epName = endpoints[0].Name() |
Robin Thellend | 1ec18e2 | 2015-04-09 11:11:14 -0700 | [diff] [blame] | 206 | } |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 207 | ctx.Infof("Unclaimed device manager (%v) with public_key: %s", epName, base64.URLEncoding.EncodeToString(publicKey)) |
| 208 | ctx.FlushLog() |
Bogdan Caprita | e807368 | 2015-04-25 15:37:53 -0700 | [diff] [blame] | 209 | return epName, shutdown, nil |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 210 | } |
| 211 | |
| 212 | func waitToBeClaimedAndStartClaimedDevice(ctx *context.T, stopClaimable func(), claimed, stop <-chan struct{}, stopped chan<- struct{}, args Args) { |
| 213 | // Wait for either the claimable service to complete, or be stopped |
| 214 | defer close(stopped) |
| 215 | select { |
| 216 | case <-claimed: |
| 217 | stopClaimable() |
| 218 | case <-stop: |
| 219 | stopClaimable() |
| 220 | return |
| 221 | } |
| 222 | shutdown, err := startClaimedDevice(ctx, args) |
| 223 | if err != nil { |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 224 | ctx.Errorf("Failed to start device service after it was claimed: %v", err) |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 225 | v23.GetAppCycle(ctx).Stop(ctx) |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 226 | return |
| 227 | } |
| 228 | defer shutdown() |
| 229 | <-stop // Wait to be stopped |
| 230 | } |
| 231 | |
| 232 | func startClaimedDevice(ctx *context.T, args Args) (func(), error) { |
Bogdan Caprita | f18888c | 2015-08-12 09:53:31 -0700 | [diff] [blame] | 233 | ctx.Infof("Starting claimed device services...") |
Cosmos Nicolaou | 7a4221f | 2015-06-21 08:02:23 -0700 | [diff] [blame] | 234 | permStore := pathperms.NewPathStore(ctx) |
Bogdan Caprita | e90bcfd | 2015-08-07 13:31:55 -0700 | [diff] [blame] | 235 | permsDir := impl.PermsDir(args.Device.ConfigState) |
| 236 | debugAuth, err := pathperms.NewHierarchicalAuthorizer(permsDir, permsDir, permStore, nil) |
Robert Kroeger | 3bbf3c7 | 2015-03-25 13:04:55 -0700 | [diff] [blame] | 237 | if err != nil { |
| 238 | return nil, err |
| 239 | } |
| 240 | |
Cosmos Nicolaou | 64d573d | 2015-07-13 16:22:18 -0700 | [diff] [blame] | 241 | debugDisp := debuglib.NewDispatcher(debugAuth) |
Robert Kroeger | 3bbf3c7 | 2015-03-25 13:04:55 -0700 | [diff] [blame] | 242 | |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 243 | ctx = v23.WithReservedNameDispatcher(ctx, debugDisp) |
Robert Kroeger | 3bbf3c7 | 2015-03-25 13:04:55 -0700 | [diff] [blame] | 244 | |
Bogdan Caprita | f18888c | 2015-08-12 09:53:31 -0700 | [diff] [blame] | 245 | ctx.Infof("Starting mount table...") |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 246 | mtName, stopMT, err := startMounttable(ctx, args.Namespace) |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 247 | if err != nil { |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 248 | ctx.Errorf("Failed to start mounttable service: %v", err) |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 249 | return nil, err |
Bogdan Caprita | f18888c | 2015-08-12 09:53:31 -0700 | [diff] [blame] | 250 | } else { |
| 251 | ctx.Infof("Started mount table.") |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 252 | } |
Todd Wang | cd4b3cc | 2015-04-06 16:42:02 -0700 | [diff] [blame] | 253 | // TODO(caprita): We link in a proxy server into the device manager so that we |
| 254 | // can bootstrap with install-local before we can install an actual proxy app. |
| 255 | // Once support is added to the RPC layer to allow install-local to serve on |
| 256 | // the same connection it established to the device manager (see TODO in |
| 257 | // v.io/x/ref/services/device/device/local_install.go), we can get rid of this |
| 258 | // local proxy altogether. |
Bogdan Caprita | f18888c | 2015-08-12 09:53:31 -0700 | [diff] [blame] | 259 | ctx.Infof("Starting proxy service...") |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 260 | stopProxy, err := startProxyServer(ctx, args.Proxy, mtName) |
| 261 | if err != nil { |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 262 | ctx.Errorf("Failed to start proxy service: %v", err) |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 263 | stopMT() |
| 264 | return nil, err |
Bogdan Caprita | f18888c | 2015-08-12 09:53:31 -0700 | [diff] [blame] | 265 | } else { |
| 266 | ctx.Infof("Started proxy service.") |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 267 | } |
Bogdan Caprita | f18888c | 2015-08-12 09:53:31 -0700 | [diff] [blame] | 268 | ctx.Infof("Starting device service...") |
Robert Kroeger | 3bbf3c7 | 2015-03-25 13:04:55 -0700 | [diff] [blame] | 269 | stopDevice, err := startDeviceServer(ctx, args.Device, mtName, permStore) |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 270 | if err != nil { |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 271 | ctx.Errorf("Failed to start device service: %v", err) |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 272 | stopProxy() |
| 273 | stopMT() |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 274 | return nil, err |
Bogdan Caprita | f18888c | 2015-08-12 09:53:31 -0700 | [diff] [blame] | 275 | } else { |
| 276 | ctx.Infof("Started device service.") |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 277 | } |
| 278 | if args.MountGlobalNamespaceInLocalNamespace { |
Bogdan Caprita | f18888c | 2015-08-12 09:53:31 -0700 | [diff] [blame] | 279 | ctx.Infof("Mounting %v ...", mtName) |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 280 | mountGlobalNamespaceInLocalNamespace(ctx, mtName) |
Bogdan Caprita | f18888c | 2015-08-12 09:53:31 -0700 | [diff] [blame] | 281 | ctx.Infof("Mounted %v", mtName) |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 282 | } |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 283 | |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 284 | impl.InvokeCallback(ctx, args.Device.ConfigState.Name) |
| 285 | |
Bogdan Caprita | f18888c | 2015-08-12 09:53:31 -0700 | [diff] [blame] | 286 | ctx.Infof("Started claimed device services.") |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 287 | return func() { |
| 288 | stopDevice() |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 289 | stopProxy() |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 290 | stopMT() |
| 291 | }, nil |
| 292 | } |
| 293 | |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 294 | func startProxyServer(ctx *context.T, p ProxyArgs, localMT string) (func(), error) { |
| 295 | switch port := p.Port; { |
| 296 | case port == 0: |
| 297 | return func() {}, nil |
| 298 | case port < 0: |
Mike Burrows | 39bbaaf | 2015-03-24 11:27:32 -0700 | [diff] [blame] | 299 | return nil, verror.New(errBadPort, ctx, port) |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 300 | } |
| 301 | port := strconv.Itoa(p.Port) |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 302 | protocol, addr := "tcp", net.JoinHostPort("", port) |
| 303 | // Attempt to get a publicly accessible address for the proxy to publish |
| 304 | // under. |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 305 | ls := v23.GetListenSpec(ctx) |
Cosmos Nicolaou | aa87e29 | 2015-04-21 22:15:50 -0700 | [diff] [blame] | 306 | ls.Addrs = rpc.ListenAddrs{{protocol, addr}} |
Asim Shankar | 99b18a7 | 2015-04-25 23:19:28 -0700 | [diff] [blame] | 307 | // TODO(ashankar): Revisit this choice of security.AllowEveryone |
| 308 | // See: https://v.io/i/387 |
| 309 | shutdown, ep, err := roaming.NewProxy(ctx, ls, security.AllowEveryone()) |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 310 | if err != nil { |
Mike Burrows | 39bbaaf | 2015-03-24 11:27:32 -0700 | [diff] [blame] | 311 | return nil, verror.New(errCantCreateProxy, ctx, err) |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 312 | } |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 313 | ctx.Infof("Local proxy (%v)", ep.Name()) |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 314 | return func() { |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 315 | ctx.Infof("Stopping proxy...") |
Matt Rosencrantz | 2b675f9 | 2015-03-05 12:52:50 -0800 | [diff] [blame] | 316 | shutdown() |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 317 | ctx.Infof("Stopped proxy.") |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 318 | }, nil |
Bogdan Caprita | 2250a3c | 2015-02-19 21:50:13 -0800 | [diff] [blame] | 319 | } |
| 320 | |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 321 | func startMounttable(ctx *context.T, n NamespaceArgs) (string, func(), error) { |
David Why Use Two When One Will Do Presotto | ba9593f | 2015-04-22 12:29:26 -0700 | [diff] [blame] | 322 | mtName, stopMT, err := mounttablelib.StartServers(ctx, n.ListenSpec, n.Name, n.Neighborhood, n.PermissionsFile, n.PersistenceDir, "mounttable") |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 323 | if err != nil { |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 324 | ctx.Errorf("mounttablelib.StartServers(%#v) failed: %v", n, err) |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 325 | } else { |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 326 | ctx.Infof("Local mounttable (%v) published as %q", mtName, n.Name) |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 327 | } |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 328 | return mtName, func() { |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 329 | ctx.Infof("Stopping mounttable...") |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 330 | stopMT() |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 331 | ctx.Infof("Stopped mounttable.") |
Bogdan Caprita | 394af41 | 2015-03-04 16:45:13 -0800 | [diff] [blame] | 332 | }, err |
Asim Shankar | 23dac32 | 2015-02-14 12:42:26 -0800 | [diff] [blame] | 333 | } |
| 334 | |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 335 | // startDeviceServer creates an rpc.Server and sets it up to server the Device service. |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 336 | // |
| 337 | // ls: ListenSpec for the server |
| 338 | // configState: configuration for the Device service dispatcher |
| 339 | // mt: Object address of the mounttable |
| 340 | // dm: Name to publish the device service under |
| 341 | // testMode: whether the service is to be run in test mode |
| 342 | // restarted: callback invoked when the device manager is restarted. |
| 343 | // |
| 344 | // Returns: |
| 345 | // (1) Function to be called to force the service to shutdown |
| 346 | // (2) Any errors in starting the service (in which case, (1) will be nil) |
Adam Sadovsky | a4d4a69 | 2015-04-20 11:36:49 -0700 | [diff] [blame] | 347 | func startDeviceServer(ctx *context.T, args DeviceArgs, mt string, permStore *pathperms.PathStore) (shutdown func(), err error) { |
Matt Rosencrantz | e4a49f4 | 2015-09-03 17:08:51 -0700 | [diff] [blame] | 348 | ctx = v23.WithListenSpec(ctx, args.ListenSpec) |
| 349 | wrapper := displib.NewDispatcherWrapper() |
Matt Rosencrantz | 53ac585 | 2015-09-04 15:14:54 -0700 | [diff] [blame] | 350 | ctx, server, err := v23.WithNewDispatchingServer(ctx, args.name(mt), wrapper) |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 351 | if err != nil { |
| 352 | return nil, err |
| 353 | } |
Matt Rosencrantz | e4a49f4 | 2015-09-03 17:08:51 -0700 | [diff] [blame] | 354 | args.ConfigState.Name = server.Status().Endpoints[0].Name() |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 355 | |
Bogdan Caprita | 24404f2 | 2015-06-30 18:56:33 -0700 | [diff] [blame] | 356 | dispatcher, dShutdown, err := impl.NewDispatcher(ctx, args.ConfigState, mt, args.TestMode, args.RestartCallback, permStore) |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 357 | if err != nil { |
Matt Rosencrantz | e4a49f4 | 2015-09-03 17:08:51 -0700 | [diff] [blame] | 358 | server.Stop() |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 359 | return nil, err |
| 360 | } |
| 361 | |
| 362 | shutdown = func() { |
Bogdan Caprita | 019f0ad | 2015-05-21 10:45:10 -0700 | [diff] [blame] | 363 | // TODO(caprita): Capture the Dying state by feeding it back to |
| 364 | // the dispatcher and exposing it in Status. |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 365 | ctx.Infof("Stopping device server...") |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 366 | server.Stop() |
Bogdan Caprita | 24404f2 | 2015-06-30 18:56:33 -0700 | [diff] [blame] | 367 | dShutdown() |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 368 | ctx.Infof("Stopped device.") |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 369 | } |
Matt Rosencrantz | e4a49f4 | 2015-09-03 17:08:51 -0700 | [diff] [blame] | 370 | wrapper.SetDispatcher(dispatcher) |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 371 | ctx.Infof("Device manager (%v) published as %v", args.ConfigState.Name, args.name(mt)) |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 372 | return shutdown, nil |
| 373 | } |
| 374 | |
| 375 | func mountGlobalNamespaceInLocalNamespace(ctx *context.T, localMT string) { |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 376 | ns := v23.GetNamespace(ctx) |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 377 | for _, root := range ns.Roots() { |
| 378 | go func(r string) { |
| 379 | for { |
David Why Use Two When One Will Do Presotto | 38788d4 | 2015-03-31 17:13:54 -0700 | [diff] [blame] | 380 | err := ns.Mount(ctx, naming.Join(localMT, "global"), r, 0 /* forever */, naming.ServesMountTable(true)) |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 381 | if err == nil { |
| 382 | break |
| 383 | } |
Cosmos Nicolaou | 1848973 | 2015-06-29 16:01:38 -0700 | [diff] [blame] | 384 | ctx.Infof("Failed to Mount global namespace: %v", err) |
Asim Shankar | ab75bc3 | 2015-02-12 21:52:04 -0800 | [diff] [blame] | 385 | time.Sleep(time.Second) |
| 386 | } |
| 387 | }(root) |
| 388 | } |
| 389 | } |