| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package device defines interfaces for managing devices and their |
| // applications. |
| package device |
| |
| import ( |
| "time" |
| |
| "v.io/v23/security" |
| "v.io/v23/security/access" |
| "v.io/v23/services/application" |
| "v.io/v23/services/binary" |
| "v.io/v23/services/permissions" |
| "v.io/v23/services/tidyable" |
| ) |
| |
| // TODO(caprita): Merge with v23/config and v.io/x/ref/lib/exec/config.go. |
| |
| // Config specifies app configuration that overrides what's in the envelope. |
| type Config map[string]string |
| |
| // InstallationState describes the states that an installation can be in at any |
| // time. |
| type InstallationState enum { |
| Active |
| Uninstalled |
| } |
| |
| // InstanceState describes the states that an instance can be in at any |
| // time. |
| type InstanceState enum { |
| Launching |
| Running |
| Dying |
| NotRunning |
| Updating |
| Deleted |
| } |
| |
| // Application can be used to manage applications on a device. This interface |
| // will be invoked using an object name that identifies the application and its |
| // installations and instances where applicable. |
| // |
| // An application is defined by a title. An application can have multiple |
| // installations on a device. The installations are grouped under the same |
| // application, but are otherwise independent of each other. Each installation |
| // can have zero or more instances (which can be running or not). The instances |
| // are independent of each other, and do not share state (like local storage). |
| // Interaction among instances should occur via Vanadium RPC, facilitated by the |
| // local mounttable. |
| // |
| // The device manager supports versioning of applications. Each installation |
| // maintains a tree of versions, where a version is defined by a specific |
| // envelope. The tree structure comes from 'previous version' references: each |
| // version (except the initial installation version) maintains a reference to |
| // the version that preceded it. The installation maintains a current version |
| // reference that is used for new instances. Each update operation on the |
| // installation creates a new version, sets the previous reference of the new |
| // version to the current version, and then updates the current version to refer |
| // to the new version. Each revert operation on the installation sets the |
| // current version to the previous version of the current version. Each |
| // instance maintains a current version reference that is used to run the |
| // instance. The initial version of the instance is set to the current version |
| // of the installation at the time of instantiation. Each update operation on |
| // the instance updates the instance's current version to the current version of |
| // the installation. Each revert operation on the instance updates the |
| // instance's current version to the previous version of the instance's version. |
| // |
| // The Application interface methods can be divided based on their intended |
| // receiver: |
| // |
| // 1) Method receiver is an application: |
| // - Install() |
| // |
| // 2) Method receiver is an application installation: |
| // - Instantiate() |
| // - Uninstall() |
| // |
| // 3) Method receiver is an application instance: |
| // - Run() |
| // - Kill() |
| // - Delete() |
| // |
| // 4) Method receiver is an application installation or instance: |
| // - Update() |
| // - Revert() |
| // |
| // The following methods complement one another: |
| // - Install() and Uninstall() |
| // - Instantiate() and Delete() |
| // - Run() and Kill() |
| // - Update() and Revert() |
| // |
| // |
| // |
| // Examples: |
| // |
| // Install Google Maps on the device. |
| // device/apps.Install("/google.com/appstore/maps", nil, nil) --> "google maps/0" |
| // |
| // Create and start an instance of the previously installed maps application |
| // installation. |
| // device/apps/google maps/0.Instantiate() --> { "0" } |
| // device/apps/google maps/0/0.Run() |
| // |
| // Create and start a second instance of the previously installed maps |
| // application installation. |
| // device/apps/google maps/0.Instantiate() --> { "1" } |
| // device/apps/google maps/0/1.Run() |
| // |
| // Kill and delete the first instance previously started. |
| // device/apps/google maps/0/0.Kill() |
| // device/apps/google maps/0/0.Delete() |
| // |
| // Install a second Google Maps installation. |
| // device/apps.Install("/google.com/appstore/maps", nil, nil) --> "google maps/1" |
| // |
| // Update the second maps installation to the latest version available. |
| // device/apps/google maps/1.Update() |
| // |
| // Update the first maps installation to a specific version. |
| // device/apps/google maps/0.UpdateTo("/google.com/appstore/beta/maps") |
| // |
| // Finally, an application installation instance can be in one of three abstract |
| // states: 1) "does not exist/deleted", 2) "running", or 3) "not-running". The |
| // interface methods transition between these abstract states using the |
| // following state machine: |
| // |
| // apply(Instantiate(), "does not exist") = "not-running" |
| // apply(Run(), "not-running") = "running" |
| // apply(Kill(), "running") = "not-running" |
| // apply(Delete(), "not-running") = "deleted" |
| type Application interface { |
| // Object provides GetPermissions/SetPermissions methods to read/modify |
| // AccessLists for the Application methods. After a device has been |
| // claimed, only the claimant will be able to modify the AccessLists for |
| // the device. |
| permissions.Object |
| |
| // TODO(caprita): Rather than overriding config and package piecemeal, |
| // consider providing an envelope override during install. |
| |
| // Install installs the application identified by the first argument and |
| // returns an object name suffix that identifies the new installation. |
| // |
| // The name argument should be an object name for an application |
| // envelope. The service it identifies must implement |
| // repository.Application, and is expected to return either the |
| // requested version (if the object name encodes a specific version), or |
| // otherwise the latest available version, as appropriate. This object |
| // name will be used by default by the Update method, as a source for |
| // updated application envelopes (can be overriden by setting |
| // AppOriginConfigKey in the config). |
| // |
| // The config argument specifies config settings that will take |
| // precedence over those present in the application envelope. |
| // |
| // The packages argument specifies packages to be installed in addition |
| // to those specified in the envelope. If a package in the envelope has |
| // the same key, the package in the packages argument takes precedence. |
| // |
| // The returned suffix, when appended to the name used to reach the |
| // receiver for Install, can be used to control the installation object. |
| // The suffix will contain the title of the application as a prefix, |
| // which can then be used to control all the installations of the given |
| // application. |
| // TODO(rjkroege): Use customized labels. |
| Install(name string, config Config, packages application.Packages) (string | error) {access.Write} |
| |
| // Uninstall uninstalls an application installation. |
| // The installation must be in state Active. |
| Uninstall() error {access.Admin} |
| |
| // Instantiate creates an instance of an application installation. |
| // The installation must be in state Active. |
| // |
| // The server sends the application instance's Public Key on the stream. |
| // When the client receives the Public Key it must send Blessings back |
| // to the server. When the instance is created, the server returns the |
| // instance name to the client. |
| // |
| // Client Server |
| // "object".Instantiate() --> |
| // <-- InstancePublicKey |
| // AppBlessings --> |
| // <-- return InstanceName |
| Instantiate() stream<BlessClientMessage, BlessServerMessage> (string | error) {access.Read} |
| |
| // TODO(caprita): Add a new method Shutdown for Device instead of using |
| // Delete. |
| |
| // Delete deletes an instance. Once deleted, the instance cannot be |
| // revived. |
| // The instance must be in state NotRunning. |
| // |
| // If called against a Device, causes the Device to shut itself down. |
| Delete() error {access.Admin} |
| |
| // Run begins execution of an application instance. |
| // The instance must be in state NotRunning. |
| Run() error {access.Write} |
| |
| // Kill attempts a clean shutdown an of application instance. |
| // The instance must be in state Running. |
| // |
| // If the deadline is non-zero and the instance in question is still |
| // running after the given deadline, shutdown of the instance is |
| // enforced. |
| // |
| // If called against a Device, causes the Device to stop itself (which |
| // may or may not result in a restart depending on the device manager |
| // setup). |
| Kill(deadline time.Duration) error {access.Write} |
| |
| // Update updates an application installation's version to a new version |
| // created from the envelope at the object name provided during Install. |
| // If the new application envelope contains a different application |
| // title, the update does not occur, and an error is returned. The |
| // installation must be in state Active. |
| // |
| // Update updates an application instance's version to the current |
| // installation version. The instance must be in state NotRunning. |
| Update() error {access.Admin} |
| // TODO(caprita): Decide if we keep this in v0.1. If we do, we may want |
| // to use it over the origin override mechanism in the config, to |
| // specify a new origin for the app installation. |
| |
| // UpdateTo updates the application installation(s) to the application |
| // specified by the object name argument. If the new application |
| // envelope contains a different application title, the update does not |
| // occur, and an error is returned. |
| // The installation must be in state Active. |
| UpdateTo(name string) error {access.Admin} |
| |
| // Revert reverts an application installation's version to the previous |
| // version of its current version. The installation must be in state |
| // Active. |
| // |
| // Revert reverts an application instance's version to the previous |
| // version of its current version. The instance must be in state |
| // NotRunning. |
| Revert() error {access.Admin} |
| |
| // Debug returns debug information about the application installation or |
| // instance. This is generally highly implementation-specific, and |
| // presented in an unstructured form. No guarantees are given about the |
| // stability of the format, and parsing it programmatically is |
| // specifically discouraged. |
| Debug() (string | error) {access.Debug} |
| |
| // Status returns structured information about the application |
| // installation or instance. |
| Status() (Status | error) {access.Read} |
| } |
| |
| // Status is returned by the Application Status method. |
| type Status union { |
| Instance InstanceStatus |
| Installation InstallationStatus |
| Device DeviceStatus |
| } |
| |
| // InstallationStatus specifies the Status returned by the Application Status |
| // method for installation objects. |
| type InstallationStatus struct { |
| State InstallationState |
| Version string |
| } |
| |
| // InstanceStatus specifies the Status returned by the Application Status method |
| // for instance objects. |
| type InstanceStatus struct { |
| State InstanceState |
| Version string |
| } |
| |
| // DeviceStatus specifies the Status returned by the Application Status method |
| // for the device service object. |
| type DeviceStatus struct { |
| State InstanceState |
| Version string |
| } |
| |
| // BlessServerMessage is the data type that is streamed from the server to the |
| // client during an Instantiate method call. |
| // This is a union to enable backward compatible changes. |
| type BlessServerMessage union { |
| // The public key of the instance being blessed. The client must return |
| // blessings for this key. |
| InstancePublicKey []byte |
| } |
| |
| // BlessClientMessage is the data type that is streamed from the client to the |
| // server during a Instantiate method call. |
| // This is a union to enable backward compatible changes. |
| type BlessClientMessage union { |
| // Blessings for the application instance. |
| AppBlessings security.WireBlessings |
| } |
| |
| // Description enumerates the profiles that a Device supports. |
| type Description struct { |
| // Profiles is a set of names of supported profiles. Each name can |
| // either be an object name that resolves to a Profile, or can be the |
| // profile's label, e.g.: |
| // "profiles/google/cluster/diskfull" |
| // "linux-media" |
| // |
| // Profiles for devices can be provided by hand, but they can also be |
| // automatically derived by examining the device. |
| Profiles set[string] |
| } |
| |
| // Association is a tuple containing an association between a Vanadium |
| // identity and a system account name. |
| type Association struct { |
| IdentityName string |
| AccountName string |
| } |
| |
| // Claimable represents an uninitialized device with no owner |
| // (i.e., a device that has no blessings). |
| // |
| // Claim is used to claim ownership by blessing the device's private key. |
| // Devices that have provided a pairing token to the claimer through an |
| // out-of-band communication channel (eg: display/email) would expect this |
| // pairing token to be replayed by the claimer. |
| // |
| // Once claimed, the device will export the "Device" interface and all methods |
| // will be restricted to the claimer. |
| // |
| // The blessings that the device is to be claimed with is provided |
| // via the ipc.Granter option in Go. |
| type Claimable interface { |
| Claim(pairingToken string) error {access.Admin} |
| } |
| |
| // Device can be used to manage a device remotely using an object name that |
| // identifies it. |
| type Device interface { |
| // Each method of the Application interface invoked at the device |
| // level applies to all applications installed on the device (and |
| // their installations and instances where applicable). |
| Application |
| // The device manager is tidyable. |
| tidyable.Tidyable |
| // Describe generates a description of the device. |
| Describe() (Description | error) {access.Admin} |
| // IsRunnable checks if the device can execute the given binary. |
| IsRunnable(description binary.Description) (bool | error) {access.Admin} |
| // Reset resets the device. If the deadline is non-zero and the device |
| // in question is still running after the given deadline expired, |
| // reset of the device is enforced. |
| Reset(deadline time.Duration) error {access.Admin} |
| // AssociateAccount associates a local system account name with the provided |
| // Vanadium identities. It replaces the existing association if one already exists for that |
| // identity. Setting an AccountName to "" removes the association for each |
| // listed identity. |
| AssociateAccount(identityNames []string, accountName string) error {access.Admin} |
| // ListAssociations returns all of the associations between Vanadium identities |
| // and system names. |
| ListAssociations() ([]Association | error) {access.Admin} |
| } |