vagrant-bosh 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }