├── .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 | --------------------------------------------------------------------------------