vagrant-bosh 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.gitmodules +6 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +73 -0
- data/Rakefile +2 -0
- data/dev/.gitignore +1 -0
- data/dev/Vagrantfile +30 -0
- data/dev/example-bosh-manifest.yml +188 -0
- data/dev/example-winston-manifest.yml +70 -0
- data/go/.gitignore +11 -0
- data/go/bin/build +10 -0
- data/go/bin/build-linux-amd64 +9 -0
- data/go/bin/env +13 -0
- data/go/bin/go +5 -0
- data/go/bin/golint +19 -0
- data/go/bin/test +37 -0
- data/go/src/boshprovisioner/agent/client/client_interface.go +73 -0
- data/go/src/boshprovisioner/agent/client/fakes/fake_client.go +81 -0
- data/go/src/boshprovisioner/agent/client/http_client.go +299 -0
- data/go/src/boshprovisioner/agent/client/http_client_envelope.go +107 -0
- data/go/src/boshprovisioner/deployment/deployment.go +221 -0
- data/go/src/boshprovisioner/deployment/instance.go +54 -0
- data/go/src/boshprovisioner/deployment/manifest/deployment.go +80 -0
- data/go/src/boshprovisioner/deployment/manifest/ips.go +23 -0
- data/go/src/boshprovisioner/deployment/manifest/manifest.go +143 -0
- data/go/src/boshprovisioner/deployment/manifest/manifest_suite_test.go +13 -0
- data/go/src/boshprovisioner/deployment/manifest/manifest_test.go +86 -0
- data/go/src/boshprovisioner/deployment/manifest/syntax_validator.go +186 -0
- data/go/src/boshprovisioner/deployment/manifest/watch_time.go +47 -0
- data/go/src/boshprovisioner/deployment/manifest_reader.go +46 -0
- data/go/src/boshprovisioner/deployment/reader_factory.go +25 -0
- data/go/src/boshprovisioner/deployment/semantic_validator.go +111 -0
- data/go/src/boshprovisioner/downloader/blobstore_downloader.go +55 -0
- data/go/src/boshprovisioner/downloader/default_mux_downloader.go +22 -0
- data/go/src/boshprovisioner/downloader/downloader_interface.go +6 -0
- data/go/src/boshprovisioner/downloader/http_downloader.go +53 -0
- data/go/src/boshprovisioner/downloader/local_fs_downloader.go +48 -0
- data/go/src/boshprovisioner/downloader/mux_downloader.go +69 -0
- data/go/src/boshprovisioner/eventlog/log.go +72 -0
- data/go/src/boshprovisioner/eventlog/stage.go +39 -0
- data/go/src/boshprovisioner/eventlog/task.go +58 -0
- data/go/src/boshprovisioner/index/file_index.go +289 -0
- data/go/src/boshprovisioner/index/file_index_test.go +296 -0
- data/go/src/boshprovisioner/index/index_interface.go +18 -0
- data/go/src/boshprovisioner/index/index_suite_test.go +13 -0
- data/go/src/boshprovisioner/instance/templatescompiler/concrete_templates_compiler.go +273 -0
- data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/erb_renderer.go +117 -0
- data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/erbrenderer_suite_test.go +13 -0
- data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/render_properties.go +77 -0
- data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/render_properties_test.go +142 -0
- data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/template_evaluation_context.go +85 -0
- data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/template_evaluation_context_rb.go +155 -0
- data/go/src/boshprovisioner/instance/templatescompiler/jobsrepo/concrete_jobs_repository.go +64 -0
- data/go/src/boshprovisioner/instance/templatescompiler/jobsrepo/concrete_runtime_packages_repository.go +105 -0
- data/go/src/boshprovisioner/instance/templatescompiler/jobsrepo/concrete_template_to_job_repository.go +76 -0
- data/go/src/boshprovisioner/instance/templatescompiler/jobsrepo/jobs_repository_interface.go +31 -0
- data/go/src/boshprovisioner/instance/templatescompiler/rendered_archives_compiler.go +81 -0
- data/go/src/boshprovisioner/instance/templatescompiler/templates_compiler_interface.go +20 -0
- data/go/src/boshprovisioner/instance/templatescompiler/templatesrepo/ct_repository.go +54 -0
- data/go/src/boshprovisioner/instance/templatescompiler/templatesrepo/templates_repository_interface.go +16 -0
- data/go/src/boshprovisioner/instance/updater/applier/applier.go +93 -0
- data/go/src/boshprovisioner/instance/updater/applier/empty_state.go +66 -0
- data/go/src/boshprovisioner/instance/updater/applier/job_state.go +178 -0
- data/go/src/boshprovisioner/instance/updater/drainer.go +72 -0
- data/go/src/boshprovisioner/instance/updater/preparer.go +39 -0
- data/go/src/boshprovisioner/instance/updater/starter.go +36 -0
- data/go/src/boshprovisioner/instance/updater/stopper.go +36 -0
- data/go/src/boshprovisioner/instance/updater/updater.go +102 -0
- data/go/src/boshprovisioner/instance/updater/updater_factory.go +83 -0
- data/go/src/boshprovisioner/instance/updater/updater_suite_test.go +13 -0
- data/go/src/boshprovisioner/instance/updater/waiter.go +77 -0
- data/go/src/boshprovisioner/instance/updater/waiter_test.go +103 -0
- data/go/src/boshprovisioner/main/config.go +77 -0
- data/go/src/boshprovisioner/main/main.go +183 -0
- data/go/src/boshprovisioner/main/repos_factory.go +96 -0
- data/go/src/boshprovisioner/packagescompiler/compiledpackagesrepo/compiled_packages_repository_interface.go +17 -0
- data/go/src/boshprovisioner/packagescompiler/compiledpackagesrepo/concrete_compiled_packages_repository.go +61 -0
- data/go/src/boshprovisioner/packagescompiler/concrete_packages_compiler.go +179 -0
- data/go/src/boshprovisioner/packagescompiler/concrete_packages_compiler_factory.go +48 -0
- data/go/src/boshprovisioner/packagescompiler/packages_compiler_interface.go +20 -0
- data/go/src/boshprovisioner/packagescompiler/packagesrepo/concrete_packages_repository.go +65 -0
- data/go/src/boshprovisioner/packagescompiler/packagesrepo/packages_repository_interface.go +16 -0
- data/go/src/boshprovisioner/provisioner/blobstore_config.go +65 -0
- data/go/src/boshprovisioner/provisioner/blobstore_provisioner.go +38 -0
- data/go/src/boshprovisioner/provisioner/deployment_provisioner.go +97 -0
- data/go/src/boshprovisioner/provisioner/instance_provisioner.go +48 -0
- data/go/src/boshprovisioner/provisioner/release_compiler.go +133 -0
- data/go/src/boshprovisioner/release/job/job.go +86 -0
- data/go/src/boshprovisioner/release/job/manifest/manifest.go +79 -0
- data/go/src/boshprovisioner/release/job/manifest/manifest_suite_test.go +13 -0
- data/go/src/boshprovisioner/release/job/manifest/manifest_test.go +42 -0
- data/go/src/boshprovisioner/release/job/manifest/syntax_validator.go +43 -0
- data/go/src/boshprovisioner/release/job/reader_factory.go +34 -0
- data/go/src/boshprovisioner/release/job/tar_reader.go +133 -0
- data/go/src/boshprovisioner/release/manifest/manifest.go +96 -0
- data/go/src/boshprovisioner/release/manifest_reader.go +29 -0
- data/go/src/boshprovisioner/release/reader_factory.go +34 -0
- data/go/src/boshprovisioner/release/release.go +144 -0
- data/go/src/boshprovisioner/release/release_suite_test.go +13 -0
- data/go/src/boshprovisioner/release/release_test.go +129 -0
- data/go/src/boshprovisioner/release/tar_reader.go +139 -0
- data/go/src/boshprovisioner/releasesrepo/blobstore_releases_repository.go +114 -0
- data/go/src/boshprovisioner/releasesrepo/releases_repository_interface.go +15 -0
- data/go/src/boshprovisioner/tar/cmd_compressor.go +68 -0
- data/go/src/boshprovisioner/tar/cmd_extractor.go +47 -0
- data/go/src/boshprovisioner/tar/compressor_interface.go +6 -0
- data/go/src/boshprovisioner/tar/extractor_interface.go +6 -0
- data/go/src/boshprovisioner/util/string_keyed.go +70 -0
- data/go/src/boshprovisioner/vm/agent_provisioner.go +266 -0
- data/go/src/boshprovisioner/vm/asset_manager.go +61 -0
- data/go/src/boshprovisioner/vm/deps_provisioner.go +92 -0
- data/go/src/boshprovisioner/vm/monit_provisioner.go +83 -0
- data/go/src/boshprovisioner/vm/runit_provisioner.go +225 -0
- data/go/src/boshprovisioner/vm/simple_cmds.go +54 -0
- data/go/src/boshprovisioner/vm/vcap_user_provisioner.go +120 -0
- data/go/src/boshprovisioner/vm/vm.go +19 -0
- data/go/src/boshprovisioner/vm/vm_provisioner.go +57 -0
- data/go/src/boshprovisioner/vm/vm_provisioner_factory.go +97 -0
- data/lib/vagrant-bosh/asset_uploader.rb +53 -0
- data/lib/vagrant-bosh/assets/agent/agent-log +5 -0
- data/lib/vagrant-bosh/assets/agent/agent-run +12 -0
- data/lib/vagrant-bosh/assets/agent/agent.cert +18 -0
- data/lib/vagrant-bosh/assets/agent/agent.json +9 -0
- data/lib/vagrant-bosh/assets/agent/agent.key +27 -0
- data/lib/vagrant-bosh/assets/agent/bosh-agent +0 -0
- data/lib/vagrant-bosh/assets/agent/bosh-agent-rc +18 -0
- data/lib/vagrant-bosh/assets/agent/bosh-blobstore-dav +0 -0
- data/lib/vagrant-bosh/assets/monit/monit +0 -0
- data/lib/vagrant-bosh/assets/monit/monit-log +5 -0
- data/lib/vagrant-bosh/assets/monit/monit-run +9 -0
- data/lib/vagrant-bosh/assets/monit/monitrc +8 -0
- data/lib/vagrant-bosh/assets/provisioner +0 -0
- data/lib/vagrant-bosh/bootstrapper.rb +59 -0
- data/lib/vagrant-bosh/communicator.rb +50 -0
- data/lib/vagrant-bosh/config.rb +15 -0
- data/lib/vagrant-bosh/errors.rb +11 -0
- data/lib/vagrant-bosh/plugin.rb +25 -0
- data/lib/vagrant-bosh/provisioner.rb +46 -0
- data/lib/vagrant-bosh/provisioner_tracker.rb +41 -0
- data/lib/vagrant-bosh/ui.rb +77 -0
- data/lib/vagrant-bosh/version.rb +5 -0
- data/lib/vagrant-bosh.rb +15 -0
- data/templates/locales/en.yml +15 -0
- data/vagrant-bosh.gemspec +20 -0
- metadata +191 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
package deployment
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
bosherr "bosh/errors"
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
// SemanticValidator validates deployment to determine if it represents a meaningful state.
|
|
8
|
+
// e.g. - is each job template associated with a release?
|
|
9
|
+
// - are there enough static ips for each job instance?
|
|
10
|
+
type SemanticValidator struct {
|
|
11
|
+
deployment Deployment
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
func NewSemanticValidator(deployment Deployment) SemanticValidator {
|
|
15
|
+
return SemanticValidator{deployment: deployment}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
func (v SemanticValidator) Validate() error {
|
|
19
|
+
for _, net := range v.deployment.Networks {
|
|
20
|
+
err := v.validateNetwork(net)
|
|
21
|
+
if err != nil {
|
|
22
|
+
return bosherr.WrapError(err, "Network %s", net.Name)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
for _, release := range v.deployment.Releases {
|
|
27
|
+
err := v.validateRelease(release)
|
|
28
|
+
if err != nil {
|
|
29
|
+
return bosherr.WrapError(err, "Release %s", release.Name)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
err := v.validateInstance(v.deployment.CompilationInstance)
|
|
34
|
+
if err != nil {
|
|
35
|
+
return bosherr.WrapError(err, "Compilation instance")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
for _, job := range v.deployment.Jobs {
|
|
39
|
+
err := v.validateJob(job)
|
|
40
|
+
if err != nil {
|
|
41
|
+
return bosherr.WrapError(err, "Job %s", job.Name)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return nil
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
func (v SemanticValidator) validateNetwork(network Network) error {
|
|
49
|
+
if network.Type == NetworkTypeManual {
|
|
50
|
+
return bosherr.New("Manual networking is not supported")
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return nil
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
func (v SemanticValidator) validateRelease(release Release) error {
|
|
57
|
+
if release.Version == "latest" {
|
|
58
|
+
return bosherr.New("Version 'latest' is not supported")
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return nil
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
func (v SemanticValidator) validateJob(job Job) error {
|
|
65
|
+
for _, template := range job.Templates {
|
|
66
|
+
err := v.validateTemplate(template)
|
|
67
|
+
if err != nil {
|
|
68
|
+
return bosherr.WrapError(err, "Template %s", template.Name)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for _, instance := range job.Instances {
|
|
73
|
+
err := v.validateInstance(instance)
|
|
74
|
+
if err != nil {
|
|
75
|
+
return bosherr.WrapError(err, "Instance %d", instance.Index)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return nil
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
func (v SemanticValidator) validateTemplate(template Template) error {
|
|
83
|
+
if template.Release == nil {
|
|
84
|
+
return bosherr.New("Missing associated release")
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return nil
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
func (v SemanticValidator) validateInstance(instance Instance) error {
|
|
91
|
+
for i, na := range instance.NetworkAssociations {
|
|
92
|
+
err := v.validateNetworkAssociation(na)
|
|
93
|
+
if err != nil {
|
|
94
|
+
return bosherr.WrapError(err, "Network association %d", i)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return nil
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
func (v SemanticValidator) validateNetworkAssociation(na NetworkAssociation) error {
|
|
102
|
+
if na.Network == nil {
|
|
103
|
+
return bosherr.New("Missing associated network")
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if na.MustHaveStaticIP && na.StaticIP == nil {
|
|
107
|
+
return bosherr.New("Missing static IP assignment")
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return nil
|
|
111
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
package downloader
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
gourl "net/url"
|
|
5
|
+
|
|
6
|
+
boshblob "bosh/blobstore"
|
|
7
|
+
bosherr "bosh/errors"
|
|
8
|
+
boshlog "bosh/logger"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
const blobstoreDownloaderLogTag = "BlobstoreDownloader"
|
|
12
|
+
|
|
13
|
+
type BlobstoreDownloader struct {
|
|
14
|
+
blobstore boshblob.Blobstore
|
|
15
|
+
logger boshlog.Logger
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
func NewBlobstoreDownloader(
|
|
19
|
+
blobstore boshblob.Blobstore,
|
|
20
|
+
logger boshlog.Logger,
|
|
21
|
+
) BlobstoreDownloader {
|
|
22
|
+
return BlobstoreDownloader{
|
|
23
|
+
blobstore: blobstore,
|
|
24
|
+
logger: logger,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Download takes URL of format blobstore:///blobId?fingerprint=sha1-value
|
|
29
|
+
func (d BlobstoreDownloader) Download(url string) (string, error) {
|
|
30
|
+
parsedURL, err := gourl.Parse(url)
|
|
31
|
+
if err != nil {
|
|
32
|
+
return "", bosherr.WrapError(err, "Parsing url %s", url)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
var fingerprint string
|
|
36
|
+
|
|
37
|
+
if fingerprints, found := parsedURL.Query()["fingerprint"]; found {
|
|
38
|
+
if len(fingerprints) > 0 {
|
|
39
|
+
fingerprint = fingerprints[0]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
path, err := d.blobstore.Get(parsedURL.Path, fingerprint)
|
|
44
|
+
if err != nil {
|
|
45
|
+
return "", bosherr.WrapError(err, "Downloading blob")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
d.logger.Debug(blobstoreDownloaderLogTag, "Downloaded %s to %s", url, path)
|
|
49
|
+
|
|
50
|
+
return path, nil
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func (d BlobstoreDownloader) CleanUp(path string) error {
|
|
54
|
+
return d.blobstore.CleanUp(path)
|
|
55
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
package downloader
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
boshblob "bosh/blobstore"
|
|
5
|
+
boshlog "bosh/logger"
|
|
6
|
+
boshsys "bosh/system"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
func NewDefaultMuxDownloader(
|
|
10
|
+
blobstore boshblob.Blobstore,
|
|
11
|
+
fs boshsys.FileSystem,
|
|
12
|
+
logger boshlog.Logger,
|
|
13
|
+
) MuxDownloader {
|
|
14
|
+
mux := map[string]Downloader{
|
|
15
|
+
"http": NewHTTPDownloader(fs, logger),
|
|
16
|
+
"https": NewHTTPDownloader(fs, logger),
|
|
17
|
+
"file": NewLocalFSDownloader(fs, logger),
|
|
18
|
+
"blobstore": NewBlobstoreDownloader(blobstore, logger),
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return NewMuxDownloader(mux, logger)
|
|
22
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
package downloader
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"io"
|
|
5
|
+
"net/http"
|
|
6
|
+
|
|
7
|
+
bosherr "bosh/errors"
|
|
8
|
+
boshlog "bosh/logger"
|
|
9
|
+
boshsys "bosh/system"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
const httpDownloaderLogTag = "HTTPDownloader"
|
|
13
|
+
|
|
14
|
+
type HTTPDownloader struct {
|
|
15
|
+
fs boshsys.FileSystem
|
|
16
|
+
logger boshlog.Logger
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
func NewHTTPDownloader(
|
|
20
|
+
fs boshsys.FileSystem,
|
|
21
|
+
logger boshlog.Logger,
|
|
22
|
+
) HTTPDownloader {
|
|
23
|
+
return HTTPDownloader{fs: fs, logger: logger}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func (d HTTPDownloader) Download(url string) (string, error) {
|
|
27
|
+
file, err := d.fs.TempFile("release-Downloader-HTTPDownloader")
|
|
28
|
+
if err != nil {
|
|
29
|
+
return "", bosherr.WrapError(err, "Creating download destination")
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
d.logger.Debug(httpDownloaderLogTag, "Downloaded %s to %s", url, file.Name())
|
|
33
|
+
|
|
34
|
+
defer file.Close()
|
|
35
|
+
|
|
36
|
+
resp, err := http.Get(url)
|
|
37
|
+
if err != nil {
|
|
38
|
+
return "", bosherr.WrapError(err, "Get url")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
defer resp.Body.Close()
|
|
42
|
+
|
|
43
|
+
_, err = io.Copy(file, resp.Body)
|
|
44
|
+
if err != nil {
|
|
45
|
+
return "", bosherr.WrapError(err, "Copying response to file")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return file.Name(), nil
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
func (d HTTPDownloader) CleanUp(path string) error {
|
|
52
|
+
return d.fs.RemoveAll(path)
|
|
53
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
package downloader
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"strings"
|
|
5
|
+
|
|
6
|
+
bosherr "bosh/errors"
|
|
7
|
+
boshlog "bosh/logger"
|
|
8
|
+
boshsys "bosh/system"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
const localFSDownloaderLogTag = "Downloader"
|
|
12
|
+
|
|
13
|
+
type LocalFSDownloader struct {
|
|
14
|
+
fs boshsys.FileSystem
|
|
15
|
+
logger boshlog.Logger
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
func NewLocalFSDownloader(
|
|
19
|
+
fs boshsys.FileSystem,
|
|
20
|
+
logger boshlog.Logger,
|
|
21
|
+
) LocalFSDownloader {
|
|
22
|
+
return LocalFSDownloader{fs: fs, logger: logger}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func (d LocalFSDownloader) Download(url string) (string, error) {
|
|
26
|
+
file, err := d.fs.TempFile("downloader-LocalFSDownloader")
|
|
27
|
+
if err != nil {
|
|
28
|
+
return "", bosherr.WrapError(err, "Creating download destination")
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
d.logger.Debug(localFSDownloaderLogTag, "Downloaded %s to %s", url, file.Name())
|
|
32
|
+
|
|
33
|
+
err = file.Close()
|
|
34
|
+
if err != nil {
|
|
35
|
+
return "", bosherr.WrapError(err, "Closing download destination")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
err = d.fs.CopyFile(strings.TrimPrefix(url, "file://"), file.Name())
|
|
39
|
+
if err != nil {
|
|
40
|
+
return "", bosherr.WrapError(err, "Copying to destination")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return file.Name(), nil
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func (d LocalFSDownloader) CleanUp(path string) error {
|
|
47
|
+
return d.fs.RemoveAll(path)
|
|
48
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
package downloader
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"strings"
|
|
5
|
+
|
|
6
|
+
bosherr "bosh/errors"
|
|
7
|
+
boshlog "bosh/logger"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
const muxDownloaderLogTag = "Downloader"
|
|
11
|
+
|
|
12
|
+
type MuxDownloader struct {
|
|
13
|
+
// e.g. {"http": NewHTTPDownloader()}
|
|
14
|
+
mux map[string]Downloader
|
|
15
|
+
|
|
16
|
+
logger boshlog.Logger
|
|
17
|
+
|
|
18
|
+
// Track which Downloader should be used to clean up
|
|
19
|
+
downloadedPaths map[string]Downloader
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
func NewMuxDownloader(
|
|
23
|
+
mux map[string]Downloader,
|
|
24
|
+
logger boshlog.Logger,
|
|
25
|
+
) MuxDownloader {
|
|
26
|
+
return MuxDownloader{
|
|
27
|
+
mux: mux,
|
|
28
|
+
logger: logger,
|
|
29
|
+
|
|
30
|
+
downloadedPaths: map[string]Downloader{},
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func (d MuxDownloader) Download(url string) (string, error) {
|
|
35
|
+
for prefix, downloader := range d.mux {
|
|
36
|
+
if strings.HasPrefix(url, prefix+"://") {
|
|
37
|
+
path, err := downloader.Download(url)
|
|
38
|
+
if err != nil {
|
|
39
|
+
return path, err
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Only remember path if Downloader succeeded
|
|
43
|
+
d.downloadedPaths[path] = downloader
|
|
44
|
+
|
|
45
|
+
return path, err
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return "", bosherr.New("URL %s without matching downloader", url)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func (d MuxDownloader) CleanUp(path string) error {
|
|
53
|
+
downloader, ok := d.downloadedPaths[path]
|
|
54
|
+
if !ok {
|
|
55
|
+
// programmer error
|
|
56
|
+
return bosherr.New("Unknown path %s requested to be cleaned up", path)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
err := downloader.CleanUp(path)
|
|
60
|
+
if err != nil {
|
|
61
|
+
return err
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Forget path only if associated Downloader succeeded cleaning up
|
|
65
|
+
// so that CleanUp could be called multiple times
|
|
66
|
+
delete(d.downloadedPaths, path)
|
|
67
|
+
|
|
68
|
+
return nil
|
|
69
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
package eventlog
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"io"
|
|
6
|
+
"os"
|
|
7
|
+
|
|
8
|
+
bosherr "bosh/errors"
|
|
9
|
+
boshlog "bosh/logger"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
const logLogTag = "Log"
|
|
13
|
+
|
|
14
|
+
type Log struct {
|
|
15
|
+
writer io.Writer
|
|
16
|
+
logger boshlog.Logger
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type logEntry struct {
|
|
20
|
+
Time int64 `json:"time"`
|
|
21
|
+
|
|
22
|
+
Stage string `json:"stage"`
|
|
23
|
+
Task string `json:"task"`
|
|
24
|
+
Tags []string `json:"tags"`
|
|
25
|
+
|
|
26
|
+
Total int `json:"total"`
|
|
27
|
+
Index int `json:"index"`
|
|
28
|
+
|
|
29
|
+
State string `json:"state"`
|
|
30
|
+
Progress int `json:"progress"`
|
|
31
|
+
|
|
32
|
+
// Might contain error key
|
|
33
|
+
Data map[string]interface{} `json:"data,omitempty"`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
func NewLog(logger boshlog.Logger) Log {
|
|
37
|
+
return Log{
|
|
38
|
+
writer: os.Stdout,
|
|
39
|
+
logger: logger,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
func (l Log) BeginStage(name string, total int) *Stage {
|
|
44
|
+
return &Stage{
|
|
45
|
+
log: l,
|
|
46
|
+
name: name,
|
|
47
|
+
total: total,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
func (l Log) writeLogEntryNoErr(entry logEntry) {
|
|
52
|
+
err := l.writeLogEntry(entry)
|
|
53
|
+
if err != nil {
|
|
54
|
+
l.logger.Error(logLogTag, "Failed writing log entry %s", err.Error())
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func (l Log) writeLogEntry(entry logEntry) error {
|
|
59
|
+
bytes, err := json.Marshal(entry)
|
|
60
|
+
if err != nil {
|
|
61
|
+
return bosherr.WrapError(err, "Marshalling log entry")
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
bytes = append(bytes, []byte("\n")...)
|
|
65
|
+
|
|
66
|
+
_, err = l.writer.Write(bytes)
|
|
67
|
+
if err != nil {
|
|
68
|
+
return bosherr.WrapError(err, "Writing log entry")
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return nil
|
|
72
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
package eventlog
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"sync"
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
type Stage struct {
|
|
8
|
+
log Log
|
|
9
|
+
|
|
10
|
+
name string
|
|
11
|
+
|
|
12
|
+
total int
|
|
13
|
+
currTaskIndex int
|
|
14
|
+
|
|
15
|
+
indexLock sync.Mutex
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
func (s *Stage) BeginTask(name string) Task {
|
|
19
|
+
s.indexLock.Lock()
|
|
20
|
+
|
|
21
|
+
index := s.currTaskIndex
|
|
22
|
+
s.currTaskIndex++
|
|
23
|
+
|
|
24
|
+
s.indexLock.Unlock()
|
|
25
|
+
|
|
26
|
+
task := Task{
|
|
27
|
+
log: s.log,
|
|
28
|
+
|
|
29
|
+
stageName: s.name,
|
|
30
|
+
name: name,
|
|
31
|
+
|
|
32
|
+
total: s.total,
|
|
33
|
+
index: index,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
task.Start()
|
|
37
|
+
|
|
38
|
+
return task
|
|
39
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
package eventlog
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"time"
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
type Task struct {
|
|
8
|
+
log Log
|
|
9
|
+
|
|
10
|
+
stageName string
|
|
11
|
+
name string
|
|
12
|
+
|
|
13
|
+
total int
|
|
14
|
+
index int
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
func (t Task) Start() {
|
|
18
|
+
entry := logEntry{
|
|
19
|
+
Time: time.Now().Unix(),
|
|
20
|
+
|
|
21
|
+
Stage: t.stageName,
|
|
22
|
+
Task: t.name,
|
|
23
|
+
|
|
24
|
+
Total: t.total,
|
|
25
|
+
Index: t.index,
|
|
26
|
+
|
|
27
|
+
State: "started",
|
|
28
|
+
Progress: 0,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
t.log.writeLogEntryNoErr(entry)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func (t Task) End(err error) error {
|
|
35
|
+
entry := logEntry{
|
|
36
|
+
Time: time.Now().Unix(),
|
|
37
|
+
|
|
38
|
+
Stage: t.stageName,
|
|
39
|
+
Task: t.name,
|
|
40
|
+
|
|
41
|
+
Total: t.total,
|
|
42
|
+
Index: t.index,
|
|
43
|
+
|
|
44
|
+
State: "finished",
|
|
45
|
+
Progress: 100,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if err != nil {
|
|
49
|
+
entry.State = "failed"
|
|
50
|
+
entry.Data = map[string]interface{}{
|
|
51
|
+
"error": err.Error(),
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
t.log.writeLogEntryNoErr(entry)
|
|
56
|
+
|
|
57
|
+
return err
|
|
58
|
+
}
|