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,299 @@
|
|
|
1
|
+
package client
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"crypto/tls"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"io/ioutil"
|
|
7
|
+
"net/http"
|
|
8
|
+
"net/url"
|
|
9
|
+
"strings"
|
|
10
|
+
"time"
|
|
11
|
+
|
|
12
|
+
boshaction "bosh/agent/action"
|
|
13
|
+
boshas "bosh/agent/applier/applyspec"
|
|
14
|
+
boshcomp "bosh/agent/compiler"
|
|
15
|
+
bosherr "bosh/errors"
|
|
16
|
+
boshlog "bosh/logger"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
const httpClientLogTag = "HTTPClient"
|
|
20
|
+
|
|
21
|
+
type HTTPRequester interface {
|
|
22
|
+
Do(*http.Request) (*http.Response, error)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type HTTPClient struct {
|
|
26
|
+
url *url.URL
|
|
27
|
+
requester HTTPRequester
|
|
28
|
+
logger boshlog.Logger
|
|
29
|
+
|
|
30
|
+
// Alias to method calls for convenience
|
|
31
|
+
quickRequest requestFunc
|
|
32
|
+
longRequest requestFunc
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type requestFunc func(reqMethod, reqArgs) (responseEnvelope, error)
|
|
36
|
+
|
|
37
|
+
func NewInsecureHTTPClientWithURI(uri string, logger boshlog.Logger) (HTTPClient, error) {
|
|
38
|
+
mTLSConfig := &tls.Config{InsecureSkipVerify: true}
|
|
39
|
+
transport := &http.Transport{TLSClientConfig: mTLSConfig}
|
|
40
|
+
httpRequester := &http.Client{Transport: transport}
|
|
41
|
+
return NewHTTPClientWithURI(uri, httpRequester, logger)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
func NewHTTPClientWithURI(uri string, requester HTTPRequester, logger boshlog.Logger) (HTTPClient, error) {
|
|
45
|
+
url, err := url.ParseRequestURI(uri)
|
|
46
|
+
if err != nil {
|
|
47
|
+
return HTTPClient{}, bosherr.WrapError(err, "Parsing request uri")
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return NewHTTPClient(url, requester, logger), nil
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func NewHTTPClient(url *url.URL, requester HTTPRequester, logger boshlog.Logger) HTTPClient {
|
|
54
|
+
client := HTTPClient{
|
|
55
|
+
url: url,
|
|
56
|
+
requester: requester,
|
|
57
|
+
logger: logger,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
client.quickRequest = client.makeQuickRequest
|
|
61
|
+
client.longRequest = client.makeLongRequest
|
|
62
|
+
|
|
63
|
+
return client
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
func (ac HTTPClient) Ping() (string, error) {
|
|
67
|
+
return ac.makeStringRequest(ac.quickRequest, "ping", reqArgs{})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
func (ac HTTPClient) GetTask(taskID string) (interface{}, error) {
|
|
71
|
+
val, err := ac.makeQuickRequest("get_task", reqArgs{taskID})
|
|
72
|
+
if err != nil {
|
|
73
|
+
return nil, bosherr.WrapError(err, "makeRequest")
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return val.MapValue()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
func (ac HTTPClient) CancelTask(taskID string) (string, error) {
|
|
80
|
+
return ac.makeStringRequest(ac.quickRequest, "cancel_task", reqArgs{taskID})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func (ac HTTPClient) SSH(cmd string, params boshaction.SshParams) (map[string]interface{}, error) {
|
|
84
|
+
val, err := ac.makeQuickRequest("ssh", reqArgs{cmd, params})
|
|
85
|
+
if err != nil {
|
|
86
|
+
return nil, bosherr.WrapError(err, "makeRequest")
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return val.MapValue()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
func (ac HTTPClient) FetchLogs(logType string, filters []string) (map[string]interface{}, error) {
|
|
93
|
+
val, err := ac.makeLongRequest("fetch_logs", reqArgs{logType, filters})
|
|
94
|
+
if err != nil {
|
|
95
|
+
return nil, bosherr.WrapError(err, "makeRequest")
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return val.MapValue()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
func (ac HTTPClient) Prepare(desiredSpec boshas.V1ApplySpec) (string, error) {
|
|
102
|
+
return ac.makeStringRequest(ac.longRequest, "prepare", reqArgs{desiredSpec})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
func (ac HTTPClient) Apply(desiredSpec boshas.V1ApplySpec) (string, error) {
|
|
106
|
+
return ac.makeStringRequest(ac.longRequest, "apply", reqArgs{desiredSpec})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
func (ac HTTPClient) Start() (string, error) {
|
|
110
|
+
return ac.makeStringRequest(ac.quickRequest, "start", reqArgs{})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
func (ac HTTPClient) Stop() (string, error) {
|
|
114
|
+
return ac.makeStringRequest(ac.longRequest, "stop", reqArgs{})
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
func (ac HTTPClient) Drain(drainType boshaction.DrainType, newSpecs ...boshas.V1ApplySpec) (int, error) {
|
|
118
|
+
var result int
|
|
119
|
+
|
|
120
|
+
args := reqArgs{drainType}
|
|
121
|
+
|
|
122
|
+
for _, newSpec := range newSpecs {
|
|
123
|
+
args = append(args, newSpec)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
val, err := ac.makeLongRequest("drain", args)
|
|
127
|
+
if err != nil {
|
|
128
|
+
return result, bosherr.WrapError(err, "makeRequest")
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
err = val.CustomValue(&result)
|
|
132
|
+
if err != nil {
|
|
133
|
+
return result, bosherr.WrapError(err, "Converting response to int")
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return result, nil
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
func (ac HTTPClient) GetState(filters ...string) (boshaction.GetStateV1ApplySpec, error) {
|
|
140
|
+
var result boshaction.GetStateV1ApplySpec
|
|
141
|
+
|
|
142
|
+
args := reqArgs{}
|
|
143
|
+
|
|
144
|
+
for _, filter := range filters {
|
|
145
|
+
args = append(args, filter)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
val, err := ac.makeQuickRequest("get_state", args)
|
|
149
|
+
if err != nil {
|
|
150
|
+
return result, bosherr.WrapError(err, "makeRequest")
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
err = val.CustomValue(&result)
|
|
154
|
+
if err != nil {
|
|
155
|
+
return result, bosherr.WrapError(err, "Converting response to apply spec")
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return result, nil
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
func (ac HTTPClient) RunErrand() (boshaction.ErrandResult, error) {
|
|
162
|
+
var result errandResultEnvelope
|
|
163
|
+
|
|
164
|
+
val, err := ac.makeLongRequest("run_errand", reqArgs{})
|
|
165
|
+
if err != nil {
|
|
166
|
+
return result.Result, bosherr.WrapError(err, "makeRequest")
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
err = val.CustomValue(&result)
|
|
170
|
+
if err != nil {
|
|
171
|
+
return result.Result, bosherr.WrapError(
|
|
172
|
+
err, "Converting response to errand result")
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return result.Result, nil
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
func (ac HTTPClient) CompilePackage(blobID, sha1, name, version string, deps boshcomp.Dependencies) (CompiledPackage, error) {
|
|
179
|
+
var result compiledPackageEnvelope
|
|
180
|
+
|
|
181
|
+
val, err := ac.makeLongRequest(
|
|
182
|
+
"compile_package",
|
|
183
|
+
reqArgs{blobID, sha1, name, version, deps},
|
|
184
|
+
)
|
|
185
|
+
if err != nil {
|
|
186
|
+
return result.Result, bosherr.WrapError(err, "makeRequest")
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
err = val.CustomValue(&result)
|
|
190
|
+
if err != nil {
|
|
191
|
+
return result.Result, bosherr.WrapError(
|
|
192
|
+
err, "Converting response to errand result")
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return result.Result, nil
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
func (ac HTTPClient) makeStringRequest(f requestFunc, method reqMethod, args reqArgs) (string, error) {
|
|
199
|
+
val, err := f(method, args)
|
|
200
|
+
if err != nil {
|
|
201
|
+
return "", bosherr.WrapError(err, "makeXRequest")
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return val.StringValue()
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
func (ac HTTPClient) makeLongRequest(method reqMethod, args reqArgs) (responseEnvelope, error) {
|
|
208
|
+
val, err := ac.makeQuickRequest(method, args)
|
|
209
|
+
if err != nil {
|
|
210
|
+
return responseEnvelope{}, bosherr.WrapError(err, "makeRequest")
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
for {
|
|
214
|
+
taskID, found := val.TaskID()
|
|
215
|
+
if !found {
|
|
216
|
+
return val, nil
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
time.Sleep(1 * time.Second)
|
|
220
|
+
|
|
221
|
+
val, err = ac.makeQuickRequest("get_task", reqArgs{taskID})
|
|
222
|
+
if err != nil {
|
|
223
|
+
return responseEnvelope{}, bosherr.WrapError(err, "makeRequest")
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
func (ac HTTPClient) makeQuickRequest(method reqMethod, args reqArgs) (responseEnvelope, error) {
|
|
229
|
+
var responseBody responseEnvelope
|
|
230
|
+
|
|
231
|
+
requestBody := requestEnvelope{
|
|
232
|
+
Method: method,
|
|
233
|
+
Arguments: args,
|
|
234
|
+
ReplyTo: "n-a",
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
requestBytes, err := json.Marshal(requestBody)
|
|
238
|
+
if err != nil {
|
|
239
|
+
return responseBody, bosherr.WrapError(err, "Marshalling request body")
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
responseBytes, err := ac.makePlainRequest(string(requestBytes), "application/json")
|
|
243
|
+
if err != nil {
|
|
244
|
+
return responseBody, bosherr.WrapError(err, "Making plain request")
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
err = json.Unmarshal(responseBytes, &responseBody)
|
|
248
|
+
if err != nil {
|
|
249
|
+
return responseBody, bosherr.WrapError(err, "Unmarshalling response body")
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if responseBody.HasException() {
|
|
253
|
+
return responseBody, bosherr.New("Ended with exception %#v", responseBody.Exception)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return responseBody, nil
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
func (ac HTTPClient) makePlainRequest(requestBody, contentType string) ([]byte, error) {
|
|
260
|
+
ac.logger.Debug(httpClientLogTag, "Making request url=%s", ac.url.String())
|
|
261
|
+
|
|
262
|
+
ac.logger.DebugWithDetails(httpClientLogTag, "Request body", requestBody)
|
|
263
|
+
|
|
264
|
+
request, err := http.NewRequest("POST", "", strings.NewReader(requestBody))
|
|
265
|
+
if err != nil {
|
|
266
|
+
return []byte{}, bosherr.WrapError(err, "Building request")
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Basic auth credentials are retrieved from the url
|
|
270
|
+
request.URL = ac.url
|
|
271
|
+
|
|
272
|
+
request.Header.Set("Content-Type", contentType)
|
|
273
|
+
|
|
274
|
+
response, err := ac.requester.Do(request)
|
|
275
|
+
if err != nil {
|
|
276
|
+
if response != nil {
|
|
277
|
+
ac.logger.Error(httpClientLogTag,
|
|
278
|
+
"Received error=%v (response=%d)", err, response.StatusCode)
|
|
279
|
+
} else {
|
|
280
|
+
ac.logger.Error(httpClientLogTag,
|
|
281
|
+
"Received error=%v (no response)", err)
|
|
282
|
+
}
|
|
283
|
+
return []byte{}, bosherr.WrapError(err, "Making request failed")
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
ac.logger.Debug(httpClientLogTag,
|
|
287
|
+
"Received response status=%d", response.StatusCode)
|
|
288
|
+
|
|
289
|
+
defer response.Body.Close()
|
|
290
|
+
|
|
291
|
+
responseBytes, err := ioutil.ReadAll(response.Body)
|
|
292
|
+
if err != nil {
|
|
293
|
+
return nil, bosherr.WrapError(err, "Reading response body")
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
ac.logger.DebugWithDetails(httpClientLogTag, "Response body", responseBytes)
|
|
297
|
+
|
|
298
|
+
return responseBytes, nil
|
|
299
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
package client
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
|
|
6
|
+
boshaction "bosh/agent/action"
|
|
7
|
+
bosherr "bosh/errors"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
type requestEnvelope struct {
|
|
11
|
+
Method reqMethod `json:"method"`
|
|
12
|
+
Arguments reqArgs `json:"arguments"`
|
|
13
|
+
ReplyTo string `json:"reply_to"`
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type reqMethod string
|
|
17
|
+
type reqArgs []interface{}
|
|
18
|
+
|
|
19
|
+
type responseEnvelope struct {
|
|
20
|
+
Value json.RawMessage `json:"value"`
|
|
21
|
+
Exception respException `json:"exception"`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type respException struct {
|
|
25
|
+
Message string `json:"message"`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type errandResultEnvelope struct {
|
|
29
|
+
Result boshaction.ErrandResult `json:"result"`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type compiledPackageEnvelope struct {
|
|
33
|
+
Result CompiledPackage `json:"result"`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
func (re responseEnvelope) HasException() bool {
|
|
37
|
+
return len(re.Exception.Message) > 0
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func (re responseEnvelope) StringValue() (string, error) {
|
|
41
|
+
value, err := re.interfaceValue()
|
|
42
|
+
if err != nil {
|
|
43
|
+
return "", err
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
str, ok := value.(string)
|
|
47
|
+
if !ok {
|
|
48
|
+
return "", bosherr.WrapError(err, "Converting value to string")
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return str, nil
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
func (re responseEnvelope) MapValue() (map[string]interface{}, error) {
|
|
55
|
+
var m map[string]interface{}
|
|
56
|
+
|
|
57
|
+
value, err := re.interfaceValue()
|
|
58
|
+
if err != nil {
|
|
59
|
+
return m, err
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
m, ok := value.(map[string]interface{})
|
|
63
|
+
if !ok {
|
|
64
|
+
return m, bosherr.WrapError(err, "Converting value to map[string]interface{}")
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return m, nil
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
func (re responseEnvelope) CustomValue(value interface{}) error {
|
|
71
|
+
return json.Unmarshal(re.Value, &value)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
func (re responseEnvelope) TaskID() (string, bool) {
|
|
75
|
+
value, err := re.interfaceValue()
|
|
76
|
+
if err != nil {
|
|
77
|
+
return "", false
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check if it looks like a task status
|
|
81
|
+
result, ok := value.(map[string]interface{})
|
|
82
|
+
if !ok {
|
|
83
|
+
return "", false
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
taskID, found := result["agent_task_id"]
|
|
87
|
+
if !found {
|
|
88
|
+
return "", false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if result["state"] != "running" {
|
|
92
|
+
return "", false
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return taskID.(string), true
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func (re responseEnvelope) interfaceValue() (interface{}, error) {
|
|
99
|
+
var value interface{}
|
|
100
|
+
|
|
101
|
+
err := json.Unmarshal(re.Value, &value)
|
|
102
|
+
if err != nil {
|
|
103
|
+
return value, err
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return value, nil
|
|
107
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
package deployment
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
gonet "net"
|
|
5
|
+
|
|
6
|
+
boshaction "bosh/agent/action"
|
|
7
|
+
|
|
8
|
+
bpdepman "boshprovisioner/deployment/manifest"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
type Deployment struct {
|
|
12
|
+
Manifest bpdepman.Manifest
|
|
13
|
+
|
|
14
|
+
Name string
|
|
15
|
+
|
|
16
|
+
Releases []Release
|
|
17
|
+
|
|
18
|
+
Networks []Network
|
|
19
|
+
|
|
20
|
+
Jobs []Job
|
|
21
|
+
|
|
22
|
+
CompilationInstance Instance
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type Release struct {
|
|
26
|
+
Name string
|
|
27
|
+
Version string
|
|
28
|
+
|
|
29
|
+
// Not offical BOSH manifest construct
|
|
30
|
+
URL string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const (
|
|
34
|
+
NetworkTypeManual = bpdepman.NetworkTypeManual
|
|
35
|
+
NetworkTypeDynamic = bpdepman.NetworkTypeDynamic
|
|
36
|
+
NetworkTypeVip = bpdepman.NetworkTypeVip
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
var NetworkTypes = []string{NetworkTypeManual, NetworkTypeDynamic, NetworkTypeVip}
|
|
40
|
+
|
|
41
|
+
type Network struct {
|
|
42
|
+
Name string
|
|
43
|
+
Type string
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
type Job struct {
|
|
47
|
+
Name string
|
|
48
|
+
|
|
49
|
+
Templates []Template
|
|
50
|
+
|
|
51
|
+
Instances []Instance
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type Template struct {
|
|
55
|
+
Name string
|
|
56
|
+
|
|
57
|
+
Release *Release
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
type Instance struct {
|
|
61
|
+
Index int
|
|
62
|
+
|
|
63
|
+
// Denormalized values to avoid passing dep/job/instance tuple
|
|
64
|
+
JobName string
|
|
65
|
+
DeploymentName string
|
|
66
|
+
|
|
67
|
+
// Watch time will vary depending if an instance is a canary
|
|
68
|
+
WatchTime bpdepman.WatchTime
|
|
69
|
+
|
|
70
|
+
Properties Properties
|
|
71
|
+
|
|
72
|
+
NetworkAssociations []NetworkAssociation
|
|
73
|
+
|
|
74
|
+
// Represents current state of an associated VM
|
|
75
|
+
CurrentState boshaction.GetStateV1ApplySpec
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
type Properties map[string]interface{}
|
|
79
|
+
|
|
80
|
+
type NetworkAssociation struct {
|
|
81
|
+
Network *Network
|
|
82
|
+
|
|
83
|
+
StaticIP gonet.IP
|
|
84
|
+
|
|
85
|
+
// StaticIP might equal to nil, though that does not indicate
|
|
86
|
+
// that this instance does not need a static IP
|
|
87
|
+
MustHaveStaticIP bool
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// populateFromManifest populates deployment information
|
|
91
|
+
// interpreted from deployment manifest.
|
|
92
|
+
func (d *Deployment) populateFromManifest(manifest bpdepman.Manifest) {
|
|
93
|
+
d.populateNetworks(manifest)
|
|
94
|
+
d.populateReleases(manifest)
|
|
95
|
+
d.populateCompilationInstances(manifest)
|
|
96
|
+
d.populateJobs(manifest)
|
|
97
|
+
d.Manifest = manifest
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
func (d *Deployment) populateNetworks(manifest bpdepman.Manifest) {
|
|
101
|
+
for _, manNet := range manifest.Deployment.Networks {
|
|
102
|
+
d.Networks = append(d.Networks, Network{
|
|
103
|
+
Name: manNet.Name,
|
|
104
|
+
Type: manNet.Type,
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
func (d *Deployment) populateReleases(manifest bpdepman.Manifest) {
|
|
110
|
+
for _, manRelease := range manifest.Deployment.Releases {
|
|
111
|
+
d.Releases = append(d.Releases, Release{
|
|
112
|
+
Name: manRelease.Name,
|
|
113
|
+
Version: manRelease.Version,
|
|
114
|
+
URL: manRelease.URL,
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
func (d *Deployment) populateCompilationInstances(manifest bpdepman.Manifest) {
|
|
120
|
+
network := d.findNetworkOrDefault(manifest.Deployment.Compilation.NetworkName)
|
|
121
|
+
|
|
122
|
+
d.CompilationInstance = Instance{
|
|
123
|
+
Index: 0,
|
|
124
|
+
|
|
125
|
+
JobName: "compilation",
|
|
126
|
+
DeploymentName: manifest.Deployment.Name,
|
|
127
|
+
|
|
128
|
+
NetworkAssociations: []NetworkAssociation{
|
|
129
|
+
NetworkAssociation{Network: network},
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
func (d *Deployment) populateJobs(manifest bpdepman.Manifest) {
|
|
135
|
+
for _, manJob := range manifest.Deployment.Jobs {
|
|
136
|
+
d.Jobs = append(d.Jobs, d.buildJob(manifest.Deployment, manJob))
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
func (d *Deployment) buildJob(manDep bpdepman.Deployment, manJob bpdepman.Job) Job {
|
|
141
|
+
job := Job{Name: manJob.Name}
|
|
142
|
+
|
|
143
|
+
for i := 0; i < manJob.Instances; i++ {
|
|
144
|
+
watchTime := manDep.InstanceWatchTime(manJob, i)
|
|
145
|
+
properties := manDep.InstanceProperties(manJob, i)
|
|
146
|
+
netAssocs := d.buildNetworkAssociations(manJob, i)
|
|
147
|
+
|
|
148
|
+
job.Instances = append(job.Instances, Instance{
|
|
149
|
+
Index: i,
|
|
150
|
+
|
|
151
|
+
JobName: manJob.Name,
|
|
152
|
+
DeploymentName: manDep.Name,
|
|
153
|
+
|
|
154
|
+
WatchTime: watchTime,
|
|
155
|
+
Properties: Properties(properties),
|
|
156
|
+
|
|
157
|
+
NetworkAssociations: netAssocs,
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// todo check to make sure release is present
|
|
162
|
+
for _, manTemplate := range manJob.Templates {
|
|
163
|
+
release := d.findReleaseOrDefault(manTemplate.ReleaseName)
|
|
164
|
+
|
|
165
|
+
job.Templates = append(job.Templates, Template{
|
|
166
|
+
Name: manTemplate.Name,
|
|
167
|
+
Release: release,
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return job
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
func (d *Deployment) buildNetworkAssociations(manJob bpdepman.Job, i int) []NetworkAssociation {
|
|
175
|
+
var netAssocs []NetworkAssociation
|
|
176
|
+
|
|
177
|
+
for _, manNa := range manJob.NetworkAssociations {
|
|
178
|
+
var staticIP gonet.IP
|
|
179
|
+
|
|
180
|
+
network := d.findNetworkOrDefault(manNa.NetworkName)
|
|
181
|
+
|
|
182
|
+
if i < len(manNa.StaticIPs) {
|
|
183
|
+
staticIP = manNa.StaticIPs[i]
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
netAssocs = append(netAssocs, NetworkAssociation{
|
|
187
|
+
Network: network,
|
|
188
|
+
StaticIP: staticIP,
|
|
189
|
+
|
|
190
|
+
MustHaveStaticIP: len(manNa.StaticIPs) > 0,
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return netAssocs
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
func (d *Deployment) findReleaseOrDefault(name string) *Release {
|
|
198
|
+
// todo check against empty release name
|
|
199
|
+
for _, release := range d.Releases {
|
|
200
|
+
if release.Name == name {
|
|
201
|
+
return &release
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Assume if there is only one release it's default
|
|
206
|
+
if len(d.Releases) == 1 {
|
|
207
|
+
return &d.Releases[0]
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return nil
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
func (d *Deployment) findNetworkOrDefault(name string) *Network {
|
|
214
|
+
for _, net := range d.Networks {
|
|
215
|
+
if net.Name == name {
|
|
216
|
+
return &net
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return nil
|
|
221
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
package deployment
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
type NetworkConfiguration struct {
|
|
8
|
+
IP string
|
|
9
|
+
Netmask string
|
|
10
|
+
Gateway string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
func (i Instance) NetworkConfigurationForNetworkAssociation(na NetworkAssociation) NetworkConfiguration {
|
|
14
|
+
// If instance is always has static ip assigned there is nothing to resolve
|
|
15
|
+
if na.MustHaveStaticIP {
|
|
16
|
+
return NetworkConfiguration{IP: na.StaticIP.String()}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Dynamic network information can be resolved after VM is powered on.
|
|
20
|
+
if na.Network.Type == NetworkTypeDynamic {
|
|
21
|
+
networkSpec, ok := i.CurrentState.NetworkSpecs[na.Network.Name]
|
|
22
|
+
if !ok {
|
|
23
|
+
return NetworkConfiguration{}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// todo better way to deserialize? structmap?
|
|
27
|
+
ipStr, ok := networkSpec.Fields["ip"].(string)
|
|
28
|
+
if !ok {
|
|
29
|
+
return NetworkConfiguration{}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
netmaskStr, ok := networkSpec.Fields["netmask"].(string)
|
|
33
|
+
if !ok {
|
|
34
|
+
return NetworkConfiguration{}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
gatewayStr, ok := networkSpec.Fields["gateway"].(string)
|
|
38
|
+
if !ok {
|
|
39
|
+
return NetworkConfiguration{}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return NetworkConfiguration{
|
|
43
|
+
IP: ipStr,
|
|
44
|
+
Netmask: netmaskStr,
|
|
45
|
+
Gateway: gatewayStr,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return NetworkConfiguration{}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func (i Instance) DNDRecordName(na NetworkAssociation) string {
|
|
53
|
+
return fmt.Sprintf("%d.%s.%s.%s.bosh", i.Index, i.JobName, na.Network.Name, i.DeploymentName)
|
|
54
|
+
}
|