├── .gitignore
├── .npmrc
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── Procfile
├── README.md
├── jbuild.coffee
├── lib-src
├── cfenv.coffee
└── server.coffee
├── lib
├── cfenv.js
└── server.js
├── manifest.yml
├── package.json
├── sample-data
└── README.md
├── server.js
└── tests
├── data-01.cson
├── fixtures
├── vcap-local-bad.json
└── vcap-local-good.json
├── test-core.coffee
└── test-package.coffee
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | tmp
3 | npm-debug.log
4 | .vscode
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock = false
2 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | Contributor Code of Conduct
2 | ================================================================================
3 |
4 | As contributors and maintainers of this project, and in the interest of
5 | fostering an open and welcoming community, we pledge to respect all people who
6 | contribute through reporting issues, posting feature requests, updating
7 | documentation, submitting pull requests or patches, and other activities.
8 |
9 | We are committed to making participation in this project a harassment-free
10 | experience for everyone, regardless of level of experience, gender, gender
11 | identity and expression, sexual orientation, disability, personal appearance,
12 | body size, race, ethnicity, age, religion, or nationality.
13 |
14 | Examples of unacceptable behavior by participants include:
15 |
16 | * The use of sexualized language or imagery
17 | * Personal attacks
18 | * Trolling or insulting/derogatory comments
19 | * Public or private harassment
20 | * Publishing other's private information, such as physical or electronic
21 | addresses, without explicit permission
22 | * Other unethical or unprofessional conduct.
23 |
24 | Project maintainers have the right and responsibility to remove, edit, or reject
25 | comments, commits, code, wiki edits, issues, and other contributions that are
26 | not aligned to this Code of Conduct. By adopting this Code of Conduct, project
27 | maintainers commit themselves to fairly and consistently applying these
28 | principles to every aspect of managing this project. Project maintainers who do
29 | not follow or enforce the Code of Conduct may be permanently removed from the
30 | project team.
31 |
32 | This code of conduct applies both within project spaces and in public spaces
33 | when an individual is representing the project or its community.
34 |
35 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
36 | reported by opening an issue or contacting one or more of the project
37 | maintainers.
38 |
39 | This Code of Conduct is adapted from the
40 | [Contributor Covenant](http://contributor-covenant.org),
41 | version 1.2.0, available at
42 |
43 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing
2 | ================================================================================
3 |
4 | Awesome! We're happy that you want to contribute.
5 |
6 | Make sure that you're read and understand the [Code of Conduct](CODE_OF_CONDUCT.md).
7 |
8 |
9 | Building from source
10 | --------------------------------------------------------------------------------
11 |
12 | The following `npm` scripts are available when doing development on this
13 | package:
14 |
15 | * `npm run build` - build the library from the CoffeeScript source
16 | * `npm run serve` - run a test server
17 | * `npm test` - run the tests
18 | * `npm run watch` - watch for source file changes, then `build`, then `test`
19 |
20 |
21 | GitHub usage
22 | --------------------------------------------------------------------------------
23 |
24 | * Develop major features on feature branches, and submit PRs to `master`.
25 |
26 | * Never force push onto `master`.
27 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: node server
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | cfenv - easy access to your Cloud Foundry application environment
2 | ================================================================================
3 |
4 | The cfenv package provides functions to parse Cloud Foundry-provided environment
5 | variables. Provides easy access to your port, http
6 | binding host name/ip address, URL of the application, etc. Also provides
7 | useful default values when you're running locally.
8 |
9 | The package determines if you are running "locally" versus running as a
10 | Cloud Foundry app, based on whether the `VCAP_APPLICATION` environment variable is set.
11 | If not set, the functions run in "local" mode, otherwise they run in "cloud"
12 | mode.
13 |
14 |
15 | quick start
16 | ================================================================================
17 |
18 | var cfenv = require("cfenv")
19 |
20 | var appEnv = cfenv.getAppEnv()
21 | ...
22 | // start the server on the given port and binding host, and print
23 | // url to server when it starts
24 |
25 | server.listen(appEnv.port, appEnv.bind, function() {
26 | console.log("server starting on " + appEnv.url)
27 | })
28 |
29 | This code snippet above will get the port, binding host, and full URL to your HTTP
30 | server and use them to bind the server and print the server URL when starting.
31 |
32 |
33 | running in Cloud Foundry vs locally
34 | ================================================================================
35 |
36 | This package makes use of a number of environment variables that are set when
37 | your application is running in Cloud Foundry. These include:
38 |
39 | * `VCAP_SERVICES`
40 | * `VCAP_APPLICATION`
41 | * `PORT`
42 |
43 | If these aren't set, the `getAppEnv()` API will still return useful values,
44 | as appropriate. This means you can use this package in your program and
45 | it will provide useful values when you're running in Cloud Foundry AND
46 | when you're running locally. You can supply local versions of
47 | `VCAP_SERVICES` and/or `VCAP_APPLICATION` by using the `vcap` and `vcapFile`
48 | options described below.
49 |
50 |
51 | api
52 | ================================================================================
53 |
54 | The `cfenv` package exports the following function:
55 |
56 |
57 | `getAppEnv(options)`
58 | --------------------------------------------------------------------------------
59 |
60 | Get the core bits of Cloud Foundry data as an object.
61 |
62 | The `options` parameter is optional, and can contain the following properties:
63 |
64 | * `name` - name of the application
65 |
66 | This value is used as the default `name` property of the returned object,
67 | and as the name passed to
68 | [the ports package `getPort()` function](https://www.npmjs.org/package/ports)
69 | to get a default port.
70 |
71 | If not specified, the name will looked for in the following places:
72 |
73 | * the `name` property of the `VCAP_APPLICATION` environment variable
74 | * the `name` property from the `manifest.yml` file in the current directory
75 | * the `name` property from the `package.json` file in the current directory
76 |
77 | * `protocol` - protocol used in the generated URLs
78 |
79 | This value is to override the default protocol used when generating
80 | the URLs in the returned object. It should be the same format as
81 | [node's url `protocol` property](http://nodejs.org/api/url.html).
82 | That is, it should end with a `:` character.
83 |
84 | * `vcap` - provide values for the `VCAP_APPLICATION` and `VCAP_SERVICES`
85 | environment variable, when running locally. The object can have
86 | properties `application` and/or `services`, whose values are the same
87 | as the values serialized in the respective environment variables.
88 |
89 | Note that the `url` and `urls` properties of the returned object are not
90 | based on the vcap `application` object, when running locally.
91 |
92 | This option property is ignored if not running locally.
93 |
94 | * `vcapFile` - provide the same function as the `vcap` option, but instead of
95 | setting the option value to an object, you set it to the name of a JSON
96 | file, which will be parsed and used as the `vcap` option value is used,
97 | as described above.
98 |
99 | When both `vcap` and `vcapFile` options are provided, the values in `vcap`
100 | are ignored.
101 |
102 | This option property is ignored if not running locally.
103 |
104 | #### return value
105 |
106 | The `getAppEnv()` function returns an object with the following properties:
107 |
108 | * `app`: object version of `VCAP_APPLICATION` env var
109 | * `services`: object version of `VCAP_SERVICES` env var
110 | * `name`: name of the application
111 | * `port`: HTTP port
112 | * `bind`: hostname/ip address for binding
113 | * `urls`: URLs used to access the servers
114 | * `url`: first URL in `urls`
115 | * `isLocal`: false if a valid `VCAP_APPLICATION` env var was found, true otherwise
116 |
117 | The returned object also has the following methods available:
118 |
119 | * `appEnv.getServices()`
120 | * `appEnv.getService(spec)`
121 | * `appEnv.getServiceURL(spec, replacements)`
122 | * `appEnv.getServiceCreds(spec)`
123 |
124 | If no value can be determined for `port`, and the `name` property on the
125 | `options` parameter is not set and cannot be determined,
126 | a port of 3000 will be used.
127 |
128 | If no value can be determined for `port`, and the `name` property on the
129 | `options` parameter is set or can otherwise be determined,
130 | that name will be passed to
131 | [the ports package `getPort()` function](https://www.npmjs.org/package/ports)
132 | to get a default port.
133 |
134 | The protocol used for the URLs will be `http:` if the app
135 | is running locally, and `https:` otherwise; you can
136 | force a particular protocol by using the `protocol` property
137 | on the `options` parameter.
138 |
139 | When running in Cloud Foundry, the `url` and `urls` values will have
140 | `localhost` as their hostname, if the actual hostnames cannot be determined.
141 |
142 |
143 | AppEnv methods
144 | --------------------------------------------------------------------------------
145 |
146 | The following methods are also available on the object returned by
147 | `cfenv.getAppEnv()`.
148 |
149 |
150 |
151 | **`appEnv.getServices()`**
152 | --------------------------------------------------------------------------------
153 |
154 | Return all services, in an object keyed by service name.
155 |
156 | Note that this is different than the `services` property
157 | returned from `getAppEnv()`.
158 |
159 | For example, assume VCAP_SERVICES was set to the following:
160 |
161 | {
162 | "user-provided": [
163 | {
164 | "name": "cf-env-test",
165 | "label": "user-provided",
166 | "tags": [],
167 | "credentials": {
168 | "database": "database",
169 | "password": "passw0rd",
170 | "url": "https://example.com/",
171 | "username": "userid"
172 | },
173 | "syslog_drain_url": "http://example.com/syslog"
174 | }
175 | ]
176 | }
177 |
178 | In this case, `appEnv.services` would be set to that same object, but
179 | `appEnv.getServices()` would return
180 |
181 | {
182 | "cf-env-test": {
183 | "name": "cf-env-test",
184 | "label": "user-provided",
185 | "tags": [],
186 | "credentials": {
187 | "database": "database",
188 | "password": "passw0rd",
189 | "url": "https://example.com/",
190 | "username": "userid"
191 | },
192 | "syslog_drain_url": "http://example.com/syslog"
193 | }
194 | }
195 |
196 |
197 | **`appEnv.getService(spec)`**
198 | --------------------------------------------------------------------------------
199 |
200 | Return a service object by name.
201 |
202 | The `spec` parameter should be a regular expression, or a string which is the
203 | exact name of the service. For a regular expression, the first service name
204 | which matches the regular expression will be returned.
205 |
206 | Returns the service object from VCAP_SERVICES or null if not found.
207 |
208 |
209 |
210 | **`appEnv.getServiceURL(spec, replacements)`**
211 | --------------------------------------------------------------------------------
212 |
213 | Returns a service URL by name.
214 |
215 | The `spec` parameter should be a regular expression, or a string which is the
216 | exact name of the service. For a regular expression, the first service name
217 | which matches the regular expression will be returned.
218 |
219 | The `replacements` parameter is an object with the properties used in
220 | [node's url function `url.format()`](http://nodejs.org/api/url.html#url_url_format_urlobj).
221 |
222 | Returns a URL generated from VCAP_SERVICES or null if not found.
223 |
224 | To generate the URL, processing first starts with a `url` property
225 | in the service credentials. You can override the `url` property in the
226 | service credentials (if no such property exists), with a `replacements`
227 | property of `url`, and a value which is the name of the property in
228 | the service credentials whose value contains the base URL.
229 |
230 | That url is parsed with
231 | [node's url function `url.parse()`](http://nodejs.org/api/url.html#url_url_parse_urlstr_parsequerystring_slashesdenotehost)
232 | to get a set of initial url properties.
233 | These properties are then overridden by entries in `replacements`, using the
234 | following operation, for a given replacement `key` and `value`.
235 |
236 | url[key] = service.credentials[value]
237 |
238 | The URL `auth` replacement is a bit special, in that it's value should
239 | be a two-element array of [userid, password], where those values are
240 | keys in the service.credentials
241 |
242 | For example, assume VCAP_SERVICES was set to the following:
243 |
244 | {
245 | "user-provided": [
246 | {
247 | "name": "cf-env-test",
248 | "label": "user-provided",
249 | "tags": [],
250 | "credentials": {
251 | "database": "database",
252 | "password": "passw0rd",
253 | "url": "https://example.com/",
254 | "username": "userid"
255 | },
256 | "syslog_drain_url": "http://example.com/syslog"
257 | }
258 | ]
259 | }
260 |
261 | Assume you run the following code:
262 |
263 | url = appEnv.getServiceURL("cf-env-test", {
264 | pathname: "database",
265 | auth: ["username", "password"]
266 | })
267 |
268 | The `url` result will be `https://userid:passw0rd@example.com/database`
269 |
270 | Note that there **MUST** be a `url` property in the credentials,
271 | or replacement for it, in the
272 | service, or the call will return `null`. Also, because the `url` is parsed
273 | first with `url.parse()`, there will be a `host` property in the result, so
274 | you won't be able to use the `hostname` and `port` values directly. You
275 | can **ONLY** set the resultant hostname and port with the `host` property.
276 |
277 | Note that `url.parse()` and the later `url.format()` calls to construct the
278 | result, will not produce pleasing results for "unusual" URLs, especially
279 | those which do not use `http:` or `https:` protocols. The `url` `parse()`
280 | and `format()` methods will not be used though, if you have no replacement
281 | values, or the only replacement property is `url`, and so are safe to
282 | use in that case.
283 |
284 | Since the `appEnv.getServiceURL()` method operates against the
285 | `appEnv.services` property, you can fudge this object if that makes your
286 | life easier.
287 |
288 | **`appEnv.getServiceCreds(spec)`**
289 | --------------------------------------------------------------------------------
290 |
291 | Returns the `credentials` object of a service by name.
292 |
293 | The `spec` parameter is the same as that used by the `appEnv.getServiceURL()`
294 | method. If there is no service that matches the `spec` parameter, this method
295 | will return `null`.
296 |
297 | If there is a service that matches the `spec` parameter, the value of it's
298 | `credentials` property will be returned. If for some reason, there is no
299 | `credentials` property on the service, an empty object - `{}` - will be
300 | returned.
301 |
302 |
303 |
304 | testing with Cloud Foundry
305 | ================================================================================
306 |
307 | You can push this project as a Cloud Foundry project to try it out.
308 |
309 | First, create a service name `cf-env-test` with the following command:
310 |
311 | cf cups cf-env-test -p "url, username, password, database"
312 |
313 | You will be prompted for these values; enter something reasonable like:
314 |
315 | url> http://example.com
316 | username> userid
317 | password> passw0rd
318 | database> the-db
319 |
320 | Next, push the app with `cf push`.
321 |
322 | When you visit the site, you'll see the output of various cfenv calls.
323 |
324 |
325 | changes
326 | ================================================================================
327 |
328 | **1.2.4** - 2021/04/03
329 |
330 | - upgrade most dependencies, but not CoffeeScript, since the latest
331 | version generates code that can't be run in older versions of node - [pr #50][]
332 |
333 | - change to call `yaml.load()` instead of `yaml.safeLoad()` since it's no
334 | longer supported, noticed via an error message: - [pr #50][]
335 |
336 | ```
337 | Error: Function yaml.safeLoad is removed in js-yaml 4. Use yaml.load instead, which is now safe by default.
338 | ```
339 |
340 | [pr #50]: https://github.com/cloudfoundry-community/node-cfenv/pull/50
341 |
342 | **1.2.3** - 2020/07/24
343 |
344 | - remove `.cfignore` file - [commit #02bb92d][]
345 |
346 | [commit #02bb92d]: https://github.com/cloudfoundry-community/node-cfenv/commit/02bb92dacf5f59244b188dae11fd2fe732c4940e
347 |
348 | **1.2.2** - 2019/03/26
349 |
350 | - handle ports package race condition by returning port 3000 - [pr #41][]
351 |
352 | [pr #41]: https://github.com/cloudfoundry-community/node-cfenv/pull/41
353 |
354 | **1.2.1** - 2019/03/25
355 |
356 | - upgrade js-yaml to avoid vulnerability - [pr #39][]
357 |
358 | [pr #39]: https://github.com/cloudfoundry-community/node-cfenv/pull/39
359 |
360 | **1.2.0** - 2019/02/21
361 |
362 | - use vcapFile port value if available - [pr #36][]
363 | - upgrade underscore from 1.8.x to 1.9.x - [pr #37][]
364 | - use `random-route:` instead of `${random-word}` in sample manifest - [pr #38][]
365 |
366 | [pr #36]: https://github.com/cloudfoundry-community/node-cfenv/pull/36
367 | [pr #37]: https://github.com/cloudfoundry-community/node-cfenv/pull/37
368 | [pr #38]: https://github.com/cloudfoundry-community/node-cfenv/pull/38
369 |
370 | **1.1.0** - 2018/04/18
371 |
372 | - add the `vcapFile` option - [issue #31][]
373 |
374 | [issue #31]: https://github.com/cloudfoundry-community/node-cfenv/issues/31
375 |
376 | **1.0.4** - 2017/01/13
377 |
378 | - fix to getServiceURL() with non-http URLs - [issue #21][]
379 |
380 | [issue #21]: https://github.com/cloudfoundry-community/node-cfenv/issues/21
381 |
382 | **1.0.3** - 2014/10/02
383 |
384 | - fixes for compatibility with Diego - [issue #11][]
385 |
386 | [issue #11]: https://github.com/cloudfoundry-community/node-cfenv/issues/11
387 |
388 | **1.0.2** - 2014/09/29
389 |
390 | - delete a lingering `npm-debug.log` left behind
391 | - add `npm-debug.log` to `.gitignore`
392 |
393 | **1.0.1** - 2014/09/29
394 |
395 | - remove node_modules from .cfignore - [issue #8][]
396 | - updated package dependencies
397 | - changed README.md to correct sample service to cf-env-test
398 | - files in lib/ recompiled due to coffee-script update
399 |
400 | [issue #8]: https://github.com/cloudfoundry-community/node-cfenv/issues/8
401 |
402 | **1.0.0** - 2014/09/03
403 |
404 | - initial 1.0.0 release
405 |
406 |
407 | contributing
408 | ================================================================================
409 |
410 | See the [CONTRIBUTING.md](CONTRIBUTING.md) doc for more information on
411 | contributing to this project.
412 |
413 |
414 | license
415 | ================================================================================
416 |
417 | Apache License, Version 2.0
418 |
419 |
420 |
--------------------------------------------------------------------------------
/jbuild.coffee:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License. See footer for details.
2 |
3 | #-------------------------------------------------------------------------------
4 | # use this file with jbuild: https://www.npmjs.org/package/jbuild
5 | # install jbuild with:
6 | # linux/mac: sudo npm -g install jbuild
7 | # windows: npm -g install jbuild
8 | #-------------------------------------------------------------------------------
9 |
10 | #-------------------------------------------------------------------------------
11 | tasks = defineTasks exports,
12 | watch: "watch for source file changes, then run build, test and server"
13 | serve: "run the test server stand-alone"
14 | build: "build the server"
15 | test: "run tests"
16 |
17 | WatchSpec = "lib-src lib-src/* tests tests/*"
18 |
19 | #-------------------------------------------------------------------------------
20 | mkdir "-p", "tmp"
21 |
22 | #-------------------------------------------------------------------------------
23 | tasks.build = ->
24 | log "running build"
25 |
26 | unless test "-d", "node_modules"
27 | exec "npm install"
28 |
29 | log ""
30 | log "---------------------------------------"
31 | log "exiting jbuild because of `npm install`"
32 | log "---------------------------------------"
33 |
34 | process.exit 1
35 |
36 | cleanDir "lib"
37 |
38 | log "- compiling server coffee files"
39 | coffee "--output lib lib-src"
40 |
41 | #-------------------------------------------------------------------------------
42 | tasks.watch = ->
43 | watchIter()
44 |
45 | watch
46 | files: WatchSpec.split " "
47 | run: watchIter
48 |
49 | watchFiles "jbuild.coffee" :->
50 | log "jbuild file changed; exiting"
51 | process.exit 0
52 |
53 | #-------------------------------------------------------------------------------
54 | tasks.serve = ->
55 | log "running server"
56 |
57 | command = "server --verbose --serve"
58 | #command = "lib/db"
59 | server.start "tmp/server.pid", "node", command.split " "
60 |
61 | #-------------------------------------------------------------------------------
62 | tasks.test = ->
63 | log "running tests"
64 |
65 | tests = "tests/test-*.coffee"
66 |
67 | options =
68 | ui: "bdd"
69 | reporter: "spec"
70 | slow: 300
71 | # compilers: "coffee:coffeescript"
72 | require: "coffeescript/register"
73 |
74 | options = for key, val of options
75 | "--#{key} #{val}"
76 |
77 | options = options.join " "
78 |
79 | mocha "#{options} #{tests}", silent:true, (code, output) ->
80 | console.log "test results:\n#{output}"
81 |
82 | #-------------------------------------------------------------------------------
83 | watchIter = ->
84 | tasks.build()
85 | tasks.serve()
86 | tasks.test()
87 |
88 | #-------------------------------------------------------------------------------
89 | cleanDir = (dir) ->
90 | mkdir "-p", dir
91 | rm "-rf", "#{dir}/*"
92 |
93 | #-------------------------------------------------------------------------------
94 | # Copyright IBM Corp. 2014
95 | #
96 | # Licensed under the Apache License, Version 2.0 (the "License");
97 | # you may not use this file except in compliance with the License.
98 | # You may obtain a copy of the License at
99 | #
100 | # http://www.apache.org/licenses/LICENSE-2.0
101 | #
102 | # Unless required by applicable law or agreed to in writing, software
103 | # distributed under the License is distributed on an "AS IS" BASIS,
104 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
105 | # See the License for the specific language governing permissions and
106 | # limitations under the License.
107 | #-------------------------------------------------------------------------------
108 |
--------------------------------------------------------------------------------
/lib-src/cfenv.coffee:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License. See footer for details.
2 |
3 | fs = require "fs"
4 | URL = require "url"
5 |
6 | pkg = require "../package.json"
7 | _ = require "underscore"
8 | ports = require "ports"
9 | yaml = require "js-yaml"
10 |
11 | #-------------------------------------------------------------------------------
12 | # properties on the cfenv object will be the module exports
13 | #-------------------------------------------------------------------------------
14 | cfenv = exports
15 |
16 | #-------------------------------------------------------------------------------
17 | cfenv.getAppEnv = (options={}) ->
18 | return new AppEnv options
19 |
20 | #-------------------------------------------------------------------------------
21 | class AppEnv
22 |
23 | #-----------------------------------------------------------------------------
24 | constructor: (options = {}) ->
25 | @isLocal = not process.env.VCAP_APPLICATION?
26 | unless @isLocal
27 | try
28 | JSON.parse process.env.VCAP_APPLICATION
29 | catch
30 | @isLocal = true
31 |
32 | @_getVcapFromFile(options) if @isLocal
33 |
34 | @app = getApp @, options
35 | @services = getServices @, options
36 |
37 | @name = getName @, options
38 | @port = getPort @
39 | @bind = getBind @
40 | @urls = getURLs @, options
41 | @url = @urls[0]
42 |
43 | #-----------------------------------------------------------------------------
44 | _getVcapFromFile: (options) ->
45 | return if not options?.vcapFile
46 |
47 | contents = null
48 | try
49 | contents = fs.readFileSync options.vcapFile, 'utf8'
50 | catch err
51 | console.log "error reading vcapFile '#{options.vcapFile}': #{err}; ignoring"
52 | return
53 |
54 | vcap = null
55 | try
56 | vcap = JSON.parse contents
57 | catch err
58 | console.log "error parsing vcapFile '#{options.vcapFile}': #{err}; ignoring"
59 | return
60 |
61 | options.vcap = vcap
62 |
63 | #-----------------------------------------------------------------------------
64 | toJSON: ->
65 | {@app, @services, @isLocal, @name, @port, @bind, @urls, @url}
66 |
67 | #-----------------------------------------------------------------------------
68 | getServices: ->
69 | result = {}
70 |
71 | for type, services of @services
72 | for service in services
73 | result[service.name] = service
74 |
75 | return result
76 |
77 | #-----------------------------------------------------------------------------
78 | getService: (spec) ->
79 |
80 | # set our matching function
81 | if _.isRegExp spec
82 | matches = (name) -> name.match spec
83 | else
84 | spec = "#{spec}"
85 | matches = (name) -> name is spec
86 |
87 | services = @getServices()
88 | for name, service of services
89 | if matches name
90 | return service
91 |
92 | # no matches
93 | return null
94 |
95 | #-----------------------------------------------------------------------------
96 | getServiceURL: (spec, replacements={}) ->
97 | service = @getService spec
98 |
99 | credentials = service?.credentials
100 | return null unless credentials?
101 |
102 | replacements = _.clone replacements
103 |
104 | if replacements.url
105 | url = credentials[replacements.url]
106 | else
107 | url = credentials.url || credentials.uri
108 |
109 | return null unless url?
110 |
111 | delete replacements.url
112 |
113 | return url if _.isEmpty replacements
114 |
115 | purl = URL.parse url
116 |
117 | for key, value of replacements
118 | if key is "auth"
119 | [userid, password] = value
120 | purl[key] = "#{credentials[userid]}:#{credentials[password]}"
121 | else
122 | purl[key] = credentials[value]
123 |
124 | return URL.format purl
125 |
126 | #-----------------------------------------------------------------------------
127 | getServiceCreds: (spec) ->
128 | service = @getService spec
129 | return null unless service?
130 |
131 | return service.credentials || {}
132 |
133 | #-------------------------------------------------------------------------------
134 | getApp = (appEnv, options) ->
135 | string = process.env.VCAP_APPLICATION
136 |
137 | envValue = {}
138 | if string?
139 | try
140 | envValue = JSON.parse string
141 | catch e
142 | throwError "env var VCAP_APPLICATION is not JSON: /#{string}/"
143 |
144 | return envValue unless appEnv.isLocal
145 |
146 | locValue = options?.vcap?.application
147 | return locValue if locValue?
148 | return envValue
149 |
150 | #-------------------------------------------------------------------------------
151 | getServices = (appEnv, options) ->
152 | string = process.env.VCAP_SERVICES
153 |
154 | envValue = {}
155 | if string?
156 | try
157 | envValue = JSON.parse string
158 | catch e
159 | throwError "env var VCAP_SERVICES is not JSON: /#{string}/"
160 |
161 | return envValue unless appEnv.isLocal
162 |
163 | locValue = options?.vcap?.services
164 | return locValue if locValue?
165 | return envValue
166 |
167 | #-------------------------------------------------------------------------------
168 | getPort = (appEnv) ->
169 | portString = process.env.PORT ||
170 | process.env.CF_INSTANCE_PORT ||
171 | process.env.VCAP_APP_PORT ||
172 | appEnv?.app?.port
173 |
174 | unless portString?
175 | return 3000 unless appEnv.name?
176 |
177 | try
178 | portString = "#{ports.getPort appEnv.name}"
179 | catch e
180 | portString = '3000'
181 |
182 | port = parseInt portString, 10
183 | throwError "invalid PORT value: /#{portString}/" if isNaN port
184 |
185 | return port
186 |
187 | #-------------------------------------------------------------------------------
188 | getName = (appEnv, options) ->
189 | return options.name if options.name?
190 |
191 | val = appEnv.app?.name
192 | return val if val?
193 |
194 | if fs.existsSync "manifest.yml"
195 | yString = fs.readFileSync "manifest.yml", "utf8"
196 | yObject = yaml.load yString, filename: "manifest.yml"
197 |
198 | yObject = yObject.applications[0] if yObject.applications?
199 | return yObject.name if yObject.name?
200 |
201 | if fs.existsSync "package.json"
202 | pString = fs.readFileSync "package.json", "utf8"
203 | try
204 | pObject = JSON.parse pString
205 | catch
206 | pObject = null
207 |
208 | return pObject.name if pObject?.name
209 |
210 | return null
211 |
212 | #-------------------------------------------------------------------------------
213 | getBind = (appEnv) ->
214 | return appEnv.app?.host || "localhost"
215 |
216 | #-------------------------------------------------------------------------------
217 | getURLs = (appEnv, options) ->
218 |
219 | uris = appEnv.app?.uris
220 |
221 | if appEnv.isLocal
222 | uris = [ "localhost:#{appEnv.port}" ]
223 |
224 | else
225 | unless uris?
226 | uris = [ "localhost" ]
227 |
228 | protocol = options.protocol
229 |
230 | unless protocol?
231 | if appEnv.isLocal
232 | protocol = "http:"
233 | else
234 | protocol = "https:"
235 |
236 | urls = for uri in uris
237 | "#{protocol}//#{uri}"
238 |
239 | return urls
240 |
241 | #-------------------------------------------------------------------------------
242 | throwError = (message) ->
243 | message = "#{pkg.name}: #{message}"
244 | console.log "error: #{message}"
245 | throw new Error message
246 |
247 | #-------------------------------------------------------------------------------
248 | # Copyright IBM Corp. 2014
249 | # Copyright Patrick Mueller 2015, 2017
250 | #
251 | # Licensed under the Apache License, Version 2.0 (the "License");
252 | # you may not use this file except in compliance with the License.
253 | # You may obtain a copy of the License at
254 | #
255 | # http://www.apache.org/licenses/LICENSE-2.0
256 | #
257 | # Unless required by applicable law or agreed to in writing, software
258 | # distributed under the License is distributed on an "AS IS" BASIS,
259 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
260 | # See the License for the specific language governing permissions and
261 | # limitations under the License.
262 | #-------------------------------------------------------------------------------
263 |
--------------------------------------------------------------------------------
/lib-src/server.coffee:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License. See footer for details.
2 |
3 | http = require "http"
4 |
5 | cfenv = require ".."
6 |
7 | #-------------------------------------------------------------------------------
8 | exports.main = ->
9 | appEnv = cfenv.getAppEnv()
10 |
11 | dump = generateDump appEnv
12 | # console.log "#{dump}\n"
13 |
14 | server = http.createServer()
15 |
16 | server.on "request", (request, response) ->
17 | response.writeHead 200,
18 | "Content-Type": "text/plain"
19 |
20 | response.end dump
21 |
22 | server.listen appEnv.port, appEnv.bind, ->
23 | console.log "server starting on #{appEnv.url}"
24 |
25 | #-------------------------------------------------------------------------------
26 | generateDump = (appEnv) ->
27 | result = []
28 |
29 | result.push "cfenv.getAppEnv(): #{JL appEnv}"
30 |
31 | services = appEnv.getServices()
32 | result.push "appEnv.getServices(): #{JL services}"
33 |
34 | serviceURL = appEnv.getServiceURL "cf-env-test",
35 | pathname: "database"
36 | auth: ["username", "password"]
37 |
38 | result.push "appEnv.getServiceURL(): #{serviceURL}"
39 |
40 | return result.join "\n\n"
41 |
42 | #-------------------------------------------------------------------------------
43 | JS = (object) -> JSON.stringify object
44 | JL = (object) -> JSON.stringify object, null, 4
45 |
46 | exports.main() if require.main is module
47 |
48 | #-------------------------------------------------------------------------------
49 | # Copyright IBM Corp. 2014
50 | #
51 | # Licensed under the Apache License, Version 2.0 (the "License");
52 | # you may not use this file except in compliance with the License.
53 | # You may obtain a copy of the License at
54 | #
55 | # http://www.apache.org/licenses/LICENSE-2.0
56 | #
57 | # Unless required by applicable law or agreed to in writing, software
58 | # distributed under the License is distributed on an "AS IS" BASIS,
59 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
60 | # See the License for the specific language governing permissions and
61 | # limitations under the License.
62 | #-------------------------------------------------------------------------------
63 |
--------------------------------------------------------------------------------
/lib/cfenv.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.12.7
2 | (function() {
3 | var AppEnv, URL, _, cfenv, fs, getApp, getBind, getName, getPort, getServices, getURLs, pkg, ports, throwError, yaml;
4 |
5 | fs = require("fs");
6 |
7 | URL = require("url");
8 |
9 | pkg = require("../package.json");
10 |
11 | _ = require("underscore");
12 |
13 | ports = require("ports");
14 |
15 | yaml = require("js-yaml");
16 |
17 | cfenv = exports;
18 |
19 | cfenv.getAppEnv = function(options) {
20 | if (options == null) {
21 | options = {};
22 | }
23 | return new AppEnv(options);
24 | };
25 |
26 | AppEnv = (function() {
27 | function AppEnv(options) {
28 | if (options == null) {
29 | options = {};
30 | }
31 | this.isLocal = process.env.VCAP_APPLICATION == null;
32 | if (!this.isLocal) {
33 | try {
34 | JSON.parse(process.env.VCAP_APPLICATION);
35 | } catch (error) {
36 | this.isLocal = true;
37 | }
38 | }
39 | if (this.isLocal) {
40 | this._getVcapFromFile(options);
41 | }
42 | this.app = getApp(this, options);
43 | this.services = getServices(this, options);
44 | this.name = getName(this, options);
45 | this.port = getPort(this);
46 | this.bind = getBind(this);
47 | this.urls = getURLs(this, options);
48 | this.url = this.urls[0];
49 | }
50 |
51 | AppEnv.prototype._getVcapFromFile = function(options) {
52 | var contents, err, vcap;
53 | if (!(options != null ? options.vcapFile : void 0)) {
54 | return;
55 | }
56 | contents = null;
57 | try {
58 | contents = fs.readFileSync(options.vcapFile, 'utf8');
59 | } catch (error) {
60 | err = error;
61 | console.log("error reading vcapFile '" + options.vcapFile + "': " + err + "; ignoring");
62 | return;
63 | }
64 | vcap = null;
65 | try {
66 | vcap = JSON.parse(contents);
67 | } catch (error) {
68 | err = error;
69 | console.log("error parsing vcapFile '" + options.vcapFile + "': " + err + "; ignoring");
70 | return;
71 | }
72 | return options.vcap = vcap;
73 | };
74 |
75 | AppEnv.prototype.toJSON = function() {
76 | return {
77 | app: this.app,
78 | services: this.services,
79 | isLocal: this.isLocal,
80 | name: this.name,
81 | port: this.port,
82 | bind: this.bind,
83 | urls: this.urls,
84 | url: this.url
85 | };
86 | };
87 |
88 | AppEnv.prototype.getServices = function() {
89 | var i, len, ref, result, service, services, type;
90 | result = {};
91 | ref = this.services;
92 | for (type in ref) {
93 | services = ref[type];
94 | for (i = 0, len = services.length; i < len; i++) {
95 | service = services[i];
96 | result[service.name] = service;
97 | }
98 | }
99 | return result;
100 | };
101 |
102 | AppEnv.prototype.getService = function(spec) {
103 | var matches, name, service, services;
104 | if (_.isRegExp(spec)) {
105 | matches = function(name) {
106 | return name.match(spec);
107 | };
108 | } else {
109 | spec = "" + spec;
110 | matches = function(name) {
111 | return name === spec;
112 | };
113 | }
114 | services = this.getServices();
115 | for (name in services) {
116 | service = services[name];
117 | if (matches(name)) {
118 | return service;
119 | }
120 | }
121 | return null;
122 | };
123 |
124 | AppEnv.prototype.getServiceURL = function(spec, replacements) {
125 | var credentials, key, password, purl, service, url, userid, value;
126 | if (replacements == null) {
127 | replacements = {};
128 | }
129 | service = this.getService(spec);
130 | credentials = service != null ? service.credentials : void 0;
131 | if (credentials == null) {
132 | return null;
133 | }
134 | replacements = _.clone(replacements);
135 | if (replacements.url) {
136 | url = credentials[replacements.url];
137 | } else {
138 | url = credentials.url || credentials.uri;
139 | }
140 | if (url == null) {
141 | return null;
142 | }
143 | delete replacements.url;
144 | if (_.isEmpty(replacements)) {
145 | return url;
146 | }
147 | purl = URL.parse(url);
148 | for (key in replacements) {
149 | value = replacements[key];
150 | if (key === "auth") {
151 | userid = value[0], password = value[1];
152 | purl[key] = credentials[userid] + ":" + credentials[password];
153 | } else {
154 | purl[key] = credentials[value];
155 | }
156 | }
157 | return URL.format(purl);
158 | };
159 |
160 | AppEnv.prototype.getServiceCreds = function(spec) {
161 | var service;
162 | service = this.getService(spec);
163 | if (service == null) {
164 | return null;
165 | }
166 | return service.credentials || {};
167 | };
168 |
169 | return AppEnv;
170 |
171 | })();
172 |
173 | getApp = function(appEnv, options) {
174 | var e, envValue, locValue, ref, string;
175 | string = process.env.VCAP_APPLICATION;
176 | envValue = {};
177 | if (string != null) {
178 | try {
179 | envValue = JSON.parse(string);
180 | } catch (error) {
181 | e = error;
182 | throwError("env var VCAP_APPLICATION is not JSON: /" + string + "/");
183 | }
184 | }
185 | if (!appEnv.isLocal) {
186 | return envValue;
187 | }
188 | locValue = options != null ? (ref = options.vcap) != null ? ref.application : void 0 : void 0;
189 | if (locValue != null) {
190 | return locValue;
191 | }
192 | return envValue;
193 | };
194 |
195 | getServices = function(appEnv, options) {
196 | var e, envValue, locValue, ref, string;
197 | string = process.env.VCAP_SERVICES;
198 | envValue = {};
199 | if (string != null) {
200 | try {
201 | envValue = JSON.parse(string);
202 | } catch (error) {
203 | e = error;
204 | throwError("env var VCAP_SERVICES is not JSON: /" + string + "/");
205 | }
206 | }
207 | if (!appEnv.isLocal) {
208 | return envValue;
209 | }
210 | locValue = options != null ? (ref = options.vcap) != null ? ref.services : void 0 : void 0;
211 | if (locValue != null) {
212 | return locValue;
213 | }
214 | return envValue;
215 | };
216 |
217 | getPort = function(appEnv) {
218 | var e, port, portString, ref;
219 | portString = process.env.PORT || process.env.CF_INSTANCE_PORT || process.env.VCAP_APP_PORT || (appEnv != null ? (ref = appEnv.app) != null ? ref.port : void 0 : void 0);
220 | if (portString == null) {
221 | if (appEnv.name == null) {
222 | return 3000;
223 | }
224 | try {
225 | portString = "" + (ports.getPort(appEnv.name));
226 | } catch (error) {
227 | e = error;
228 | portString = '3000';
229 | }
230 | }
231 | port = parseInt(portString, 10);
232 | if (isNaN(port)) {
233 | throwError("invalid PORT value: /" + portString + "/");
234 | }
235 | return port;
236 | };
237 |
238 | getName = function(appEnv, options) {
239 | var pObject, pString, ref, val, yObject, yString;
240 | if (options.name != null) {
241 | return options.name;
242 | }
243 | val = (ref = appEnv.app) != null ? ref.name : void 0;
244 | if (val != null) {
245 | return val;
246 | }
247 | if (fs.existsSync("manifest.yml")) {
248 | yString = fs.readFileSync("manifest.yml", "utf8");
249 | yObject = yaml.load(yString, {
250 | filename: "manifest.yml"
251 | });
252 | if (yObject.applications != null) {
253 | yObject = yObject.applications[0];
254 | }
255 | if (yObject.name != null) {
256 | return yObject.name;
257 | }
258 | }
259 | if (fs.existsSync("package.json")) {
260 | pString = fs.readFileSync("package.json", "utf8");
261 | try {
262 | pObject = JSON.parse(pString);
263 | } catch (error) {
264 | pObject = null;
265 | }
266 | if (pObject != null ? pObject.name : void 0) {
267 | return pObject.name;
268 | }
269 | }
270 | return null;
271 | };
272 |
273 | getBind = function(appEnv) {
274 | var ref;
275 | return ((ref = appEnv.app) != null ? ref.host : void 0) || "localhost";
276 | };
277 |
278 | getURLs = function(appEnv, options) {
279 | var protocol, ref, uri, uris, urls;
280 | uris = (ref = appEnv.app) != null ? ref.uris : void 0;
281 | if (appEnv.isLocal) {
282 | uris = ["localhost:" + appEnv.port];
283 | } else {
284 | if (uris == null) {
285 | uris = ["localhost"];
286 | }
287 | }
288 | protocol = options.protocol;
289 | if (protocol == null) {
290 | if (appEnv.isLocal) {
291 | protocol = "http:";
292 | } else {
293 | protocol = "https:";
294 | }
295 | }
296 | urls = (function() {
297 | var i, len, results;
298 | results = [];
299 | for (i = 0, len = uris.length; i < len; i++) {
300 | uri = uris[i];
301 | results.push(protocol + "//" + uri);
302 | }
303 | return results;
304 | })();
305 | return urls;
306 | };
307 |
308 | throwError = function(message) {
309 | message = pkg.name + ": " + message;
310 | console.log("error: " + message);
311 | throw new Error(message);
312 | };
313 |
314 | }).call(this);
315 |
--------------------------------------------------------------------------------
/lib/server.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.12.7
2 | (function() {
3 | var JL, JS, cfenv, generateDump, http;
4 |
5 | http = require("http");
6 |
7 | cfenv = require("..");
8 |
9 | exports.main = function() {
10 | var appEnv, dump, server;
11 | appEnv = cfenv.getAppEnv();
12 | dump = generateDump(appEnv);
13 | server = http.createServer();
14 | server.on("request", function(request, response) {
15 | response.writeHead(200, {
16 | "Content-Type": "text/plain"
17 | });
18 | return response.end(dump);
19 | });
20 | return server.listen(appEnv.port, appEnv.bind, function() {
21 | return console.log("server starting on " + appEnv.url);
22 | });
23 | };
24 |
25 | generateDump = function(appEnv) {
26 | var result, serviceURL, services;
27 | result = [];
28 | result.push("cfenv.getAppEnv(): " + (JL(appEnv)));
29 | services = appEnv.getServices();
30 | result.push("appEnv.getServices(): " + (JL(services)));
31 | serviceURL = appEnv.getServiceURL("cf-env-test", {
32 | pathname: "database",
33 | auth: ["username", "password"]
34 | });
35 | result.push("appEnv.getServiceURL(): " + serviceURL);
36 | return result.join("\n\n");
37 | };
38 |
39 | JS = function(object) {
40 | return JSON.stringify(object);
41 | };
42 |
43 | JL = function(object) {
44 | return JSON.stringify(object, null, 4);
45 | };
46 |
47 | if (require.main === module) {
48 | exports.main();
49 | }
50 |
51 | }).call(this);
52 |
--------------------------------------------------------------------------------
/manifest.yml:
--------------------------------------------------------------------------------
1 | applications:
2 | - name: cf-env-test
3 | mem: 128M
4 | random-route: true
5 | services:
6 | - cf-env-test
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cfenv",
3 | "main": "./lib/cfenv",
4 | "description": "easy access to your Cloud Foundry application environment",
5 | "version": "1.2.4",
6 | "author": "pmuellr",
7 | "license": "Apache-2.0",
8 | "homepage": "https://github.com/cloudfoundry-community/node-cfenv",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/cloudfoundry-community/node-cfenv.git"
12 | },
13 | "scripts": {
14 | "build": "jbuild build",
15 | "serve": "jbuild serve",
16 | "test": "jbuild test",
17 | "watch": "jbuild watch"
18 | },
19 | "dependencies": {
20 | "js-yaml": "4.0.x",
21 | "ports": "1.1.x",
22 | "underscore": "1.12.x"
23 | },
24 | "devDependencies": {
25 | "coffeescript": "1.12.x",
26 | "expect.js": "0.3.x",
27 | "jbuild": "1.0.x",
28 | "mocha": "8.3.x"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/sample-data/README.md:
--------------------------------------------------------------------------------
1 | # sample environmental data
2 |
3 | Some sample data for a node app which is bound to a mongodb service.
4 |
5 | ## `cf files logs/env.log`
6 |
7 | Getting files for app hello-node in org / space dev as ...
8 | OK
9 |
10 | TMPDIR=/home/vcap/tmp
11 | VCAP_APP_PORT=62372
12 | USER=vcap
13 | VCAP_APPLICATION={"limits":{"mem":128,"disk":1024,"fds":16384},"application_version":"b65714f0-7ccc-4ec1-a426-f007a9bc9de9","application_name":"hello-node","application_uris":["."],"version":"b65714f0-7ccc-4ec1-a426-f007a9bc9de9","name":"hello-node","space_name":"dev","space_id":"ca6e986f-be29-4ee0-a297-7e4ffde4ef49","uris":["."],"users":null,"instance_id":"9c7837ed0ef441bbb11e7436093698dd","instance_index":0,"host":"0.0.0.0","port":62372,"started_at":"2014-04-29 17:30:54 +0000","started_at_timestamp":1398792654,"start":"2014-04-29 17:30:54 +0000","state_timestamp":1398792654}
14 | PATH=/home/vcap/app/vendor/node/bin:/home/vcap/app/bin:/home/vcap/app/node_modules/.bin:/bin:/usr/bin
15 | PWD=/home/vcap
16 | VCAP_SERVICES={"mongodb-2.2":[{"name":"my-db","label":"mongodb-2.2","tags":["nosql","document","data_management"],"plan":"100","credentials":{"hostname":"","host":"","port":,"username":"","password":"","name":"","db":"db","url":"mongodb://:@:/db"}}]}
17 | SHLVL=1
18 | HOME=/home/vcap/app
19 | PORT=62372
20 | VCAP_APP_HOST=0.0.0.0
21 | DATABASE_URL=
22 | MEMORY_LIMIT=128m
23 | _=/usr/bin/env
24 |
25 | ## `process.env`
26 |
27 | {
28 | "TMPDIR": "/home/vcap/tmp",
29 | "VCAP_APP_PORT": "62372",
30 | "USER": "vcap",
31 | "VCAP_APPLICATION": "{\"limits\":{\"mem\":128,\"disk\":1024,\"fds\":16384},\"application_version\":\"b65714f0-7ccc-4ec1-a426-f007a9bc9de9\",\"application_name\":\"hello-node\",\"application_uris\":[\".\"],\"version\":\"b65714f0-7ccc-4ec1-a426-f007a9bc9de9\",\"name\":\"hello-node\",\"space_name\":\"dev\",\"space_id\":\"ca6e986f-be29-4ee0-a297-7e4ffde4ef49\",\"uris\":[\".\"],\"users\":null,\"instance_id\":\"9c7837ed0ef441bbb11e7436093698dd\",\"instance_index\":0,\"host\":\"0.0.0.0\",\"port\":62372,\"started_at\":\"2014-04-29 17:30:54 +0000\",\"started_at_timestamp\":1398792654,\"start\":\"2014-04-29 17:30:54 +0000\",\"state_timestamp\":1398792654}",
32 | "PATH": "/home/vcap/app/vendor/node/bin:/home/vcap/app/bin:/home/vcap/app/node_modules/.bin:/bin:/usr/bin",
33 | "PWD": "/home/vcap/app",
34 | "VCAP_SERVICES": "{\"mongodb-2.2\":[{\"name\":\"my-db\",\"label\":\"mongodb-2.2\",\"tags\":[\"nosql\",\"document\",\"data_management\"],\"plan\":\"100\",\"credentials\":{\"hostname\":\"\",\"host\":\"\",\"port\":,\"username\":\"\",\"password\":\"\",\"name\":\"\",\"db\":\"db\",\"url\":\"mongodb://:@:/db\"}}]}",
35 | "SHLVL": "1",
36 | "HOME": "/home/vcap/app",
37 | "PORT": "62372",
38 | "VCAP_APP_HOST": "0.0.0.0",
39 | "DATABASE_URL": "",
40 | "MEMORY_LIMIT": "128m",
41 | "_": "/home/vcap/app/vendor/node/bin/node",
42 | "OLDPWD": "/home/vcap"
43 | }
44 |
45 | ## `cfenv.getAppEnv()`
46 |
47 | {
48 | "app": {
49 | "limits": {
50 | "mem": 128,
51 | "disk": 1024,
52 | "fds": 16384
53 | },
54 | "application_version": "b65714f0-7ccc-4ec1-a426-f007a9bc9de9",
55 | "application_name": "hello-node",
56 | "application_uris": [
57 | "."
58 | ],
59 | "version": "b65714f0-7ccc-4ec1-a426-f007a9bc9de9",
60 | "name": "hello-node",
61 | "space_name": "dev",
62 | "space_id": "ca6e986f-be29-4ee0-a297-7e4ffde4ef49",
63 | "uris": [
64 | "."
65 | ],
66 | "users": null,
67 | "instance_id": "9c7837ed0ef441bbb11e7436093698dd",
68 | "instance_index": 0,
69 | "host": "0.0.0.0",
70 | "port": 62372,
71 | "started_at": "2014-04-29 17:30:54 +0000",
72 | "started_at_timestamp": 1398792654,
73 | "start": "2014-04-29 17:30:54 +0000",
74 | "state_timestamp": 1398792654
75 | },
76 | "services": {
77 | "mongodb-2.2": [
78 | {
79 | "name": "my-db",
80 | "label": "mongodb-2.2",
81 | "tags": [
82 | "nosql",
83 | "document",
84 | "data_management"
85 | ],
86 | "plan": "100",
87 | "credentials": {
88 | "hostname": "",
89 | "host": "",
90 | "port": ,
91 | "username": "",
92 | "password": "",
93 | "name": "",
94 | "db": "db",
95 | "url": "mongodb://:@:/db"
96 | }
97 | }
98 | ]
99 | },
100 | "name": "hello-node",
101 | "port": 62372,
102 | "bind": "0.0.0.0",
103 | "urls": [
104 | "https://."
105 | ],
106 | "url": "https://.",
107 | "isLocal": false
108 | }
109 |
110 | ## `appEnv.getServices()`
111 |
112 | {
113 | "my-db": {
114 | "name": "my-db",
115 | "label": "mongodb-2.2",
116 | "tags": [
117 | "nosql",
118 | "document",
119 | "data_management"
120 | ],
121 | "plan": "100",
122 | "credentials": {
123 | "hostname": "",
124 | "host": "",
125 | "port": ,
126 | "username": "",
127 | "password": "",
128 | "name": "",
129 | "db": "db",
130 | "url": "mongodb://:@:/db"
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | // Licensed under the Apache License. See footer for details.
2 |
3 | require("./lib/server").main()
4 |
5 | //------------------------------------------------------------------------------
6 | // Copyright IBM Corp. 2014
7 | //
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 | //------------------------------------------------------------------------------
20 |
--------------------------------------------------------------------------------
/tests/data-01.cson:
--------------------------------------------------------------------------------
1 | PORT: "61165"
2 | VCAP_APP_PORT: "61165"
3 | VCAP_APP_HOST: "0.0.0.0"
4 | DATABASE_URL: ""
5 | MEMORY_LIMIT: "128m"
6 |
7 | VCAP_SERVICES:
8 | "user-provided": [
9 | name: "cf-env-test"
10 | label: "user-provided"
11 | tags: []
12 | credentials:
13 | database: "database"
14 | password: "passw0rd"
15 | url: "https://example.com/"
16 | username: "userid"
17 | syslog_drain_url: "http://example.com/syslog"
18 | ]
19 |
20 | VCAP_APPLICATION:
21 | instance_id: "606eac20570f48e7b39390cf9d2b8fcc"
22 | instance_index: 0
23 | host: "0.0.0.0"
24 | port: 61165
25 | started_at: "2014-03-11 03:02:29 +0000"
26 | started_at_timestamp: 1394506949,
27 | start: "2014-03-11 03:02:29 +0000"
28 | state_timestamp: 1394506949
29 | limits:
30 | mem: 128
31 | disk: 1024
32 | fds: 16384
33 | application_version: "17378da2-08c7-4221-accb-46464c3ad755"
34 | version: "17378da2-08c7-4221-accb-46464c3ad755"
35 | application_name: "cf-env-test"
36 | name: "cf-env-test"
37 | application_uris: [
38 | "cf-env-test.ng.bluemix.net"
39 | ]
40 | uris: [
41 | "cf-env-test.ng.bluemix.net"
42 | ]
43 | users: null
44 |
--------------------------------------------------------------------------------
/tests/fixtures/vcap-local-bad.json:
--------------------------------------------------------------------------------
1 | this file intentially does not contain valid JSON
2 |
--------------------------------------------------------------------------------
/tests/fixtures/vcap-local-good.json:
--------------------------------------------------------------------------------
1 | {
2 | "application": {
3 | "port": 42
4 | },
5 | "services": {
6 | "service-a-label": [
7 | {
8 | "name": "service-a",
9 | "label": "service-a-label",
10 | "credentials": {
11 | "url": "foo"
12 | }
13 | }
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tests/test-core.coffee:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License. See footer for details.
2 |
3 | fs = require "fs"
4 | path = require "path"
5 |
6 | _ = require "underscore"
7 | coffee = require "coffeescript"
8 | expect = require "expect.js"
9 | ports = require "ports"
10 |
11 | cfenv = require ".."
12 |
13 | SavedEnv = JSON.stringify process.env
14 | SavedDir = process.cwd()
15 | TestDir = path.join SavedDir, "tmp"
16 |
17 | SampleName = "cf-env-testing-app"
18 | SamplePort = ports.getPort SampleName
19 |
20 | Manifest_01 = """
21 | """
22 |
23 | #-------------------------------------------------------------------------------
24 | describe "appEnv", ->
25 |
26 | #-----------------------------------------------------------------------------
27 | beforeEach ->
28 | process.env = {}
29 | process.chdir TestDir
30 | fs.unlinkSync "manifest.yml" if fs.existsSync "manifest.yml"
31 | fs.unlinkSync "package.json" if fs.existsSync "package.json"
32 |
33 | #-----------------------------------------------------------------------------
34 | afterEach ->
35 | fs.unlinkSync "package.json" if fs.existsSync "package.json"
36 | fs.unlinkSync "manifest.yml" if fs.existsSync "manifest.yml"
37 | process.chdir SavedDir
38 | process.env = JSON.parse SavedEnv
39 |
40 | #-----------------------------------------------------------------------------
41 | it "local - empty environment", ->
42 | appEnv = cfenv.getAppEnv()
43 | expect(appEnv.name).to.be null
44 | expect(appEnv.port).to.be 3000
45 | expect(appEnv.bind).to.be "localhost"
46 | expect(appEnv.urls.length).to.be 1
47 | expect(appEnv.urls[0]).to.be appEnv.url
48 | expect(appEnv.url).to.be "http://localhost:3000"
49 | expect(appEnv.isLocal).to.be true
50 |
51 | app = appEnv.app
52 | svs = appEnv.services
53 |
54 | expect(_.isEmpty(app)).to.be true
55 | expect(_.isEmpty(svs)).to.be true
56 |
57 | #-----------------------------------------------------------------------------
58 | it "local - getting port via name parm and ports.getPort()", ->
59 | appEnv = cfenv.getAppEnv {name: SampleName}
60 | expect(appEnv.name).to.be SampleName
61 | expect(appEnv.port).to.be SamplePort
62 | expect(appEnv.bind).to.be "localhost"
63 | expect(appEnv.urls.length).to.be 1
64 | expect(appEnv.urls[0]).to.be appEnv.url
65 | expect(appEnv.url).to.be "http://localhost:#{SamplePort}"
66 | expect(appEnv.isLocal).to.be true
67 |
68 | #-----------------------------------------------------------------------------
69 | it "local - getting port via PORT env var", ->
70 |
71 | port = 6000
72 | process.env.PORT = "#{port}"
73 |
74 | appEnv = cfenv.getAppEnv()
75 | expect(appEnv.name).to.be null
76 | expect(appEnv.port).to.be port
77 | expect(appEnv.bind).to.be "localhost"
78 | expect(appEnv.urls.length).to.be 1
79 | expect(appEnv.urls[0]).to.be appEnv.url
80 | expect(appEnv.url).to.be "http://localhost:#{port}"
81 | expect(appEnv.isLocal).to.be true
82 |
83 | #-----------------------------------------------------------------------------
84 | it "local - getAppEnv({protocol})", ->
85 |
86 | appEnv = cfenv.getAppEnv({protocol: "foo:"})
87 | expect(appEnv.urls.length).to.be 1
88 | expect(appEnv.url).to.be "foo://localhost:3000"
89 |
90 | #-----------------------------------------------------------------------------
91 | it "local - getAppEnv({vcap.application})", ->
92 |
93 | vcap =
94 | application:
95 | name: SampleName
96 | host: "sample-host"
97 | uris: [ "sample-uri.example.com", "sample-uri.example.net" ]
98 |
99 | appEnv = cfenv.getAppEnv({vcap})
100 | expect(appEnv.name).to.be SampleName
101 | expect(appEnv.port).to.be SamplePort
102 | expect(appEnv.bind).to.be vcap.application.host
103 | expect(appEnv.urls.length).to.be 1
104 | expect(appEnv.url).to.be "http://localhost:#{SamplePort}"
105 | expect(appEnv.isLocal).to.be true
106 |
107 | app = appEnv.app
108 |
109 | expect(JSON.stringify(app)).to.be JSON.stringify(vcap.application)
110 |
111 | #-----------------------------------------------------------------------------
112 | it "local - getAppEnv({vcap.services})", ->
113 |
114 | vcap = services: SampleVCAPServices_1
115 |
116 | appEnv = cfenv.getAppEnv({vcap})
117 |
118 | svs = appEnv.services
119 |
120 | expect(JSON.stringify(svs)).to.be JSON.stringify(vcap.services)
121 |
122 | expected = {}
123 | for label, services of vcap.services
124 | for service in services
125 | expected[service.name] = service
126 |
127 | expected = SampleVCAPServices_1.serviceLabel_2[1]
128 | service = appEnv.getService "serviceName_B"
129 | expect(JSON.stringify(service)).to.be JSON.stringify(expected)
130 |
131 | service = appEnv.getService /serviceName_B/
132 | expect(JSON.stringify(service)).to.be JSON.stringify(expected)
133 |
134 | service = appEnv.getService /B/
135 | expect(JSON.stringify(service)).to.be JSON.stringify(expected)
136 |
137 | #-----------------------------------------------------------------------------
138 | it "local - getServiceURL()", ->
139 |
140 | #-------------------------------------------
141 | vcap = getVCAPServicesWithCreds "service-a",
142 | url: "foo"
143 |
144 | appEnv = cfenv.getAppEnv {vcap}
145 | url = appEnv.getServiceURL "service-a"
146 | expect(url).to.be "foo"
147 |
148 | #-------------------------------------------
149 | vcap = getVCAPServicesWithCreds "service-a",
150 | uri: "foo"
151 |
152 | appEnv = cfenv.getAppEnv {vcap}
153 | url = appEnv.getServiceURL "service-a"
154 | expect(url).to.be "foo"
155 |
156 | #-------------------------------------------
157 | vcap = getVCAPServicesWithCreds "service-a",
158 | url: "org-protocol://org-host:666/org-path"
159 | proto: "http:"
160 | server: "example.com:80"
161 | PORT: "80"
162 | path: "new-path"
163 |
164 | appEnv = cfenv.getAppEnv {vcap}
165 | url = appEnv.getServiceURL "service-a",
166 | protocol: "proto"
167 | host: "server"
168 | pathname: "path"
169 |
170 | expect(url).to.be "http://example.com:80/new-path"
171 |
172 | #-------------------------------------------
173 | vcap = getVCAPServicesWithCreds "service-a",
174 | protocol: "proto:"
175 | host: "server"
176 | pathname: "path"
177 |
178 | appEnv = cfenv.getAppEnv {vcap}
179 | url = appEnv.getServiceURL "service-a"
180 |
181 | expect(url).to.be null
182 |
183 | #-------------------------------------------
184 | vcap = getVCAPServicesWithCreds "service-a",
185 | URL: "org-protocol://org-host:666/org-path"
186 |
187 | appEnv = cfenv.getAppEnv {vcap}
188 | url = appEnv.getServiceURL "service-a",
189 | url: "URL"
190 |
191 | expect(url).to.be "org-protocol://org-host:666/org-path"
192 |
193 | #-------------------------------------------
194 | testURL = "mongodb://user:pass@example.com:18394,example.com:18394/admin"
195 | vcap = getVCAPServicesWithCreds "service-a",
196 | uri: testURL
197 |
198 | appEnv = cfenv.getAppEnv {vcap}
199 | url = appEnv.getServiceURL "service-a"
200 |
201 | expect(url).to.be testURL
202 |
203 | #-----------------------------------------------------------------------------
204 | it "local - getServiceCreds()", ->
205 |
206 | #-------------------------------------------
207 | vcap = getVCAPServicesWithCreds "service-a",
208 | url: "foo"
209 |
210 | appEnv = cfenv.getAppEnv {vcap}
211 | creds = appEnv.getServiceCreds "service-b"
212 | expect(creds).to.be null
213 |
214 | #-------------------------------------------
215 | vcap = getVCAPServicesWithCreds "service-a",
216 | url: "foo"
217 |
218 | vcap["services"]["service-a-label"][0].credentials = null
219 |
220 | appEnv = cfenv.getAppEnv {vcap}
221 | creds = appEnv.getServiceCreds "service-a"
222 | creds = JSON.stringify(creds)
223 | expect(creds).to.be '{}'
224 |
225 | #-------------------------------------------
226 | vcap = getVCAPServicesWithCreds "service-a",
227 | url: "foo"
228 |
229 | delete vcap["services"]["service-a-label"][0].credentials
230 |
231 | appEnv = cfenv.getAppEnv {vcap}
232 | creds = appEnv.getServiceCreds "service-a"
233 | creds = JSON.stringify(creds)
234 | expect(creds).to.be '{}'
235 |
236 | #-------------------------------------------
237 | vcap = getVCAPServicesWithCreds "service-a",
238 | url: "foo"
239 |
240 | appEnv = cfenv.getAppEnv {vcap}
241 | creds = appEnv.getServiceCreds "service-a"
242 | creds = JSON.stringify(creds)
243 | expect(creds).to.be '{"url":"foo"}'
244 |
245 | #-----------------------------------------------------------------------------
246 | it "local - with vcapFile option", ->
247 |
248 | #-------------------------------------------
249 | vcapFile = path.join(__dirname, 'fixtures', 'vcap-local-good.json')
250 |
251 | appEnv = cfenv.getAppEnv {vcapFile}
252 | creds = appEnv.getServiceCreds "service-a"
253 | creds = JSON.stringify(creds)
254 | expect(creds).to.be '{"url":"foo"}'
255 | expect(appEnv.port).to.be 42
256 |
257 | #-------------------------------------------
258 | vcapFile = path.join(__dirname, 'fixtures', 'vcap-local-bad.json')
259 |
260 | console.log "expecting an error printed below:"
261 | appEnv = cfenv.getAppEnv {vcapFile}
262 | creds = appEnv.getServiceCreds "service-a"
263 | expect(creds).to.be null
264 |
265 | #-------------------------------------------
266 | vcap = getVCAPServicesWithCreds "service-a",
267 | url: "bar"
268 |
269 | vcapFile = path.join(__dirname, 'fixtures', 'vcap-local-good.json')
270 |
271 | appEnv = cfenv.getAppEnv {vcap, vcapFile}
272 | creds = appEnv.getServiceCreds "service-a"
273 | creds = JSON.stringify(creds)
274 | expect(creds).to.be '{"url":"foo"}'
275 |
276 | #-----------------------------------------------------------------------------
277 | it "remote - VCAP_APPLICATION", ->
278 |
279 | vcap =
280 | application:
281 | name: SampleName
282 | host: "sample-host"
283 | uris: [ "sample-uri.example.com", "sample-uri.example.net" ]
284 |
285 | process.env.VCAP_APPLICATION = JSON.stringify vcap.application
286 | process.env.PORT = "666"
287 |
288 | appEnv = cfenv.getAppEnv()
289 | expect(appEnv.name).to.be SampleName
290 | expect(appEnv.port).to.be 666
291 | expect(appEnv.bind).to.be vcap.application.host
292 | expect(appEnv.urls.length).to.be 2
293 | expect(appEnv.url).to.be "https://sample-uri.example.com"
294 | expect(appEnv.isLocal).to.be false
295 |
296 | app = appEnv.app
297 |
298 | expect(JSON.stringify(app)).to.be JSON.stringify(vcap.application)
299 |
300 | #-----------------------------------------------------------------------------
301 | it "remote - getAppEnv({protocol})", ->
302 |
303 | vcap =
304 | application:
305 | name: SampleName
306 | host: "sample-host"
307 | uris: [ "sample-uri.example.com", "sample-uri.example.net" ]
308 |
309 | process.env.VCAP_APPLICATION = JSON.stringify vcap.application
310 | process.env.PORT = "666"
311 |
312 | appEnv = cfenv.getAppEnv({protocol: "foo:"})
313 | expect(appEnv.url).to.be "foo://sample-uri.example.com"
314 |
315 | #-----------------------------------------------------------------------------
316 | it "remote - getAppEnv({vcap}) ignored", ->
317 |
318 | vcap = getVCAPServicesWithCreds "service-a", uri: "http://example.com"
319 | vcap.application =
320 | name: SampleName
321 | host: "sample-host"
322 | uris: [ "sample-uri.example.com", "sample-uri.example.net" ]
323 |
324 | process.env.VCAP_APPLICATION = JSON.stringify vcap.application
325 | process.env.VCAP_SERVICES = JSON.stringify vcap.services
326 | process.env.PORT = "666"
327 |
328 | vcap = getVCAPServicesWithCreds "service-a", uri: "http://example.net"
329 | vcap.application =
330 | name: "foo"
331 | host: "foo"
332 | uris: [ "foo" ]
333 |
334 | appEnv = cfenv.getAppEnv {vcap}
335 | expect(appEnv.url).to.be "https://sample-uri.example.com"
336 |
337 | url = appEnv.getServiceURL "service-a"
338 | expect(url).to.be "http://example.com"
339 |
340 | #-----------------------------------------------------------------------------
341 | it "name - from option", ->
342 |
343 | appEnv = cfenv.getAppEnv name: "foo"
344 | expect(appEnv.name).to.be "foo"
345 |
346 | #----------------------------------------
347 | vcapApplication =
348 | name: "bar"
349 | uris: []
350 |
351 | process.env.VCAP_APPLICATION = JSON.stringify vcapApplication
352 |
353 | appEnv = cfenv.getAppEnv name: "foo"
354 | expect(appEnv.name).to.be "foo"
355 |
356 | #-----------------------------------------------------------------------------
357 | it "name - from manifest.yml", ->
358 |
359 | fs.writeFileSync "manifest.yml", """
360 | applications:
361 | - name: foo
362 | memory: 128M
363 | """
364 |
365 | fs.writeFileSync "package.json", """
366 | {
367 | "name": "bar",
368 | "main": "./lib/bar"
369 | }
370 | """
371 |
372 | appEnv = cfenv.getAppEnv()
373 | expect(appEnv.name).to.be "foo"
374 |
375 | #-----------------------------------------------------------------------------
376 | it "name - bogus manifest.yml", ->
377 |
378 | fs.writeFileSync "manifest.yml", """
379 | ap)(*&))plications:
380 | )(*&9 name: foo
381 | m(*)()emory: 128M
382 | """
383 |
384 | fs.writeFileSync "package.json", """
385 | {
386 | "name": "bar",
387 | "main": "./lib/bar"
388 | }
389 | """
390 |
391 | appEnv = cfenv.getAppEnv()
392 | expect(appEnv.name).to.be "bar"
393 |
394 | #-----------------------------------------------------------------------------
395 | it "name - from package.json", ->
396 |
397 | fs.writeFileSync "package.json", """
398 | {
399 | "name": "bar",
400 | "main": "./lib/bar"
401 | }
402 | """
403 |
404 | appEnv = cfenv.getAppEnv()
405 | expect(appEnv.name).to.be "bar"
406 |
407 | #-----------------------------------------------------------------------------
408 | it "name - bogus package.json", ->
409 |
410 | fs.writeFileSync "package.json", """
411 | foop)(*)(*){
412 | "name": "bar",
413 | "main": "./lib/bar"
414 | }
415 | """
416 |
417 | appEnv = cfenv.getAppEnv()
418 | expect(appEnv.name).to.be null
419 |
420 | #-----------------------------------------------------------------------------
421 | it "error - VCAP_APPLICATION is not JSON", ->
422 |
423 | process.env.VCAP_APPLICATION = ":foo:)("
424 |
425 | fn = -> appEnv = cfenv.getAppEnv()
426 | console.log "expecting an error printed below:"
427 | expect(fn).to.throwError /VCAP_APPLICATION is not JSON/
428 |
429 | #-----------------------------------------------------------------------------
430 | it "error - VCAP_SERVICES is not JSON", ->
431 |
432 | process.env.VCAP_SERVICES = ":foo:)("
433 |
434 | fn = -> appEnv = cfenv.getAppEnv()
435 | console.log "expecting an error printed below:"
436 | expect(fn).to.throwError /VCAP_SERVICES is not JSON/
437 |
438 | #-----------------------------------------------------------------------------
439 | it "error - invalid port", ->
440 |
441 | process.env.PORT = ":foo:)("
442 |
443 | fn = -> appEnv = cfenv.getAppEnv()
444 | console.log "expecting an error printed below:"
445 | expect(fn).to.throwError /invalid PORT value:/
446 |
447 | #-----------------------------------------------------------------------------
448 | it "Diego - use localhost in url", ->
449 |
450 | # VCAP_APPLICATION with no uris/uri in it
451 | vcapApplication =
452 | name: SampleName
453 | host: "sample-host"
454 |
455 | process.env.VCAP_APPLICATION = JSON.stringify vcapApplication
456 |
457 | appEnv = cfenv.getAppEnv()
458 |
459 | expect(appEnv.isLocal).to.be false
460 | expect(appEnv.urls.length).to.be 1
461 | expect(appEnv.url).to.be "https://localhost"
462 |
463 | #-----------------------------------------------------------------------------
464 | it "env PORT", ->
465 | vcapApplication =
466 | name: SampleName
467 | host: "sample-host"
468 |
469 | process.env.VCAP_APPLICATION = JSON.stringify vcapApplication
470 | process.env.PORT = "4000"
471 |
472 | appEnv = cfenv.getAppEnv()
473 |
474 | expect(appEnv.port).to.be 4000
475 |
476 | #-----------------------------------------------------------------------------
477 | it "env CF_INSTANCE_PORT", ->
478 | vcapApplication =
479 | name: SampleName
480 | host: "sample-host"
481 |
482 | process.env.VCAP_APPLICATION = JSON.stringify vcapApplication
483 | process.env.CF_INSTANCE_PORT = "4001"
484 |
485 | appEnv = cfenv.getAppEnv()
486 |
487 | expect(appEnv.port).to.be 4001
488 |
489 | #-----------------------------------------------------------------------------
490 | it "env VCAP_APP_PORT", ->
491 | vcapApplication =
492 | name: SampleName
493 | host: "sample-host"
494 |
495 | process.env.VCAP_APPLICATION = JSON.stringify vcapApplication
496 | process.env.VCAP_APP_PORT = "4002"
497 |
498 | appEnv = cfenv.getAppEnv()
499 |
500 | expect(appEnv.port).to.be 4002
501 |
502 | #-------------------------------------------------------------------------------
503 | SampleVCAPServices_1 =
504 | serviceLabel_1: [
505 | {
506 | name: "serviceName_1"
507 | label: "serviceLabel_1"
508 | credentials:
509 | "credKey_1": "credVal_1"
510 | "credKey_2": "credVal_2"
511 | "credKey_3": "credVal_3"
512 | }
513 | {
514 | name: "serviceName_2"
515 | label: "serviceLabel_1"
516 | credentials:
517 | "credKey_A": "credVal_A"
518 | "credKey_B": "credVal_B"
519 | "credKey_C": "credVal_C"
520 | }
521 | ]
522 | serviceLabel_2: [
523 | {
524 | name: "serviceName_A"
525 | label: "serviceLabel_2"
526 | credentials:
527 | "credKey_4": "credVal_4"
528 | "credKey_5": "credVal_5"
529 | "credKey_6": "credVal_6"
530 | }
531 | {
532 | name: "serviceName_B"
533 | label: "serviceLabel_2"
534 | credentials:
535 | "credKey_D": "credVal_D"
536 | "credKey_E": "credVal_E"
537 | "credKey_F": "credVal_F"
538 | }
539 | ]
540 |
541 | #-------------------------------------------------------------------------------
542 | getVCAPServicesWithCreds = (name, creds) ->
543 | label = "#{name}-label"
544 | credentials = JSON.parse JSON.stringify creds
545 |
546 | services = {}
547 | services[label] = []
548 | services[label].push {name, label, credentials}
549 |
550 | return {services}
551 |
552 | #-------------------------------------------------------------------------------
553 | JS = (object) -> JSON.stringify object
554 | JL = (object) -> JSON.stringify object, null, 4
555 |
556 | #-------------------------------------------------------------------------------
557 | # Copyright IBM Corp. 2014
558 | # Copyright Patrick Mueller 2015, 2017
559 | #
560 | # Licensed under the Apache License, Version 2.0 (the "License");
561 | # you may not use this file except in compliance with the License.
562 | # You may obtain a copy of the License at
563 | #
564 | # http://www.apache.org/licenses/LICENSE-2.0
565 | #
566 | # Unless required by applicable law or agreed to in writing, software
567 | # distributed under the License is distributed on an "AS IS" BASIS,
568 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
569 | # See the License for the specific language governing permissions and
570 | # limitations under the License.
571 | #-------------------------------------------------------------------------------
572 |
--------------------------------------------------------------------------------
/tests/test-package.coffee:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License. See footer for details.
2 |
3 | expect = require "expect.js"
4 |
5 | pkg = require "../package.json"
6 |
7 | #-------------------------------------------------------------------------------
8 | describe "package", ->
9 |
10 | #-----------------------------------------------------------------------------
11 | it "name should be a string", ->
12 | expect(pkg.name).to.be.a "string"
13 |
14 | #-----------------------------------------------------------------------------
15 | it "version should be a semver", ->
16 | expect(pkg.version).to.match /^\d+\.\d+\.\d+(.*)$/
17 |
18 | #-------------------------------------------------------------------------------
19 | # Copyright IBM Corp. 2014
20 | #
21 | # Licensed under the Apache License, Version 2.0 (the "License");
22 | # you may not use this file except in compliance with the License.
23 | # You may obtain a copy of the License at
24 | #
25 | # http://www.apache.org/licenses/LICENSE-2.0
26 | #
27 | # Unless required by applicable law or agreed to in writing, software
28 | # distributed under the License is distributed on an "AS IS" BASIS,
29 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30 | # See the License for the specific language governing permissions and
31 | # limitations under the License.
32 | #-------------------------------------------------------------------------------
33 |
--------------------------------------------------------------------------------