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.
Files changed (147) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.gitmodules +6 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +20 -0
  6. data/README.md +73 -0
  7. data/Rakefile +2 -0
  8. data/dev/.gitignore +1 -0
  9. data/dev/Vagrantfile +30 -0
  10. data/dev/example-bosh-manifest.yml +188 -0
  11. data/dev/example-winston-manifest.yml +70 -0
  12. data/go/.gitignore +11 -0
  13. data/go/bin/build +10 -0
  14. data/go/bin/build-linux-amd64 +9 -0
  15. data/go/bin/env +13 -0
  16. data/go/bin/go +5 -0
  17. data/go/bin/golint +19 -0
  18. data/go/bin/test +37 -0
  19. data/go/src/boshprovisioner/agent/client/client_interface.go +73 -0
  20. data/go/src/boshprovisioner/agent/client/fakes/fake_client.go +81 -0
  21. data/go/src/boshprovisioner/agent/client/http_client.go +299 -0
  22. data/go/src/boshprovisioner/agent/client/http_client_envelope.go +107 -0
  23. data/go/src/boshprovisioner/deployment/deployment.go +221 -0
  24. data/go/src/boshprovisioner/deployment/instance.go +54 -0
  25. data/go/src/boshprovisioner/deployment/manifest/deployment.go +80 -0
  26. data/go/src/boshprovisioner/deployment/manifest/ips.go +23 -0
  27. data/go/src/boshprovisioner/deployment/manifest/manifest.go +143 -0
  28. data/go/src/boshprovisioner/deployment/manifest/manifest_suite_test.go +13 -0
  29. data/go/src/boshprovisioner/deployment/manifest/manifest_test.go +86 -0
  30. data/go/src/boshprovisioner/deployment/manifest/syntax_validator.go +186 -0
  31. data/go/src/boshprovisioner/deployment/manifest/watch_time.go +47 -0
  32. data/go/src/boshprovisioner/deployment/manifest_reader.go +46 -0
  33. data/go/src/boshprovisioner/deployment/reader_factory.go +25 -0
  34. data/go/src/boshprovisioner/deployment/semantic_validator.go +111 -0
  35. data/go/src/boshprovisioner/downloader/blobstore_downloader.go +55 -0
  36. data/go/src/boshprovisioner/downloader/default_mux_downloader.go +22 -0
  37. data/go/src/boshprovisioner/downloader/downloader_interface.go +6 -0
  38. data/go/src/boshprovisioner/downloader/http_downloader.go +53 -0
  39. data/go/src/boshprovisioner/downloader/local_fs_downloader.go +48 -0
  40. data/go/src/boshprovisioner/downloader/mux_downloader.go +69 -0
  41. data/go/src/boshprovisioner/eventlog/log.go +72 -0
  42. data/go/src/boshprovisioner/eventlog/stage.go +39 -0
  43. data/go/src/boshprovisioner/eventlog/task.go +58 -0
  44. data/go/src/boshprovisioner/index/file_index.go +289 -0
  45. data/go/src/boshprovisioner/index/file_index_test.go +296 -0
  46. data/go/src/boshprovisioner/index/index_interface.go +18 -0
  47. data/go/src/boshprovisioner/index/index_suite_test.go +13 -0
  48. data/go/src/boshprovisioner/instance/templatescompiler/concrete_templates_compiler.go +273 -0
  49. data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/erb_renderer.go +117 -0
  50. data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/erbrenderer_suite_test.go +13 -0
  51. data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/render_properties.go +77 -0
  52. data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/render_properties_test.go +142 -0
  53. data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/template_evaluation_context.go +85 -0
  54. data/go/src/boshprovisioner/instance/templatescompiler/erbrenderer/template_evaluation_context_rb.go +155 -0
  55. data/go/src/boshprovisioner/instance/templatescompiler/jobsrepo/concrete_jobs_repository.go +64 -0
  56. data/go/src/boshprovisioner/instance/templatescompiler/jobsrepo/concrete_runtime_packages_repository.go +105 -0
  57. data/go/src/boshprovisioner/instance/templatescompiler/jobsrepo/concrete_template_to_job_repository.go +76 -0
  58. data/go/src/boshprovisioner/instance/templatescompiler/jobsrepo/jobs_repository_interface.go +31 -0
  59. data/go/src/boshprovisioner/instance/templatescompiler/rendered_archives_compiler.go +81 -0
  60. data/go/src/boshprovisioner/instance/templatescompiler/templates_compiler_interface.go +20 -0
  61. data/go/src/boshprovisioner/instance/templatescompiler/templatesrepo/ct_repository.go +54 -0
  62. data/go/src/boshprovisioner/instance/templatescompiler/templatesrepo/templates_repository_interface.go +16 -0
  63. data/go/src/boshprovisioner/instance/updater/applier/applier.go +93 -0
  64. data/go/src/boshprovisioner/instance/updater/applier/empty_state.go +66 -0
  65. data/go/src/boshprovisioner/instance/updater/applier/job_state.go +178 -0
  66. data/go/src/boshprovisioner/instance/updater/drainer.go +72 -0
  67. data/go/src/boshprovisioner/instance/updater/preparer.go +39 -0
  68. data/go/src/boshprovisioner/instance/updater/starter.go +36 -0
  69. data/go/src/boshprovisioner/instance/updater/stopper.go +36 -0
  70. data/go/src/boshprovisioner/instance/updater/updater.go +102 -0
  71. data/go/src/boshprovisioner/instance/updater/updater_factory.go +83 -0
  72. data/go/src/boshprovisioner/instance/updater/updater_suite_test.go +13 -0
  73. data/go/src/boshprovisioner/instance/updater/waiter.go +77 -0
  74. data/go/src/boshprovisioner/instance/updater/waiter_test.go +103 -0
  75. data/go/src/boshprovisioner/main/config.go +77 -0
  76. data/go/src/boshprovisioner/main/main.go +183 -0
  77. data/go/src/boshprovisioner/main/repos_factory.go +96 -0
  78. data/go/src/boshprovisioner/packagescompiler/compiledpackagesrepo/compiled_packages_repository_interface.go +17 -0
  79. data/go/src/boshprovisioner/packagescompiler/compiledpackagesrepo/concrete_compiled_packages_repository.go +61 -0
  80. data/go/src/boshprovisioner/packagescompiler/concrete_packages_compiler.go +179 -0
  81. data/go/src/boshprovisioner/packagescompiler/concrete_packages_compiler_factory.go +48 -0
  82. data/go/src/boshprovisioner/packagescompiler/packages_compiler_interface.go +20 -0
  83. data/go/src/boshprovisioner/packagescompiler/packagesrepo/concrete_packages_repository.go +65 -0
  84. data/go/src/boshprovisioner/packagescompiler/packagesrepo/packages_repository_interface.go +16 -0
  85. data/go/src/boshprovisioner/provisioner/blobstore_config.go +65 -0
  86. data/go/src/boshprovisioner/provisioner/blobstore_provisioner.go +38 -0
  87. data/go/src/boshprovisioner/provisioner/deployment_provisioner.go +97 -0
  88. data/go/src/boshprovisioner/provisioner/instance_provisioner.go +48 -0
  89. data/go/src/boshprovisioner/provisioner/release_compiler.go +133 -0
  90. data/go/src/boshprovisioner/release/job/job.go +86 -0
  91. data/go/src/boshprovisioner/release/job/manifest/manifest.go +79 -0
  92. data/go/src/boshprovisioner/release/job/manifest/manifest_suite_test.go +13 -0
  93. data/go/src/boshprovisioner/release/job/manifest/manifest_test.go +42 -0
  94. data/go/src/boshprovisioner/release/job/manifest/syntax_validator.go +43 -0
  95. data/go/src/boshprovisioner/release/job/reader_factory.go +34 -0
  96. data/go/src/boshprovisioner/release/job/tar_reader.go +133 -0
  97. data/go/src/boshprovisioner/release/manifest/manifest.go +96 -0
  98. data/go/src/boshprovisioner/release/manifest_reader.go +29 -0
  99. data/go/src/boshprovisioner/release/reader_factory.go +34 -0
  100. data/go/src/boshprovisioner/release/release.go +144 -0
  101. data/go/src/boshprovisioner/release/release_suite_test.go +13 -0
  102. data/go/src/boshprovisioner/release/release_test.go +129 -0
  103. data/go/src/boshprovisioner/release/tar_reader.go +139 -0
  104. data/go/src/boshprovisioner/releasesrepo/blobstore_releases_repository.go +114 -0
  105. data/go/src/boshprovisioner/releasesrepo/releases_repository_interface.go +15 -0
  106. data/go/src/boshprovisioner/tar/cmd_compressor.go +68 -0
  107. data/go/src/boshprovisioner/tar/cmd_extractor.go +47 -0
  108. data/go/src/boshprovisioner/tar/compressor_interface.go +6 -0
  109. data/go/src/boshprovisioner/tar/extractor_interface.go +6 -0
  110. data/go/src/boshprovisioner/util/string_keyed.go +70 -0
  111. data/go/src/boshprovisioner/vm/agent_provisioner.go +266 -0
  112. data/go/src/boshprovisioner/vm/asset_manager.go +61 -0
  113. data/go/src/boshprovisioner/vm/deps_provisioner.go +92 -0
  114. data/go/src/boshprovisioner/vm/monit_provisioner.go +83 -0
  115. data/go/src/boshprovisioner/vm/runit_provisioner.go +225 -0
  116. data/go/src/boshprovisioner/vm/simple_cmds.go +54 -0
  117. data/go/src/boshprovisioner/vm/vcap_user_provisioner.go +120 -0
  118. data/go/src/boshprovisioner/vm/vm.go +19 -0
  119. data/go/src/boshprovisioner/vm/vm_provisioner.go +57 -0
  120. data/go/src/boshprovisioner/vm/vm_provisioner_factory.go +97 -0
  121. data/lib/vagrant-bosh/asset_uploader.rb +53 -0
  122. data/lib/vagrant-bosh/assets/agent/agent-log +5 -0
  123. data/lib/vagrant-bosh/assets/agent/agent-run +12 -0
  124. data/lib/vagrant-bosh/assets/agent/agent.cert +18 -0
  125. data/lib/vagrant-bosh/assets/agent/agent.json +9 -0
  126. data/lib/vagrant-bosh/assets/agent/agent.key +27 -0
  127. data/lib/vagrant-bosh/assets/agent/bosh-agent +0 -0
  128. data/lib/vagrant-bosh/assets/agent/bosh-agent-rc +18 -0
  129. data/lib/vagrant-bosh/assets/agent/bosh-blobstore-dav +0 -0
  130. data/lib/vagrant-bosh/assets/monit/monit +0 -0
  131. data/lib/vagrant-bosh/assets/monit/monit-log +5 -0
  132. data/lib/vagrant-bosh/assets/monit/monit-run +9 -0
  133. data/lib/vagrant-bosh/assets/monit/monitrc +8 -0
  134. data/lib/vagrant-bosh/assets/provisioner +0 -0
  135. data/lib/vagrant-bosh/bootstrapper.rb +59 -0
  136. data/lib/vagrant-bosh/communicator.rb +50 -0
  137. data/lib/vagrant-bosh/config.rb +15 -0
  138. data/lib/vagrant-bosh/errors.rb +11 -0
  139. data/lib/vagrant-bosh/plugin.rb +25 -0
  140. data/lib/vagrant-bosh/provisioner.rb +46 -0
  141. data/lib/vagrant-bosh/provisioner_tracker.rb +41 -0
  142. data/lib/vagrant-bosh/ui.rb +77 -0
  143. data/lib/vagrant-bosh/version.rb +5 -0
  144. data/lib/vagrant-bosh.rb +15 -0
  145. data/templates/locales/en.yml +15 -0
  146. data/vagrant-bosh.gemspec +20 -0
  147. 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
+ }