veyron/services/mgmt/device/impl: share packages across instances
Instead of making a fresh copy of all package dirs and files for each new
instance, only create them once in the version directory, and add a symlink from
each instance.
To make this work in multi-user mode, change the permissions for the created
package dirs and files to 755.
Change-Id: I28ac21f69ade980824349b1aa435bf19baac51f7
diff --git a/services/mgmt/device/impl/app_service.go b/services/mgmt/device/impl/app_service.go
index d696aa7..4614bab 100644
--- a/services/mgmt/device/impl/app_service.go
+++ b/services/mgmt/device/impl/app_service.go
@@ -21,17 +21,16 @@
// origin(700d) - object name for application envelope
// config(700d) - Config provided by the installer
// packages(700d) - set of packages specified by the installer
-// pkg/(700d) - downloaded packages
+// pkg(700d)/ - downloaded packages
// <pkg name>(700d)
// <pkg name>.__info(700d)
// ...
-// <version 1 timestamp>/(700d) - timestamp of when the version was downloaded
+// <version 1 timestamp>(700d)/ - timestamp of when the version was downloaded
// bin(755d) - application binary
// previous - symbolic link to previous version directory
// envelope - application envelope (JSON-encoded)
-// pkg(700d)/ - the application packages
-// <pkg name>(700d)
-// <pkg name>.__info(700d)
+// packages(755d)/ - installed packages (from envelope+installer)
+// <pkg name>(755d)/
// ...
// <version 2 timestamp>(700d)
// ...
@@ -41,9 +40,7 @@
// credentials(700d)/ - holds veyron credentials (unless running
// through security agent)
// root(700a)/ - workspace that the instance is run from
-// packages(700a)/ - the installed packages
-// <pkg name>(700a)/
-// ...
+// packages - symbolic link to version's packages
// logs(755a)/ - stderr/stdout and log files generated by instance
// info(700d) - metadata for the instance (such as app
// cycle manager name and process id)
@@ -394,6 +391,9 @@
if err := mkdirPerm(versionDir, 0711); err != nil {
return "", verror.New(ErrOperationFailed, nil)
}
+ if err := saveEnvelope(versionDir, envelope); err != nil {
+ return versionDir, err
+ }
pkgDir := filepath.Join(versionDir, "pkg")
if err := mkdir(pkgDir); err != nil {
return "", verror.New(ErrOperationFailed, nil)
@@ -410,8 +410,13 @@
if err := downloadPackages(ctx, publisher, envelope.Packages, pkgDir); err != nil {
return versionDir, err
}
- if err := saveEnvelope(versionDir, envelope); err != nil {
- return versionDir, err
+ if err := installPackages(installationDir, versionDir); err != nil {
+ vlog.Errorf("installPackages(%v, %v) failed: %v", installationDir, versionDir, err)
+ return versionDir, verror.New(ErrOperationFailed, nil)
+ }
+ if err := os.RemoveAll(pkgDir); err != nil {
+ vlog.Errorf("RemoveAll(%v) failed: %v", pkgDir, err)
+ return versionDir, verror.New(ErrOperationFailed, nil)
}
if oldVersionDir != "" {
previousLink := filepath.Join(versionDir, "previous")
@@ -441,14 +446,14 @@
deferrer := func() {
cleanupDir(installationDir, "")
}
+ if err := mkdirPerm(installationDir, 0711); err != nil {
+ return "", verror.New(ErrOperationFailed, nil)
+ }
defer func() {
if deferrer != nil {
deferrer()
}
}()
- if _, err := newVersion(call.Context(), installationDir, envelope, ""); err != nil {
- return "", err
- }
if newOrigin, ok := config[mgmt.AppOriginConfigKey]; ok {
delete(config, mgmt.AppOriginConfigKey)
applicationVON = newOrigin
@@ -462,9 +467,6 @@
if err := savePackages(installationDir, packages); err != nil {
return "", err
}
- if err := mkdirPerm(installationDir, 0711); err != nil {
- return "", verror.New(ErrOperationFailed, nil)
- }
pkgDir := filepath.Join(installationDir, "pkg")
if err := mkdir(pkgDir); err != nil {
return "", verror.New(ErrOperationFailed, nil)
@@ -475,6 +477,9 @@
if err := downloadPackages(call.Context(), nil, packages, pkgDir); err != nil {
return "", err
}
+ if _, err := newVersion(call.Context(), installationDir, envelope, ""); err != nil {
+ return "", err
+ }
if err := initializeInstallation(installationDir, active); err != nil {
return "", err
}
@@ -669,8 +674,8 @@
return installationDirCore(i.suffix, i.config.Root)
}
-// installPackages installs all the packages for a new instance.
-func installPackages(installationDir, versionDir, instanceDir string) error {
+// installPackages installs all the packages for a new version.
+func installPackages(installationDir, versionDir string) error {
overridePackages, err := loadPackages(installationDir)
if err != nil {
return err
@@ -682,13 +687,11 @@
for pkg, _ := range overridePackages {
delete(envelope.Packages, pkg)
}
- packagesDir := filepath.Join(instanceDir, "root", "packages")
- if err := os.MkdirAll(packagesDir, os.FileMode(0700)); err != nil {
+ packagesDir := filepath.Join(versionDir, "packages")
+ if err := os.MkdirAll(packagesDir, os.FileMode(0755)); err != nil {
return err
}
installFrom := func(packages application.Packages, sourceDir string) error {
- // TODO(rthellend): Consider making the packages read-only and
- // sharing them between apps or instances.
for pkg, _ := range packages {
pkgFile := filepath.Join(sourceDir, "pkg", pkg)
dst := filepath.Join(packagesDir, pkg)
@@ -745,8 +748,13 @@
vlog.Errorf("Symlink(%v, %v) failed: %v", versionDir, versionLink, err)
return instanceDir, instanceID, verror.New(ErrOperationFailed, call.Context())
}
- if err := installPackages(installationDir, versionDir, instanceDir); err != nil {
- vlog.Errorf("installPackages(%v, %v, %v) failed: %v", installationDir, versionDir, instanceDir, err)
+ rootDir := filepath.Join(instanceDir, "root")
+ if err := mkdir(rootDir); err != nil {
+ return instanceDir, instanceID, verror.New(ErrOperationFailed, call.Context())
+ }
+ packagesDir, packagesLink := filepath.Join(versionDir, "packages"), filepath.Join(rootDir, "packages")
+ if err := os.Symlink(packagesDir, packagesLink); err != nil {
+ vlog.Errorf("Symlink(%v, %v) failed: %v", packagesDir, packagesLink, err)
return instanceDir, instanceID, verror.New(ErrOperationFailed, call.Context())
}
instanceInfo := new(instanceInfo)
@@ -799,9 +807,6 @@
cmd.Env = []string{consts.NamespaceRootPrefix + "=" + nsRoot}
cmd.Env = append(cmd.Env, envelope.Env...)
rootDir := filepath.Join(instanceDir, "root")
- if err := mkdir(rootDir); err != nil {
- return nil, err
- }
cmd.Dir = rootDir
cmd.Args = append(cmd.Args, "--workspace", rootDir)
diff --git a/services/mgmt/lib/packages/packages.go b/services/mgmt/lib/packages/packages.go
index 2b42ade..9f3accf 100644
--- a/services/mgmt/lib/packages/packages.go
+++ b/services/mgmt/lib/packages/packages.go
@@ -17,7 +17,10 @@
"v.io/v23/services/mgmt/repository"
)
-const defaultType = "application/octet-stream"
+const (
+ defaultType = "application/octet-stream"
+ createFileMode = 0755
+)
var typemap = map[string]repository.MediaInfo{
".zip": repository.MediaInfo{Type: "application/zip"},
@@ -153,7 +156,7 @@
}
func extractZip(zipFile, installDir string) error {
- if err := os.Mkdir(installDir, os.FileMode(0700)); err != nil {
+ if err := os.Mkdir(installDir, os.FileMode(createFileMode)); err != nil {
return fmt.Errorf("os.Mkdir(%q) failed: %v", installDir, err)
}
zr, err := zip.OpenReader(zipFile)
@@ -167,7 +170,7 @@
return fmt.Errorf("failed to extract file %q outside of install directory", file.Name)
}
if fi.IsDir() {
- if err := os.MkdirAll(name, os.FileMode(fi.Mode()&0700)); err != nil && !os.IsExist(err) {
+ if err := os.MkdirAll(name, os.FileMode(fi.Mode()&createFileMode)); err != nil && !os.IsExist(err) {
return err
}
continue
@@ -177,10 +180,10 @@
return err
}
parentName := filepath.Dir(name)
- if err := os.MkdirAll(parentName, os.FileMode(0700)); err != nil {
+ if err := os.MkdirAll(parentName, os.FileMode(createFileMode)); err != nil {
return err
}
- out, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY, os.FileMode(fi.Mode()&0700))
+ out, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY, os.FileMode(fi.Mode()&createFileMode))
if err != nil {
in.Close()
return err
@@ -199,7 +202,7 @@
}
func extractTar(pkgFile string, encoding string, installDir string) error {
- if err := os.Mkdir(installDir, os.FileMode(0700)); err != nil {
+ if err := os.Mkdir(installDir, os.FileMode(createFileMode)); err != nil {
return fmt.Errorf("os.Mkdir(%q) failed: %v", installDir, err)
}
f, err := os.Open(pkgFile)
@@ -238,7 +241,7 @@
}
// Regular file
if hdr.Typeflag == tar.TypeReg {
- out, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY, os.FileMode(hdr.Mode&0700))
+ out, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY, os.FileMode(hdr.Mode&createFileMode))
if err != nil {
return err
}
@@ -254,7 +257,7 @@
}
// Directory
if hdr.Typeflag == tar.TypeDir {
- if err := os.Mkdir(name, os.FileMode(hdr.Mode&0700)); err != nil && !os.IsExist(err) {
+ if err := os.Mkdir(name, os.FileMode(hdr.Mode&createFileMode)); err != nil && !os.IsExist(err) {
return err
}
continue