forked from cloudfoundry/bosh-agent
-
Notifications
You must be signed in to change notification settings - Fork 0
/
compiled_package_applier.go
167 lines (136 loc) · 4.16 KB
/
compiled_package_applier.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package packages
import (
bc "github.com/cloudfoundry/bosh-agent/agent/applier/bundlecollection"
models "github.com/cloudfoundry/bosh-agent/agent/applier/models"
boshblob "github.com/cloudfoundry/bosh-utils/blobstore"
bosherr "github.com/cloudfoundry/bosh-utils/errors"
boshcmd "github.com/cloudfoundry/bosh-utils/fileutil"
boshlog "github.com/cloudfoundry/bosh-utils/logger"
boshsys "github.com/cloudfoundry/bosh-utils/system"
)
const logTag = "compiledPackageApplier"
type compiledPackageApplier struct {
packagesBc bc.BundleCollection
// KeepOnly will permanently uninstall packages when operating as owner
packagesBcOwner bool
blobstore boshblob.DigestBlobstore
compressor boshcmd.Compressor
fs boshsys.FileSystem
logger boshlog.Logger
}
func NewCompiledPackageApplier(
packagesBc bc.BundleCollection,
packagesBcOwner bool,
blobstore boshblob.DigestBlobstore,
compressor boshcmd.Compressor,
fs boshsys.FileSystem,
logger boshlog.Logger,
) Applier {
return &compiledPackageApplier{
packagesBc: packagesBc,
packagesBcOwner: packagesBcOwner,
blobstore: blobstore,
compressor: compressor,
fs: fs,
logger: logger,
}
}
func (s compiledPackageApplier) Prepare(pkg models.Package) error {
s.logger.Debug(logTag, "Preparing package %v", pkg)
pkgBundle, err := s.packagesBc.Get(pkg)
if err != nil {
return bosherr.WrapError(err, "Getting package bundle")
}
pkgInstalled, err := pkgBundle.IsInstalled()
if err != nil {
return bosherr.WrapError(err, "Checking if package is installed")
}
if !pkgInstalled {
err := s.downloadAndInstall(pkg, pkgBundle)
if err != nil {
return err
}
}
return nil
}
func (s compiledPackageApplier) Apply(pkg models.Package) error {
s.logger.Debug(logTag, "Applying package %v", pkg)
err := s.Prepare(pkg)
if err != nil {
return err
}
pkgBundle, err := s.packagesBc.Get(pkg)
if err != nil {
return bosherr.WrapError(err, "Getting package bundle")
}
_, _, err = pkgBundle.Enable()
if err != nil {
return bosherr.WrapError(err, "Enabling package")
}
return nil
}
func (s *compiledPackageApplier) downloadAndInstall(pkg models.Package, pkgBundle bc.Bundle) error {
tmpDir, err := s.fs.TempDir("bosh-agent-applier-packages-CompiledPackageApplier-Apply")
if err != nil {
return bosherr.WrapError(err, "Getting temp dir")
}
defer func() {
if err = s.fs.RemoveAll(tmpDir); err != nil {
s.logger.Warn(logTag, "Failed to clean up tmpDir: %s", err.Error())
}
}()
file, err := s.blobstore.Get(pkg.Source.BlobstoreID, pkg.Source.Sha1)
if err != nil {
return bosherr.WrapError(err, "Fetching package blob")
}
defer func() {
if err = s.blobstore.CleanUp(file); err != nil {
s.logger.Warn(logTag, "Failed to clean up blobstore blob: %s", err.Error())
}
}()
err = s.compressor.DecompressFileToDir(file, tmpDir, boshcmd.CompressorOptions{})
if err != nil {
return bosherr.WrapError(err, "Decompressing package files")
}
_, _, err = pkgBundle.Install(tmpDir)
if err != nil {
return bosherr.WrapError(err, "Installling package directory")
}
return nil
}
func (s *compiledPackageApplier) KeepOnly(pkgs []models.Package) error {
s.logger.Debug(logTag, "Keeping only packages %v", pkgs)
installedBundles, err := s.packagesBc.List()
if err != nil {
return bosherr.WrapError(err, "Retrieving installed bundles")
}
for _, installedBundle := range installedBundles {
var shouldKeep bool
for _, pkg := range pkgs {
pkgBundle, err := s.packagesBc.Get(pkg)
if err != nil {
return bosherr.WrapError(err, "Getting package bundle")
}
if pkgBundle == installedBundle {
shouldKeep = true
break
}
}
if !shouldKeep {
err = installedBundle.Disable()
if err != nil {
return bosherr.WrapError(err, "Disabling package bundle")
}
if s.packagesBcOwner {
// If we uninstall the bundle first, and the disable failed (leaving the symlink),
// then the next time bundle collection will not include bundle in its list
// which means that symlink will never be deleted.
err = installedBundle.Uninstall()
if err != nil {
return bosherr.WrapError(err, "Uninstalling package bundle")
}
}
}
}
return nil
}