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,80 @@
|
|
|
1
|
+
package manifest
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
|
|
6
|
+
bosherr "bosh/errors"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
func (d Deployment) InstanceWatchTime(job Job, i int) WatchTime {
|
|
10
|
+
var canaries int
|
|
11
|
+
|
|
12
|
+
if job.Update.Canaries != nil {
|
|
13
|
+
canaries = *job.Update.Canaries
|
|
14
|
+
} else if d.Update.Canaries != nil {
|
|
15
|
+
canaries = *d.Update.Canaries
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if canaries > i {
|
|
19
|
+
return d.CanaryWatchTime(job)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return d.CanaryWatchTime(job)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func (d Deployment) CanaryWatchTime(job Job) WatchTime {
|
|
26
|
+
if job.Update.CanaryWatchTime != nil {
|
|
27
|
+
return *job.Update.CanaryWatchTime
|
|
28
|
+
} else if d.Update.CanaryWatchTime != nil {
|
|
29
|
+
return *d.Update.CanaryWatchTime
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return DefaultWatchTime
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func (d Deployment) UpdateWatchTime(job Job) WatchTime {
|
|
36
|
+
if job.Update.UpdateWatchTime != nil {
|
|
37
|
+
return *job.Update.UpdateWatchTime
|
|
38
|
+
} else if d.Update.UpdateWatchTime != nil {
|
|
39
|
+
return *d.Update.UpdateWatchTime
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return DefaultWatchTime
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
func (d Deployment) InstanceProperties(job Job, i int) Properties {
|
|
46
|
+
result, err := job.deepCopyProperties()
|
|
47
|
+
if err != nil {
|
|
48
|
+
panic("Deep copying job properties")
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for name, value := range d.Properties {
|
|
52
|
+
if _, ok := result[name]; !ok {
|
|
53
|
+
result[name] = value
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return result
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// deepCopyJobProperties makes a deep copy of job properties.
|
|
61
|
+
// Always returns an initialized map even if job properties are nil.
|
|
62
|
+
func (j Job) deepCopyProperties() (Properties, error) {
|
|
63
|
+
result := map[string]interface{}{}
|
|
64
|
+
|
|
65
|
+
if j.Properties == nil {
|
|
66
|
+
return result, nil
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
bytes, err := json.Marshal(j.Properties)
|
|
70
|
+
if err != nil {
|
|
71
|
+
return result, bosherr.WrapError(err, "Marshalling job properties")
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
err = json.Unmarshal(bytes, &result)
|
|
75
|
+
if err != nil {
|
|
76
|
+
return result, bosherr.WrapError(err, "Unmarshalling job properties")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return result, nil
|
|
80
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
package manifest
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
gonet "net"
|
|
5
|
+
"strings"
|
|
6
|
+
|
|
7
|
+
bosherr "bosh/errors"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func NewIPsFromStrings(strs []string) ([]gonet.IP, error) {
|
|
11
|
+
var ips []gonet.IP
|
|
12
|
+
|
|
13
|
+
for _, str := range strs {
|
|
14
|
+
ip := gonet.ParseIP(strings.Trim(str, " "))
|
|
15
|
+
if ip == nil {
|
|
16
|
+
return ips, bosherr.New("Parsing IP %s", str)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
ips = append(ips, ip)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return ips, nil
|
|
23
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// Package manifest represents structure
|
|
2
|
+
// of a user entered YAML deployment manifest.
|
|
3
|
+
package manifest
|
|
4
|
+
|
|
5
|
+
import (
|
|
6
|
+
gonet "net"
|
|
7
|
+
|
|
8
|
+
bosherr "bosh/errors"
|
|
9
|
+
boshsys "bosh/system"
|
|
10
|
+
"github.com/fraenkel/candiedyaml"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
type Manifest struct {
|
|
14
|
+
Deployment Deployment
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type Deployment struct {
|
|
18
|
+
Name string `yaml:"name"`
|
|
19
|
+
|
|
20
|
+
Releases []Release `yaml:"releases"`
|
|
21
|
+
|
|
22
|
+
Networks []Network `yaml:"networks"`
|
|
23
|
+
|
|
24
|
+
Compilation Compilation `yaml:"compilation"`
|
|
25
|
+
|
|
26
|
+
// Deployment-wide update config can be
|
|
27
|
+
// overwritten by job-specific update config
|
|
28
|
+
Update Update `yaml:"update"`
|
|
29
|
+
|
|
30
|
+
Jobs []Job `yaml:"jobs"`
|
|
31
|
+
|
|
32
|
+
// Global properties.
|
|
33
|
+
// Non-raw field is populated by the validator.
|
|
34
|
+
PropertiesRaw map[interface{}]interface{} `yaml:"properties"`
|
|
35
|
+
Properties Properties
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type Release struct {
|
|
39
|
+
Name string `yaml:"name"`
|
|
40
|
+
Version string `yaml:"version"`
|
|
41
|
+
|
|
42
|
+
// Not offical BOSH manifest construct
|
|
43
|
+
URL string `yaml:"url"`
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const (
|
|
47
|
+
NetworkTypeManual = "manual"
|
|
48
|
+
NetworkTypeDynamic = "dynamic"
|
|
49
|
+
NetworkTypeVip = "vip"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
var NetworkTypes = []string{NetworkTypeManual, NetworkTypeDynamic, NetworkTypeVip}
|
|
53
|
+
|
|
54
|
+
type Network struct {
|
|
55
|
+
Name string `yaml:"name"`
|
|
56
|
+
|
|
57
|
+
// e.g. manual, dynamic, vip
|
|
58
|
+
Type string `yaml:"type"`
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type Compilation struct {
|
|
62
|
+
NetworkName string `yaml:"network"`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type Job struct {
|
|
66
|
+
Name string `yaml:"name"`
|
|
67
|
+
Instances int `yaml:"instances"`
|
|
68
|
+
|
|
69
|
+
Update Update `yaml:"update"`
|
|
70
|
+
|
|
71
|
+
// Deprecated in favor of Templates
|
|
72
|
+
Template interface{} `yaml:"template"`
|
|
73
|
+
|
|
74
|
+
Templates []Template `yaml:"templates"`
|
|
75
|
+
|
|
76
|
+
// Job specific properties that override global properties.
|
|
77
|
+
// Non-raw field is populated by the validator.
|
|
78
|
+
PropertiesRaw map[interface{}]interface{} `yaml:"properties"`
|
|
79
|
+
Properties Properties
|
|
80
|
+
|
|
81
|
+
NetworkAssociations []NetworkAssociation `yaml:"networks"`
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type Template struct {
|
|
85
|
+
Name string `yaml:"name"`
|
|
86
|
+
ReleaseName string `yaml:"release"`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
type Properties map[string]interface{}
|
|
90
|
+
|
|
91
|
+
type Update struct {
|
|
92
|
+
// Integer pointers to determine absence
|
|
93
|
+
Canaries *int `yaml:"canaries"`
|
|
94
|
+
MaxInFlight *int `yaml:"max_in_flight"`
|
|
95
|
+
|
|
96
|
+
// String pointers to determine absence
|
|
97
|
+
CanaryWatchTimeRaw *string `yaml:"canary_watch_time"`
|
|
98
|
+
UpdateWatchTimeRaw *string `yaml:"update_watch_time"`
|
|
99
|
+
|
|
100
|
+
// Populated by the validator
|
|
101
|
+
CanaryWatchTime *WatchTime
|
|
102
|
+
UpdateWatchTime *WatchTime
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
type NetworkAssociation struct {
|
|
106
|
+
NetworkName string `yaml:"name"`
|
|
107
|
+
|
|
108
|
+
// Non-raw field populated by the validator.
|
|
109
|
+
StaticIPsRaw []string `yaml:"static_ips"`
|
|
110
|
+
StaticIPs []gonet.IP
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// NewManifestFromPath returns manifest read from the file system.
|
|
114
|
+
// Before returning manifest is syntactically validated.
|
|
115
|
+
func NewManifestFromPath(path string, fs boshsys.FileSystem) (Manifest, error) {
|
|
116
|
+
bytes, err := fs.ReadFile(path)
|
|
117
|
+
if err != nil {
|
|
118
|
+
return Manifest{}, bosherr.WrapError(err, "Reading manifest %s", path)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return NewManifestFromBytes(bytes)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// NewManifestFromBytes returns manifest built from given bytes.
|
|
125
|
+
// Before returning manifest is syntactically validated.
|
|
126
|
+
func NewManifestFromBytes(bytes []byte) (Manifest, error) {
|
|
127
|
+
var manifest Manifest
|
|
128
|
+
var deployment Deployment
|
|
129
|
+
|
|
130
|
+
err := candiedyaml.Unmarshal(bytes, &deployment)
|
|
131
|
+
if err != nil {
|
|
132
|
+
return manifest, bosherr.WrapError(err, "Parsing deployment")
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
manifest.Deployment = deployment
|
|
136
|
+
|
|
137
|
+
err = NewSyntaxValidator(&manifest).Validate()
|
|
138
|
+
if err != nil {
|
|
139
|
+
return manifest, bosherr.WrapError(err, "Validating manifest syntactically")
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return manifest, nil
|
|
143
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
package manifest_test
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
. "github.com/onsi/ginkgo"
|
|
5
|
+
. "github.com/onsi/gomega"
|
|
6
|
+
|
|
7
|
+
. "boshprovisioner/deployment/manifest"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
var _ = Describe("Manifest", func() {
|
|
11
|
+
Describe("NewManifestFromBytes", func() {
|
|
12
|
+
It("returns manifest with deployment properties that have string keys", func() {
|
|
13
|
+
manifestBytes := []byte(`
|
|
14
|
+
name: fake-deployment
|
|
15
|
+
|
|
16
|
+
networks:
|
|
17
|
+
- name: net1
|
|
18
|
+
type: dynamic
|
|
19
|
+
|
|
20
|
+
compilation:
|
|
21
|
+
network: net1
|
|
22
|
+
|
|
23
|
+
properties:
|
|
24
|
+
prop:
|
|
25
|
+
nest-prop: instance-val
|
|
26
|
+
props:
|
|
27
|
+
- name: nest-prop
|
|
28
|
+
`)
|
|
29
|
+
|
|
30
|
+
manifest, err := NewManifestFromBytes(manifestBytes)
|
|
31
|
+
Expect(err).ToNot(HaveOccurred())
|
|
32
|
+
|
|
33
|
+
depProps := manifest.Deployment.Properties
|
|
34
|
+
|
|
35
|
+
// candiedyaml unmarshals manifest to map[interface{}]interface{}
|
|
36
|
+
// (encoding/json unmarshals manifest to map[string]interface{})
|
|
37
|
+
Expect(depProps).To(Equal(Properties(
|
|
38
|
+
map[string]interface{}{
|
|
39
|
+
"prop": map[string]interface{}{
|
|
40
|
+
"nest-prop": "instance-val",
|
|
41
|
+
},
|
|
42
|
+
"props": []interface{}{
|
|
43
|
+
map[string]interface{}{"name": "nest-prop"},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
)))
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
It("returns manifest with job properties that have string keys", func() {
|
|
50
|
+
manifestBytes := []byte(`
|
|
51
|
+
name: fake-deployment
|
|
52
|
+
|
|
53
|
+
networks:
|
|
54
|
+
- name: net1
|
|
55
|
+
type: dynamic
|
|
56
|
+
|
|
57
|
+
compilation:
|
|
58
|
+
network: net1
|
|
59
|
+
|
|
60
|
+
jobs:
|
|
61
|
+
- name: job-1
|
|
62
|
+
properties:
|
|
63
|
+
prop:
|
|
64
|
+
nest-prop: instance-val
|
|
65
|
+
props:
|
|
66
|
+
- name: nest-prop
|
|
67
|
+
`)
|
|
68
|
+
|
|
69
|
+
manifest, err := NewManifestFromBytes(manifestBytes)
|
|
70
|
+
Expect(err).ToNot(HaveOccurred())
|
|
71
|
+
|
|
72
|
+
jobProps := manifest.Deployment.Jobs[0].Properties
|
|
73
|
+
|
|
74
|
+
Expect(jobProps).To(Equal(Properties(
|
|
75
|
+
map[string]interface{}{
|
|
76
|
+
"prop": map[string]interface{}{
|
|
77
|
+
"nest-prop": "instance-val",
|
|
78
|
+
},
|
|
79
|
+
"props": []interface{}{
|
|
80
|
+
map[string]interface{}{"name": "nest-prop"},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
)))
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
})
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
package manifest
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
bosherr "bosh/errors"
|
|
5
|
+
|
|
6
|
+
bputil "boshprovisioner/util"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// SyntaxValidator parses and saves all manifest values to determine
|
|
10
|
+
// their syntactic validity. Determining if individual values make sense
|
|
11
|
+
// in a greater context (within a deployment or a job) is outside of scope.
|
|
12
|
+
// e.g. - can watch time string value be parsed into a time range?
|
|
13
|
+
type SyntaxValidator struct {
|
|
14
|
+
deployment *Deployment
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
func NewSyntaxValidator(manifest *Manifest) SyntaxValidator {
|
|
18
|
+
if manifest == nil {
|
|
19
|
+
panic("Expected manifest to not be nil")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return SyntaxValidator{deployment: &manifest.Deployment}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func (v SyntaxValidator) Validate() error {
|
|
26
|
+
if v.deployment.Name == "" {
|
|
27
|
+
return bosherr.New("Missing deployment name")
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
err := v.validateUpdate(&v.deployment.Update)
|
|
31
|
+
if err != nil {
|
|
32
|
+
return bosherr.WrapError(err, "Deployment update")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
for i, net := range v.deployment.Networks {
|
|
36
|
+
err := v.validateNetwork(&v.deployment.Networks[i])
|
|
37
|
+
if err != nil {
|
|
38
|
+
return bosherr.WrapError(err, "Network %s (%d)", net.Name, i)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for i, release := range v.deployment.Releases {
|
|
43
|
+
err := v.validateRelease(&v.deployment.Releases[i])
|
|
44
|
+
if err != nil {
|
|
45
|
+
return bosherr.WrapError(err, "Release %s (%d)", release.Name, i)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
err = v.validateCompilation(&v.deployment.Compilation)
|
|
50
|
+
if err != nil {
|
|
51
|
+
return bosherr.WrapError(err, "Compilation")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
for i, job := range v.deployment.Jobs {
|
|
55
|
+
err := v.validateJob(&v.deployment.Jobs[i])
|
|
56
|
+
if err != nil {
|
|
57
|
+
return bosherr.WrapError(err, "Job %s (%d)", job.Name, i)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
props, err := bputil.NewStringKeyed().ConvertMap(v.deployment.PropertiesRaw)
|
|
62
|
+
if err != nil {
|
|
63
|
+
return bosherr.WrapError(err, "Deployment properties")
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
v.deployment.Properties = props
|
|
67
|
+
|
|
68
|
+
return nil
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func (v SyntaxValidator) validateNetwork(network *Network) error {
|
|
72
|
+
if network.Name == "" {
|
|
73
|
+
return bosherr.New("Missing network name")
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return v.validateNetworkType(network.Type)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
func (v SyntaxValidator) validateNetworkType(networkType string) error {
|
|
80
|
+
if networkType == "" {
|
|
81
|
+
return bosherr.New("Missing network type")
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
for _, t := range NetworkTypes {
|
|
85
|
+
if networkType == t {
|
|
86
|
+
return nil
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return bosherr.New("Unknown network type %s", networkType)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
func (v SyntaxValidator) validateRelease(release *Release) error {
|
|
94
|
+
if release.Name == "" {
|
|
95
|
+
return bosherr.New("Missing release name")
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if release.Version == "" {
|
|
99
|
+
return bosherr.New("Missing release version")
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if release.URL == "" {
|
|
103
|
+
return bosherr.New("Missing release URL")
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return nil
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
func (v SyntaxValidator) validateCompilation(compilation *Compilation) error {
|
|
110
|
+
if compilation.NetworkName == "" {
|
|
111
|
+
return bosherr.New("Missing network name")
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return nil
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
func (v SyntaxValidator) validateJob(job *Job) error {
|
|
118
|
+
if job.Name == "" {
|
|
119
|
+
return bosherr.New("Missing job name")
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if job.Template != nil {
|
|
123
|
+
return bosherr.New("'template' is deprecated in favor of 'templates'")
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
err := v.validateUpdate(&job.Update)
|
|
127
|
+
if err != nil {
|
|
128
|
+
return bosherr.WrapError(err, "Update")
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
props, err := bputil.NewStringKeyed().ConvertMap(job.PropertiesRaw)
|
|
132
|
+
if err != nil {
|
|
133
|
+
return bosherr.WrapError(err, "Properties")
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
job.Properties = props
|
|
137
|
+
|
|
138
|
+
for i, na := range job.NetworkAssociations {
|
|
139
|
+
err := v.validateNetworkAssociation(&job.NetworkAssociations[i])
|
|
140
|
+
if err != nil {
|
|
141
|
+
return bosherr.WrapError(err, "Network association %s (%d)", na.NetworkName, i)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return nil
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// validateUpdate validates deployment level or job level update section
|
|
149
|
+
func (v SyntaxValidator) validateUpdate(update *Update) error {
|
|
150
|
+
if update.CanaryWatchTimeRaw != nil {
|
|
151
|
+
watchTime, err := NewWatchTimeFromString(*update.CanaryWatchTimeRaw)
|
|
152
|
+
if err != nil {
|
|
153
|
+
return bosherr.WrapError(err, "Canary watch time")
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
update.CanaryWatchTime = &watchTime
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if update.UpdateWatchTimeRaw != nil {
|
|
160
|
+
watchTime, err := NewWatchTimeFromString(*update.UpdateWatchTimeRaw)
|
|
161
|
+
if err != nil {
|
|
162
|
+
return bosherr.WrapError(err, "Update watch time")
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
update.UpdateWatchTime = &watchTime
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return nil
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
func (v SyntaxValidator) validateNetworkAssociation(na *NetworkAssociation) error {
|
|
172
|
+
if na.NetworkName == "" {
|
|
173
|
+
return bosherr.New("Missing network name")
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if na.StaticIPsRaw != nil {
|
|
177
|
+
ips, err := NewIPsFromStrings(na.StaticIPsRaw)
|
|
178
|
+
if err != nil {
|
|
179
|
+
return bosherr.WrapError(err, "Static IPs")
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
na.StaticIPs = ips
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return nil
|
|
186
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
package manifest
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"strconv"
|
|
5
|
+
"strings"
|
|
6
|
+
|
|
7
|
+
bosherr "bosh/errors"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
type WatchTime [2]int
|
|
11
|
+
|
|
12
|
+
var (
|
|
13
|
+
DefaultWatchTime = WatchTime{0, 0}
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
func NewWatchTimeFromString(str string) (WatchTime, error) {
|
|
17
|
+
var watchTime WatchTime
|
|
18
|
+
|
|
19
|
+
parts := strings.Split(str, "-")
|
|
20
|
+
if len(parts) != 2 {
|
|
21
|
+
return watchTime, bosherr.New("Invalid watch time range %s", str)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
min, err := strconv.Atoi(strings.Trim(parts[0], " "))
|
|
25
|
+
if err != nil {
|
|
26
|
+
return watchTime, bosherr.WrapError(
|
|
27
|
+
err, "Non-positive number as watch time minimum %s", parts[0])
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
max, err := strconv.Atoi(strings.Trim(parts[1], " "))
|
|
31
|
+
if err != nil {
|
|
32
|
+
return watchTime, bosherr.WrapError(
|
|
33
|
+
err, "Non-positive number as watch time maximum %s", parts[1])
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if max < min {
|
|
37
|
+
return watchTime, bosherr.New(
|
|
38
|
+
"Watch time must have maximum greater than or equal minimum %s", str)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
watchTime[0], watchTime[1] = min, max
|
|
42
|
+
|
|
43
|
+
return watchTime, nil
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func (wt WatchTime) Start() int { return wt[0] }
|
|
47
|
+
func (wt WatchTime) End() int { return wt[1] }
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
package deployment
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
bosherr "bosh/errors"
|
|
5
|
+
boshlog "bosh/logger"
|
|
6
|
+
boshsys "bosh/system"
|
|
7
|
+
|
|
8
|
+
bpdepman "boshprovisioner/deployment/manifest"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
type ManifestReader struct {
|
|
12
|
+
path string
|
|
13
|
+
fs boshsys.FileSystem
|
|
14
|
+
logger boshlog.Logger
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
func NewManifestReader(
|
|
18
|
+
path string,
|
|
19
|
+
fs boshsys.FileSystem,
|
|
20
|
+
logger boshlog.Logger,
|
|
21
|
+
) ManifestReader {
|
|
22
|
+
return ManifestReader{path: path, fs: fs, logger: logger}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func (r ManifestReader) Read() (Deployment, error) {
|
|
26
|
+
var deployment Deployment
|
|
27
|
+
|
|
28
|
+
manifest, err := bpdepman.NewManifestFromPath(r.path, r.fs)
|
|
29
|
+
if err != nil {
|
|
30
|
+
return deployment, bosherr.WrapError(err, "Reading manifest")
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
deployment.populateFromManifest(manifest)
|
|
34
|
+
|
|
35
|
+
// todo pass by ref?
|
|
36
|
+
err = NewSemanticValidator(deployment).Validate()
|
|
37
|
+
if err != nil {
|
|
38
|
+
return deployment, bosherr.WrapError(err, "Validating deployment semantically")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return deployment, nil
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func (r ManifestReader) Close() error {
|
|
45
|
+
return nil
|
|
46
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
package deployment
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
boshlog "bosh/logger"
|
|
5
|
+
boshsys "bosh/system"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
type ReaderFactory struct {
|
|
9
|
+
fs boshsys.FileSystem
|
|
10
|
+
logger boshlog.Logger
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
func NewReaderFactory(
|
|
14
|
+
fs boshsys.FileSystem,
|
|
15
|
+
logger boshlog.Logger,
|
|
16
|
+
) ReaderFactory {
|
|
17
|
+
return ReaderFactory{
|
|
18
|
+
fs: fs,
|
|
19
|
+
logger: logger,
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
func (rf ReaderFactory) NewManifestReader(path string) ManifestReader {
|
|
24
|
+
return NewManifestReader(path, rf.fs, rf.logger)
|
|
25
|
+
}
|