blob: 89bfdd1f0ff90914165830204149a0d985758cf9 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// 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
Bogdan Caprita4d67c042014-08-19 10:41:19 -07005package impl
6
7// The app invoker is responsible for managing the state of applications on the
Bogdan Caprita2b219362014-12-09 17:03:33 -08008// device manager. The device manager manages the applications it installs and
Bogdan Caprita2b050322015-04-17 09:04:03 -07009// runs using the following directory structure. Permissions and owners are
10// noted as parentheses enclosed octal perms with an 'a' or 'd' suffix for app
11// or device manager respectively. For example: (755d)
Bogdan Caprita4d67c042014-08-19 10:41:19 -070012//
13// TODO(caprita): Not all is yet implemented.
14//
Robert Kroeger38cc2d82015-02-09 17:54:12 -080015// <config.Root>(711d)/
16// app-<hash 1>(711d)/ - the application dir is named using a hash of the application title
17// installation-<id 1>(711d)/ - installations are labelled with ids
18// acls(700d)/
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -070019// data(700d) - the AccessList data for this
Bogdan Caprita2b050322015-04-17 09:04:03 -070020// installation. Controls access to
21// Instantiate, Uninstall, Update,
22// UpdateTo and Revert.
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -070023// signature(700d) - the signature for the AccessLists in data
Bogdan Caprita2b050322015-04-17 09:04:03 -070024// <status>(700d) - one of the values for InstallationState enum
Robert Kroeger38cc2d82015-02-09 17:54:12 -080025// origin(700d) - object name for application envelope
26// config(700d) - Config provided by the installer
27// packages(700d) - set of packages specified by the installer
Bogdan Capritad2cdd532015-02-25 11:51:19 -080028// pkg(700d)/ - downloaded packages
Robert Kroeger38cc2d82015-02-09 17:54:12 -080029// <pkg name>(700d)
30// <pkg name>.__info(700d)
Bogdan Capritac25a48c2015-02-12 13:45:51 -080031// ...
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -080032// <version 1 timestamp>(711d)/ - timestamp of when the version was downloaded
Robert Kroeger38cc2d82015-02-09 17:54:12 -080033// bin(755d) - application binary
34// previous - symbolic link to previous version directory
35// envelope - application envelope (JSON-encoded)
Bogdan Capritad2cdd532015-02-25 11:51:19 -080036// packages(755d)/ - installed packages (from envelope+installer)
37// <pkg name>(755d)/
Robin Thellende2627892014-11-26 09:34:37 -080038// ...
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -080039// <version 2 timestamp>(711d)
Bogdan Caprita4d67c042014-08-19 10:41:19 -070040// ...
Robert Kroeger38cc2d82015-02-09 17:54:12 -080041// current - symbolic link to the current version
42// instances(711d)/
43// instance-<id a>(711d)/ - instances are labelled with ids
Suharsh Sivakumar1d38dc02015-03-16 17:53:29 -070044// credentials(700d)/ - holds vanadium credentials (unless running
Robert Kroeger38cc2d82015-02-09 17:54:12 -080045// through security agent)
46// root(700a)/ - workspace that the instance is run from
Bogdan Capritad2cdd532015-02-25 11:51:19 -080047// packages - symbolic link to version's packages
Robert Kroeger38cc2d82015-02-09 17:54:12 -080048// logs(755a)/ - stderr/stdout and log files generated by instance
49// info(700d) - metadata for the instance (such as app
50// cycle manager name and process id)
51// installation - symbolic link to installation for the instance
52// version - symbolic link to installation version for the instance
Bogdan Caprita19ccdee2015-08-21 11:12:33 -070053// agent-sock-dir - symbolic link to the agent socket dir
Robert Kroeger38cc2d82015-02-09 17:54:12 -080054// acls(700d)/
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -070055// data(700d) - the AccessLists for this instance. These
Bogdan Caprita2b050322015-04-17 09:04:03 -070056// AccessLists control access to Run,
57// Kill and Delete.
Adam Sadovskya4d4a692015-04-20 11:36:49 -070058// signature(700d) - the signature for these AccessLists.
Bogdan Caprita2b050322015-04-17 09:04:03 -070059// <status>(700d) - one of the values for InstanceState enum
Robert Kroeger38cc2d82015-02-09 17:54:12 -080060// systemname(700d) - the system name used to execute this instance
Robert Kroeger16ee22b2015-03-12 14:57:09 -070061// debugacls (711d)/
Adam Sadovskya4d4a692015-04-20 11:36:49 -070062// data(644)/ - the Permissions for Debug access to the application. Shared
Robert Kroeger16ee22b2015-03-12 14:57:09 -070063// with the application.
Adam Sadovskya4d4a692015-04-20 11:36:49 -070064// signature(644)/ - the signature for these Permissions.
Robert Kroeger38cc2d82015-02-09 17:54:12 -080065// instance-<id b>(711d)
Bogdan Caprita4d67c042014-08-19 10:41:19 -070066// ...
Robert Kroeger38cc2d82015-02-09 17:54:12 -080067// installation-<id 2>(711d)
Bogdan Caprita4d67c042014-08-19 10:41:19 -070068// ...
Robert Kroeger38cc2d82015-02-09 17:54:12 -080069// app-<hash 2>(711d)
Bogdan Caprita4d67c042014-08-19 10:41:19 -070070// ...
Bogdan Caprita19ccdee2015-08-21 11:12:33 -070071// socks(711d)/ - agent sockets
72// <id X>(711d)/ - one for each app instance
73// s(660d) - the socket file
74// <id Y>
75// ...
Bogdan Caprita4d67c042014-08-19 10:41:19 -070076//
Bogdan Caprita2b219362014-12-09 17:03:33 -080077// The device manager uses the suid helper binary to invoke an application as a
Bogdan Caprita962d5e02014-10-28 18:36:09 -070078// specified user. The path to the helper is specified as config.Helper.
79
Bogdan Caprita2b050322015-04-17 09:04:03 -070080// When device manager starts up, it goes through all instances and launches the
81// ones that are not running. If an instance fails to launch, it stays not
82// running.
Bogdan Caprita4d67c042014-08-19 10:41:19 -070083//
Bogdan Caprita2b050322015-04-17 09:04:03 -070084// Instantiate creates an instance. Run launches the process. Kill kills the
85// process but leaves the workspace untouched. Delete prevents future launches
86// (it also eventually gc's the workspace, logs, and other instance state).
Bogdan Caprita4d67c042014-08-19 10:41:19 -070087//
Bogdan Caprita2b050322015-04-17 09:04:03 -070088// If the process dies on its own, it stays dead and is assumed not running.
Bogdan Caprita4d67c042014-08-19 10:41:19 -070089// TODO(caprita): Later, we'll add auto-restart option.
90//
91// Concurrency model: installations can be created independently of one another;
Bogdan Caprita2b050322015-04-17 09:04:03 -070092// installations can be removed at any time (TODO(caprita): ensure all instances
93// are Deleted). The first call to Uninstall will rename the installation dir
94// as a first step; subsequent Uninstall's will fail. Instances can be created
Bogdan Caprita4d67c042014-08-19 10:41:19 -070095// independently of one another, as long as the installation exists (if it gets
Bogdan Caprita2b050322015-04-17 09:04:03 -070096// Uninstall'ed during a Instantiate, the Instantiate call may fail).
Bogdan Caprita268b4192014-08-28 10:04:44 -070097//
98// The status file present in each instance is used to flag the state of the
99// instance and prevent concurrent operations against the instance:
100//
Bogdan Caprita2b050322015-04-17 09:04:03 -0700101// - when an instance is created with Instantiate, it is placed in state
102// 'not-running'.
Bogdan Caprita268b4192014-08-28 10:04:44 -0700103//
Bogdan Caprita2b050322015-04-17 09:04:03 -0700104// - Run attempts to transition from 'not-running' to 'launching' (if the
105// instance was not in 'not-running' state, Run fails). From 'launching', the
106// instance transitions to 'running' upon success or back to 'not-running' upon
Bogdan Caprita268b4192014-08-28 10:04:44 -0700107// failure.
108//
Bogdan Caprita2b050322015-04-17 09:04:03 -0700109// - Kill attempts to transition from 'running' to 'dying' (if the
110// instance was not in 'running' state, Kill fails). From 'dying', the
111// instance transitions to 'not-running' upon success or back to 'running' upon
Bogdan Caprita268b4192014-08-28 10:04:44 -0700112// failure.
113//
Bogdan Caprita2b050322015-04-17 09:04:03 -0700114// - Delete transitions from 'not-running' to 'deleted'. If the initial
115// state is not 'not-running', Delete fails.
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700116//
Bogdan Caprita2b219362014-12-09 17:03:33 -0800117// TODO(caprita): There is room for synergy between how device manager organizes
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700118// its own workspace and that for the applications it runs. In particular,
119// previous, origin, and envelope could be part of a single config. We'll
120// refine that later.
121
122import (
Bogdan Capritad8373a12015-01-28 19:52:37 -0800123 "bytes"
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700124 "crypto/md5"
125 "encoding/base64"
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700126 "encoding/json"
127 "fmt"
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700128 "io/ioutil"
129 "os"
130 "os/exec"
Robert Kroegeracc778b2014-11-03 17:17:21 -0800131 "path"
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700132 "path/filepath"
Bogdan Capritabce0a632014-09-03 16:15:26 -0700133 "reflect"
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -0700134 "regexp"
Bogdan Caprita7f491672014-11-13 14:51:08 -0800135 "strconv"
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700136 "strings"
Bogdan Capritad8373a12015-01-28 19:52:37 -0800137 "text/template"
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700138 "time"
139
Jiri Simsa6ac95222015-02-23 16:11:49 -0800140 "v.io/v23"
141 "v.io/v23/context"
Robin Thellendf15f2952015-07-17 21:49:58 -0700142 "v.io/v23/glob"
Jiri Simsa6ac95222015-02-23 16:11:49 -0800143 "v.io/v23/naming"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700144 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -0800145 "v.io/v23/security"
Todd Wang387d8a42015-03-30 17:09:05 -0700146 "v.io/v23/security/access"
Todd Wang94c9d0b2015-04-01 14:27:00 -0700147 "v.io/v23/services/appcycle"
148 "v.io/v23/services/application"
149 "v.io/v23/services/device"
Jiri Simsa6ac95222015-02-23 16:11:49 -0800150 "v.io/v23/verror"
Todd Wang8123b5e2015-05-14 18:44:43 -0700151 "v.io/x/ref"
Jiri Simsaffceefa2015-02-28 11:03:34 -0800152 vexec "v.io/x/ref/lib/exec"
Todd Wang712eeef2015-04-03 17:13:50 -0700153 "v.io/x/ref/lib/mgmt"
Todd Wangb3511492015-04-07 23:32:34 -0700154 vsecurity "v.io/x/ref/lib/security"
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700155 "v.io/x/ref/services/agent"
Todd Wang88509682015-04-10 10:28:24 -0700156 "v.io/x/ref/services/agent/agentlib"
Todd Wangb3511492015-04-07 23:32:34 -0700157 "v.io/x/ref/services/agent/keymgr"
Todd Wangcd4b3cc2015-04-06 16:42:02 -0700158 "v.io/x/ref/services/device/internal/config"
Bogdan Caprita040603b2015-06-23 18:19:30 -0700159 "v.io/x/ref/services/device/internal/errors"
Todd Wang5fc36442015-04-07 15:15:27 -0700160 "v.io/x/ref/services/internal/packages"
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700161 "v.io/x/ref/services/internal/pathperms"
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700162)
163
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700164// instanceInfo holds state about an instance.
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700165type instanceInfo struct {
Bogdan Caprita2b219362014-12-09 17:03:33 -0800166 AppCycleMgrName string
167 Pid int
168 DeviceManagerPeerPattern string
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700169 // TODO(caprita): Change to [agent.PrincipalHandleByteSize]byte and
170 // remove handle() and setHandle() converters.
171 SecurityAgentHandle []byte
172 Restarts int32
173 RestartWindowBegan time.Time
174}
175
176func (i *instanceInfo) handle() (ret [agent.PrincipalHandleByteSize]byte) {
177 if len(i.SecurityAgentHandle) != agent.PrincipalHandleByteSize {
178 panic(fmt.Sprintf("Handle of unexpected length (%d): %v", len(i.SecurityAgentHandle), i.SecurityAgentHandle))
179 }
180 copy(ret[:], i.SecurityAgentHandle[0:agent.PrincipalHandleByteSize])
181 return
182}
183
184func (i *instanceInfo) setHandle(h [agent.PrincipalHandleByteSize]byte) {
185 i.SecurityAgentHandle = h[:]
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700186}
187
gauthamtfd1e34e2015-03-05 15:30:52 -0800188func saveInstanceInfo(ctx *context.T, dir string, info *instanceInfo) error {
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700189 jsonInfo, err := json.Marshal(info)
190 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700191 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Marshal(%v) failed: %v", info, err))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700192 }
193 infoPath := filepath.Join(dir, "info")
194 if err := ioutil.WriteFile(infoPath, jsonInfo, 0600); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700195 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("WriteFile(%v) failed: %v", infoPath, err))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700196 }
197 return nil
198}
199
gauthamtfd1e34e2015-03-05 15:30:52 -0800200func loadInstanceInfo(ctx *context.T, dir string) (*instanceInfo, error) {
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700201 infoPath := filepath.Join(dir, "info")
202 info := new(instanceInfo)
203 if infoBytes, err := ioutil.ReadFile(infoPath); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700204 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("ReadFile(%v) failed: %v", infoPath, err))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700205 } else if err := json.Unmarshal(infoBytes, info); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700206 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Unmarshal(%v) failed: %v", infoBytes, err))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700207 }
208 return info, nil
209}
210
Bogdan Caprita7f491672014-11-13 14:51:08 -0800211type securityAgentState struct {
212 // Security agent key manager client.
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700213 keyMgr agent.KeyManager
214 // Deprecated: security agent key manager client based on pipe
215 // connections.
Bogdan Caprita7f491672014-11-13 14:51:08 -0800216 keyMgrAgent *keymgr.Agent
Bogdan Caprita7f491672014-11-13 14:51:08 -0800217}
218
Robert Kroegercc9f55d2015-05-20 16:25:36 -0700219// appRunner is the subset of the appService object needed to
Robert Kroeger450fdf12015-05-19 14:40:42 -0700220// (re)start an application.
Robert Kroegercc9f55d2015-05-20 16:25:36 -0700221type appRunner struct {
222 callback *callbackState
Robert Kroeger450fdf12015-05-19 14:40:42 -0700223 // securityAgent holds state related to the security agent (nil if not
224 // using the agent).
225 securityAgent *securityAgentState
Robert Kroegercc9f55d2015-05-20 16:25:36 -0700226 // reap is the app process monitoring subsystem.
227 reap *reaper
Robert Kroeger450fdf12015-05-19 14:40:42 -0700228 // mtAddress is the address of the local mounttable.
229 mtAddress string
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -0700230 // appServiceName is a name by which the appService can be reached
231 appServiceName string
Robert Kroeger450fdf12015-05-19 14:40:42 -0700232}
233
Bogdan Caprita2b219362014-12-09 17:03:33 -0800234// appService implements the Device manager's Application interface.
Robin Thellend9bc8fcb2014-11-17 10:23:04 -0800235type appService struct {
Robert Kroeger450fdf12015-05-19 14:40:42 -0700236 config *config.State
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700237 // suffix contains the name components of the current invocation name
238 // suffix. It is used to identify an application, installation, or
239 // instance.
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700240 suffix []string
241 uat BlessingSystemAssociationStore
242 permsStore *pathperms.PathStore
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700243 // Reference to the devicemanager top-level AccessList list.
244 deviceAccessList access.Permissions
Robert Kroegercc9f55d2015-05-20 16:25:36 -0700245 // State needed to (re)start an application.
246 runner *appRunner
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700247}
248
gauthamtfd1e34e2015-03-05 15:30:52 -0800249func saveEnvelope(ctx *context.T, dir string, envelope *application.Envelope) error {
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700250 jsonEnvelope, err := json.Marshal(envelope)
251 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700252 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Marshal(%v) failed: %v", envelope, err))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700253 }
Bogdan Capritabce0a632014-09-03 16:15:26 -0700254 path := filepath.Join(dir, "envelope")
255 if err := ioutil.WriteFile(path, jsonEnvelope, 0600); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700256 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("WriteFile(%v) failed: %v", path, err))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700257 }
258 return nil
259}
260
gauthamtfd1e34e2015-03-05 15:30:52 -0800261func loadEnvelope(ctx *context.T, dir string) (*application.Envelope, error) {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700262 path := filepath.Join(dir, "envelope")
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700263 envelope := new(application.Envelope)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700264 if envelopeBytes, err := ioutil.ReadFile(path); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700265 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("ReadFile(%v) failed: %v", path, err))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700266 } else if err := json.Unmarshal(envelopeBytes, envelope); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700267 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Unmarshal(%v) failed: %v", envelopeBytes, err))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700268 }
269 return envelope, nil
270}
271
Robert Kroegercc9f55d2015-05-20 16:25:36 -0700272func loadEnvelopeForInstance(ctx *context.T, instanceDir string) (*application.Envelope, error) {
273 versionLink := filepath.Join(instanceDir, "version")
274 versionDir, err := filepath.EvalSymlinks(versionLink)
275 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700276 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", versionLink, err))
Robert Kroegercc9f55d2015-05-20 16:25:36 -0700277 }
278 return loadEnvelope(ctx, versionDir)
279}
280
gauthamtfd1e34e2015-03-05 15:30:52 -0800281func saveConfig(ctx *context.T, dir string, config device.Config) error {
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800282 jsonConfig, err := json.Marshal(config)
283 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700284 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Marshal(%v) failed: %v", config, err))
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800285 }
286 path := filepath.Join(dir, "config")
287 if err := ioutil.WriteFile(path, jsonConfig, 0600); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700288 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("WriteFile(%v) failed: %v", path, err))
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800289 }
290 return nil
291}
292
gauthamtfd1e34e2015-03-05 15:30:52 -0800293func loadConfig(ctx *context.T, dir string) (device.Config, error) {
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800294 path := filepath.Join(dir, "config")
295 var config device.Config
296 if configBytes, err := ioutil.ReadFile(path); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700297 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("ReadFile(%v) failed: %v", path, err))
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800298 } else if err := json.Unmarshal(configBytes, &config); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700299 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Unmarshal(%v) failed: %v", configBytes, err))
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800300 }
301 return config, nil
302}
303
gauthamtfd1e34e2015-03-05 15:30:52 -0800304func savePackages(ctx *context.T, dir string, packages application.Packages) error {
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800305 jsonPackages, err := json.Marshal(packages)
306 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700307 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Marshal(%v) failed: %v", packages, err))
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800308 }
309 path := filepath.Join(dir, "packages")
310 if err := ioutil.WriteFile(path, jsonPackages, 0600); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700311 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("WriteFile(%v) failed: %v", path, err))
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800312 }
313 return nil
314}
315
gauthamtfd1e34e2015-03-05 15:30:52 -0800316func loadPackages(ctx *context.T, dir string) (application.Packages, error) {
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800317 path := filepath.Join(dir, "packages")
318 var packages application.Packages
319 if packagesBytes, err := ioutil.ReadFile(path); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700320 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("ReadFile(%v) failed: %v", path, err))
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800321 } else if err := json.Unmarshal(packagesBytes, &packages); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700322 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Unmarshal(%v) failed: %v", packagesBytes, err))
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800323 }
324 return packages, nil
325}
326
gauthamtfd1e34e2015-03-05 15:30:52 -0800327func saveOrigin(ctx *context.T, dir, originVON string) error {
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700328 path := filepath.Join(dir, "origin")
329 if err := ioutil.WriteFile(path, []byte(originVON), 0600); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700330 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("WriteFile(%v) failed: %v", path, err))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700331 }
332 return nil
333}
334
gauthamtfd1e34e2015-03-05 15:30:52 -0800335func loadOrigin(ctx *context.T, dir string) (string, error) {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700336 path := filepath.Join(dir, "origin")
337 if originBytes, err := ioutil.ReadFile(path); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700338 return "", verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("ReadFile(%v) failed: %v", path, err))
Bogdan Capritabce0a632014-09-03 16:15:26 -0700339 } else {
340 return string(originBytes), nil
341 }
342}
343
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700344// generateID returns a new unique id string. The uniqueness is based on the
345// current timestamp. Not cryptographically secure.
346func generateID() string {
Arup Mukherjeee7f75722015-03-06 10:52:56 -0800347 const timeFormat = "20060102-15:04:05.0000"
348 return time.Now().UTC().Format(timeFormat)
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700349}
350
351// TODO(caprita): Nothing prevents different applications from sharing the same
352// title, and thereby being installed in the same app dir. Do we want to
353// prevent that for the same user or across users?
354
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -0700355const (
356 appDirPrefix = "app-"
357 installationPrefix = "installation-"
358 instancePrefix = "instance-"
359)
360
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700361// applicationDirName generates a cryptographic hash of the application title,
362// to be used as a directory name for installations of the application with the
363// given title.
364func applicationDirName(title string) string {
365 h := md5.New()
366 h.Write([]byte(title))
367 hash := strings.TrimRight(base64.URLEncoding.EncodeToString(h.Sum(nil)), "=")
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -0700368 return appDirPrefix + hash
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700369}
370
371func installationDirName(installationID string) string {
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -0700372 return installationPrefix + installationID
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700373}
374
375func instanceDirName(instanceID string) string {
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -0700376 return instancePrefix + instanceID
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700377}
378
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700379func mkdir(ctx *context.T, dir string) error {
380 return mkdirPerm(ctx, dir, 0700)
Robert Kroeger38cc2d82015-02-09 17:54:12 -0800381}
382
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700383func mkdirPerm(ctx *context.T, dir string, permissions int) error {
Robert Kroeger38cc2d82015-02-09 17:54:12 -0800384 perm := os.FileMode(permissions)
Bogdan Caprita268b4192014-08-28 10:04:44 -0700385 if err := os.MkdirAll(dir, perm); err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700386 ctx.Errorf("MkdirAll(%v, %v) failed: %v", dir, perm, err)
Bogdan Caprita268b4192014-08-28 10:04:44 -0700387 return err
388 }
389 return nil
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700390}
391
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700392func sockPath(instanceDir string) (string, error) {
393 sockLink := filepath.Join(instanceDir, "agent-sock-dir")
394 sock, err := filepath.EvalSymlinks(sockLink)
395 if err != nil {
396 return "", err
397 }
398 return filepath.Join(sock, "s"), nil
399}
400
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -0800401func fetchAppEnvelope(ctx *context.T, origin string) (*application.Envelope, error) {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700402 envelope, err := fetchEnvelope(ctx, origin)
403 if err != nil {
404 return nil, err
405 }
Bogdan Caprita2b219362014-12-09 17:03:33 -0800406 if envelope.Title == application.DeviceManagerTitle {
407 // Disallow device manager apps from being installed like a
Bogdan Capritabce0a632014-09-03 16:15:26 -0700408 // regular app.
Bogdan Caprita040603b2015-06-23 18:19:30 -0700409 return nil, verror.New(errors.ErrInvalidOperation, ctx, "DeviceManager apps cannot be installed")
Bogdan Capritabce0a632014-09-03 16:15:26 -0700410 }
411 return envelope, nil
412}
413
414// newVersion sets up the directory for a new application version.
Matt Rosencrantz4f8ac602014-12-29 14:42:48 -0800415func newVersion(ctx *context.T, installationDir string, envelope *application.Envelope, oldVersionDir string) (string, error) {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700416 versionDir := filepath.Join(installationDir, generateVersionDirName())
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700417 if err := mkdirPerm(ctx, versionDir, 0711); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700418 return "", verror.New(errors.ErrOperationFailed, ctx, err)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700419 }
gauthamtfd1e34e2015-03-05 15:30:52 -0800420 if err := saveEnvelope(ctx, versionDir, envelope); err != nil {
Bogdan Capritad2cdd532015-02-25 11:51:19 -0800421 return versionDir, err
422 }
Robin Thellende2627892014-11-26 09:34:37 -0800423 pkgDir := filepath.Join(versionDir, "pkg")
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700424 if err := mkdir(ctx, pkgDir); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700425 return "", verror.New(errors.ErrOperationFailed, ctx, err)
Robin Thellende2627892014-11-26 09:34:37 -0800426 }
Asim Shankarb07ec692015-02-27 23:40:44 -0800427 publisher := envelope.Publisher
Bogdan Capritabce0a632014-09-03 16:15:26 -0700428 // TODO(caprita): Share binaries if already existing locally.
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800429 if err := downloadBinary(ctx, publisher, &envelope.Binary, versionDir, "bin"); err != nil {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700430 return versionDir, err
431 }
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800432 if err := downloadPackages(ctx, publisher, envelope.Packages, pkgDir); err != nil {
gauthamt3dbef0c2015-02-10 12:26:02 -0800433 return versionDir, err
Robin Thellende2627892014-11-26 09:34:37 -0800434 }
gauthamtfd1e34e2015-03-05 15:30:52 -0800435 if err := installPackages(ctx, installationDir, versionDir); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700436 return versionDir, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("installPackages(%v, %v) failed: %v", installationDir, versionDir, err))
Bogdan Capritad2cdd532015-02-25 11:51:19 -0800437 }
438 if err := os.RemoveAll(pkgDir); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700439 return versionDir, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("RemoveAll(%v) failed: %v", pkgDir, err))
Bogdan Capritabce0a632014-09-03 16:15:26 -0700440 }
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700441 if oldVersionDir != "" {
442 previousLink := filepath.Join(versionDir, "previous")
443 if err := os.Symlink(oldVersionDir, previousLink); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700444 return versionDir, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Symlink(%v, %v) failed: %v", oldVersionDir, previousLink, err))
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700445 }
446 }
Bogdan Caprita0bae4ea2015-06-23 22:55:22 -0700447 // UpdateLink should be the last thing we do, after we've ensured the
Bogdan Capritabce0a632014-09-03 16:15:26 -0700448 // new version is viable (currently, that just means it installs
449 // properly).
Bogdan Caprita0bae4ea2015-06-23 22:55:22 -0700450 return versionDir, UpdateLink(versionDir, filepath.Join(installationDir, "current"))
Bogdan Capritabce0a632014-09-03 16:15:26 -0700451}
452
Todd Wang4264e4b2015-04-16 22:43:40 -0700453func (i *appService) Install(ctx *context.T, call rpc.ServerCall, applicationVON string, config device.Config, packages application.Packages) (string, error) {
Bogdan Caprita2968f4b2014-08-22 14:11:58 -0700454 if len(i.suffix) > 0 {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700455 return "", verror.New(errors.ErrInvalidSuffix, ctx)
Bogdan Caprita2968f4b2014-08-22 14:11:58 -0700456 }
Todd Wang54feabe2015-04-15 23:38:26 -0700457 ctx, cancel := context.WithTimeout(ctx, rpcContextLongTimeout)
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700458 defer cancel()
Bogdan Capritabce0a632014-09-03 16:15:26 -0700459 envelope, err := fetchAppEnvelope(ctx, applicationVON)
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700460 if err != nil {
461 return "", err
462 }
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700463 installationID := generateID()
464 installationDir := filepath.Join(i.config.Root, applicationDirName(envelope.Title), installationDirName(installationID))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700465 deferrer := func() {
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700466 CleanupDir(ctx, installationDir, "")
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700467 }
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700468 if err := mkdirPerm(ctx, installationDir, 0711); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700469 return "", verror.New(errors.ErrOperationFailed, nil)
Bogdan Capritad2cdd532015-02-25 11:51:19 -0800470 }
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700471 defer func() {
472 if deferrer != nil {
473 deferrer()
474 }
475 }()
Bogdan Caprita8964d3f2015-02-02 13:47:39 -0800476 if newOrigin, ok := config[mgmt.AppOriginConfigKey]; ok {
477 delete(config, mgmt.AppOriginConfigKey)
478 applicationVON = newOrigin
479 }
Todd Wang54feabe2015-04-15 23:38:26 -0700480 if err := saveOrigin(ctx, installationDir, applicationVON); err != nil {
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700481 return "", err
482 }
Todd Wang54feabe2015-04-15 23:38:26 -0700483 if err := saveConfig(ctx, installationDir, config); err != nil {
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800484 return "", err
485 }
Todd Wang54feabe2015-04-15 23:38:26 -0700486 if err := savePackages(ctx, installationDir, packages); err != nil {
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800487 return "", err
488 }
489 pkgDir := filepath.Join(installationDir, "pkg")
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700490 if err := mkdir(ctx, pkgDir); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700491 return "", verror.New(errors.ErrOperationFailed, ctx, err)
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800492 }
Asim Shankar2bf7b1e2015-02-27 00:45:12 -0800493 // We use a zero value publisher, meaning that any signatures present in the
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800494 // package files are not verified.
495 // TODO(caprita): Issue warnings when signatures are present and ignored.
Todd Wang54feabe2015-04-15 23:38:26 -0700496 if err := downloadPackages(ctx, security.Blessings{}, packages, pkgDir); err != nil {
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800497 return "", err
498 }
Todd Wang54feabe2015-04-15 23:38:26 -0700499 if _, err := newVersion(ctx, installationDir, envelope, ""); err != nil {
Bogdan Capritad2cdd532015-02-25 11:51:19 -0800500 return "", err
501 }
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700502 // TODO(caprita,rjkroege): Should the installation AccessLists really be
503 // seeded with the device AccessList? Instead, might want to hide the deviceAccessList
Asim Shankar68885192014-11-26 12:48:35 -0800504 // from the app?
Todd Wang4264e4b2015-04-16 22:43:40 -0700505 blessings, _ := security.RemoteBlessingNames(ctx, call.Security())
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700506 if err := i.initializeSubAccessLists(installationDir, blessings, i.deviceAccessList.Copy()); err != nil {
Robert Kroegeracc778b2014-11-03 17:17:21 -0800507 return "", err
508 }
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700509 if err := initializeInstallation(installationDir, device.InstallationStateActive); err != nil {
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800510 return "", err
511 }
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700512 deferrer = nil
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800513 // TODO(caprita): Using the title without cleaning out slashes
514 // introduces extra name components that mess up the device manager's
515 // apps object space. We should fix this either by santizing the title,
516 // or disallowing slashes in titles to begin with.
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700517 return naming.Join(envelope.Title, installationID), nil
518}
519
Bogdan Caprita25d4faa2014-08-28 10:21:23 -0700520func openWriteFile(path string) (*os.File, error) {
Arup Mukherjee29827c02015-03-30 13:06:09 -0700521 perm := os.FileMode(0644)
gauthamtfd1e34e2015-03-05 15:30:52 -0800522 return os.OpenFile(path, os.O_WRONLY|os.O_CREATE, perm)
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700523}
524
gauthamtfd1e34e2015-03-05 15:30:52 -0800525// TODO(gauthamt): Make sure we pass the context to installationDirCore.
Robert Kroegeracc778b2014-11-03 17:17:21 -0800526func installationDirCore(components []string, root string) (string, error) {
Bogdan Caprita2968f4b2014-08-22 14:11:58 -0700527 if nComponents := len(components); nComponents != 2 {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700528 return "", verror.New(errors.ErrInvalidSuffix, nil)
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700529 }
530 app, installation := components[0], components[1]
Robert Kroegeracc778b2014-11-03 17:17:21 -0800531 installationDir := filepath.Join(root, applicationDirName(app), installationDirName(installation))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700532 if _, err := os.Stat(installationDir); err != nil {
533 if os.IsNotExist(err) {
Jiri Simsa074bf362015-02-17 09:29:45 -0800534 return "", verror.New(verror.ErrNoExist, nil, naming.Join(components...))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700535 }
Bogdan Caprita040603b2015-06-23 18:19:30 -0700536 return "", verror.New(errors.ErrOperationFailed, nil, fmt.Sprintf("Stat(%v) failed: %v", installationDir, err))
Bogdan Caprita2968f4b2014-08-22 14:11:58 -0700537 }
538 return installationDir, nil
539}
540
Bogdan Capritad8373a12015-01-28 19:52:37 -0800541// agentPrincipal creates a Principal backed by the given agent connection,
542// taking ownership of the connection. The returned cancel function is to be
543// called when the Principal is no longer in use.
544func agentPrincipal(ctx *context.T, conn *os.File) (security.Principal, func(), error) {
545 agentctx, cancel := context.WithCancel(ctx)
546 var err error
Todd Wangad492042015-04-17 15:58:40 -0700547 if agentctx, err = v23.WithNewStreamManager(agentctx); err != nil {
Bogdan Capritad8373a12015-01-28 19:52:37 -0800548 cancel()
549 conn.Close()
550 return nil, nil, err
551 }
Ryan Brown7f950a82015-04-20 18:08:39 -0700552 // TODO: This should use the same network as the agent we're using,
553 // not whatever this process was compiled with.
554 ep, err := v23.NewEndpoint(agentlib.AgentEndpoint(int(conn.Fd())))
Bogdan Capritad8373a12015-01-28 19:52:37 -0800555 if err != nil {
556 cancel()
557 conn.Close()
558 return nil, nil, err
559 }
Ryan Brown7f950a82015-04-20 18:08:39 -0700560 p, err := agentlib.NewAgentPrincipal(agentctx, ep, v23.GetClient(agentctx))
561 if err != nil {
562 cancel()
563 conn.Close()
564 return nil, nil, err
565 }
566 conn.Close()
Bogdan Capritad8373a12015-01-28 19:52:37 -0800567 return p, cancel, nil
568}
569
Bogdan Caprita730bde12014-11-08 15:35:43 -0800570// setupPrincipal sets up the instance's principal, with the right blessings.
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700571func setupPrincipal(ctx *context.T, instanceDir string, call device.ApplicationInstantiateServerCall, securityAgent *securityAgentState, info *instanceInfo, rootDir string) error {
Bogdan Caprita7f491672014-11-13 14:51:08 -0800572 var p security.Principal
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700573 switch {
574 case securityAgent != nil && securityAgent.keyMgr != nil:
575 // TODO(caprita): Part of the cleanup upon destroying an
576 // instance, we should tell the agent to drop the principal.
577 handle, err := securityAgent.keyMgr.NewPrincipal(false)
578 if err != nil {
579 return verror.New(errors.ErrOperationFailed, ctx, "NewPrincipal() failed", err)
580 }
581 info.setHandle(handle)
Robin Thellendf0a422b2015-08-27 09:55:07 -0700582 sockDir, err := generateAgentSockDir(rootDir)
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700583 if err != nil {
Robin Thellendf0a422b2015-08-27 09:55:07 -0700584 return verror.New(errors.ErrOperationFailed, ctx, "generateAgentSockDir() failed", err)
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700585 }
586 sockLink := filepath.Join(instanceDir, "agent-sock-dir")
587 if err := os.Symlink(sockDir, sockLink); err != nil {
588 return verror.New(errors.ErrOperationFailed, ctx, "Symlink failed", err)
589 }
590 // TODO(caprita): Add a check to ensure that len(sockPath) < 108.
591 sockPath := filepath.Join(sockDir, "s")
592 if err := securityAgent.keyMgr.ServePrincipal(handle, sockPath); err != nil {
593 return verror.New(errors.ErrOperationFailed, ctx, "ServePrincipal failed", err)
594 }
595 defer func() {
596 if err := securityAgent.keyMgr.StopServing(handle); err != nil {
597 ctx.Errorf("StopServing failed: %v", err)
598 }
599 }()
600 if p, err = agentlib.NewAgentPrincipalX(sockPath); err != nil {
601 return verror.New(errors.ErrOperationFailed, ctx, "NewAgentPrincipalX failed", err)
602 }
603 case securityAgent != nil && securityAgent.keyMgrAgent != nil:
604 // This code path is deprecated in favor of the socket agent
605 // connection.
606
Bogdan Caprita7f491672014-11-13 14:51:08 -0800607 // TODO(caprita): Part of the cleanup upon destroying an
608 // instance, we should tell the agent to drop the principal.
Matt Rosencrantz5180d162014-12-03 13:48:40 -0800609 handle, conn, err := securityAgent.keyMgrAgent.NewPrincipal(ctx, false)
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800610 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700611 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("NewPrincipal() failed %v", err))
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800612 }
Bogdan Capritad8373a12015-01-28 19:52:37 -0800613 var cancel func()
614 if p, cancel, err = agentPrincipal(ctx, conn); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700615 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("agentPrincipal failed: %v", err))
Bogdan Caprita6613fc42015-01-28 11:54:23 -0800616 }
617 defer cancel()
Bogdan Caprita7f491672014-11-13 14:51:08 -0800618 info.SecurityAgentHandle = handle
Bogdan Caprita6613fc42015-01-28 11:54:23 -0800619 // conn will be closed when the connection to the agent is shut
620 // down, as a result of cancel() shutting down the stream
621 // manager. No need to call conn.Close().
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700622 default:
Bogdan Caprita7f491672014-11-13 14:51:08 -0800623 credentialsDir := filepath.Join(instanceDir, "credentials")
624 // TODO(caprita): The app's system user id needs access to this dir.
625 // Use the suidhelper to chown it.
626 var err error
627 if p, err = vsecurity.CreatePersistentPrincipal(credentialsDir, nil); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700628 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("CreatePersistentPrincipal(%v, nil) failed: %v", credentialsDir, err))
Bogdan Caprita7f491672014-11-13 14:51:08 -0800629 }
Bogdan Caprita26929102014-11-07 11:56:56 -0800630 }
Robin Thellend3480f8e2015-03-13 09:50:41 -0700631 mPubKey, err := p.PublicKey().MarshalBinary()
Bogdan Caprita26929102014-11-07 11:56:56 -0800632 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700633 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("PublicKey().MarshalBinary() failed: %v", err))
Bogdan Caprita26929102014-11-07 11:56:56 -0800634 }
Arup Mukherjeee4d75c92015-05-18 19:10:02 -0700635 if err := call.SendStream().Send(device.BlessServerMessageInstancePublicKey{Value: mPubKey}); err != nil {
Robin Thellend3480f8e2015-03-13 09:50:41 -0700636 return err
637 }
638 if !call.RecvStream().Advance() {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700639 return verror.New(errors.ErrInvalidBlessing, ctx, fmt.Sprintf("no blessings on stream: %v", call.RecvStream().Err()))
Robin Thellend3480f8e2015-03-13 09:50:41 -0700640 }
641 msg := call.RecvStream().Value()
Arup Mukherjee13c00382015-06-04 15:54:38 -0700642 appBlessingsFromInstantiator, ok := msg.(device.BlessClientMessageAppBlessings)
Robin Thellend3480f8e2015-03-13 09:50:41 -0700643 if !ok {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700644 return verror.New(errors.ErrInvalidBlessing, ctx, fmt.Sprintf("wrong message type: %#v", msg))
Robin Thellend3480f8e2015-03-13 09:50:41 -0700645 }
Arup Mukherjee13c00382015-06-04 15:54:38 -0700646 // Should we move this after the addition of publisher blessings, and thus allow
647 // apps to run with only publisher blessings?
648 if appBlessingsFromInstantiator.Value.IsZero() {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700649 return verror.New(errors.ErrInvalidBlessing, ctx)
Robin Thellend3480f8e2015-03-13 09:50:41 -0700650 }
Arup Mukherjee13c00382015-06-04 15:54:38 -0700651 if err := p.BlessingStore().SetDefault(appBlessingsFromInstantiator.Value); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700652 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("BlessingStore.SetDefault() failed: %v", err))
Bogdan Caprita26929102014-11-07 11:56:56 -0800653 }
Arup Mukherjee13c00382015-06-04 15:54:38 -0700654 // If there were any publisher blessings in the envelope, add those to the set of blessings
655 // sent to servers by default
656 appBlessings, err := addPublisherBlessings(ctx, instanceDir, p, appBlessingsFromInstantiator.Value)
657 if _, err := p.BlessingStore().Set(appBlessings, security.AllPrincipals); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700658 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("BlessingStore.Set() failed: %v", err))
Bogdan Caprita26929102014-11-07 11:56:56 -0800659 }
Arup Mukherjee13c00382015-06-04 15:54:38 -0700660 if err := p.AddToRoots(appBlessings); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700661 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("AddToRoots() failed: %v", err))
Bogdan Caprita26929102014-11-07 11:56:56 -0800662 }
663 // In addition, we give the app separate blessings for the purpose of
Bogdan Caprita2b219362014-12-09 17:03:33 -0800664 // communicating with the device manager.
Bogdan Caprita730bde12014-11-08 15:35:43 -0800665 //
666 // NOTE(caprita/ataly): Giving the app an unconstrained blessing from
Bogdan Caprita2b219362014-12-09 17:03:33 -0800667 // the device manager's default presents the app with a blessing that's
Bogdan Caprita730bde12014-11-08 15:35:43 -0800668 // potentially more powerful than what is strictly needed to allow
Bogdan Caprita2b219362014-12-09 17:03:33 -0800669 // communication between device manager and app (which could be more
Bogdan Caprita730bde12014-11-08 15:35:43 -0800670 // narrowly accomplished by using a custom-purpose self-signed blessing
Bogdan Caprita2b219362014-12-09 17:03:33 -0800671 // that the device manger produces solely to talk to the app).
Todd Wang54feabe2015-04-15 23:38:26 -0700672 dmPrincipal := v23.GetPrincipal(ctx)
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800673 dmBlessings, err := dmPrincipal.Bless(p.PublicKey(), dmPrincipal.BlessingStore().Default(), "callback", security.UnconstrainedUse())
Bogdan Caprita2b219362014-12-09 17:03:33 -0800674 // Put the names of the device manager's default blessings as patterns
675 // for the child, so that the child uses the right blessing when talking
676 // back to the device manager.
Ankurd8646812015-03-12 10:48:41 -0700677 for n, _ := range dmPrincipal.BlessingsInfo(dmPrincipal.BlessingStore().Default()) {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800678 if _, err := p.BlessingStore().Set(dmBlessings, security.BlessingPattern(n)); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700679 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("BlessingStore.Set() failed: %v", err))
Bogdan Caprita26929102014-11-07 11:56:56 -0800680 }
681 }
682 // We also want to override the app cycle manager's server blessing in
Bogdan Caprita2b219362014-12-09 17:03:33 -0800683 // the child (so that the device manager can send RPCs to it). We
684 // signal to the child's app manager to use a randomly generated pattern
685 // to extract the right blessing to use from its store for this purpose.
Bogdan Caprita26929102014-11-07 11:56:56 -0800686 randomPattern, err := generateRandomString()
687 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700688 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("generateRandomString() failed: %v", err))
Bogdan Caprita26929102014-11-07 11:56:56 -0800689 }
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800690 if _, err := p.BlessingStore().Set(dmBlessings, security.BlessingPattern(randomPattern)); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700691 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("BlessingStore.Set() failed: %v", err))
Bogdan Caprita26929102014-11-07 11:56:56 -0800692 }
Bogdan Caprita2b219362014-12-09 17:03:33 -0800693 info.DeviceManagerPeerPattern = randomPattern
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800694 if err := p.AddToRoots(dmBlessings); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700695 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("AddToRoots() failed: %v", err))
Bogdan Caprita26929102014-11-07 11:56:56 -0800696 }
697 return nil
698}
699
Arup Mukherjee13c00382015-06-04 15:54:38 -0700700func addPublisherBlessings(ctx *context.T, instanceDir string, p security.Principal, b security.Blessings) (security.Blessings, error) {
701 // Load the envelope for the instance, and get the publisher blessings in it
702 envelope, err := loadEnvelopeForInstance(ctx, instanceDir)
703 if err != nil {
704 return security.Blessings{}, err
705 }
706
707 // Extend the device manager blessing with each publisher blessing provided
708 dmPrincipal := v23.GetPrincipal(ctx)
709
710 blessings, _ := publisherBlessingNames(ctx, *envelope)
711 for _, s := range blessings {
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700712 ctx.VI(2).Infof("adding publisher blessing %v for app %v", s, envelope.Title)
Arup Mukherjee6d29c6e2015-06-08 18:35:41 -0700713 tmpBlessing, err := dmPrincipal.Bless(p.PublicKey(), dmPrincipal.BlessingStore().Default(), "a/"+s, security.UnconstrainedUse())
Arup Mukherjee13c00382015-06-04 15:54:38 -0700714 if b, err = security.UnionOfBlessings(b, tmpBlessing); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700715 return b, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("UnionOfBlessings failed: %v %v", b, tmpBlessing))
Arup Mukherjee13c00382015-06-04 15:54:38 -0700716 }
717 }
718
719 return b, nil
720}
721
Robert Kroegeracc778b2014-11-03 17:17:21 -0800722// installationDir returns the path to the directory containing the app
723// installation referred to by the invoker's suffix. Returns an error if the
724// suffix does not name an installation or if the named installation does not
725// exist.
Robin Thellend9bc8fcb2014-11-17 10:23:04 -0800726func (i *appService) installationDir() (string, error) {
Robert Kroegeracc778b2014-11-03 17:17:21 -0800727 return installationDirCore(i.suffix, i.config.Root)
728}
729
Bogdan Capritad2cdd532015-02-25 11:51:19 -0800730// installPackages installs all the packages for a new version.
gauthamtfd1e34e2015-03-05 15:30:52 -0800731func installPackages(ctx *context.T, installationDir, versionDir string) error {
732 overridePackages, err := loadPackages(ctx, installationDir)
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800733 if err != nil {
734 return err
735 }
gauthamtfd1e34e2015-03-05 15:30:52 -0800736 envelope, err := loadEnvelope(ctx, versionDir)
Robin Thellende2627892014-11-26 09:34:37 -0800737 if err != nil {
738 return err
739 }
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800740 for pkg, _ := range overridePackages {
741 delete(envelope.Packages, pkg)
742 }
Bogdan Capritad2cdd532015-02-25 11:51:19 -0800743 packagesDir := filepath.Join(versionDir, "packages")
744 if err := os.MkdirAll(packagesDir, os.FileMode(0755)); err != nil {
Robin Thellende2627892014-11-26 09:34:37 -0800745 return err
746 }
Todd Wang5fc36442015-04-07 15:15:27 -0700747 installFrom := func(pkgs application.Packages, sourceDir string) error {
748 for pkg, _ := range pkgs {
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800749 pkgFile := filepath.Join(sourceDir, "pkg", pkg)
750 dst := filepath.Join(packagesDir, pkg)
Todd Wang5fc36442015-04-07 15:15:27 -0700751 if err := packages.Install(pkgFile, dst); err != nil {
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800752 return err
753 }
Robin Thellende2627892014-11-26 09:34:37 -0800754 }
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800755 return nil
Robin Thellende2627892014-11-26 09:34:37 -0800756 }
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800757 if err := installFrom(envelope.Packages, versionDir); err != nil {
758 return err
759 }
760 return installFrom(overridePackages, installationDir)
Robin Thellende2627892014-11-26 09:34:37 -0800761}
762
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700763// initializeSubAccessLists updates the provided perms for instance-specific
764// Permissions.
765func (i *appService) initializeSubAccessLists(instanceDir string, blessings []string, perms access.Permissions) error {
Asim Shankar68885192014-11-26 12:48:35 -0800766 for _, b := range blessings {
Robert Kroeger2595b762015-04-07 14:13:40 -0700767 b = b + string(security.ChainSeparator) + string(security.NoExtension)
Asim Shankar68885192014-11-26 12:48:35 -0800768 for _, tag := range access.AllTypicalTags() {
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700769 perms.Add(security.BlessingPattern(b), string(tag))
Asim Shankar68885192014-11-26 12:48:35 -0800770 }
Robert Kroegeracc778b2014-11-03 17:17:21 -0800771 }
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700772 permsDir := path.Join(instanceDir, "acls")
773 return i.permsStore.Set(permsDir, perms, "")
Robert Kroegeracc778b2014-11-03 17:17:21 -0800774}
775
Bogdan Caprita2b050322015-04-17 09:04:03 -0700776func (i *appService) newInstance(ctx *context.T, call device.ApplicationInstantiateServerCall) (string, string, error) {
Bogdan Caprita2968f4b2014-08-22 14:11:58 -0700777 installationDir, err := i.installationDir()
778 if err != nil {
Bogdan Caprita268b4192014-08-28 10:04:44 -0700779 return "", "", err
780 }
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700781 if !installationStateIs(installationDir, device.InstallationStateActive) {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700782 return "", "", verror.New(errors.ErrInvalidOperation, ctx)
Bogdan Caprita8c776b22014-08-28 17:29:07 -0700783 }
Bogdan Caprita268b4192014-08-28 10:04:44 -0700784 instanceID := generateID()
785 instanceDir := filepath.Join(installationDir, "instances", instanceDirName(instanceID))
Robert Kroeger38cc2d82015-02-09 17:54:12 -0800786 // Set permissions for app to have access.
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700787 if mkdirPerm(ctx, instanceDir, 0711) != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700788 return "", "", verror.New(errors.ErrOperationFailed, ctx)
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700789 }
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800790 rootDir := filepath.Join(instanceDir, "root")
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700791 if err := mkdir(ctx, rootDir); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700792 return instanceDir, instanceID, verror.New(errors.ErrOperationFailed, ctx, err)
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800793 }
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800794 installationLink := filepath.Join(instanceDir, "installation")
795 if err := os.Symlink(installationDir, installationLink); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700796 return instanceDir, instanceID, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Symlink(%v, %v) failed: %v", installationDir, installationLink, err))
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800797 }
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700798 currLink := filepath.Join(installationDir, "current")
Bogdan Caprita268b4192014-08-28 10:04:44 -0700799 versionDir, err := filepath.EvalSymlinks(currLink)
800 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700801 return instanceDir, instanceID, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", currLink, err))
Bogdan Caprita268b4192014-08-28 10:04:44 -0700802 }
803 versionLink := filepath.Join(instanceDir, "version")
804 if err := os.Symlink(versionDir, versionLink); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700805 return instanceDir, instanceID, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Symlink(%v, %v) failed: %v", versionDir, versionLink, err))
Bogdan Caprita268b4192014-08-28 10:04:44 -0700806 }
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800807 packagesDir, packagesLink := filepath.Join(versionLink, "packages"), filepath.Join(rootDir, "packages")
Bogdan Capritad2cdd532015-02-25 11:51:19 -0800808 if err := os.Symlink(packagesDir, packagesLink); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700809 return instanceDir, instanceID, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Symlink(%v, %v) failed: %v", packagesDir, packagesLink, err))
Robin Thellende2627892014-11-26 09:34:37 -0800810 }
Bogdan Caprita26929102014-11-07 11:56:56 -0800811 instanceInfo := new(instanceInfo)
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700812 if err := setupPrincipal(ctx, instanceDir, call, i.runner.securityAgent, instanceInfo, i.config.Root); err != nil {
Bogdan Caprita26929102014-11-07 11:56:56 -0800813 return instanceDir, instanceID, err
814 }
Todd Wang54feabe2015-04-15 23:38:26 -0700815 if err := saveInstanceInfo(ctx, instanceDir, instanceInfo); err != nil {
Bogdan Caprita26929102014-11-07 11:56:56 -0800816 return instanceDir, instanceID, err
817 }
Todd Wang4264e4b2015-04-16 22:43:40 -0700818 blessings, _ := security.RemoteBlessingNames(ctx, call.Security())
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700819 permsCopy := i.deviceAccessList.Copy()
820 if err := i.initializeSubAccessLists(instanceDir, blessings, permsCopy); err != nil {
Robert Kroegeracc778b2014-11-03 17:17:21 -0800821 return instanceDir, instanceID, err
822 }
Bogdan Caprita2b050322015-04-17 09:04:03 -0700823 if err := initializeInstance(instanceDir, device.InstanceStateNotRunning); err != nil {
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800824 return instanceDir, instanceID, err
825 }
Robert Kroeger9732f012015-03-16 13:41:25 -0700826 // TODO(rjkroege): Divide the permission lists into those used by the device manager
827 // and those used by the application itself.
Todd Wang4264e4b2015-04-16 22:43:40 -0700828 dmBlessings := security.LocalBlessingNames(ctx, call.Security())
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700829 if err := setPermsForDebugging(dmBlessings, permsCopy, instanceDir, i.permsStore); err != nil {
Robert Kroeger16ee22b2015-03-12 14:57:09 -0700830 return instanceDir, instanceID, err
831 }
Bogdan Caprita268b4192014-08-28 10:04:44 -0700832 return instanceDir, instanceID, nil
833}
834
Robert Kroegercc9f55d2015-05-20 16:25:36 -0700835func genCmd(ctx *context.T, instanceDir string, nsRoot string) (*exec.Cmd, error) {
836 systemName, err := readSystemNameForInstance(instanceDir)
837 if err != nil {
838 return nil, err
839 }
Robert Kroeger450fdf12015-05-19 14:40:42 -0700840
Bogdan Caprita268b4192014-08-28 10:04:44 -0700841 versionLink := filepath.Join(instanceDir, "version")
842 versionDir, err := filepath.EvalSymlinks(versionLink)
843 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700844 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", versionLink, err))
Bogdan Caprita268b4192014-08-28 10:04:44 -0700845 }
gauthamtfd1e34e2015-03-05 15:30:52 -0800846 envelope, err := loadEnvelope(ctx, versionDir)
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700847 if err != nil {
848 return nil, err
849 }
Bogdan Caprita268b4192014-08-28 10:04:44 -0700850 binPath := filepath.Join(versionDir, "bin")
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700851 if _, err := os.Stat(binPath); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700852 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Stat(%v) failed: %v", binPath, err))
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700853 }
Robert Kroegerdd07b362014-09-18 17:34:42 -0700854
Arup Mukherjee746444f2015-04-16 19:13:24 -0700855 saArgs := suidAppCmdArgs{targetUser: systemName, binpath: binPath}
Robert Kroegerdd07b362014-09-18 17:34:42 -0700856
Arup Mukherjee504a1e62015-02-25 11:09:56 -0800857 // Pass the displayed name of the program (argv0 as seen in ps output)
858 // Envelope data comes from the user so we sanitize it for safety
859 _, relativeBinaryName := naming.SplitAddressName(envelope.Binary.File)
860 rawAppName := envelope.Title + "@" + relativeBinaryName + "/app"
861 sanitize := func(r rune) rune {
862 if strconv.IsPrint(r) {
863 return r
864 } else {
865 return '_'
866 }
867 }
868 appName := strings.Map(sanitize, rawAppName)
Arup Mukherjee746444f2015-04-16 19:13:24 -0700869 saArgs.progname = appName
Arup Mukherjee504a1e62015-02-25 11:09:56 -0800870
Robin Thellendacaa4322015-02-05 11:00:28 -0800871 // Set the app's default namespace root to the local namespace.
Todd Wang8123b5e2015-05-14 18:44:43 -0700872 saArgs.env = []string{ref.EnvNamespacePrefix + "=" + nsRoot}
Arup Mukherjee746444f2015-04-16 19:13:24 -0700873 saArgs.env = append(saArgs.env, envelope.Env...)
Bogdan Caprita25d4faa2014-08-28 10:21:23 -0700874 rootDir := filepath.Join(instanceDir, "root")
Arup Mukherjee746444f2015-04-16 19:13:24 -0700875 saArgs.dir = rootDir
876 saArgs.workspace = rootDir
Robert Kroegerdd07b362014-09-18 17:34:42 -0700877
Bogdan Caprita25d4faa2014-08-28 10:21:23 -0700878 logDir := filepath.Join(instanceDir, "logs")
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700879 suidHelper.chownTree(ctx, suidHelper.getCurrentUser(), instanceDir, os.Stdout, os.Stdin)
880 if err := mkdirPerm(ctx, logDir, 0755); err != nil {
Bogdan Caprita25d4faa2014-08-28 10:21:23 -0700881 return nil, err
882 }
Arup Mukherjee746444f2015-04-16 19:13:24 -0700883 saArgs.logdir = logDir
Bogdan Caprita25d4faa2014-08-28 10:21:23 -0700884 timestamp := time.Now().UnixNano()
Robert Kroegera99ad142014-10-30 17:56:39 -0700885
Robert Kroegerdd07b362014-09-18 17:34:42 -0700886 stdoutLog := filepath.Join(logDir, fmt.Sprintf("STDOUT-%d", timestamp))
Arup Mukherjee746444f2015-04-16 19:13:24 -0700887 if saArgs.stdout, err = openWriteFile(stdoutLog); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700888 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("OpenFile(%v) failed: %v", stdoutLog, err))
Bogdan Caprita25d4faa2014-08-28 10:21:23 -0700889 }
Robert Kroegerdd07b362014-09-18 17:34:42 -0700890 stderrLog := filepath.Join(logDir, fmt.Sprintf("STDERR-%d", timestamp))
Arup Mukherjee746444f2015-04-16 19:13:24 -0700891 if saArgs.stderr, err = openWriteFile(stderrLog); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700892 return nil, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("OpenFile(%v) failed: %v", stderrLog, err))
Bogdan Caprita25d4faa2014-08-28 10:21:23 -0700893 }
Robert Kroegerdd07b362014-09-18 17:34:42 -0700894
Bogdan Caprita2556a6c2014-12-04 15:51:01 -0800895 // Args to be passed by helper to the app.
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800896 appArgs := []string{"--log_dir=../logs"}
897 appArgs = append(appArgs, envelope.Args...)
898
Arup Mukherjee746444f2015-04-16 19:13:24 -0700899 saArgs.appArgs = appArgs
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700900 return suidHelper.getAppCmd(ctx, &saArgs)
Bogdan Caprita268b4192014-08-28 10:04:44 -0700901}
902
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -0700903// instanceNameFromDir returns the instance name, given the instanceDir.
904func instanceNameFromDir(ctx *context.T, instanceDir string) (string, error) {
905 _, _, installation, instance := parseInstanceDir(instanceDir)
906 if installation == "" || instance == "" {
907 return "", fmt.Errorf("Unable to parse instanceDir %v", instanceDir)
908 }
909
910 env, err := loadEnvelopeForInstance(ctx, instanceDir)
911 if err != nil {
912 return "", err
913 }
914 return env.Title + "/" + installation + "/" + instance, nil
915}
916
Robert Kroegercc9f55d2015-05-20 16:25:36 -0700917func (i *appRunner) startCmd(ctx *context.T, instanceDir string, cmd *exec.Cmd) (int, error) {
gauthamtfd1e34e2015-03-05 15:30:52 -0800918 info, err := loadInstanceInfo(ctx, instanceDir)
Bogdan Caprita26929102014-11-07 11:56:56 -0800919 if err != nil {
Robert Kroeger936853a2015-01-28 17:42:55 -0800920 return 0, err
Bogdan Caprita26929102014-11-07 11:56:56 -0800921 }
Bogdan Caprita4d67c042014-08-19 10:41:19 -0700922 // Setup up the child process callback.
923 callbackState := i.callback
Bogdan Caprita78b62162014-08-21 15:35:08 -0700924 listener := callbackState.listenFor(mgmt.AppCycleManagerConfigKey)
925 defer listener.cleanup()
Cosmos Nicolaou486d3492014-09-30 22:21:20 -0700926 cfg := vexec.NewConfig()
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800927 installationLink := filepath.Join(instanceDir, "installation")
928 installationDir, err := filepath.EvalSymlinks(installationLink)
929 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -0700930 return 0, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", installationLink, err))
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800931 }
gauthamtfd1e34e2015-03-05 15:30:52 -0800932 config, err := loadConfig(ctx, installationDir)
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800933 if err != nil {
Robert Kroeger936853a2015-01-28 17:42:55 -0800934 return 0, err
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800935 }
936 for k, v := range config {
937 cfg.Set(k, v)
938 }
Jiri Simsaf57930f2014-11-05 15:19:31 -0800939 cfg.Set(mgmt.ParentNameConfigKey, listener.name())
940 cfg.Set(mgmt.ProtocolConfigKey, "tcp")
941 cfg.Set(mgmt.AddressConfigKey, "127.0.0.1:0")
Bogdan Caprita2b219362014-12-09 17:03:33 -0800942 cfg.Set(mgmt.ParentBlessingConfigKey, info.DeviceManagerPeerPattern)
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -0700943 cfg.Set(mgmt.PublisherBlessingPrefixesKey,
944 v23.GetPrincipal(ctx).BlessingStore().Default().String())
945
946 if instanceName, err := instanceNameFromDir(ctx, instanceDir); err != nil {
947 return 0, err
948 } else {
949 cfg.Set(mgmt.InstanceNameKey, naming.Join(i.appServiceName, instanceName))
950 }
Bogdan Caprita7f491672014-11-13 14:51:08 -0800951
Adam Sadovskya4d4a692015-04-20 11:36:49 -0700952 appPermsDir := filepath.Join(instanceDir, "debugacls", "data")
953 cfg.Set("v23.permissions.file", "runtime:"+appPermsDir)
Robert Kroeger9732f012015-03-16 13:41:25 -0700954
Arup Mukherjee9302a582015-04-06 11:48:18 -0700955 // This adds to cmd.Extrafiles. The helper expects a fixed fd, so this call needs
956 // to go before anything that conditionally adds to Extrafiles, like the agent
957 // setup code immediately below.
958 var handshaker appHandshaker
959 handshaker.prepareToStart(ctx, cmd)
960 defer handshaker.cleanup()
961
Bogdan Caprita7f491672014-11-13 14:51:08 -0800962 // Set up any agent-specific state.
Bogdan Caprita6613fc42015-01-28 11:54:23 -0800963 // NOTE(caprita): This ought to belong in genCmd.
Bogdan Caprita7f491672014-11-13 14:51:08 -0800964 var agentCleaner func()
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700965 stopServingAgentSocket := true
966 switch sa := i.securityAgent; {
967 case sa != nil && sa.keyMgr != nil:
968 sockPath, err := sockPath(instanceDir)
969 if err != nil {
970 return 0, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("failed to obtain socket path: %v", err))
971 }
972 if err := sa.keyMgr.ServePrincipal(info.handle(), sockPath); err != nil {
973 // TODO(caprita): Consider only logging a warning for
974 // verror.ErrExist errors if the principal is already
975 // serving. This may point to some unhandled corner
976 // cases, but at lest we'd not prevent the app from
977 // running.
978 return 0, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("ServePrincipal failed: %v", err))
979 }
Robin Thellendf0a422b2015-08-27 09:55:07 -0700980 cfg.Set(mgmt.SecurityAgentPathConfigKey, sockPath)
Bogdan Caprita19ccdee2015-08-21 11:12:33 -0700981 defer func() {
982 if !stopServingAgentSocket {
983 return
984 }
985 if err := sa.keyMgr.StopServing(info.handle()); err != nil {
986 ctx.Errorf("StopServing failed: %v", err)
987 }
988 }()
989 case sa != nil && sa.keyMgrAgent != nil:
990 // This code path is deprecated in favor of the socket agent
991 // connection.
Bogdan Caprita7f491672014-11-13 14:51:08 -0800992 file, err := sa.keyMgrAgent.NewConnection(info.SecurityAgentHandle)
993 if err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -0700994 ctx.Errorf("NewConnection(%v) failed: %v", info.SecurityAgentHandle, err)
Robert Kroeger936853a2015-01-28 17:42:55 -0800995 return 0, err
Bogdan Caprita7f491672014-11-13 14:51:08 -0800996 }
997 agentCleaner = func() {
998 file.Close()
Bogdan Caprita7f491672014-11-13 14:51:08 -0800999 }
1000 // We need to account for the file descriptors corresponding to
1001 // std{err|out|in} as well as the implementation-specific pipes
1002 // that the vexec library adds to ExtraFiles during
1003 // handle.Start. vexec.FileOffset properly offsets fd
1004 // accordingly.
1005 fd := len(cmd.ExtraFiles) + vexec.FileOffset
1006 cmd.ExtraFiles = append(cmd.ExtraFiles, file)
Ryan Brown7f950a82015-04-20 18:08:39 -07001007 ep := agentlib.AgentEndpoint(fd)
1008 cfg.Set(mgmt.SecurityAgentEndpointConfigKey, ep)
Bogdan Caprita19ccdee2015-08-21 11:12:33 -07001009 default:
Todd Wang8123b5e2015-05-14 18:44:43 -07001010 cmd.Env = append(cmd.Env, ref.EnvCredentials+"="+filepath.Join(instanceDir, "credentials"))
Bogdan Caprita7f491672014-11-13 14:51:08 -08001011 }
Arup Mukherjeee4d75c92015-05-18 19:10:02 -07001012 handle := vexec.NewParentHandle(cmd, vexec.ConfigOpt{Config: cfg})
Bogdan Caprita268b4192014-08-28 10:04:44 -07001013 defer func() {
1014 if handle != nil {
1015 if err := handle.Clean(); err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001016 ctx.Errorf("Clean() failed: %v", err)
Bogdan Caprita268b4192014-08-28 10:04:44 -07001017 }
1018 }
1019 }()
Arup Mukherjee9302a582015-04-06 11:48:18 -07001020
Bogdan Caprita4d67c042014-08-19 10:41:19 -07001021 // Start the child process.
Arup Mukherjee9302a582015-04-06 11:48:18 -07001022 startErr := handle.Start()
Bogdan Caprita2b050322015-04-17 09:04:03 -07001023 // Perform unconditional cleanup before dealing with any error from
1024 // handle.Start()
Bogdan Caprita7f491672014-11-13 14:51:08 -08001025 if agentCleaner != nil {
1026 agentCleaner()
1027 }
Arup Mukherjee9302a582015-04-06 11:48:18 -07001028 // Now react to any error in handle.Start()
1029 if startErr != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001030 return 0, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Start() failed: %v", err))
Arup Mukherjee9302a582015-04-06 11:48:18 -07001031 }
Bogdan Caprita7f491672014-11-13 14:51:08 -08001032
Bogdan Caprita2b050322015-04-17 09:04:03 -07001033 // Wait for the suidhelper to exit. This is blocking as we assume the
1034 // helper won't get stuck.
Robert Kroeger6f8ca632015-04-01 13:57:45 -07001035 if err := handle.Wait(0); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001036 return 0, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Wait() on suidhelper failed: %v", err))
Robert Kroeger6f8ca632015-04-01 13:57:45 -07001037 }
1038
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001039 pid, childName, err := handshaker.doHandshake(ctx, handle, listener)
Arup Mukherjee9302a582015-04-06 11:48:18 -07001040
Bogdan Caprita78b62162014-08-21 15:35:08 -07001041 if err != nil {
Arup Mukherjee9302a582015-04-06 11:48:18 -07001042 return 0, err
Bogdan Caprita4d67c042014-08-19 10:41:19 -07001043 }
Robert Kroegerb5d6bda2015-01-30 16:10:49 -08001044
Robert Kroegerb5d6bda2015-01-30 16:10:49 -08001045 info.AppCycleMgrName, info.Pid = childName, pid
gauthamtfd1e34e2015-03-05 15:30:52 -08001046 if err := saveInstanceInfo(ctx, instanceDir, info); err != nil {
Robert Kroeger936853a2015-01-28 17:42:55 -08001047 return 0, err
Bogdan Caprita78b62162014-08-21 15:35:08 -07001048 }
Bogdan Caprita268b4192014-08-28 10:04:44 -07001049 handle = nil
Bogdan Caprita19ccdee2015-08-21 11:12:33 -07001050 stopServingAgentSocket = false
Robert Kroeger936853a2015-01-28 17:42:55 -08001051 return pid, nil
Bogdan Caprita268b4192014-08-28 10:04:44 -07001052}
1053
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001054func (i *appRunner) run(ctx *context.T, instanceDir string) error {
1055 if err := transitionInstance(instanceDir, device.InstanceStateNotRunning, device.InstanceStateLaunching); err != nil {
Bogdan Caprita268b4192014-08-28 10:04:44 -07001056 return err
1057 }
Robert Kroeger936853a2015-01-28 17:42:55 -08001058 var pid int
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001059
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001060 cmd, err := genCmd(ctx, instanceDir, i.mtAddress)
Bogdan Caprita268b4192014-08-28 10:04:44 -07001061 if err == nil {
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001062 pid, err = i.startCmd(ctx, instanceDir, cmd)
Bogdan Caprita268b4192014-08-28 10:04:44 -07001063 }
1064 if err != nil {
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001065 transitionInstance(instanceDir, device.InstanceStateLaunching, device.InstanceStateNotRunning)
Bogdan Caprita268b4192014-08-28 10:04:44 -07001066 return err
1067 }
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001068 if err := transitionInstance(instanceDir, device.InstanceStateLaunching, device.InstanceStateRunning); err != nil {
Robert Kroeger936853a2015-01-28 17:42:55 -08001069 return err
1070 }
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001071 i.reap.startWatching(instanceDir, pid)
Robert Kroeger936853a2015-01-28 17:42:55 -08001072 return nil
Bogdan Caprita268b4192014-08-28 10:04:44 -07001073}
1074
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001075func synchronizedShouldRestart(ctx *context.T, instanceDir string) bool {
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001076 info, err := loadInstanceInfo(nil, instanceDir)
1077 if err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001078 ctx.Error(err)
Robert Kroeger68d24342015-06-03 17:42:10 -07001079 return false
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001080 }
1081
1082 envelope, err := loadEnvelopeForInstance(nil, instanceDir)
1083 if err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001084 ctx.Error(err)
Robert Kroeger68d24342015-06-03 17:42:10 -07001085 return false
1086 }
1087
1088 shouldRestart := newBasicRestartPolicy().decide(envelope, info)
1089
1090 if err := saveInstanceInfo(nil, instanceDir, info); err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001091 ctx.Error(err)
Robert Kroeger68d24342015-06-03 17:42:10 -07001092 return false
1093 }
1094 return shouldRestart
1095}
1096
Robert Kroegerec2e5af2015-06-11 13:05:08 -07001097// restartAppIfNecessary restarts an application if its daemon
1098// configuration indicates that it should be running but the reaping
1099// functionality has previously determined that it is not.
1100// TODO(rjkroege): This routine has a low-likelyhood race condition in
1101// which it fails to restart an application when the app crashes and the
1102// device manager then crashes between the reaper marking the app not
1103// running and the go routine invoking this function having a chance to
1104// complete.
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -07001105func (i *appRunner) restartAppIfNecessary(ctx *context.T, instanceDir string) {
Robert Kroeger68d24342015-06-03 17:42:10 -07001106 if err := transitionInstance(instanceDir, device.InstanceStateNotRunning, device.InstanceStateLaunching); err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001107 ctx.Error(err)
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001108 return
1109 }
Bogdan Caprita19ccdee2015-08-21 11:12:33 -07001110 // TODO(caprita): Putting the StopServing call here means that the
1111 // socket is still serving after the app instance has been transitioned
1112 // in state 'not running'. This creates the possibility of a Run()
1113 // happening after the app state has changed to 'not running' in the
1114 // reaper, but before restartAppIfNecessary has a chance to execute
1115 // (resulting int he ServePrincipal call failing). We should either
1116 // move the StopServing call before we transition the instance to 'not
1117 // running', or make the ServePrincipal robust w.r.t. already serving
1118 // state.
1119 if sa := i.securityAgent; sa != nil && sa.keyMgr != nil {
1120 info, err := loadInstanceInfo(ctx, instanceDir)
1121 if err != nil {
1122 ctx.Errorf("Failed to load instance info: %v", err)
1123 }
1124 if err := sa.keyMgr.StopServing(info.handle()); err != nil {
1125 ctx.Errorf("StopServing failed: %v", err)
1126 }
1127 }
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001128 shouldRestart := synchronizedShouldRestart(ctx, instanceDir)
Robert Kroeger68d24342015-06-03 17:42:10 -07001129
1130 if err := transitionInstance(instanceDir, device.InstanceStateLaunching, device.InstanceStateNotRunning); err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001131 ctx.Error(err)
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001132 return
1133 }
1134
Robert Kroeger68d24342015-06-03 17:42:10 -07001135 if !shouldRestart {
1136 return
1137 }
1138
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -07001139 if err := i.run(ctx, instanceDir); err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001140 ctx.Error(err)
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001141 }
1142}
1143
Bogdan Caprita2b050322015-04-17 09:04:03 -07001144func (i *appService) Instantiate(ctx *context.T, call device.ApplicationInstantiateServerCall) (string, error) {
Robert Kroeger94ec7562014-10-28 17:58:44 -07001145 helper := i.config.Helper
Todd Wang54feabe2015-04-15 23:38:26 -07001146 instanceDir, instanceID, err := i.newInstance(ctx, call)
Bogdan Caprita268b4192014-08-28 10:04:44 -07001147 if err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001148 CleanupDir(ctx, instanceDir, helper)
Bogdan Caprita2b050322015-04-17 09:04:03 -07001149 return "", err
Bogdan Caprita268b4192014-08-28 10:04:44 -07001150 }
Todd Wang4264e4b2015-04-16 22:43:40 -07001151 systemName := suidHelper.usernameForPrincipal(ctx, call.Security(), i.uat)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001152 if err := saveSystemNameForInstance(instanceDir, systemName); err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001153 CleanupDir(ctx, instanceDir, helper)
Bogdan Caprita2b050322015-04-17 09:04:03 -07001154 return "", err
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001155 }
Bogdan Caprita2b050322015-04-17 09:04:03 -07001156 return instanceID, nil
Bogdan Caprita4d67c042014-08-19 10:41:19 -07001157}
1158
Bogdan Caprita2968f4b2014-08-22 14:11:58 -07001159// instanceDir returns the path to the directory containing the app instance
Robin Thellend4c5266e2014-10-27 13:19:29 -07001160// referred to by the given suffix relative to the given root directory.
gauthamtfd1e34e2015-03-05 15:30:52 -08001161// TODO(gauthamt): Make sure we pass the context to instanceDir.
Robin Thellend4c5266e2014-10-27 13:19:29 -07001162func instanceDir(root string, suffix []string) (string, error) {
1163 if nComponents := len(suffix); nComponents != 3 {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001164 return "", verror.New(errors.ErrInvalidSuffix, nil)
Robin Thellend4c5266e2014-10-27 13:19:29 -07001165 }
1166 app, installation, instance := suffix[0], suffix[1], suffix[2]
1167 instancesDir := filepath.Join(root, applicationDirName(app), installationDirName(installation), "instances")
1168 instanceDir := filepath.Join(instancesDir, instanceDirName(instance))
1169 return instanceDir, nil
1170}
1171
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -07001172// parseInstanceDir is a partial inverse of instanceDir. It cannot retrieve the app name,
1173// as that has been hashed so it returns an appDir instead.
1174func parseInstanceDir(dir string) (prefix, appDir, installation, instance string) {
1175 dirRE := regexp.MustCompile("(/.*)(/" + appDirPrefix + "[^/]+)/" + installationPrefix + "([^/]+)/" + "instances/" + instancePrefix + "([^/]+)$")
1176 matches := dirRE.FindStringSubmatch(dir)
1177 if len(matches) < 5 {
1178 return "", "", "", ""
1179 }
1180 return matches[1], matches[2], matches[3], matches[4]
1181}
1182
Robin Thellend4c5266e2014-10-27 13:19:29 -07001183// instanceDir returns the path to the directory containing the app instance
Bogdan Caprita2b050322015-04-17 09:04:03 -07001184// referred to by the invoker's suffix, as well as the corresponding not-running
Bogdan Caprita2968f4b2014-08-22 14:11:58 -07001185// instance dir. Returns an error if the suffix does not name an instance.
Robin Thellend9bc8fcb2014-11-17 10:23:04 -08001186func (i *appService) instanceDir() (string, error) {
Robin Thellend4c5266e2014-10-27 13:19:29 -07001187 return instanceDir(i.config.Root, i.suffix)
Bogdan Caprita268b4192014-08-28 10:04:44 -07001188}
1189
Bogdan Caprita2b050322015-04-17 09:04:03 -07001190func (i *appService) Run(ctx *context.T, call rpc.ServerCall) error {
Bogdan Caprita268b4192014-08-28 10:04:44 -07001191 instanceDir, err := i.instanceDir()
1192 if err != nil {
1193 return err
1194 }
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001195
Todd Wang4264e4b2015-04-16 22:43:40 -07001196 systemName := suidHelper.usernameForPrincipal(ctx, call.Security(), i.uat)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001197 startSystemName, err := readSystemNameForInstance(instanceDir)
1198 if err != nil {
1199 return err
1200 }
1201
1202 if startSystemName != systemName {
Todd Wang54feabe2015-04-15 23:38:26 -07001203 return verror.New(verror.ErrNoAccess, ctx, "Not allowed to resume an application under a different system name.")
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001204 }
Bogdan Caprita52ff4f82015-08-28 09:53:07 -07001205
1206 // TODO(caprita): We should reset the Restarts and RestartWindowBegan
1207 // fields in the instance info when the instance is started with Run.
1208
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001209 return i.runner.run(ctx, instanceDir)
Bogdan Caprita2968f4b2014-08-22 14:11:58 -07001210}
1211
Arup Mukherjee746444f2015-04-16 19:13:24 -07001212func stopAppRemotely(ctx *context.T, appVON string, deadline time.Duration) error {
Todd Wang702385a2014-11-07 01:54:08 -08001213 appStub := appcycle.AppCycleClient(appVON)
Arup Mukherjee746444f2015-04-16 19:13:24 -07001214 ctx, cancel := context.WithTimeout(ctx, deadline)
Bogdan Caprita2968f4b2014-08-22 14:11:58 -07001215 defer cancel()
1216 stream, err := appStub.Stop(ctx)
1217 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001218 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("%v.Stop() failed: %v", appVON, err))
Bogdan Caprita2968f4b2014-08-22 14:11:58 -07001219 }
1220 rstream := stream.RecvStream()
1221 for rstream.Advance() {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001222 ctx.VI(2).Infof("%v.Stop() task update: %v", appVON, rstream.Value())
Bogdan Caprita2968f4b2014-08-22 14:11:58 -07001223 }
1224 if err := rstream.Err(); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001225 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Advance() failed: %v", err))
Bogdan Caprita2968f4b2014-08-22 14:11:58 -07001226 }
1227 if err := stream.Finish(); err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001228 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Finish() failed: %v", err))
Bogdan Caprita2968f4b2014-08-22 14:11:58 -07001229 }
1230 return nil
1231}
1232
Bogdan Caprita19ccdee2015-08-21 11:12:33 -07001233func (i *appService) stop(ctx *context.T, instanceDir string, reap *reaper, deadline time.Duration) error {
gauthamtfd1e34e2015-03-05 15:30:52 -08001234 info, err := loadInstanceInfo(ctx, instanceDir)
Bogdan Caprita2968f4b2014-08-22 14:11:58 -07001235 if err != nil {
1236 return err
1237 }
Arup Mukherjee746444f2015-04-16 19:13:24 -07001238 err = stopAppRemotely(ctx, info.AppCycleMgrName, deadline)
1239 reap.forciblySuspend(instanceDir)
Robert Kroeger936853a2015-01-28 17:42:55 -08001240 if err == nil {
1241 reap.stopWatching(instanceDir)
Bogdan Caprita19ccdee2015-08-21 11:12:33 -07001242 if sa := i.runner.securityAgent; sa != nil && sa.keyMgr != nil {
1243 if err := sa.keyMgr.StopServing(info.handle()); err != nil {
1244 ctx.Errorf("StopServing failed: %v", err)
1245 }
1246 }
Robert Kroeger936853a2015-01-28 17:42:55 -08001247 }
1248 return err
Bogdan Caprita4d67c042014-08-19 10:41:19 -07001249}
1250
Bogdan Caprita2b050322015-04-17 09:04:03 -07001251func (i *appService) Delete(ctx *context.T, _ rpc.ServerCall) error {
Bogdan Caprita268b4192014-08-28 10:04:44 -07001252 instanceDir, err := i.instanceDir()
1253 if err != nil {
1254 return err
1255 }
Bogdan Caprita2b050322015-04-17 09:04:03 -07001256 return transitionInstance(instanceDir, device.InstanceStateNotRunning, device.InstanceStateDeleted)
1257}
1258
1259func (i *appService) Kill(ctx *context.T, _ rpc.ServerCall, deadline time.Duration) error {
1260 instanceDir, err := i.instanceDir()
1261 if err != nil {
Bogdan Caprita268b4192014-08-28 10:04:44 -07001262 return err
1263 }
Bogdan Caprita2b050322015-04-17 09:04:03 -07001264 if err := transitionInstance(instanceDir, device.InstanceStateRunning, device.InstanceStateDying); err != nil {
Bogdan Caprita268b4192014-08-28 10:04:44 -07001265 return err
1266 }
Bogdan Caprita19ccdee2015-08-21 11:12:33 -07001267 if err := i.stop(ctx, instanceDir, i.runner.reap, deadline); err != nil {
Bogdan Caprita2b050322015-04-17 09:04:03 -07001268 transitionInstance(instanceDir, device.InstanceStateDying, device.InstanceStateRunning)
Bogdan Caprita268b4192014-08-28 10:04:44 -07001269 return err
1270 }
Bogdan Caprita2b050322015-04-17 09:04:03 -07001271 return transitionInstance(instanceDir, device.InstanceStateDying, device.InstanceStateNotRunning)
Bogdan Caprita4d67c042014-08-19 10:41:19 -07001272}
1273
Todd Wang54feabe2015-04-15 23:38:26 -07001274func (i *appService) Uninstall(*context.T, rpc.ServerCall) error {
Bogdan Caprita8c776b22014-08-28 17:29:07 -07001275 installationDir, err := i.installationDir()
1276 if err != nil {
1277 return err
1278 }
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001279 return transitionInstallation(installationDir, device.InstallationStateActive, device.InstallationStateUninstalled)
Bogdan Caprita8c776b22014-08-28 17:29:07 -07001280}
1281
Bogdan Capritaa48f7ee2015-05-27 10:34:59 -07001282func updateInstance(ctx *context.T, instanceDir string) (err error) {
Bogdan Caprita2b050322015-04-17 09:04:03 -07001283 // Only not-running instances can be updated.
1284 if err := transitionInstance(instanceDir, device.InstanceStateNotRunning, device.InstanceStateUpdating); err != nil {
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -08001285 return err
1286 }
1287 defer func() {
Bogdan Caprita2b050322015-04-17 09:04:03 -07001288 terr := transitionInstance(instanceDir, device.InstanceStateUpdating, device.InstanceStateNotRunning)
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -08001289 if err == nil {
1290 err = terr
1291 }
1292 }()
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -08001293 // Check if a newer version of the installation is available.
1294 versionLink := filepath.Join(instanceDir, "version")
1295 versionDir, err := filepath.EvalSymlinks(versionLink)
1296 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001297 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", versionLink, err))
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -08001298 }
1299 latestVersionLink := filepath.Join(instanceDir, "installation", "current")
1300 latestVersionDir, err := filepath.EvalSymlinks(latestVersionLink)
1301 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001302 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", latestVersionLink, err))
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -08001303 }
1304 if versionDir == latestVersionDir {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001305 return verror.New(errors.ErrUpdateNoOp, ctx)
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -08001306 }
1307 // Update to the newer version. Note, this is the only mutation
1308 // performed to the instance, and, since it's atomic, the state of the
1309 // instance is consistent at all times.
Bogdan Caprita0bae4ea2015-06-23 22:55:22 -07001310 return UpdateLink(latestVersionDir, versionLink)
Bogdan Caprita942f73f2015-02-25 09:24:30 -08001311}
1312
gauthamtfd1e34e2015-03-05 15:30:52 -08001313func updateInstallation(ctx *context.T, installationDir string) error {
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001314 if !installationStateIs(installationDir, device.InstallationStateActive) {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001315 return verror.New(errors.ErrInvalidOperation, ctx)
Bogdan Capritabce0a632014-09-03 16:15:26 -07001316 }
gauthamtfd1e34e2015-03-05 15:30:52 -08001317 originVON, err := loadOrigin(ctx, installationDir)
Bogdan Capritabce0a632014-09-03 16:15:26 -07001318 if err != nil {
1319 return err
1320 }
Matt Rosencrantz94502cf2015-03-18 09:43:44 -07001321 ctx, cancel := context.WithTimeout(ctx, rpcContextLongTimeout)
Bogdan Capritabce0a632014-09-03 16:15:26 -07001322 defer cancel()
1323 newEnvelope, err := fetchAppEnvelope(ctx, originVON)
1324 if err != nil {
1325 return err
1326 }
1327 currLink := filepath.Join(installationDir, "current")
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -07001328 oldVersionDir, err := filepath.EvalSymlinks(currLink)
1329 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001330 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", currLink, err))
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -07001331 }
Bogdan Capritabce0a632014-09-03 16:15:26 -07001332 // NOTE(caprita): A race can occur between two competing updates, where
1333 // both use the old version as their baseline. This can result in both
1334 // updates succeeding even if they are updating the app installation to
1335 // the same new envelope. This will result in one of the updates
1336 // becoming the new 'current'. Both versions will point their
1337 // 'previous' link to the old version. This doesn't appear to be of
1338 // practical concern, so we avoid the complexity of synchronizing
1339 // updates.
gauthamtfd1e34e2015-03-05 15:30:52 -08001340 oldEnvelope, err := loadEnvelope(ctx, oldVersionDir)
Bogdan Capritabce0a632014-09-03 16:15:26 -07001341 if err != nil {
1342 return err
1343 }
1344 if oldEnvelope.Title != newEnvelope.Title {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001345 return verror.New(errors.ErrAppTitleMismatch, ctx)
Bogdan Capritabce0a632014-09-03 16:15:26 -07001346 }
1347 if reflect.DeepEqual(oldEnvelope, newEnvelope) {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001348 return verror.New(errors.ErrUpdateNoOp, ctx)
Bogdan Capritabce0a632014-09-03 16:15:26 -07001349 }
Bogdan Caprita942f73f2015-02-25 09:24:30 -08001350 versionDir, err := newVersion(ctx, installationDir, newEnvelope, oldVersionDir)
Bogdan Capritabce0a632014-09-03 16:15:26 -07001351 if err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001352 CleanupDir(ctx, versionDir, "")
Bogdan Capritabce0a632014-09-03 16:15:26 -07001353 return err
1354 }
Bogdan Caprita4d67c042014-08-19 10:41:19 -07001355 return nil
1356}
1357
Todd Wang54feabe2015-04-15 23:38:26 -07001358func (i *appService) Update(ctx *context.T, _ rpc.ServerCall) error {
Bogdan Caprita942f73f2015-02-25 09:24:30 -08001359 if installationDir, err := i.installationDir(); err == nil {
Todd Wang54feabe2015-04-15 23:38:26 -07001360 return updateInstallation(ctx, installationDir)
Bogdan Caprita942f73f2015-02-25 09:24:30 -08001361 }
1362 if instanceDir, err := i.instanceDir(); err == nil {
Bogdan Capritaa48f7ee2015-05-27 10:34:59 -07001363 return updateInstance(ctx, instanceDir)
Bogdan Caprita942f73f2015-02-25 09:24:30 -08001364 }
Bogdan Caprita040603b2015-06-23 18:19:30 -07001365 return verror.New(errors.ErrInvalidSuffix, nil)
Bogdan Caprita942f73f2015-02-25 09:24:30 -08001366}
1367
Todd Wang54feabe2015-04-15 23:38:26 -07001368func (*appService) UpdateTo(_ *context.T, _ rpc.ServerCall, von string) error {
Bogdan Caprita4d67c042014-08-19 10:41:19 -07001369 // TODO(jsimsa): Implement.
1370 return nil
1371}
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -07001372
Bogdan Capritaa48f7ee2015-05-27 10:34:59 -07001373func revertInstance(ctx *context.T, instanceDir string) (err error) {
1374 // Only not-running instances can be reverted.
1375 if err := transitionInstance(instanceDir, device.InstanceStateNotRunning, device.InstanceStateUpdating); err != nil {
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -07001376 return err
1377 }
Bogdan Capritaa48f7ee2015-05-27 10:34:59 -07001378 defer func() {
1379 terr := transitionInstance(instanceDir, device.InstanceStateUpdating, device.InstanceStateNotRunning)
1380 if err == nil {
1381 err = terr
1382 }
1383 }()
1384 versionLink := filepath.Join(instanceDir, "version")
1385 versionDir, err := filepath.EvalSymlinks(versionLink)
1386 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001387 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", versionLink, err))
Bogdan Capritaa48f7ee2015-05-27 10:34:59 -07001388 }
1389 previousLink := filepath.Join(versionDir, "previous")
1390 if _, err := os.Lstat(previousLink); err != nil {
1391 if os.IsNotExist(err) {
1392 // No 'previous' link -- must be the first version.
Bogdan Caprita040603b2015-06-23 18:19:30 -07001393 return verror.New(errors.ErrUpdateNoOp, ctx)
Bogdan Capritaa48f7ee2015-05-27 10:34:59 -07001394 }
Bogdan Caprita040603b2015-06-23 18:19:30 -07001395 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Lstat(%v) failed: %v", previousLink, err))
Bogdan Capritaa48f7ee2015-05-27 10:34:59 -07001396 }
1397 prevVersionDir, err := filepath.EvalSymlinks(previousLink)
1398 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001399 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", previousLink, err))
Bogdan Capritaa48f7ee2015-05-27 10:34:59 -07001400 }
Bogdan Caprita0bae4ea2015-06-23 22:55:22 -07001401 return UpdateLink(prevVersionDir, versionLink)
Bogdan Capritaa48f7ee2015-05-27 10:34:59 -07001402}
1403
1404func revertInstallation(ctx *context.T, installationDir string) error {
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001405 if !installationStateIs(installationDir, device.InstallationStateActive) {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001406 return verror.New(errors.ErrInvalidOperation, ctx)
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -07001407 }
1408 // NOTE(caprita): A race can occur between an update and a revert, where
1409 // both use the same current version as their starting point. This will
1410 // render the update inconsequential. This doesn't appear to be of
1411 // practical concern, so we avoid the complexity of synchronizing
1412 // updates and revert operations.
1413 currLink := filepath.Join(installationDir, "current")
1414 currVersionDir, err := filepath.EvalSymlinks(currLink)
1415 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001416 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", currLink, err))
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -07001417 }
1418 previousLink := filepath.Join(currVersionDir, "previous")
1419 if _, err := os.Lstat(previousLink); err != nil {
1420 if os.IsNotExist(err) {
1421 // No 'previous' link -- must be the first version.
Bogdan Caprita040603b2015-06-23 18:19:30 -07001422 return verror.New(errors.ErrUpdateNoOp, ctx)
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -07001423 }
Bogdan Caprita040603b2015-06-23 18:19:30 -07001424 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("Lstat(%v) failed: %v", previousLink, err))
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -07001425 }
1426 prevVersionDir, err := filepath.EvalSymlinks(previousLink)
1427 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001428 return verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", previousLink, err))
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -07001429 }
Bogdan Caprita0bae4ea2015-06-23 22:55:22 -07001430 return UpdateLink(prevVersionDir, currLink)
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -07001431}
Robin Thellend09929f42014-10-01 10:18:13 -07001432
Bogdan Capritaa48f7ee2015-05-27 10:34:59 -07001433func (i *appService) Revert(ctx *context.T, _ rpc.ServerCall) error {
1434 if installationDir, err := i.installationDir(); err == nil {
1435 return revertInstallation(ctx, installationDir)
1436 }
1437 if instanceDir, err := i.instanceDir(); err == nil {
1438 return revertInstance(ctx, instanceDir)
1439 }
Bogdan Caprita040603b2015-06-23 18:19:30 -07001440 return verror.New(errors.ErrInvalidSuffix, nil)
Bogdan Capritaa48f7ee2015-05-27 10:34:59 -07001441}
1442
Robin Thellend9e523a62014-10-07 16:19:53 -07001443type treeNode struct {
1444 children map[string]*treeNode
1445}
1446
1447func newTreeNode() *treeNode {
Robin Thellendb9dd9bb2014-10-29 13:54:08 -07001448 return &treeNode{children: make(map[string]*treeNode)}
Robin Thellend9e523a62014-10-07 16:19:53 -07001449}
1450
1451func (n *treeNode) find(names []string, create bool) *treeNode {
1452 for {
1453 if len(names) == 0 {
1454 return n
1455 }
1456 if next, ok := n.children[names[0]]; ok {
1457 n = next
1458 names = names[1:]
1459 continue
1460 }
1461 if create {
1462 nn := newTreeNode()
1463 n.children[names[0]] = nn
1464 n = nn
1465 names = names[1:]
1466 continue
1467 }
1468 return nil
1469 }
1470}
1471
gauthamtfd1e34e2015-03-05 15:30:52 -08001472func (i *appService) scanEnvelopes(ctx *context.T, tree *treeNode, appDir string) {
Robin Thellendac7128c2014-11-11 09:58:28 -08001473 // Find all envelopes, extract installID.
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -07001474 envGlob := []string{i.config.Root, appDir, installationPrefix + "*", "*", "envelope"}
Robin Thellend9e523a62014-10-07 16:19:53 -07001475 envelopes, err := filepath.Glob(filepath.Join(envGlob...))
1476 if err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001477 ctx.Errorf("unexpected error: %v", err)
Robin Thellendac7128c2014-11-11 09:58:28 -08001478 return
Robin Thellend9e523a62014-10-07 16:19:53 -07001479 }
1480 for _, path := range envelopes {
gauthamtfd1e34e2015-03-05 15:30:52 -08001481 env, err := loadEnvelope(ctx, filepath.Dir(path))
Robin Thellend9e523a62014-10-07 16:19:53 -07001482 if err != nil {
1483 continue
1484 }
1485 relpath, _ := filepath.Rel(i.config.Root, path)
1486 elems := strings.Split(relpath, string(filepath.Separator))
1487 if len(elems) != len(envGlob)-1 {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001488 ctx.Errorf("unexpected number of path components: %q (%q)", elems, path)
Robin Thellend9e523a62014-10-07 16:19:53 -07001489 continue
1490 }
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -07001491 installID := strings.TrimPrefix(elems[1], installationPrefix)
Robin Thellend9e523a62014-10-07 16:19:53 -07001492 tree.find([]string{env.Title, installID}, true)
1493 }
Robin Thellendac7128c2014-11-11 09:58:28 -08001494 return
1495}
Robin Thellend9e523a62014-10-07 16:19:53 -07001496
gauthamtfd1e34e2015-03-05 15:30:52 -08001497func (i *appService) scanInstances(ctx *context.T, tree *treeNode) {
Robin Thellendac7128c2014-11-11 09:58:28 -08001498 if len(i.suffix) < 2 {
1499 return
1500 }
1501 title := i.suffix[0]
1502 installDir, err := installationDirCore(i.suffix[:2], i.config.Root)
1503 if err != nil {
1504 return
1505 }
Bogdan Caprita43bc7372014-12-03 21:51:12 -08001506 // Add the node corresponding to the installation itself.
1507 tree.find(i.suffix[:2], true)
Robin Thellend9e523a62014-10-07 16:19:53 -07001508 // Find all instances.
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -07001509 infoGlob := []string{installDir, "instances", instancePrefix + "*", "info"}
Robin Thellend9e523a62014-10-07 16:19:53 -07001510 instances, err := filepath.Glob(filepath.Join(infoGlob...))
1511 if err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001512 ctx.Errorf("unexpected error: %v", err)
Robin Thellendac7128c2014-11-11 09:58:28 -08001513 return
Robin Thellend9e523a62014-10-07 16:19:53 -07001514 }
1515 for _, path := range instances {
Robin Thellend4c5266e2014-10-27 13:19:29 -07001516 instanceDir := filepath.Dir(path)
gauthamtfd1e34e2015-03-05 15:30:52 -08001517 i.scanInstance(ctx, tree, title, instanceDir)
Robin Thellendac7128c2014-11-11 09:58:28 -08001518 }
1519 return
1520}
1521
gauthamtfd1e34e2015-03-05 15:30:52 -08001522func (i *appService) scanInstance(ctx *context.T, tree *treeNode, title, instanceDir string) {
1523 if _, err := loadInstanceInfo(ctx, instanceDir); err != nil {
Robin Thellendac7128c2014-11-11 09:58:28 -08001524 return
1525 }
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -07001526 rootDir, _, installID, instanceID := parseInstanceDir(instanceDir)
1527 if installID == "" || instanceID == "" || filepath.Clean(i.config.Root) != filepath.Clean(rootDir) {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001528 ctx.Errorf("failed to parse instanceDir %v (got: %v %v %v)", instanceDir, rootDir, installID, instanceID)
Robin Thellendac7128c2014-11-11 09:58:28 -08001529 return
1530 }
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -07001531
Robin Thellendac7128c2014-11-11 09:58:28 -08001532 tree.find([]string{title, installID, instanceID, "logs"}, true)
Bogdan Caprita2b050322015-04-17 09:04:03 -07001533 if instanceStateIs(instanceDir, device.InstanceStateRunning) {
Robin Thellendac7128c2014-11-11 09:58:28 -08001534 for _, obj := range []string{"pprof", "stats"} {
1535 tree.find([]string{title, installID, instanceID, obj}, true)
1536 }
1537 }
1538}
1539
Robin Thellendf15f2952015-07-17 21:49:58 -07001540func (i *appService) GlobChildren__(ctx *context.T, call rpc.GlobChildrenServerCall, m *glob.Element) error {
Robin Thellendac7128c2014-11-11 09:58:28 -08001541 tree := newTreeNode()
1542 switch len(i.suffix) {
1543 case 0:
Arup Mukherjee9d52e0d2015-06-27 00:47:30 -07001544 i.scanEnvelopes(ctx, tree, appDirPrefix+"*")
Robin Thellendac7128c2014-11-11 09:58:28 -08001545 case 1:
1546 appDir := applicationDirName(i.suffix[0])
Todd Wang54feabe2015-04-15 23:38:26 -07001547 i.scanEnvelopes(ctx, tree, appDir)
Robin Thellendac7128c2014-11-11 09:58:28 -08001548 case 2:
Todd Wang54feabe2015-04-15 23:38:26 -07001549 i.scanInstances(ctx, tree)
Robin Thellendac7128c2014-11-11 09:58:28 -08001550 case 3:
1551 dir, err := i.instanceDir()
Robin Thellendb9dd9bb2014-10-29 13:54:08 -07001552 if err != nil {
Robin Thellendac7128c2014-11-11 09:58:28 -08001553 break
Robin Thellend9e523a62014-10-07 16:19:53 -07001554 }
Todd Wang54feabe2015-04-15 23:38:26 -07001555 i.scanInstance(ctx, tree, i.suffix[0], dir)
Robin Thellendac7128c2014-11-11 09:58:28 -08001556 default:
Robin Thellendf15f2952015-07-17 21:49:58 -07001557 return verror.New(verror.ErrNoExist, nil, i.suffix)
Robin Thellend9e523a62014-10-07 16:19:53 -07001558 }
Robin Thellendac7128c2014-11-11 09:58:28 -08001559 n := tree.find(i.suffix, false)
Robin Thellend9e523a62014-10-07 16:19:53 -07001560 if n == nil {
Robin Thellendf15f2952015-07-17 21:49:58 -07001561 return verror.New(errors.ErrInvalidSuffix, nil)
Robin Thellend09929f42014-10-01 10:18:13 -07001562 }
Robin Thellendf15f2952015-07-17 21:49:58 -07001563 for child, _ := range n.children {
1564 if m.Match(child) {
Jiri Simsad9a7b3c2015-08-12 16:38:27 -07001565 call.SendStream().Send(naming.GlobChildrenReplyName{Value: child})
Robin Thellend8e9cc242014-11-26 09:43:10 -08001566 }
Robin Thellendf15f2952015-07-17 21:49:58 -07001567 }
1568 return nil
Robin Thellendb9dd9bb2014-10-29 13:54:08 -07001569}
Robert Kroegeracc778b2014-11-03 17:17:21 -08001570
1571// TODO(rjkroege): Refactor to eliminate redundancy with newAppSpecificAuthorizer.
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001572func dirFromSuffix(ctx *context.T, suffix []string, root string) (string, bool, error) {
Robert Kroegeracc778b2014-11-03 17:17:21 -08001573 if len(suffix) == 2 {
1574 p, err := installationDirCore(suffix, root)
1575 if err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001576 ctx.Errorf("dirFromSuffix failed: %v", err)
Robert Kroeger16ee22b2015-03-12 14:57:09 -07001577 return "", false, err
Robert Kroegeracc778b2014-11-03 17:17:21 -08001578 }
Robert Kroeger16ee22b2015-03-12 14:57:09 -07001579 return p, false, nil
Robert Kroegeracc778b2014-11-03 17:17:21 -08001580 } else if len(suffix) > 2 {
1581 p, err := instanceDir(root, suffix[0:3])
1582 if err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001583 ctx.Errorf("dirFromSuffix failed: %v", err)
Robert Kroeger16ee22b2015-03-12 14:57:09 -07001584 return "", false, err
Robert Kroegeracc778b2014-11-03 17:17:21 -08001585 }
Robert Kroeger16ee22b2015-03-12 14:57:09 -07001586 return p, true, nil
Robert Kroegeracc778b2014-11-03 17:17:21 -08001587 }
Bogdan Caprita040603b2015-06-23 18:19:30 -07001588 return "", false, verror.New(errors.ErrInvalidSuffix, nil)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001589}
1590
Robert Kroeger16ee22b2015-03-12 14:57:09 -07001591// TODO(rjkroege): Consider maintaining an in-memory Permissions cache.
Adam Sadovskya4d4a692015-04-20 11:36:49 -07001592func (i *appService) SetPermissions(ctx *context.T, call rpc.ServerCall, perms access.Permissions, version string) error {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001593 dir, isInstance, err := dirFromSuffix(ctx, i.suffix, i.config.Root)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001594 if err != nil {
1595 return err
1596 }
Robert Kroeger16ee22b2015-03-12 14:57:09 -07001597 if isInstance {
Todd Wang4264e4b2015-04-16 22:43:40 -07001598 dmBlessings := security.LocalBlessingNames(ctx, call.Security())
Adam Sadovskya4d4a692015-04-20 11:36:49 -07001599 if err := setPermsForDebugging(dmBlessings, perms, dir, i.permsStore); err != nil {
Robert Kroeger16ee22b2015-03-12 14:57:09 -07001600 return err
1601 }
1602 }
Adam Sadovskya4d4a692015-04-20 11:36:49 -07001603 return i.permsStore.Set(path.Join(dir, "acls"), perms, version)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001604}
1605
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001606func (i *appService) GetPermissions(ctx *context.T, _ rpc.ServerCall) (perms access.Permissions, version string, err error) {
1607 dir, _, err := dirFromSuffix(ctx, i.suffix, i.config.Root)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001608 if err != nil {
Asim Shankar68885192014-11-26 12:48:35 -08001609 return nil, "", err
Robert Kroegeracc778b2014-11-03 17:17:21 -08001610 }
Adam Sadovskya4d4a692015-04-20 11:36:49 -07001611 return i.permsStore.Get(path.Join(dir, "acls"))
Robert Kroegeracc778b2014-11-03 17:17:21 -08001612}
Bogdan Capritad8373a12015-01-28 19:52:37 -08001613
Todd Wang54feabe2015-04-15 23:38:26 -07001614func (i *appService) Debug(ctx *context.T, call rpc.ServerCall) (string, error) {
Bogdan Capritad8373a12015-01-28 19:52:37 -08001615 switch len(i.suffix) {
1616 case 2:
Todd Wang54feabe2015-04-15 23:38:26 -07001617 return i.installationDebug(ctx)
Bogdan Capritad8373a12015-01-28 19:52:37 -08001618 case 3:
Todd Wang4264e4b2015-04-16 22:43:40 -07001619 return i.instanceDebug(ctx, call.Security())
Bogdan Capritad8373a12015-01-28 19:52:37 -08001620 default:
Bogdan Caprita040603b2015-06-23 18:19:30 -07001621 return "", verror.New(errors.ErrInvalidSuffix, nil)
Bogdan Capritad8373a12015-01-28 19:52:37 -08001622 }
1623}
1624
Todd Wang54feabe2015-04-15 23:38:26 -07001625func (i *appService) installationDebug(ctx *context.T) (string, error) {
Bogdan Capritad8373a12015-01-28 19:52:37 -08001626 const installationDebug = `Installation dir: {{.InstallationDir}}
1627
1628Origin: {{.Origin}}
1629
1630Envelope: {{printf "%+v" .Envelope}}
1631
1632Config: {{printf "%+v" .Config}}
1633`
1634 installationDebugTemplate, err := template.New("installation-debug").Parse(installationDebug)
1635 if err != nil {
1636 return "", err
1637 }
1638
1639 installationDir, err := i.installationDir()
1640 if err != nil {
1641 return "", err
1642 }
1643 debugInfo := struct {
1644 InstallationDir, Origin string
1645 Envelope *application.Envelope
1646 Config device.Config
1647 }{}
1648 debugInfo.InstallationDir = installationDir
1649
Todd Wang54feabe2015-04-15 23:38:26 -07001650 if origin, err := loadOrigin(ctx, installationDir); err != nil {
Bogdan Capritad8373a12015-01-28 19:52:37 -08001651 return "", err
1652 } else {
1653 debugInfo.Origin = origin
1654 }
1655
1656 currLink := filepath.Join(installationDir, "current")
Todd Wang54feabe2015-04-15 23:38:26 -07001657 if envelope, err := loadEnvelope(ctx, currLink); err != nil {
Bogdan Capritad8373a12015-01-28 19:52:37 -08001658 return "", err
1659 } else {
1660 debugInfo.Envelope = envelope
1661 }
1662
Todd Wang54feabe2015-04-15 23:38:26 -07001663 if config, err := loadConfig(ctx, installationDir); err != nil {
Bogdan Capritad8373a12015-01-28 19:52:37 -08001664 return "", err
1665 } else {
1666 debugInfo.Config = config
1667 }
1668
1669 var buf bytes.Buffer
1670 if err := installationDebugTemplate.Execute(&buf, debugInfo); err != nil {
1671 return "", err
1672 }
1673 return buf.String(), nil
1674
1675}
1676
Todd Wang4264e4b2015-04-16 22:43:40 -07001677func (i *appService) instanceDebug(ctx *context.T, call security.Call) (string, error) {
Bogdan Capritad8373a12015-01-28 19:52:37 -08001678 const instanceDebug = `Instance dir: {{.InstanceDir}}
1679
1680System name / start system name: {{.SystemName}} / {{.StartSystemName}}
1681
1682Cmd: {{printf "%+v" .Cmd}}
1683
Bogdan Caprita52ff4f82015-08-28 09:53:07 -07001684Envelope: {{printf "%+v" .Envelope}}
1685
Bogdan Capritad8373a12015-01-28 19:52:37 -08001686Info: {{printf "%+v" .Info}}
1687
1688Principal: {{.PrincipalType}}
1689Public Key: {{.Principal.PublicKey}}
1690Blessing Store: {{.Principal.BlessingStore.DebugString}}
1691Roots: {{.Principal.Roots.DebugString}}
1692`
1693 instanceDebugTemplate, err := template.New("instance-debug").Parse(instanceDebug)
1694 if err != nil {
1695 return "", err
1696 }
1697
1698 instanceDir, err := i.instanceDir()
1699 if err != nil {
1700 return "", err
1701 }
1702 debugInfo := struct {
1703 InstanceDir, SystemName, StartSystemName string
1704 Cmd *exec.Cmd
Bogdan Caprita52ff4f82015-08-28 09:53:07 -07001705 Envelope *application.Envelope
Bogdan Capritad8373a12015-01-28 19:52:37 -08001706 Info *instanceInfo
1707 Principal security.Principal
1708 PrincipalType string
1709 }{}
1710 debugInfo.InstanceDir = instanceDir
1711
Todd Wang4264e4b2015-04-16 22:43:40 -07001712 debugInfo.SystemName = suidHelper.usernameForPrincipal(ctx, call, i.uat)
Bogdan Capritad8373a12015-01-28 19:52:37 -08001713 if startSystemName, err := readSystemNameForInstance(instanceDir); err != nil {
1714 return "", err
1715 } else {
1716 debugInfo.StartSystemName = startSystemName
1717 }
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001718
Todd Wang54feabe2015-04-15 23:38:26 -07001719 if info, err := loadInstanceInfo(ctx, instanceDir); err != nil {
Bogdan Capritad8373a12015-01-28 19:52:37 -08001720 return "", err
1721 } else {
1722 debugInfo.Info = info
1723 }
Robert Kroegercc9f55d2015-05-20 16:25:36 -07001724 if cmd, err := genCmd(ctx, instanceDir, i.runner.mtAddress); err != nil {
1725 return "", err
1726 } else {
1727 debugInfo.Cmd = cmd
1728 }
Bogdan Capritad8373a12015-01-28 19:52:37 -08001729
Bogdan Caprita52ff4f82015-08-28 09:53:07 -07001730 if envelope, err := loadEnvelopeForInstance(ctx, instanceDir); err != nil {
1731 return "", err
1732 } else {
1733 debugInfo.Envelope = envelope
1734 }
1735
Bogdan Caprita19ccdee2015-08-21 11:12:33 -07001736 switch sa := i.runner.securityAgent; {
1737 case sa != nil && sa.keyMgr != nil:
1738 // Try connecting to principal, if fails try serving, then
1739 // connect, then stop serving.
1740 // TODO(caprita): This is brittle.
1741 sockPath, err := sockPath(instanceDir)
1742 if err != nil {
1743 return "", err
1744 }
1745 if debugInfo.Principal, err = agentlib.NewAgentPrincipalX(sockPath); err != nil {
1746 agentHandle := debugInfo.Info.handle()
1747 // TODO(caprita): This will interfere with the
1748 // ServePrincipal call when Run'ning the instance. We
1749 // should instead ref count the principal and
1750 // StopServing when the last user goes away.
1751 if err := sa.keyMgr.ServePrincipal(agentHandle, sockPath); err != nil {
1752 return "", err
1753 }
1754 if debugInfo.Principal, err = agentlib.NewAgentPrincipalX(sockPath); err != nil {
1755 return "", err
1756 }
1757 defer func() {
1758 if err := sa.keyMgr.StopServing(agentHandle); err != nil {
1759 ctx.Errorf("StopServing failed: %v", err)
1760 }
1761 }()
1762 }
1763 debugInfo.PrincipalType = "Agent-based"
1764 case sa != nil && sa.keyMgrAgent != nil:
Bogdan Capritad8373a12015-01-28 19:52:37 -08001765 file, err := sa.keyMgrAgent.NewConnection(debugInfo.Info.SecurityAgentHandle)
1766 if err != nil {
Cosmos Nicolaou18489732015-06-29 16:01:38 -07001767 ctx.Errorf("NewConnection(%v) failed: %v", debugInfo.Info.SecurityAgentHandle, err)
Bogdan Capritad8373a12015-01-28 19:52:37 -08001768 return "", err
1769 }
1770 var cancel func()
Todd Wang54feabe2015-04-15 23:38:26 -07001771 if debugInfo.Principal, cancel, err = agentPrincipal(ctx, file); err != nil {
Bogdan Capritad8373a12015-01-28 19:52:37 -08001772 return "", err
1773 }
1774 defer cancel()
Bogdan Caprita19ccdee2015-08-21 11:12:33 -07001775 debugInfo.PrincipalType = "Agent-based-deprecated"
1776 default:
Bogdan Capritad8373a12015-01-28 19:52:37 -08001777 credentialsDir := filepath.Join(instanceDir, "credentials")
1778 var err error
1779 if debugInfo.Principal, err = vsecurity.LoadPersistentPrincipal(credentialsDir, nil); err != nil {
1780 return "", err
1781 }
1782 debugInfo.PrincipalType = fmt.Sprintf("Credentials dir-based (%v)", credentialsDir)
1783 }
1784 var buf bytes.Buffer
1785 if err := instanceDebugTemplate.Execute(&buf, debugInfo); err != nil {
1786 return "", err
1787 }
1788 return buf.String(), nil
1789}
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001790
Todd Wang54feabe2015-04-15 23:38:26 -07001791func (i *appService) Status(ctx *context.T, _ rpc.ServerCall) (device.Status, error) {
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001792 switch len(i.suffix) {
1793 case 2:
Todd Wang54feabe2015-04-15 23:38:26 -07001794 status, err := i.installationStatus(ctx)
Arup Mukherjeee4d75c92015-05-18 19:10:02 -07001795 return device.StatusInstallation{Value: status}, err
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001796 case 3:
Todd Wang54feabe2015-04-15 23:38:26 -07001797 status, err := i.instanceStatus(ctx)
Arup Mukherjeee4d75c92015-05-18 19:10:02 -07001798 return device.StatusInstance{Value: status}, err
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001799 default:
Bogdan Caprita040603b2015-06-23 18:19:30 -07001800 return nil, verror.New(errors.ErrInvalidSuffix, ctx)
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001801 }
1802}
1803
Todd Wang54feabe2015-04-15 23:38:26 -07001804func (i *appService) installationStatus(ctx *context.T) (device.InstallationStatus, error) {
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001805 installationDir, err := i.installationDir()
1806 if err != nil {
1807 return device.InstallationStatus{}, err
1808 }
1809 state, err := getInstallationState(installationDir)
1810 if err != nil {
1811 return device.InstallationStatus{}, err
1812 }
1813 versionLink := filepath.Join(installationDir, "current")
1814 versionDir, err := filepath.EvalSymlinks(versionLink)
1815 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001816 return device.InstallationStatus{}, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", versionLink, err))
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001817 }
1818 return device.InstallationStatus{
1819 State: state,
1820 Version: filepath.Base(versionDir),
1821 }, nil
1822}
1823
Todd Wang54feabe2015-04-15 23:38:26 -07001824func (i *appService) instanceStatus(ctx *context.T) (device.InstanceStatus, error) {
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001825 instanceDir, err := i.instanceDir()
1826 if err != nil {
1827 return device.InstanceStatus{}, err
1828 }
1829 state, err := getInstanceState(instanceDir)
1830 if err != nil {
1831 return device.InstanceStatus{}, err
1832 }
1833 versionLink := filepath.Join(instanceDir, "version")
1834 versionDir, err := filepath.EvalSymlinks(versionLink)
1835 if err != nil {
Bogdan Caprita040603b2015-06-23 18:19:30 -07001836 return device.InstanceStatus{}, verror.New(errors.ErrOperationFailed, ctx, fmt.Sprintf("EvalSymlinks(%v) failed: %v", versionLink, err))
Bogdan Capritab7f5d772015-03-24 16:37:59 -07001837 }
1838 return device.InstanceStatus{
1839 State: state,
1840 Version: filepath.Base(versionDir),
1841 }, nil
1842}