├── .editorconfig ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── enhancements-and-feature-request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── CHANGELOG.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── baker.js ├── config ├── BakerForMac │ ├── 9pfs.plist.mustache │ ├── bakerformac.sh │ ├── hyperkitrun.sh │ └── vendor │ │ ├── hyperkit │ │ ├── u9fs │ │ └── vpnkit.exe ├── ClusterVM.mustache ├── baker2Template.yml.mustache ├── bakerTemplate.yml ├── baker_rsa ├── baker_rsa.pub ├── common │ ├── CheckoutFromVault.yml │ ├── dockerBootstrap.yml │ ├── installDocker.yml │ └── registerhost.yml ├── dockerHost │ ├── DockerVM.mustache │ ├── dockerConfig.yml │ └── lxd-bridge └── provision.shell.sh ├── docs └── img │ └── demo.gif ├── global-vars.js ├── installers ├── PKGBUILD ├── README.md ├── build-installer.sh ├── linux │ ├── deb-template │ │ └── baker │ │ │ ├── DEBIAN │ │ │ └── control │ │ │ └── usr │ │ │ └── bin │ │ │ └── empty.txt │ └── deb │ │ └── empty.txt ├── macos │ ├── package.sh │ └── scripts │ │ └── postinstall └── win │ └── scripts │ └── baker.iss ├── lib ├── bakelets │ ├── bakelet.js │ ├── config │ │ ├── keys.js │ │ ├── template.js │ │ └── vault.js │ ├── custom.js │ ├── env │ │ └── env.js │ ├── lang │ │ ├── R.js │ │ ├── java.js │ │ ├── nodejs.js │ │ └── python.js │ ├── packages │ │ └── apt.js │ ├── resolve.js │ ├── resources │ │ └── git.js │ ├── services │ │ ├── docker.js │ │ ├── jenkins.js │ │ ├── mongodb.js │ │ ├── mysql.js │ │ └── neo4j.js │ ├── start.js │ └── tools │ │ ├── ansible.js │ │ ├── dazed.js │ │ ├── defects4j.js │ │ ├── jekyll.js │ │ ├── jenkins-job-builder.js │ │ ├── jupyter.js │ │ ├── latex.js │ │ └── maven.js ├── commands │ ├── bake.js │ ├── boxes.js │ ├── cluster.js │ ├── command.example.js │ ├── destroy.js │ ├── docker.js │ ├── halt.js │ ├── import.js │ ├── info.js │ ├── init.js │ ├── package.js │ ├── run.js │ ├── server.js │ ├── setup.js │ ├── setupmac.js │ ├── ssh.js │ ├── status.js │ ├── up.js │ └── vault.js └── modules │ ├── baker.js │ ├── clusters │ └── cluster.js │ ├── configstore.js │ ├── configuration │ └── ansible.js │ ├── init │ └── interactive.js │ ├── print.js │ ├── providers │ ├── digitalocean.js │ ├── docker.js │ ├── provider.js │ ├── remote.js │ ├── runc.js │ ├── vagrant.js │ └── virtualbox.js │ ├── servers.js │ ├── spinner.js │ ├── ssh.js │ ├── utils │ ├── git.js │ └── utils.js │ ├── validator.js │ └── vault.js ├── package-lock.json ├── package.json ├── remotes └── bakelets-source │ ├── README.md │ ├── config │ └── keys.yml │ ├── env │ └── env.yml.mustache │ ├── lang │ ├── R │ │ └── r.yml.mustache │ ├── java │ │ └── java8.yml │ ├── nodejs │ │ ├── nodejs13.yml │ │ └── nodejs9.yml │ └── python │ │ ├── python2.yml │ │ ├── python3.6.yml │ │ └── python3.yml │ ├── packages │ └── apt.yml.mustache │ ├── services │ ├── docker │ │ └── docker.yml │ ├── lxd │ │ └── lxd.yml │ ├── mongodb │ │ └── mongodb3.6.yml │ ├── mysql │ │ ├── mysql5.7.yml │ │ └── mysql8.yml │ └── neo4j │ │ └── neo4j.yml │ └── tools │ ├── ansible │ └── ansible.yml │ ├── dazed │ └── dazed.yml │ ├── defects4j │ └── defects4j.yml │ ├── jekyll │ └── jekyll.yml │ ├── jupyter │ └── jupyter.yml │ └── latex │ └── latex.yml └── test ├── bake └── test-326.js ├── integration ├── bake-326-onboard.js ├── baker-test-repo.js ├── test-neo4j.js ├── test-python-nb.js ├── test-r-tidy.js └── test-runc.js ├── mustache.js └── resources ├── baker-test ├── README.md ├── baker.yml └── deployment │ ├── express │ ├── index.js │ └── package.json │ ├── node.yml │ └── python.yml ├── baker.yml ├── baker2 ├── jenkins.yml ├── neo4j.yml ├── python-notebook.yml └── r-tidy.yml ├── cluster └── plain.yml ├── container └── baker.yml ├── docker-host └── baker.yml └── prompt.yml /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | # Use 4 spaces for the Python files 13 | [*.py] 14 | indent_size = 4 15 | max_line_length = 80 16 | 17 | # The JSON files contain newlines inconsistently 18 | [*.json] 19 | insert_final_newline = ignore 20 | 21 | # Minified JavaScript files shouldn't be changed 22 | [**.min.js] 23 | indent_style = ignore 24 | insert_final_newline = ignore 25 | 26 | # Makefiles always use tabs for indentation 27 | [Makefile] 28 | indent_style = tab 29 | 30 | # Batch files use tabs for indentation 31 | [*.bat] 32 | indent_style = tab 33 | 34 | [*.md] 35 | trim_trailing_whitespace = false 36 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at us@ottomatica.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute to Baker 🍞 2 | 3 | ## Reporting bugs 4 | 5 | If you're not able to find an open issue about the same bug, open a new one. Be sure to include a clear title, complete the issue template with as much detail as possible. 6 | 7 | ## Suggesting enhancements 8 | 9 | You can use GitHub issue tracker to submit an enhancement suggestions for Baker. This can include completely new features, or minor improvement to current functionality. 10 | 11 | ## Contributing to source code 12 | 13 | If you want to contribute to Baker source code but you are not sure where to start, see #enhancement and #bug issues that you might be able to address. If you have an idea for enhancement, before you start implementing the enhancement, make sure to open an issue and discuss about the idea with organizers. This will help make sure the enhancement that you want to work on is a right addition in accordance with goals of this project. 14 | 15 | ### Commit messages 16 | 17 | We use [conventional commit message format](https://www.conventionalcommits.org/en/v1.0.0-beta.2/) to be able to auto-generate our changelog. Conventional commit message format is `[optional scope]: `. The type can be `fix | feat | BREAKING CHANGE | chore | docs | style | refactor | build` and the _optional_ scope can be `bakelet | module` or anything else that would make sense. A simple example for updating a dependency is `build(deps): Bump X from 1.2.0 to 1.3.0`. 18 | 19 | You can also use multiple types, for example if adding a `feat` that is also a `BREAKING CHANGE`, your commit message can be: 20 | 21 | ``` 22 | feat: allow provided config object to extend other configs 23 | 24 | BREAKING CHANGE: `extends` key in config file is now used for extending other config files 25 | 26 | fixes #12 27 | ``` 28 | 29 | To help with writing these longer commit messages and for consistency, we have a dev-dependency ([commitizen](https://github.com/commitizen/cz-cli)). If you choose to use commitizen for writing your commit messages, simply run `npm run commit` and it will ask you to fill in some information and then commits your changes for you! 30 | 31 | ### Pull Request 32 | 33 | Implemented a feature enhacement or fixed a bug? Open a PR and make sure to complete the PR template with as much details as possible. One of the organizers will review your proposed changes and respond to your PR. 34 | 35 | > **Note:** By contributing you agree that your contributions are your own work and approved by your employer. You grant complete irrevocable copyright permission to users and developers of this project in the present and future, in accordance with the license. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Use the baker.yml below... 13 | 2. Run `baker bake` 14 | ... 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots** 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Please complete the following information:** 23 | - OS: [e.g. Windows, MacOS, Linux] 24 | - Version [e.g. 0.6.12] 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enhancements-and-feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Enhancements and Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Fixes # . 2 | 3 | Changes proposed in this pull request: 4 | - 5 | - 6 | - 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | node_modules/ 3 | builds/ 4 | installers/macos/bin/* 5 | installers/win/bin/* 6 | installers/linux/deb/baker.deb 7 | installers/linux/executable/baker 8 | installers/linux/deb-template/baker/usr/bin/baker 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [0.7.2](https://github.com/ottomatica/Baker/compare/v0.7.1...v0.7.2) (2019-08-26) 6 | 7 | 8 | ### Build System 9 | 10 | * **deps:** [Security] Bump lodash.template from 4.4.0 to 4.5.0 ([#160](https://github.com/ottomatica/Baker/issues/160)) ([d0c7c29](https://github.com/ottomatica/Baker/commit/d0c7c29)) 11 | * **deps:** Bump inquirer to 7.0.0 ([#178](https://github.com/ottomatica/Baker/issues/178)) ([4b8cd20](https://github.com/ottomatica/Baker/commit/4b8cd20)) 12 | * **deps:** Bump mustache from 3.0.1 to 3.0.2 ([#177](https://github.com/ottomatica/Baker/issues/177)) ([c37bce7](https://github.com/ottomatica/Baker/commit/c37bce7)) 13 | * **deps:** Bump node-vagrant from 1.3.9 to 1.3.10 ([#176](https://github.com/ottomatica/Baker/issues/176)) ([12e1212](https://github.com/ottomatica/Baker/commit/12e1212)) 14 | * **deps:** Bump simple-git to 1.124.0 ([#172](https://github.com/ottomatica/Baker/issues/172)) ([be21037](https://github.com/ottomatica/Baker/commit/be21037)) 15 | * **deps:** Bump ssh2 from 0.8.4 to 0.8.5 ([#162](https://github.com/ottomatica/Baker/issues/162)) ([40b6c9a](https://github.com/ottomatica/Baker/commit/40b6c9a)) 16 | * **deps:** Bump validator from 11.0.0 to 11.1.0 ([#157](https://github.com/ottomatica/Baker/issues/157)) ([478e779](https://github.com/ottomatica/Baker/commit/478e779)) 17 | * **deps:** Bump yargs to 14.0.0 ([#175](https://github.com/ottomatica/Baker/issues/175)) ([b12ae79](https://github.com/ottomatica/Baker/commit/b12ae79)) 18 | * **deps-dev:** Bump commitizen to 4.0.3 ([#170](https://github.com/ottomatica/Baker/issues/170)) ([cac2acd](https://github.com/ottomatica/Baker/commit/cac2acd)) 19 | * **deps-dev:** Bump cz-conventional-changelog to 3.0.2 ([#169](https://github.com/ottomatica/Baker/issues/169)) ([12e90c5](https://github.com/ottomatica/Baker/commit/12e90c5)) 20 | * **deps-dev:** Bump innosetup-compiler from 5.5.62 to 5.6.1 ([#171](https://github.com/ottomatica/Baker/issues/171)) ([b22da56](https://github.com/ottomatica/Baker/commit/b22da56)) 21 | * **deps-dev:** Bump mocha from 6.1.4 to 6.2.0 ([#167](https://github.com/ottomatica/Baker/issues/167)) ([2c596ff](https://github.com/ottomatica/Baker/commit/2c596ff)) 22 | * **deps-dev:** Bump standard-version from 6.0.1 to 7.0.0 ([#173](https://github.com/ottomatica/Baker/issues/173)) ([8f81226](https://github.com/ottomatica/Baker/commit/8f81226)) 23 | 24 | 25 | 26 | ### [0.7.1](https://github.com/ottomatica/Baker/compare/v0.7.0...v0.7.1) (2019-07-02) 27 | 28 | 29 | ### Bug Fixes 30 | 31 | * **build:** fixing .deb script (rm vagrant dependency) ([0570993](https://github.com/ottomatica/Baker/commit/0570993)) 32 | 33 | 34 | ### Build System 35 | 36 | * **deps:** Bump bluebird from 3.5.4 to 3.5.5 ([#146](https://github.com/ottomatica/Baker/issues/146)) ([558b3ea](https://github.com/ottomatica/Baker/commit/558b3ea)) 37 | * **deps:** Bump configstore from 4.0.0 to 5.0.0 ([#148](https://github.com/ottomatica/Baker/issues/148)) ([c4e9c09](https://github.com/ottomatica/Baker/commit/c4e9c09)) 38 | * **deps:** Bump fs-extra to 8.1.0 ([#154](https://github.com/ottomatica/Baker/issues/154)) ([9cb5f12](https://github.com/ottomatica/Baker/commit/9cb5f12)) 39 | * **deps:** Bump inquirer to 6.4.1 ([#153](https://github.com/ottomatica/Baker/issues/153)) ([d2408b4](https://github.com/ottomatica/Baker/commit/d2408b4)) 40 | * **deps:** Bump node-virtualbox to 0.2.3 ([#152](https://github.com/ottomatica/Baker/issues/152)) ([c7de810](https://github.com/ottomatica/Baker/commit/c7de810)) 41 | * **deps:** Bump simple-git to 1.117.0 ([#155](https://github.com/ottomatica/Baker/issues/155)) ([ee83b49](https://github.com/ottomatica/Baker/commit/ee83b49)) 42 | * **deps:** Bump validator from 10.11.0 to 11.0.0 ([#145](https://github.com/ottomatica/Baker/issues/145)) ([770486b](https://github.com/ottomatica/Baker/commit/770486b)) 43 | * **deps:** Bump yargs from 13.2.2 to 13.2.4 ([#141](https://github.com/ottomatica/Baker/issues/141)) ([d58cbb6](https://github.com/ottomatica/Baker/commit/d58cbb6)) 44 | * **deps-dev:** Bump pkg from 4.3.8 to 4.4.0 ([#142](https://github.com/ottomatica/Baker/issues/142)) ([d358eee](https://github.com/ottomatica/Baker/commit/d358eee)) 45 | * **deps-dev:** Bump standard-version from 5.0.2 to 6.0.1 ([#138](https://github.com/ottomatica/Baker/issues/138)) ([145b964](https://github.com/ottomatica/Baker/commit/145b964)) 46 | 47 | 48 | 49 | ## [0.7.0](https://github.com/ottomatica/Baker/compare/v0.6.15...v0.7.0) (2019-05-05) 50 | 51 | 52 | ### Bug Fixes 53 | 54 | * Upgrade node-virtualbox to add VirtBox 6 support ([ottomatica/node-virtualbox#27](https://github.com/ottomatica/node-virtualbox/pull/27)) ([faeb715](https://github.com/ottomatica/node-virtualbox/commit/faeb715f7a59b831511bedacb329f5c86d818d00)), closes [#119](https://github.com/ottomatica/Baker/issues/119) 55 | * Fixed invalid imports ([#91](https://github.com/ottomatica/Baker/issues/91)) ([ebda70c](https://github.com/ottomatica/Baker/commit/ebda70c)), closes [#90](https://github.com/ottomatica/Baker/issues/90) 56 | * Update node-virtualbox to enable symlinks in shared folder ([85fa44b](https://github.com/ottomatica/Baker/commit/85fa44b)) 57 | * Update validator logic to not need drivelist dependency ([8af6f89](https://github.com/ottomatica/Baker/commit/8af6f89)) 58 | 59 | 60 | ### Features 61 | 62 | * Better error message + suggestion for invalid Bakelet names ([145ece9](https://github.com/ottomatica/Baker/commit/145ece9)), closes [#101](https://github.com/ottomatica/Baker/issues/101) 63 | * Arch Linux PKGBUILD ([#120](https://github.com/ottomatica/Baker/pull/120)) ([59f5e81](https://github.com/ottomatica/Baker/commit/59f5e81)), closes [#115](https://github.com/ottomatica/Baker/issues/115) 64 | 65 | 66 | 67 | ## 0.6.15 (2018-11-26) 68 | 69 | ### Features 70 | 71 | * Add python3.6 Bakelet ([2e52f01](https://github.com/ottomatica/Baker/commit/2e52f01)) 72 | 73 | 74 | ## 0.6.14 (2018-11-25) 75 | 76 | ### Bug Fixes 77 | 78 | * **bakelets:** Fix R Bakelet to work when no packages are provided ([b07c20e](https://github.com/ottomatica/Baker/commit/b07c20e)), closes [#69](https://github.com/ottomatica/Baker/issues/69) 79 | * **providers:** Virtualbox stop command now stops instead of save state ([edde1a6](https://github.com/ottomatica/Baker/commit/edde1a6)) 80 | 81 | ### Features 82 | 83 | * Introducing _Vault_ ([235f144](https://github.com/ottomatica/Baker/commit/235f144)) 84 | * Add python3.6 Bakelet ([2e52f01](https://github.com/ottomatica/Baker/commit/2e52f01)) 85 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | let child_process = require('child_process'); 2 | let platform = process.platform; 3 | 4 | module.exports = function (grunt) { 5 | if(platform === 'win32'){ 6 | // Building installer for windows (inno setup) 7 | child_process.execSync('npm run build-win') 8 | grunt.loadNpmTasks('innosetup-compiler'); 9 | grunt.initConfig({ 10 | innosetup_compiler: { 11 | your_target: { 12 | options: { 13 | gui: false, 14 | verbose: false, 15 | O: './installers/win/bin/' 16 | // signtoolname: 'signtool', 17 | // signtoolcommand: '"path/to/signtool.exe" sign /f "C:\\absolute\\path\\to\\mycertificate.pfx" /t http://timestamp.globalsign.com/scripts/timstamp.dll /p "MY_PASSWORD" $f' 18 | }, 19 | script: './installers/win/scripts/baker.iss' 20 | } 21 | } 22 | }); 23 | grunt.registerTask("default", ["innosetup_compiler"]); 24 | } else if(platform === 'darwin'){ 25 | // Building installer for Mac (pkgbuild) 26 | grunt.registerTask('default', function() { 27 | child_process.execSync('npm run build-macos && bash ./installers/macos/package.sh'); 28 | }); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Baker 🍞 | [![dependencies Status](https://david-dm.org/ottomatica/Baker/status.svg)](https://david-dm.org/ottomatica/Baker) 2 | 3 | Meet Baker! -- a simple tool for provisioning virtual machines and containers. With Baker you can quickly create development environments and run your code. With one tool, you have the functionality of vagrant, docker, ansible, and task runners like grunt. 4 | 5 | See a running demo below: 6 |

7 | 8 |

9 | 10 | For more details, checkout [docs.getbaker.io](https://docs.getbaker.io/) and join our [Slack](https://getbaker.io/slack). 11 | 12 | ## Install from source 13 | 14 | ``` bash 15 | git clone https://github.com/ottomatica/Baker 16 | cd Baker 17 | npm install 18 | npm link 19 | ``` 20 | 21 | Also see other [binary installation options](https://docs.getbaker.io/installation/). 22 | ## Using Baker 23 | 24 | Baker uses a configuration file (baker.yml) in the root directory of you project. This is an example of a baker.yml file. By running `baker bake` Baker provisions a VM with nodejs installed, and the specified ip address and port forwarding rules configured for you. You can access the VM by running `baker ssh` or run commands inside the VM with `baker run `. Your code is accessible in the VM via a shared folder. 25 | 26 | ``` yaml 27 | --- 28 | name: baker-test 29 | vm: 30 | ip: 192.168.22.22 31 | ports: 8000 32 | lang: 33 | - nodejs9 34 | commands: 35 | serve: cd /baker-test/deployment/express && npm install && node index.js 36 | ``` 37 | 38 | You can also point to a git repository with a baker.yml file, and and Baker will do the rest: 39 | 40 | ``` 41 | $ baker bake --repo https://github.com/ottomatica/baker-test.git 42 | ``` 43 | 44 | Baker also supports creating environments inside containers that do not require a VM. 45 | 46 | ``` yaml 47 | name: baker-docs 48 | container: 49 | ports: 8000 50 | lang: 51 | - python2 52 | commands: 53 | build: mkdocs build 54 | serve: mkdocs serve -a 0.0.0.0:8000 55 | gh-deploy: mkdocs gh-deploy 56 | ``` 57 | 58 | Setting up a Java environment with MySQL can be done easily. 59 | ``` yaml 60 | name: onboard 61 | vm: 62 | ip: 192.168.8.8 63 | ports: 8080 64 | vars: 65 | - mysql_password: 66 | prompt: Type your password for mysql server 67 | tools: 68 | - maven 69 | services: 70 | - mysql: 71 | version: 8 72 | service_conf: env/templates/mysql.cfg 73 | client_conf: env/templates/my.cnf 74 | lang: 75 | - java8 76 | config: 77 | - template: 78 | src: env/templates/hibernate-template.cfg.xml 79 | dest: /Onboarding/CoffeeMaker/src/main/resources/hibernate.cfg.xml 80 | commands: 81 | serve: cd CoffeeMaker && mvn spring-boot:run 82 | debug: cd CoffeeMaker && mvnDebug spring-boot:run 83 | test: cd CoffeeMaker && mvn test 84 | ``` 85 | -------------------------------------------------------------------------------- /baker.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const yargs = require('yargs'); 3 | require('console.table'); 4 | const { homepage, version } = require('./package.json'); 5 | 6 | yargs 7 | .commandDir('./lib/commands') 8 | .version() 9 | .epilog( 10 | (homepage ? `| Homepage: ${homepage}\n` : '') + 11 | (`| Documentation: https://docs.getbaker.io/\n`) + 12 | (version ? `| Version: ${version}` : '') 13 | ) 14 | .demandCommand(1, 'Did you forget to specify a command?') 15 | .recommendCommands() 16 | .showHelpOnFail(false, 'Specify --help for available options') 17 | .strict(true) 18 | .help() 19 | .wrap(yargs.terminalWidth()) 20 | .argv 21 | -------------------------------------------------------------------------------- /config/BakerForMac/9pfs.plist.mustache: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | com.baker.u9fs 7 | Program 8 | {{{exe}}} 9 | ProgramArguments 10 | 11 | {{{exe}}} 12 | -l 13 | /tmp/u9fs.log 14 | -a 15 | none 16 | -u 17 | {{{username}}} 18 | -D 19 | 20 | Sockets 21 | 22 | Listeners 23 | 24 | SockPathMode 25 | 438 26 | SockPathName 27 | /Users/{{{username}}}/Library/Baker/sockets/bakershare.socket 28 | 29 | 30 | inetdCompatibility 31 | 32 | Wait 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /config/BakerForMac/bakerformac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir -p ~/Library/Baker/run 4 | 5 | SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )" 6 | pid=`cat ~/Library/Baker/run/bakerformac-vpnkit.pid` 7 | 8 | if ! `launchctl list | grep "com.baker.u9fs." > /dev/null`; then 9 | echo "Starting u9fs" 10 | launchctl load $SCRIPTPATH/9pfs.plist 11 | fi 12 | 13 | SOCKETDIR=/Users/$USER/Library/Baker/sockets 14 | mkdir -p $SOCKETDIR 15 | #mkfifo /tmp/vsocket 16 | 17 | ps -a | grep $pid | grep vpnkit.exe 18 | vpnkitRunning=$? 19 | if test $vpnkitRunning -ne 0; then 20 | echo "Starting vpnkit" 21 | $SCRIPTPATH/vendor/vpnkit.exe --host-names baker.for.mac.localhost --debug --ethernet $SOCKETDIR/bakerformac.sock --port $SOCKETDIR/bakerformac.port.socket --vsock-path $SOCKETDIR/connect >~/Library/Baker/run/bakerformac-vpnkit.log 2>&1 & 22 | echo $! > ~/Library/Baker/run/bakerformac-vpnkit.pid 23 | fi 24 | 25 | DISKDIR=/Users/$USER/Library/Baker/disks 26 | mkdir -p $DISKDIR 27 | if [ ! -f $DISKDIR/bakerdisk.img ]; then 28 | dd if=/dev/zero of=$DISKDIR/bakerdisk.img bs=1 count=1 seek=34359738368 29 | fi 30 | 31 | # com.docker.vpnkit --ethernet fd:3 --port fd:4 --introspection fd:5 --diagnostics fd:6 --vsock-path /Users/andrew/Library/Containers/com.docker.docker/Data/connect --host-names docker.for.mac.localhost,docker.for.mac.host.internal --gateway-names docker.for.mac.gateway.internal,docker.for.mac.http.internal --listen-backlog 32 --mtu 1500 --allowed-bind-addresses 0.0.0.0 --http /Users/andrew/Library/Group Containers/group.com.docker/http_proxy.json --dhcp /Users/andrew/Library/Group Containers/group.com.docker/dhcp.json --port-max-idle-time 300 --max-connections 2000 --gateway-ip 192.168.65.1 --host-ip 192.168.65.2 --lowest-ip 192.168.65.3 --highest-ip 192.168.65.254 --log-destination asl 32 | 33 | 34 | USEVPNKIT=true SCRIPTPATH=$SCRIPTPATH $SCRIPTPATH/hyperkitrun.sh 35 | -------------------------------------------------------------------------------- /config/BakerForMac/hyperkitrun.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | HYPERKIT="hyperkit" 4 | 5 | # Linux 6 | INITRD=$SCRIPTPATH/file.img.gz 7 | #KERNEL="kernel/vmlinuz-virt" 8 | #KERNEL="kernel/vmlinuz-vanilla" 9 | KERNEL=$SCRIPTPATH/kernel 10 | 11 | SOCKETDIR=/Users/$USER/Library/Baker/sockets 12 | DISKDIR=/Users/$USER/Library/Baker/disks 13 | 14 | CMDLINE="modules=virtio_net console=tty0 console=ttyS0 console=ttyAMA0" 15 | 16 | MEM="-m 1G" 17 | #SMP="-c 2" 18 | NET="-s 1:0,virtio-net" 19 | if $USEVPNKIT; then 20 | echo "using vpnkit for network" 21 | NET="-s 1:0,virtio-vpnkit,path=$SOCKETDIR/bakerformac.sock" 22 | fi 23 | 24 | #IMG_CD="-s 3,ahci-cd,/somepath/somefile.iso" 25 | IMG_HDD="-s 4,virtio-blk,$DISKDIR/bakerdisk.img" 26 | PORT="-s 5,virtio-9p,path=$SOCKETDIR/bakerformac.port.socket,tag=port" 27 | SHARE="-s 6,virtio-9p,path=$SOCKETDIR/bakershare.socket,tag=share" 28 | PCI_DEV="-s 0:0,hostbridge -s 31,lpc" 29 | LPC_DEV="-l com1,stdio" 30 | ACPI="-A" 31 | #UUID="-U deadbeef-dead-dead-dead-deaddeafbeef" 32 | 33 | FORWARD="-s 7,virtio-sock,guest_cid=3,path=$SOCKETDIR,guest_forwards=2000" 34 | RND="-s 2,virtio-rnd" 35 | 36 | $SCRIPTPATH/vendor/hyperkit $ACPI $MEM $SMP $PCI_DEV $LPC_DEV $RND $NET $PORT $SHARE $FORWARD $IMG_CD $IMG_HDD $UUID -f kexec,$KERNEL,$INITRD,"$CMDLINE" 37 | -------------------------------------------------------------------------------- /config/BakerForMac/vendor/hyperkit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ottomatica/Baker/3dfe55d6ef58e68a9c89529bc7a5e0d2b0fe4707/config/BakerForMac/vendor/hyperkit -------------------------------------------------------------------------------- /config/BakerForMac/vendor/u9fs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ottomatica/Baker/3dfe55d6ef58e68a9c89529bc7a5e0d2b0fe4707/config/BakerForMac/vendor/u9fs -------------------------------------------------------------------------------- /config/BakerForMac/vendor/vpnkit.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ottomatica/Baker/3dfe55d6ef58e68a9c89529bc7a5e0d2b0fe4707/config/BakerForMac/vendor/vpnkit.exe -------------------------------------------------------------------------------- /config/ClusterVM.mustache: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure('2') do |config| 5 | 6 | config.vm.box = 'ubuntu/xenial64' 7 | # Install python 2 if not installed. 8 | config.vm.provision "shell", 9 | inline: "test -e /usr/bin/python || (sudo apt -y update && sudo apt install -y python-minimal)" 10 | #config.vm.provision "file", source: "~/.baker/ansible-srv/keys/baker_rsa.pub", destination: "~/.ssh/authorized_keys" 11 | 12 | config.vm.provider :virtualbox do |vb| 13 | vb.customize [ 'modifyvm', :id, '--natdnshostresolver1', 'on' ] 14 | vb.customize ["modifyvm", :id, "--cpus", 1] 15 | 16 | end 17 | 18 | {{#cluster.nodes}} 19 | 20 | config.vm.define :{{name}} do |machine| 21 | machine.vm.network 'private_network', ip: '{{ip}}' 22 | machine.vm.provider :virtualbox do |vb| 23 | vb.customize ["modifyvm", :id, "--memory",{{memory}}] 24 | vb.customize ["modifyvm", :id, "--cpus", {{cpus}}] 25 | end 26 | end 27 | 28 | {{/cluster.nodes}} 29 | 30 | end 31 | -------------------------------------------------------------------------------- /config/baker2Template.yml.mustache: -------------------------------------------------------------------------------- 1 | # baker.yml Auto generated using `baker init` command 2 | --- 3 | name: {{name}} 4 | vm: 5 | memory: {{memory}} 6 | ip: {{ip}} 7 | {{#ports}} 8 | ports: {{ports}} 9 | {{/ports}} 10 | 11 | {{#langs}} 12 | lang: 13 | {{#lang}} 14 | - {{.}} 15 | {{/lang}} 16 | {{/langs}} 17 | 18 | {{#services}} 19 | services: 20 | {{#service}} 21 | - {{.}} 22 | {{/service}} 23 | {{/services}} 24 | 25 | {{#tools}} 26 | tools: 27 | {{#tool}} 28 | - {{.}} 29 | {{/tool}} 30 | {{/tools}} 31 | -------------------------------------------------------------------------------- /config/bakerTemplate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # All virtual machine configuration is done in "vagrant:" parameter and 3 | # All the provisioning steps are done in "baker:" 4 | 5 | # Common configuration options are shown in this template, 6 | # This has probably all you will need, but if you want to 7 | # lean more about available `baker.yml` configurations, please visit: 8 | # https://docs.getbaker.io/ 9 | 10 | # Set a name for your environment which will be used in virtualbox and vagrant. 11 | name: baker-demo 12 | 13 | ######################################################## 14 | # 15 | # Creating the virtual machine 16 | # 17 | ######################################################## 18 | 19 | # Define virtual machine configurations here 20 | vagrant: 21 | # Creation of vagrant environment needs a box. 22 | # You can find list of all available boxes at 23 | # https://atlas.hashicorp.com/search. 24 | box: "ubuntu/trusty64" 25 | 26 | # Configure the amount of your host machine's memory that you want to 27 | # share with the virtual machin (* required) 28 | memory: "512" 29 | 30 | network: 31 | # # You can create a forwarded port mapping(s) which vagrant will set 32 | # - forwarded_port: 33 | # guest: 80 34 | # host: 8080 35 | # 36 | # # *Note* You can also prompt user to ask for values at runtime. For example: 37 | # # host: 38 | # # prompt: "Forward VM port to what port on your host machine?" 39 | # 40 | # Create a private network for your virtual machine and set the local IP for your VM 41 | # A private network with a static IP is required by Baker server to be able to communicate with your VM. 42 | # (* required) 43 | - private_network: 44 | ip: "192.168.33.10" 45 | 46 | # # Share your host machines folder with your VM. 47 | # # By default Baker will sync the directory of baker.yml with the VM it creates. 48 | # # You can configure more sync folders like this: 49 | # synced_folders: 50 | # - folder: 51 | # src: "~/projects" 52 | # dest: "/projects" 53 | # 54 | # # *Note* You can also prompt user to ask for values at runtime. For example: 55 | # # src: 56 | # # prompt: "What host folder to sync for projects?" 57 | 58 | ######################################################## 59 | # 60 | # Provisioning the virtual machine 61 | # 62 | ######################################################## 63 | 64 | # # Define provisioning steps here 65 | # bake: 66 | # # The ansible playbooks that you want to run for the VM 67 | # ansible: 68 | # # source is the directory of the ansible playbooks 69 | # source: src/env/ 70 | # playbooks: 71 | # - provision.yml 72 | 73 | # # The ansible vault configurations 74 | # vault: 75 | # source: src/env/vault.yml 76 | # checkout: 77 | # key: ottomatica-key 78 | # dest: ~/.ssh/alt-code_rsa 79 | -------------------------------------------------------------------------------- /config/baker_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKAIBAAKCAgEAqPmEYSNho56PuTQ/jf6Qb78Owb44ujhLWYFCryX/D/az3FAk 3 | fMOw6Qz06S0jOLKQaiMKBDNQkEZx/Mf1H74a+dbVP++AOCdjIARIwpSPDOWfIqmI 4 | Q1n6EcsKP9rgda6zxyAiDO9ei0RRiA6Kp7fpXh1OMHHx5hzWvPyqgubTcXff1QcX 5 | r3odAiLu/wWt/1FbZ+gk2NrBjKNJiZNCI8yLCuNk4ES+2Tk0H26NU3dw6TgnbdNs 6 | X7ecVwpPSrkcMK43bcmWz/J/MXO/2HEZNKbMBVYjXxGlORG+Nvg069DoQoGnRg/b 7 | n8SW0oeLctlZkcnEAX49NFakDtszzS9ru+hH5DBCP07KVWp7DAoXkbbdwuUCUAr9 8 | IF57Q0rp84CDr24EoXOuOHiK5lf5IdKC2JFvhYvNM6sf3SHSjHOzqVyv7piW9fGq 9 | NiAbQaE4ja+XJWtV3qw8GVyRKerDyZUo2vcTW9MsNDwH8TIirEf348pmeRO3T2mI 10 | 0t2/iyMsY8S/hkq/GUS/t2h+5WLHQGkMHpHrMWjGVEnyg8EVpOVLxPNYKQllpIHE 11 | 3KsQhrogQnb4gVPPMl3w7haHYnYGEyd/STPb94Crr5SQLUWgW10iemE42p36M5Zq 12 | WjWCJh1D3qKGNtL5aJZl87NpZWSPoDOvBmaZ5pd3p/NCyWJ4p9upIoFjPVkCAwEA 13 | AQKCAgBRyAn5Fa3BChIXmiEUcVuoqfjTbmR4RJy7YiNLMAGl0Uo13Bf8xp3N/bZf 14 | ULhWTZ41sGW9qLRaT64FoSWTSmg1+XNWsW0GQJHqQgiRHGOr40rE9PZ9WoP8rp90 15 | TlQKwRZDztqMFiJVFyi6yAb1q75oDZj1O4DPVa/c4hEIr/0wUstjiD4/cMOvcAbq 16 | KO6QvuiVfrauuhmpHrKNwlbliq7VAz+kh8Ey00vV1qTR++ILDmGO9x/hp7UkL1o3 17 | GSZ6rSconMPAO2ayIYp9kCeZ4wylnI4cCidEWsEMS88ZPw/aeHPkJfKu/e/dTzr/ 18 | yBBgzh1ud5HZzgEzK4aDzWrAFGkOT6Oa3OuqCPmYGZZ/Z8H/lSvRxcnVG9UyjFpe 19 | yjXhnBfsJzhjFLqyIQfoSO31sbNJkmxQ1XmMEOdYwqmK8nhCSJM5WiUDZQ/X6hpc 20 | ophsS4iGExqqB5/LpodZunDdrxJbljD86iJUp34xCs1LPHqcaB3QmUEppIfYrMUk 21 | crUm6OhUy/u5IcKcpeGGATd26XIi9ljs1GwgSjNd1ejO42HLQBXq569bfhhwDfEf 22 | rVoCM9h6jMeiZQXNsOgf4f7d7T8aPHaOSipJVzoEVyM21K/CDIUtdX8SENeDZaEc 23 | Ob7cKlVDuuZkfk1v/KVDhEGVYBpOYPAiHnedSiYoL6J/9RKTvQKCAQEA1YvF0aho 24 | //O55rk5uGOwdcZ9FM+QNoJNCILGDHWlo/AQdNwd1eWLH0Yap4uYn/WJT50VwcL0 25 | efDyToLDX7GLAZtc/6eUJ7glhQ0u0dUBcIlH6Z8KBZ8BVJIR7i3V2c9FBh0jmLF1 26 | BvO5ulcGizv3r8+vcVqVU5YF33vaWlcV4iP1GeH1QzAru5wLyKtLr8SrZZ9JL5xR 27 | 5xxmNvvxyUmL7tVCoclyMR9X0qluwGriSOziBCL4mUuhvK5UElgmvFFa2kSP/gEx 28 | +D+DyY8FZ3p8NtdZWYAEs+6HXekxTfD6EhbkfB3AWYeu/N3ETRTX64tS+twYSGQT 29 | EPQZNEt34qOKIwKCAQEAypFUD1cWMaHGzRgaXODqmGZj6uwb8kQ2MUDKlJloUt6H 30 | p/9779RYmcR1Yo5W7H0lmcVH12kE0co7Sco7YtSPR1wLgicyjR+Sq+zxyetwqVEu 31 | LDsmraL3BVaTMqRnAaWpHQlbp+NIeeZcnuW3b8EBAEKPy3xujGsHuZ9miumf45qq 32 | 4DbsqMB296yhiXQB1yhWDSEHdcnBfHN8aawDEkp6cssdOB85lmBZpwqAuXxH0l/W 33 | Qrhohq7MH1X7CDefwh23Pz4b9V7XxzirNaq7zFs6ceSNuHv11bHV5QRR5YsPh+KG 34 | CdEDzMuao/1/df0TsiztYdC3K2aYaOEejyGv4sH8UwKCAQBJ8jqwHScu6pEHSkCo 35 | jyy9u9v4Zt/DYF+YgOBf1CVlnW21abuTJAeG7tmwBvD1AytnPDgafo314++kLDfH 36 | XU2LYudTSA5Pqr6jUitSUfZLp94VEhOAWs01Ide/qHOTFukJ8vEuoNSrcZ5w3k3P 37 | zRY59SsFj56B8UNbXiIAgoN7aYQoUEyD1ZxvPNv/wwFUfj/z0rKfH/xkkTr780aI 38 | s0UXkRWfvIgkZnwc4LsPOnPdWNnzIMEBJGV/VsaaC5huQaW6S1+pT3SkSCo0k6gF 39 | ay60NuIj0ebO/9w0Mtn16WpO9UptiEfhONDpk0m0f3E9iWNUpv5pou3PQxevOirr 40 | ekINAoIBACfC3v0j2vdjCeK4GHSisWm4r2QtdE7ZlMmWLi187z1U8MvJGkq5I6sL 41 | JP9zcRx6dCb60l81/fwv9fNF/uInVvhq2NdzWjjZObEFkXBRBow1oxqLgcwTcOlb 42 | VQlbu9xW6BsK+zK5KkDDNur5rEgDWm7yoccPZaOqXpnQ8A/US84hTek03r9BCBkV 43 | iZ+xZasV/84T7aLxN0l2YbVcTj4I4IAn3lRlzKf3waFILnw6KN7icOwnxlypcuez 44 | uNKkGHfB3XZMerBvLWutc+3U1YgHYDF661aK/nYzsgiCEJE9+o5xqF3E6ToJvRDz 45 | cVF3m6Ydq3rHvSyHtuLfTWBK/HtGGIECggEBAMXM4KSngNKpTCApjFpvEI3TvJtp 46 | 8A2Mvhj/M0pXkBIDxcBFqF/0cYXnGpPc/AgPekh/vEyOOGOSh3dplswXie231Bod 47 | 6h8d2I8Pn7dTl/Po1jSMpwXDQu2PlrTr9+zcRZfGgJc4f6nU4PeD5CdUyBCtvJsG 48 | DrnJ2NVUhgRXkCwn8Whe+le9GUKo3athetUZ7lKrbxz0bs2KHniUURpWltfmG+EM 49 | g08w319Gyq9XEdfcdyoxUDCoiyhyV1AYx+tHiMYidkadnKJVXHUC2YapTKtEfK1o 50 | cJmno7sstGUNY0o6+sPve4CIECE4NSMCQdE/K1JPAvF+yZwHlVUZacX+a5M= 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /config/baker_rsa.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCo+YRhI2Gjno+5ND+N/pBvvw7Bvji6OEtZgUKvJf8P9rPcUCR8w7DpDPTpLSM4spBqIwoEM1CQRnH8x/Ufvhr51tU/74A4J2MgBEjClI8M5Z8iqYhDWfoRywo/2uB1rrPHICIM716LRFGIDoqnt+leHU4wcfHmHNa8/KqC5tNxd9/VBxeveh0CIu7/Ba3/UVtn6CTY2sGMo0mJk0IjzIsK42TgRL7ZOTQfbo1Td3DpOCdt02xft5xXCk9KuRwwrjdtyZbP8n8xc7/YcRk0pswFViNfEaU5Eb42+DTr0OhCgadGD9ufxJbSh4ty2VmRycQBfj00VqQO2zPNL2u76EfkMEI/TspVansMCheRtt3C5QJQCv0gXntDSunzgIOvbgShc644eIrmV/kh0oLYkW+Fi80zqx/dIdKMc7OpXK/umJb18ao2IBtBoTiNr5cla1XerDwZXJEp6sPJlSja9xNb0yw0PAfxMiKsR/fjymZ5E7dPaYjS3b+LIyxjxL+GSr8ZRL+3aH7lYsdAaQwekesxaMZUSfKDwRWk5UvE81gpCWWkgcTcqxCGuiBCdviBU88yXfDuFodidgYTJ39JM9v3gKuvlJAtRaBbXSJ6YTjanfozlmpaNYImHUPeooY20vlolmXzs2llZI+gM68GZpnml3en80LJYnin26kigWM9WQ== Baker 2 | -------------------------------------------------------------------------------- /config/common/CheckoutFromVault.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | 4 | vars_files: 5 | - "{{vault}}" 6 | 7 | tasks: 8 | #- debug: msg="{{vars[key]}}" 9 | - copy: content="{{vars[key]}}" dest="{{dest}}" mode=0600 -------------------------------------------------------------------------------- /config/common/dockerBootstrap.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | tasks: 5 | - name: Install sudo 6 | raw: apt-get update && apt-get install -y sudo 7 | 8 | - name: Install python 9 | raw: test -e /usr/bin/python || (sudo apt -y update && sudo apt install -y python-minimal) 10 | 11 | # Address bug affecting apt_repository 12 | # https://github.com/ansible/ansible/issues/40608 13 | - name: Install lsb-release 14 | raw: sudo apt install -y lsb-release 15 | 16 | # Some apt-get installs require aptitude. Unless we specify force_apt_get: yes 17 | # then this is required 18 | # https://github.com/ansible/ansible/pull/27962/files 19 | - name: Install aptitude 20 | apt: pkg="{{item}}" state=present 21 | with_items: 22 | - python-apt 23 | - aptitude 24 | - dpkg-dev 25 | 26 | -------------------------------------------------------------------------------- /config/common/installDocker.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: yes 4 | 5 | tasks: 6 | - name: Install pip 7 | apt: name={{ item }} update_cache=yes 8 | with_items: 9 | - python-pip 10 | 11 | - name: Install the Python modules 12 | pip: 13 | name: "{{item}}" 14 | become: yes 15 | with_items: 16 | - urllib3 17 | - pyOpenSSL 18 | - ndg-httpsclient 19 | - pyasn1 20 | 21 | - name: Disable Firewall 22 | service: name=ufw state=stopped 23 | 24 | - name: Install HTTPS Apt Packages 25 | apt: name={{ item }} update_cache=yes 26 | with_items: 27 | - apt-transport-https 28 | - ca-certificates 29 | - curl 30 | - software-properties-common 31 | 32 | - name: Add Docker GPG Key 33 | apt_key: 34 | url: https://download.docker.com/linux/ubuntu/gpg 35 | state: present 36 | validate_certs: no 37 | 38 | - name: Add Docker Repository 39 | apt_repository: 40 | repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" 41 | state: present 42 | validate_certs: no 43 | 44 | - name: Install Docker CE 45 | apt: name=docker-ce state=present update_cache=yes 46 | 47 | - name: Enable Docker at Startup 48 | service: name=docker state=started enabled=yes 49 | 50 | - name: add user mod to docker 51 | command: usermod -aG docker {{ ansible_user }} 52 | -------------------------------------------------------------------------------- /config/common/registerhost.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | 4 | tasks: 5 | - name: Get host signatures and add to known_hosts. 6 | command: ssh-keyscan -H "{{ip}}" 7 | register: known_host_key 8 | 9 | - name: Remove previous VM with this ip from ansible server 10 | known_hosts: name="{{ip}}" state="absent" 11 | 12 | #- debug: msg="Signature is {{ known_host_key.stdout }}" 13 | - name: Register VM ip address to ansible server 14 | known_hosts: name="{{ip}}" key="{{known_host_key.stdout }}" 15 | -------------------------------------------------------------------------------- /config/dockerHost/DockerVM.mustache: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | 6 | config.vm.box = "ubuntu/xenial64" 7 | config.vm.hostname = "{{dockerHostName}}" 8 | 9 | config.vm.network "private_network", ip: "192.168.252.252" 10 | config.vm.network "private_network", ip: "192.168.252.251" 11 | 12 | config.vm.provider "virtualbox" do |vb| 13 | vb.memory = "2048" 14 | vb.customize ['modifyvm', :id, '--nictype1', 'virtio'] 15 | vb.customize ['modifyvm', :id, '--nicpromisc1', 'allow-all'] 16 | vb.customize ['modifyvm', :id, '--nictype2', 'virtio'] 17 | vb.customize ['modifyvm', :id, '--nicpromisc2', 'allow-all'] 18 | 19 | # fix crappy dns 20 | # https://serverfault.com/questions/453185/vagrant-virtualbox-dns-10-0-2-3-not-working 21 | vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] 22 | 23 | vb.name = "{{dockerHostName}}" 24 | end 25 | 26 | # Setting VM name in vagrant 27 | config.vm.define "{{dockerHostName}}" do |t| 28 | end 29 | 30 | config.vm.synced_folder "/", "/home/vagrant/host_root" 31 | 32 | config.vm.provision "shell", inline: <<-SHELL 33 | apt-get update 34 | apt-get -y install bridge-utils 35 | SHELL 36 | 37 | config.vm.provision "ansible_local", run: 'always' do |ansible| 38 | ansible.playbook = "dockerConfig.yml" 39 | ansible.verbose = false 40 | end 41 | 42 | config.vm.provision "shell", inline: <<-SHELL 43 | sudo ip addr del 192.168.252.252/24 dev enp0s8 44 | 45 | sudo service networking restart 46 | sudo systemctl daemon-reload 47 | sudo service docker restart 48 | SHELL 49 | end 50 | -------------------------------------------------------------------------------- /config/dockerHost/dockerConfig.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: yes 4 | 5 | tasks: 6 | ###################### 7 | ### Docker Bakelet ### 8 | ###################### 9 | - name: Disable Firewall 10 | service: name=ufw state=stopped 11 | 12 | - name: Install HTTPS Apt Packages 13 | apt: name={{ item }} update_cache=yes 14 | with_items: 15 | - apt-transport-https 16 | - ca-certificates 17 | - curl 18 | - software-properties-common 19 | - python-pip 20 | 21 | - name: Add Docker GPG Key 22 | apt_key: url=https://download.docker.com/linux/ubuntu/gpg state=present 23 | 24 | - name: Add Docker Repository 25 | apt_repository: 26 | repo="deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" 27 | state=present 28 | 29 | - name: Install Docker CE 30 | apt: name=docker-ce state=present update_cache=yes 31 | 32 | - name: Enable Docker at Startup 33 | service: name=docker state=started enabled=yes 34 | 35 | - name: add user mod to docker 36 | command: usermod -aG docker {{ ansible_user }} 37 | 38 | - name: install docker-py 39 | pip: 40 | name: docker-py 41 | state: latest 42 | 43 | ################################### 44 | ### Install Bridge dependencies ### 45 | ################################### 46 | - name: Create docker network 47 | docker_network: 48 | state: present 49 | name: shared_nw 50 | driver: bridge 51 | driver_options: 52 | com.docker.network.bridge.name: docker1 53 | ipam_options: 54 | subnet: '192.168.252.252/24' 55 | gateway: 192.168.252.252 56 | 57 | # TODO: find the interface configuration and update in /etc/network/interfaces 58 | - name: add enp0s8 interface to docker1 bridge 59 | command: sudo brctl addif docker1 enp0s8 60 | ignore_errors: yes 61 | 62 | ###################### 63 | ### Docker config ### 64 | ###################### 65 | - name: Ensure docker.service.d directory exists 66 | file: 67 | path: /etc/systemd/system/docker.service.d 68 | state: directory 69 | 70 | - name: Add docker.conf file in docker.service.d 71 | blockinfile: 72 | path: /etc/systemd/system/docker.service.d/docker.conf 73 | create: yes 74 | block: | 75 | [Service] 76 | ExecStart= 77 | ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock 78 | 79 | - name: Restart service docker 80 | service: 81 | name: docker 82 | state: restarted 83 | -------------------------------------------------------------------------------- /config/dockerHost/lxd-bridge: -------------------------------------------------------------------------------- 1 | 2 | #sudo iptables -t nat -A PREROUTING -p tcp --dport 2280 -j DNAT --to-destination 10.252.116.2:22 3 | # sudo iptables -t nat -A POSTROUTING -p tcp -d 10.252.116.2 --dport 2280 -j SNAT --to-source 127.0.0.1 4 | 5 | # /etc/default/lxd-bridge 6 | # sudo usermod -aG lxd $USER 7 | # WARNING: This file is generated by a debconf template! 8 | # It is recommended to update it by using "dpkg-reconfigure -p medium lxd" 9 | 10 | # Whether to setup a new bridge or use an existing one 11 | USE_LXD_BRIDGE="true" 12 | 13 | # Bridge name 14 | # This is still used even if USE_LXD_BRIDGE is set to false 15 | # set to an empty value to fully disable 16 | LXD_BRIDGE="br0" 17 | 18 | # Update the "default" LXD profile 19 | UPDATE_PROFILE="true" 20 | 21 | # Path to an extra dnsmasq configuration file 22 | LXD_CONFILE="/etc/default/dns.conf" 23 | 24 | # DNS domain for the bridge 25 | LXD_DOMAIN="lxd" 26 | 27 | # IPv4 28 | ## IPv4 address (e.g. 10.0.8.1) 29 | LXD_IPV4_ADDR="192.168.252.252" 30 | 31 | ## IPv4 netmask (e.g. 255.255.255.0) 32 | LXD_IPV4_NETMASK="255.255.255.0" 33 | 34 | ## IPv4 network (e.g. 10.0.8.0/24) 35 | LXD_IPV4_NETWORK="192.168.252.252/24" 36 | 37 | ## IPv4 DHCP range (e.g. 10.0.8.2,10.0.8.254) 38 | LXD_IPV4_DHCP_RANGE="192.168.252.253,192.168.252.255" 39 | 40 | ## IPv4 DHCP number of hosts (e.g. 250) 41 | LXD_IPV4_DHCP_MAX="3" 42 | 43 | ## NAT IPv4 traffic 44 | LXD_IPV4_NAT="true" 45 | 46 | # IPv6 47 | ## IPv6 address (e.g. 2001:470:b368:4242::1) 48 | LXD_IPV6_ADDR="" 49 | 50 | ## IPv6 CIDR mask (e.g. 64) 51 | LXD_IPV6_MASK="" 52 | 53 | ## IPv6 network (e.g. 2001:470:b368:4242::/64) 54 | LXD_IPV6_NETWORK="" 55 | 56 | ## NAT IPv6 traffic 57 | LXD_IPV6_NAT="false" 58 | 59 | # Run a minimal HTTP PROXY server 60 | LXD_IPV6_PROXY="true" 61 | -------------------------------------------------------------------------------- /config/provision.shell.sh: -------------------------------------------------------------------------------- 1 | sudo apt-add-repository --yes ppa:ansible/ansible 2 | sudo apt-get update 3 | sudo apt-get install -y git ansible -------------------------------------------------------------------------------- /docs/img/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ottomatica/Baker/3dfe55d6ef58e68a9c89529bc7a5e0d2b0fe4707/docs/img/demo.gif -------------------------------------------------------------------------------- /global-vars.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const boxes = path.join(require('os').homedir(), '.baker'); 3 | const bakerForMacPath = process.platform === 'darwin' ? path.join(require('os').homedir(), 'Library', 'Baker', 'BakerForMac') : undefined; 4 | const bakerSSHConfig = process.platform === 'darwin' ? {port: 6022, user: 'root', private_key: path.join(bakerForMacPath, 'baker_rsa'), hostname: 'localhost'} : 5 | {port: 6022, user: 'root', private_key: path.join(boxes, 'baker_rsa'), hostname: 'localhost'}; 6 | const privateKey = process.platform === 'darwin' ? path.join(bakerForMacPath, 'baker_rsa') : path.join(boxes, 'baker_rsa'); 7 | 8 | module.exports = { 9 | boxes : boxes, 10 | ansible : path.join(boxes, 'ansible-srv'), 11 | configPath : path.join(__dirname, './config'), 12 | bakeletsPath: path.join(__dirname, './lib/bakelets'), 13 | remotesPath : path.join(__dirname, './remotes'), 14 | envIndexPath: path.join(boxes, 'data', 'index.json'), 15 | bakerForMacPath, 16 | bakerSSHConfig, 17 | privateKey, 18 | // spinnerDot : 'dots' 19 | version: require('./package.json').version 20 | }; 21 | -------------------------------------------------------------------------------- /installers/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Samim Mirhosseini 2 | pkgname="baker" 3 | pkgver=0.7.2 4 | pkgrel=1 5 | pkgdesc="Quick and easy baking of computing environments." 6 | arch=('x86_64') 7 | url="https://github.com/ottomatica/Baker" 8 | license=('Apache') 9 | provides=('baker') 10 | makedepends=('npm' 'jq' 'python2') 11 | optdepends=('virtualbox: virtual machine support') 12 | source=($pkgname-$pkgver.tar.gz::https://github.com/ottomatica/Baker/archive/v$pkgver.tar.gz) 13 | md5sums=('159a26f533a29a26ff6b6cdd42a05407') 14 | 15 | package() { 16 | npm install -g \ 17 | --user root \ 18 | --prefix "$pkgdir"/usr \ 19 | --cache "${srcdir}/npm-cache" \ 20 | "$srcdir"/$pkgname-$pkgver.tar.gz 21 | 22 | # Non-deterministic race in npm gives 777 permissions to random directories. 23 | # See https://github.com/npm/npm/issues/9359 for details. 24 | find "${pkgdir}"/usr -type d -exec chmod 755 {} + 25 | 26 | # Remove dependency references to $pkgdir 27 | find "$pkgdir" -name package.json -print0 | xargs -0 sed -i '/_where/d' 28 | 29 | # Remove package references to $pkgdir 30 | local tmppackage="$(mktemp)" 31 | local pkgjson="$pkgdir/usr/lib/node_modules/$pkgname/package.json" 32 | jq '.|=with_entries(select(.key|test("_.+")|not))' "$pkgjson" > "$tmppackage" 33 | mv "$tmppackage" "$pkgjson" 34 | chmod 644 "$pkgjson" 35 | } 36 | -------------------------------------------------------------------------------- /installers/README.md: -------------------------------------------------------------------------------- 1 | # Current steps to create a release: 2 | 3 | ensure the semver in package.json:3, ./src/installers/linux/deb-template/baker/DEBIAN/control:2, ./src/installers/macos/package.sh:17, and ./src/installers/win/scripts/baker.iss:10,11 are correct/updated 4 | 5 | from ./src directory run: 6 | 7 | npm run package-macos # Run on Mac -- running `grunt` will do this on Mac automatically 8 | npm run package-linux # Run on Mac or Linux, you need dpkg: `brew install dpkg` 9 | grunt # On windows, it creates the setup file 10 | 11 | note: if you have a ./src/lib/.DS_Store file, this will fail and you have to remove it ... 12 | 13 | The executables are in these paths: 14 | ./src/installers/macos/bin/baker 15 | ./src/installers/linux/deb/baker.deb 16 | ./src/installers/win/bin/baker-setup.exe 17 | 18 | create a release here: https://github.com/ottomatica/baker-release/releases 19 | 20 | upload the files to that release with these changes: 21 | rename .deb file to baker-linux-.deb and upload 22 | create a .tar.gz file of Mac executable by running 23 | 24 | tar -zcvf baker-macos-.tar.gz baker 25 | 26 | upload baker-macos-.tar.gz 27 | rename Windows setup file to baker-windows-.exe and upload 28 | 29 | last step is to update the homebrew formula to use this new version. 30 | find the sha256 for .tar.gz file by running 31 | 32 | shasum -a 256 baker-macos-.tar.gz | awk '{printf $1}' | pbcopy 33 | 34 | update the url and sha256 in homebrew-ottomatica repo. 35 | -------------------------------------------------------------------------------- /installers/build-installer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z ${1+x} ]; then 4 | echo "Usage: ./build-installer.sh " 5 | exit 1 6 | else 7 | echo "Creating installers for '$1'" 8 | fi 9 | 10 | BAKER_RELEASE=$1 11 | 12 | echo "Updating package.json in ../package.json to be $BAKER_RELEASE" 13 | sed -i "" -e "s/ \"version\": .*/ \"version\": \"${BAKER_RELEASE}\",/" "../package.json" 14 | 15 | echo "Updating VERSION in macos/package.sh to be $BAKER_RELEASE"; 16 | sed -i "" -e "s/VERSION=.*/VERSION=\"${BAKER_RELEASE}\"/" "macos/package.sh" 17 | 18 | echo "Updating Version in linux/deb-template/baker/DEBIAN/control to be $BAKER_RELEASE"; 19 | sed -i "" -e "s/Version: .*/Version: ${BAKER_RELEASE}/" "linux/deb-template/baker/DEBIAN/control" 20 | 21 | echo "Updating AppVersion in win/scripts/baker.iss to be $BAKER_RELEASE"; 22 | sed -i "" -e "s/AppVersion=.*/AppVersion=${BAKER_RELEASE}/" "win/scripts/baker.iss" 23 | 24 | echo "Updating pkgver in PKGBUILD to be $BAKER_RELEASE"; 25 | sed -i "" -e "s/^pkgver=.*$/pkgver=${BAKER_RELEASE}/" "PKGBUILD" 26 | 27 | # clean any old files 28 | rm -f macos/bin/* 29 | 30 | cd ../ 31 | echo "running mac installer" 32 | npm run package-macos 33 | echo "running linux installer" 34 | npm run package-linux 35 | 36 | cd installers 37 | echo "creating tar.gz for homebrew" 38 | mkdir -p /tmp/baker-release/${BAKER_RELEASE}/ 39 | cwd=$(pwd) 40 | echo "$cwd" 41 | # clean any old files 42 | rm -f /tmp/baker-release/${BAKER_RELEASE}/* 43 | cp macos/bin/baker /tmp/baker-release/${BAKER_RELEASE}/ 44 | cd /tmp/baker-release/ && tar -zcvf $cwd/macos/bin/baker-macos-latest.tar.gz ${BAKER_RELEASE}/ 45 | cd $cwd 46 | 47 | echo "moving new pkg to baker-latest.pkg for mac" 48 | mv macos/bin/baker-${BAKER_RELEASE}.pkg macos/bin/baker-latest.pkg 49 | 50 | SHA=$(shasum -a 256 macos/bin/baker-macos-latest.tar.gz | awk '{printf $1}') 51 | echo "Update homebrew shaw: $SHA"; 52 | echo "Version: ${BAKER_RELEASE}" 53 | 54 | echo "You are not done, yet" 55 | echo "You need to upload the .tar.gz, .pkg, and .deb on github." 56 | echo "You also need to update the md5sums field in PKGBUILD to the md5 sum of the source .tar.gz." 57 | echo "Then you need to switch to a windows machine and run 'grunt'" 58 | echo "Then you need to rename win/bin/baker-setup.exe to baker-windows-latest.exe and upload too" 59 | echo "Finally, you need to update the sha to $SHA and VERSION to ${BAKER_RELEASE} in ottomatica/homebrew" 60 | -------------------------------------------------------------------------------- /installers/linux/deb-template/baker/DEBIAN/control: -------------------------------------------------------------------------------- 1 | Package: Baker 2 | Version: 0.7.2 3 | Section: base 4 | Priority: optional 5 | Architecture: amd64 6 | Depends: virtualbox 7 | Maintainer: Samim Mirhosseini 8 | Description: Baker 9 | 🍞 Quick and easy baking of computing environments. 10 | -------------------------------------------------------------------------------- /installers/linux/deb-template/baker/usr/bin/empty.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ottomatica/Baker/3dfe55d6ef58e68a9c89529bc7a5e0d2b0fe4707/installers/linux/deb-template/baker/usr/bin/empty.txt -------------------------------------------------------------------------------- /installers/linux/deb/empty.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ottomatica/Baker/3dfe55d6ef58e68a9c89529bc7a5e0d2b0fe4707/installers/linux/deb/empty.txt -------------------------------------------------------------------------------- /installers/macos/package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if this is running on a Mac 4 | if [[ "$OSTYPE" != "darwin"* ]]; then 5 | echo "You can only package (.pkg) installer on a Mac OS!" 6 | exit 1 7 | fi 8 | 9 | # Name of the package. 10 | NAME="baker" 11 | PACKAGEREL="installers/macos" 12 | 13 | # Once installed the identifier is used as the filename for a receipt files in /var/db/receipts/. 14 | IDENTIFIER="io.ottomatica.$NAME" 15 | 16 | # Package version number. 17 | VERSION="0.7.2" 18 | 19 | # The location to copy the contents of files. 20 | INSTALL_LOCATION="/opt/baker/bin" 21 | 22 | # Remove any unwanted .DS_Store files. 23 | find $PACKAGEREL/bin/ -name '*.DS_Store' -type f -delete 24 | 25 | # Set full read, write, execute permissions for owner and just read and execute permissions for group and other. 26 | /bin/chmod -R 755 $PACKAGEREL/bin/baker 27 | /bin/chmod -R 755 $PACKAGEREL/scripts 28 | 29 | 30 | # Make bin dir if doesn't exist 31 | if [ ! -d "$PACKAGEREL/bin" ]; then 32 | mkdir "$PACKAGEREL/bin" 33 | fi 34 | 35 | # Build package. 36 | /usr/bin/pkgbuild \ 37 | --root $PACKAGEREL/bin/ \ 38 | --install-location "$INSTALL_LOCATION" \ 39 | --scripts $PACKAGEREL/scripts/ \ 40 | --identifier "$IDENTIFIER" \ 41 | --version "$VERSION" \ 42 | "$PACKAGEREL/bin/$NAME-$VERSION.pkg" 43 | -------------------------------------------------------------------------------- /installers/macos/scripts/postinstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Symlink baker binary to /usr/local/bin/baker 4 | ln -s /opt/baker/bin/baker /usr/local/bin 5 | -------------------------------------------------------------------------------- /installers/win/scripts/baker.iss: -------------------------------------------------------------------------------- 1 | ; Script generated by the Inno Setup Script Wizard. 2 | ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! 3 | 4 | [Setup] 5 | ; NOTE: The value of AppId uniquely identifies this application. 6 | ; Do not use the same AppId value in installers for other applications. 7 | ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) 8 | AppId={{FF82CC8F-9CAD-4210-97AA-2C5F955DB742} 9 | AppName=Baker 10 | AppVersion=0.7.2 11 | ;AppVerName=Baker 0.4.3 12 | AppPublisher=Ottomatica LLC 13 | AppPublisherURL=https://getbaker.io/ 14 | AppSupportURL=https://getbaker.io/ 15 | AppUpdatesURL=https://getbaker.io/ 16 | DefaultDirName=C:\Ottomatica\Baker 17 | DisableDirPage=yes 18 | DefaultGroupName=Baker 19 | DisableProgramGroupPage=yes 20 | OutputDir=./bin 21 | OutputBaseFilename=baker-setup 22 | Compression=lzma 23 | SolidCompression=yes 24 | 25 | [Languages] 26 | Name: "english"; MessagesFile: "compiler:Default.isl" 27 | 28 | [Files] 29 | Source: "{#SourcePath}/../bin/baker.exe"; DestDir: "{app}"; Flags: ignoreversion 30 | ; NOTE: Don't use "Flags: ignoreversion" on any shared system files 31 | 32 | [Icons] 33 | Name: "{group}\{cm:UninstallProgram,Baker}"; Filename: "{uninstallexe}" 34 | 35 | [Registry] 36 | Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \ 37 | ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};C:\Ottomatica\Baker\" 38 | -------------------------------------------------------------------------------- /lib/bakelets/bakelet.js: -------------------------------------------------------------------------------- 1 | const Ssh = require('../modules/ssh'); 2 | 3 | class Bakelet 4 | { 5 | constructor(ansibleSSHConfig) 6 | { 7 | this.ansibleSSHConfig = ansibleSSHConfig; 8 | } 9 | 10 | setRemotesPath(remotesPath) 11 | { 12 | this.remotesPath = remotesPath; 13 | } 14 | 15 | setBakePath(bakePath) 16 | { 17 | this.bakePath = bakePath; 18 | } 19 | 20 | setVerbose(verbose) 21 | { 22 | this.verbose = verbose; 23 | } 24 | 25 | setBakeletName(bakeletName) 26 | { 27 | this.bakeletName = bakeletName; 28 | } 29 | 30 | setBakeletPath(bakeletPath) 31 | { 32 | this.bakeletPath = bakeletPath; 33 | } 34 | 35 | 36 | async copy(src,dest) 37 | { 38 | // Copy common ansible scripts files 39 | await Ssh.copyFromHostToVM( 40 | src, 41 | dest, 42 | this.ansibleSSHConfig, 43 | false 44 | ); 45 | } 46 | 47 | async exec(cmd) { 48 | // Run cmd on remote server 49 | await Ssh.sshExec(cmd, this.ansibleSSHConfig, 20000, this.verbose); 50 | } 51 | } 52 | 53 | module.exports = Bakelet; 54 | -------------------------------------------------------------------------------- /lib/bakelets/config/keys.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | const Ssh = require('../../modules/ssh'); 5 | 6 | const { privateKey } = require('../../../global-vars'); 7 | 8 | class Keys extends Bakelet { 9 | 10 | constructor(name,ansibleSSHConfig, version) { 11 | super(ansibleSSHConfig); 12 | 13 | this.name = name; 14 | this.version = version; 15 | } 16 | 17 | async load(obj, variables) 18 | { 19 | if( Array.isArray(obj.keys) ) 20 | { 21 | for (let clientName of obj.keys) 22 | { 23 | await Ssh.copyFromHostToVM( 24 | privateKey, 25 | `/home/vagrant/baker/${this.name}/${clientName}_id_rsa`, 26 | this.ansibleSSHConfig 27 | ); 28 | } 29 | 30 | variables.push({baker_client_keys : obj.keys.map( k => `${k}_id_rsa`) }); 31 | this.variables = variables; 32 | let playbook = path.resolve(this.remotesPath, `bakelets-source/config/keys${this.version}.yml`); 33 | await this.copy(playbook,`/home/vagrant/baker/${this.name}/keys${this.version}.yml`); 34 | } 35 | } 36 | 37 | async install() 38 | { 39 | var cmd = `keys${this.version}.yml`; 40 | await Ansible.runAnsiblePlaybook( 41 | {name: this.name}, cmd, this.ansibleSSHConfig, this.verbose, this.variables 42 | ); 43 | } 44 | 45 | 46 | } 47 | 48 | module.exports = Keys; 49 | 50 | -------------------------------------------------------------------------------- /lib/bakelets/config/template.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | const Ssh = require('../../modules/ssh'); 5 | 6 | class Template extends Bakelet { 7 | 8 | constructor(name,ansibleSSHConfig, version) { 9 | super(ansibleSSHConfig); 10 | 11 | this.name = name; 12 | this.version = version; 13 | } 14 | 15 | async load(obj, variables) 16 | { 17 | await Ssh.copyFromHostToVM( 18 | path.resolve(this.bakePath, obj.template.src), 19 | `/home/vagrant/baker/${this.name}/templates/`, 20 | this.ansibleSSHConfig, 21 | false 22 | ); 23 | 24 | this.src = `templates/${path.basename(path.resolve(this.bakePath, obj.template.src))}`; 25 | this.dest = obj.template.dest; 26 | this.variables = variables; 27 | } 28 | 29 | async install() 30 | { 31 | await Ansible.runAnsibleTemplateCmd( 32 | {name: this.name}, this.src, this.dest, this.variables, this.ansibleSSHConfig, this.verbose 33 | ); 34 | } 35 | 36 | } 37 | 38 | module.exports = Template; 39 | 40 | -------------------------------------------------------------------------------- /lib/bakelets/config/vault.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const path = require('path'); 3 | 4 | const { privateKey } = require('../../../global-vars'); 5 | const conf = require('../../modules/configstore') 6 | 7 | const Ansible = require('../../modules/configuration/ansible'); 8 | const VaultLib = require('../../modules/vault'); 9 | const Ssh = require('../../modules/ssh'); 10 | 11 | class Vault extends Bakelet { 12 | 13 | constructor(name,ansibleSSHConfig, version) { 14 | super(ansibleSSHConfig); 15 | 16 | this.name = name; 17 | this.version = version; 18 | } 19 | 20 | 21 | async load(obj, variables) 22 | { 23 | 24 | let passphraseKey = `vault:${this.bakePath}`; 25 | let passphrase = ''; 26 | if (conf.has(passphraseKey)) 27 | { 28 | passphrase = conf.get(passphraseKey); 29 | } 30 | else 31 | { 32 | // should be set in baking process. 33 | throw new Error("Vault pass has not been correctly set.") 34 | } 35 | let vault = new VaultLib(); 36 | 37 | if( Array.isArray(obj.vault) ) 38 | { 39 | this.vault = obj.vault; 40 | this.variables = variables || {}; 41 | 42 | for (let entry of obj.vault) 43 | { 44 | let file = path.join(this.bakePath, entry.file); 45 | let content = vault.retrieve(file, passphrase); 46 | 47 | await Ssh.writeContentToDest(content, 48 | `/home/vagrant/baker/${this.name}/templates/${entry.file}`, 49 | this.ansibleSSHConfig, 50 | false 51 | ); 52 | } 53 | } 54 | } 55 | 56 | async install() 57 | { 58 | if( this.vault ) 59 | { 60 | for (let entry of this.vault) 61 | { 62 | await Ansible.createDirectory({name: this.name}, path.dirname(entry.dest), "0755", this.ansibleSSHConfig, this.verbose ); 63 | 64 | await Ansible.runAnsibleTemplateCmd( 65 | {name: this.name}, `/home/vagrant/baker/${this.name}/templates/${entry.file}`, 66 | entry.dest, this.variables, this.ansibleSSHConfig, this.verbose); 67 | } 68 | } 69 | } 70 | 71 | 72 | } 73 | 74 | module.exports = Vault; 75 | 76 | -------------------------------------------------------------------------------- /lib/bakelets/custom.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('./bakelet'); 2 | const Ansible = require('../modules/configuration/ansible'); 3 | const path = require('path'); 4 | 5 | class Custom extends Bakelet { 6 | 7 | constructor(name, ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | } 13 | 14 | async load(obj, variables) { 15 | let playbook = path.resolve(this.remotesPath, this.bakeletPath); 16 | await this.copy(playbook, `/home/vagrant/baker/${this.name}/${this.bakeletName}${this.version}.yml`); 17 | this.variables = variables; 18 | } 19 | 20 | async install() { 21 | var cmd = `${this.bakeletName}${this.version}.yml`; 22 | await Ansible.runAnsiblePlaybook( 23 | { name: this.name }, cmd, this.ansibleSSHConfig, this.verbose, this.variables 24 | ); 25 | } 26 | 27 | } 28 | 29 | module.exports = Custom; 30 | -------------------------------------------------------------------------------- /lib/bakelets/env/env.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const fs = require('fs-extra'); 4 | const mustache = require('mustache'); 5 | const path = require('path'); 6 | 7 | class Env extends Bakelet { 8 | constructor(name, ansibleSSHConfig, version) { 9 | super(ansibleSSHConfig); 10 | 11 | this.name = name; 12 | this.version = version; 13 | } 14 | 15 | async load(obj, variables) { 16 | this.variables = variables; 17 | this.envVars = {env: []}; 18 | 19 | obj.env.forEach( e => { 20 | this.envVars.env.push({KEY: Object.keys(e)[0], VALUE: Object.values(e)[0]}) 21 | }) 22 | 23 | let playbookTemplate = path.resolve( 24 | this.remotesPath, 25 | `bakelets-source/env/env.yml.mustache` 26 | ); 27 | let playbookRendered = mustache.render(await fs.readFile(playbookTemplate, 'utf8'), this.envVars); 28 | 29 | let cmd = `echo "${playbookRendered.replace(/"/g, '\\"')}" > /home/vagrant/baker/${this.name}/env.yml`; 30 | await this.exec(cmd); 31 | } 32 | 33 | async install() { 34 | var cmd = `env.yml`; 35 | await Ansible.runAnsiblePlaybook( 36 | { name: this.name }, 37 | cmd, 38 | this.ansibleSSHConfig, 39 | this.verbose, 40 | this.variables 41 | ); 42 | } 43 | } 44 | 45 | module.exports = Env; 46 | -------------------------------------------------------------------------------- /lib/bakelets/lang/R.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const fs = require('fs-extra'); 4 | const mustache = require('mustache'); 5 | const path = require('path'); 6 | 7 | class R extends Bakelet { 8 | constructor(name, ansibleSSHConfig, version) { 9 | super(ansibleSSHConfig); 10 | 11 | this.name = name; 12 | this.version = version; 13 | } 14 | 15 | async load(obj, variables) { 16 | this.variables = variables; 17 | 18 | if (obj.R) { 19 | if (obj.R.packages) { 20 | let type = typeof(obj.R.packages); 21 | if(type == 'string') 22 | this.packages = obj.R.packages.trim().split(/\s*,\s*/g); 23 | else if(type = 'object') 24 | this.packages = obj.R.packages; 25 | } 26 | } 27 | else { 28 | this.packages = []; 29 | } 30 | 31 | let packagesObj = {'cran': this.packages.length!=0 ? true : false, 'packages': this.packages.map(p => `'${p}'`).join() }; 32 | let playbookTemplate = path.resolve( 33 | this.remotesPath, 34 | `bakelets-source/lang/R/r.yml.mustache` 35 | ); 36 | let playbookRendered = mustache.render(await fs.readFile(playbookTemplate, 'utf8'), packagesObj); 37 | 38 | let cmd = `echo "${playbookRendered.replace(/"/g, '\\"')}" > /home/vagrant/baker/${this.name}/r.yml`; 39 | await this.exec(cmd); 40 | } 41 | 42 | async install() { 43 | var cmd = `r.yml`; 44 | await Ansible.runAnsiblePlaybook( 45 | { name: this.name }, 46 | cmd, 47 | this.ansibleSSHConfig, 48 | this.verbose, 49 | this.variables 50 | ); 51 | } 52 | } 53 | 54 | module.exports = R; 55 | -------------------------------------------------------------------------------- /lib/bakelets/lang/java.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | 5 | class Java extends Bakelet { 6 | 7 | constructor(name,ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | 13 | } 14 | 15 | async load(obj, variables) 16 | { 17 | //console.log("load", "java", this.version); 18 | //console.log("Copying files to baker VM"); 19 | let playbook = path.resolve(this.remotesPath, `bakelets-source/lang/java/java${this.version}.yml`); 20 | await this.copy(playbook,`/home/vagrant/baker/${this.name}/java${this.version}.yml`); 21 | this.variables = variables; 22 | } 23 | 24 | async install() 25 | { 26 | var cmd = `java${this.version}.yml`; 27 | await Ansible.runAnsiblePlaybook( 28 | {name: this.name}, cmd, this.ansibleSSHConfig, this.verbose, this.variables 29 | ); 30 | //console.log(`installed java ${this.version}`); 31 | } 32 | 33 | 34 | } 35 | 36 | module.exports = Java; 37 | -------------------------------------------------------------------------------- /lib/bakelets/lang/nodejs.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const fs = require('fs-extra'); 4 | const path = require('path'); 5 | 6 | class Nodejs extends Bakelet { 7 | 8 | constructor(name, ansibleSSHConfig, version) { 9 | super(ansibleSSHConfig); 10 | 11 | this.name = name; 12 | this.version = version; 13 | 14 | } 15 | 16 | async load(obj, variables) 17 | { 18 | //console.log("load", "java", this.version); 19 | //console.log("Copying files to baker VM"); 20 | let playbook = path.resolve(this.remotesPath, `bakelets-source/lang/nodejs/nodejs${this.version}.yml`); 21 | await this.copy(playbook, `/home/vagrant/baker/${this.name}/nodejs${this.version}.yml`); 22 | this.variables = variables; 23 | } 24 | 25 | async install() 26 | { 27 | var cmd = `nodejs${this.version}.yml`; 28 | await Ansible.runAnsiblePlaybook( 29 | {name: this.name}, cmd, this.ansibleSSHConfig, this.verbose, this.variables 30 | ); 31 | 32 | var localPackageJsonPath = path.resolve(this.bakePath, "package.json"); 33 | if( fs.existsSync(localPackageJsonPath) ) 34 | { 35 | // There could be some funkyness depending on if there is a package-lock.json, etc: 36 | // and node_modules is manually deleted: 37 | // https://github.com/ansible/ansible/pull/29131 38 | var vmPackagePath = `/${path.basename(this.bakePath)}`; 39 | if( this.verbose ) console.log(`Attempting to run npm install in vm at ${vmPackagePath}`); 40 | await Ansible.runAnsibleNpmInstall( 41 | {name: this.name}, vmPackagePath, this.ansibleSSHConfig, this.verbose 42 | ); 43 | } 44 | 45 | } 46 | 47 | 48 | } 49 | 50 | module.exports = Nodejs; 51 | -------------------------------------------------------------------------------- /lib/bakelets/lang/python.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const fs = require('fs-extra'); 4 | const path = require('path'); 5 | 6 | class Python extends Bakelet { 7 | 8 | constructor(name, ansibleSSHConfig, version) { 9 | super(ansibleSSHConfig); 10 | 11 | this.name = name; 12 | // Default to python2 13 | this.version = version || 2; 14 | } 15 | 16 | async load(obj, variables) 17 | { 18 | let playbook = path.resolve(this.remotesPath, `bakelets-source/lang/python/python${this.version}.yml`); 19 | await this.copy(playbook, `/home/vagrant/baker/${this.name}/python${this.version}.yml`); 20 | this.variables = variables; 21 | } 22 | 23 | async install() 24 | { 25 | var cmd = `python${this.version}.yml`; 26 | await Ansible.runAnsiblePlaybook( 27 | {name: this.name}, cmd, this.ansibleSSHConfig, this.verbose, this.variables 28 | ); 29 | 30 | // Check for a requirements.txt and then run pip install -r requirements.txt 31 | // TODO: Possible to allow a requirements: parameter in the python object. 32 | // Otherwise, we might just want it in the packages: pip: requirements: path 33 | // var localRequirementsPath = path.resolve(this.bakePath, "requirements.txt"); 34 | // if( fs.existsSync(localRequirementsPath) ) 35 | // { 36 | // var vmRequirementsPath = `/${path.basename(this.bakePath)}/requirements.txt`; 37 | // await Ansible.runAnsiblePipInstall( 38 | // {name: this.name}, vmRequirementsPath, this.ansibleSSHConfig, this.verbose 39 | // ); 40 | // } 41 | } 42 | 43 | 44 | } 45 | 46 | module.exports = Python; 47 | -------------------------------------------------------------------------------- /lib/bakelets/packages/apt.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const fs = require('fs-extra'); 4 | const mustache = require('mustache'); 5 | const path = require('path'); 6 | 7 | class Apt extends Bakelet { 8 | constructor(name, ansibleSSHConfig, version) { 9 | super(ansibleSSHConfig); 10 | 11 | this.name = name; 12 | this.version = version; 13 | } 14 | 15 | async load(obj, variables) { 16 | this.variables = variables; 17 | this.packages = {default: [], deb: [], ppa: []}; 18 | 19 | // console.log('obj', obj.apt); 20 | if (obj.apt) { 21 | let type = typeof(obj.apt); 22 | if (type == 'string') 23 | this.packages.default = obj.apt.trim().split(/\s*,\s*/g); 24 | else if(type == 'object'){ 25 | obj.apt.forEach(pkg => { 26 | if(typeof(pkg) == 'object' && pkg[Object.keys(pkg)[0]].deb){ 27 | let name = Object.keys(pkg)[0]; 28 | this.packages.deb.push({name: name, deb: pkg[name].deb}); 29 | } 30 | else if(typeof(pkg) == 'string'){ 31 | this.packages.default.push(pkg); 32 | } 33 | 34 | }); 35 | } 36 | } 37 | 38 | let packagesObj = { 39 | 'packages': 40 | { 41 | 'default': this.packages.default.map(p => {return {'name': p}}), 42 | 'deb': this.packages.deb, 43 | 'ppa': this.packages.ppa.map(p => {return {'name': p}}) 44 | } 45 | }; 46 | 47 | // console.log('default', packagesObj.packages.default); 48 | // console.log('deb', packagesObj.packages.deb); 49 | // console.log('ppa', packagesObj.packages.ppa); 50 | // console.log('packagesobj', packagesObj); 51 | 52 | let playbookTemplate = path.resolve( 53 | this.remotesPath, 54 | `bakelets-source/packages/apt.yml.mustache` 55 | ); 56 | let playbookRendered = mustache.render(await fs.readFile(playbookTemplate, 'utf8'), packagesObj); 57 | 58 | // console.log('playbookrendered', playbookRendered); 59 | let cmd = `echo "${playbookRendered.replace(/"/g, '\\"')}" > /home/vagrant/baker/${this.name}/apt.yml`; 60 | await this.exec(cmd); 61 | } 62 | 63 | async install() { 64 | var cmd = `apt.yml`; 65 | await Ansible.runAnsiblePlaybook( 66 | { name: this.name }, 67 | cmd, 68 | this.ansibleSSHConfig, 69 | this.verbose, 70 | this.variables 71 | ); 72 | } 73 | } 74 | 75 | module.exports = Apt; 76 | -------------------------------------------------------------------------------- /lib/bakelets/resources/git.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const chalk = require('chalk'); 3 | const _ = require('underscore'); 4 | const Ssh = require('../../modules/ssh'); 5 | 6 | class Git extends Bakelet { 7 | constructor(name, ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | } 13 | 14 | async load(obj, variables) { 15 | this.variables = variables; 16 | 17 | if (obj.git) { 18 | let type = typeof(obj.git); 19 | if (type == 'string'){ 20 | let git = obj.git.trim(); 21 | this.dest = git.split(/\s*:\s*/).pop(); 22 | this.repo = git.substring(0, git.length-this.dest.length-1); 23 | } 24 | else if(type == 'object'){ 25 | this.repo = obj.git.repo; 26 | this.dest = obj.git.dest; 27 | if( obj.git.private ) 28 | { 29 | if( this.variables.filter( x => x.githubuser ).length == 0 || this.variables.filter( x => x.githubpass ).length == 0 ) 30 | { 31 | console.log(chalk.red("You must define a githubuser and githubpass variable in order to clone a private repo")); 32 | throw new Error("Cannot complete git operation."); 33 | } 34 | let user = encodeURIComponent(this.variables.filter( x => x.githubuser )[0].githubuser); 35 | let pass = encodeURIComponent(this.variables.filter( x => x.githubpass )[0].githubpass); 36 | // gitlab/bitbucket. 37 | this.repo = this.repo.replace('github.com', `${user}:${pass}@github.com`); 38 | } 39 | } 40 | } 41 | if( this.verbose ) 42 | { 43 | console.log('repo', this.repo); 44 | console.log('dest', this.dest); 45 | } 46 | } 47 | 48 | static async runGitClone (doc, repo, dest, ansibleSSHConfig,verbose) { 49 | return Ssh.sshExec(`export ANSIBLE_HOST_KEY_CHECKING=false && cd /home/vagrant/baker/${doc.name} && ansible all -m git -a "repo=${repo} dest=${dest} version=HEAD" -i baker_inventory`, ansibleSSHConfig, 20000, verbose); 50 | } 51 | 52 | async install() { 53 | await runGitClone({name: this.name}, this.repo, this.dest, this.ansibleSSHConfig, this.verbose); 54 | } 55 | } 56 | 57 | module.exports = Git; 58 | -------------------------------------------------------------------------------- /lib/bakelets/services/docker.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | 5 | class Docker extends Bakelet { 6 | 7 | constructor(name,ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | 13 | } 14 | 15 | async load(obj, variables) 16 | { 17 | this.variables = variables; 18 | 19 | let playbook = path.resolve(this.remotesPath, `bakelets-source/services/docker/docker${this.version}.yml`); 20 | await this.copy(playbook,`/home/vagrant/baker/${this.name}/docker${this.version}.yml`); 21 | } 22 | 23 | async install() 24 | { 25 | var cmd = `docker${this.version}.yml`; 26 | await Ansible.runAnsiblePlaybook( 27 | {name: this.name}, cmd, this.ansibleSSHConfig, this.verbose, this.variables 28 | ); 29 | } 30 | } 31 | 32 | module.exports = Docker; 33 | -------------------------------------------------------------------------------- /lib/bakelets/services/jenkins.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ottomatica/Baker/3dfe55d6ef58e68a9c89529bc7a5e0d2b0fe4707/lib/bakelets/services/jenkins.js -------------------------------------------------------------------------------- /lib/bakelets/services/mongodb.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | 5 | class MongoDB extends Bakelet { 6 | 7 | constructor(name,ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | 13 | } 14 | 15 | async load(obj, variables) 16 | { 17 | this.variables = variables; 18 | 19 | if( obj.mongodb ) 20 | { 21 | if( obj.mongodb.version ) 22 | { 23 | this.version = obj.mongodb.version; 24 | } 25 | } 26 | 27 | let playbook = path.resolve(this.remotesPath, `bakelets-source/services/mongodb/mongodb${this.version}.yml`); 28 | await this.copy(playbook,`/home/vagrant/baker/${this.name}/mongodb${this.version}.yml`); 29 | } 30 | 31 | async install() 32 | { 33 | var cmd = `mongodb${this.version}.yml`; 34 | await Ansible.runAnsiblePlaybook( 35 | {name: this.name}, cmd, this.ansibleSSHConfig, true, this.variables 36 | ); 37 | } 38 | } 39 | 40 | module.exports = MongoDB; 41 | -------------------------------------------------------------------------------- /lib/bakelets/services/mysql.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | const Ssh = require('../../modules/ssh'); 5 | 6 | class MySql extends Bakelet { 7 | 8 | constructor(name,ansibleSSHConfig, version) { 9 | super(ansibleSSHConfig); 10 | 11 | this.name = name; 12 | this.version = version; 13 | 14 | } 15 | 16 | async load(obj, variables) 17 | { 18 | this.variables = variables; 19 | 20 | if( obj.mysql ) 21 | { 22 | if( obj.mysql.version ) 23 | { 24 | this.version = obj.mysql.version; 25 | } 26 | 27 | if( obj.mysql.service_conf ) 28 | { 29 | await Ssh.copyFromHostToVM( 30 | path.resolve(this.bakePath, obj.mysql.service_conf), 31 | `/home/vagrant/baker/${this.name}/templates/`, 32 | this.ansibleSSHConfig, 33 | false 34 | ); 35 | } 36 | 37 | if( obj.mysql.client_conf ) 38 | { 39 | await Ssh.copyFromHostToVM( 40 | path.resolve(this.bakePath, obj.mysql.client_conf), 41 | `/home/vagrant/baker/${this.name}/templates/`, 42 | this.ansibleSSHConfig, 43 | false 44 | ); 45 | } 46 | 47 | /// templates/mysql.cfg 48 | 49 | } 50 | 51 | let playbook = path.resolve(this.remotesPath, `bakelets-source/services/mysql/mysql${this.version}.yml`); 52 | await this.copy(playbook,`/home/vagrant/baker/${this.name}/mysql${this.version}.yml`); 53 | } 54 | 55 | async install() 56 | { 57 | var cmd = `mysql${this.version}.yml`; 58 | await Ansible.runAnsiblePlaybook( 59 | {name: this.name}, cmd, this.ansibleSSHConfig, this.verbose, this.variables 60 | ); 61 | } 62 | } 63 | 64 | module.exports = MySql; 65 | -------------------------------------------------------------------------------- /lib/bakelets/services/neo4j.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | 5 | class Neo4j extends Bakelet { 6 | 7 | constructor(name,ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | 13 | } 14 | 15 | async load(obj, variables) 16 | { 17 | this.variables = variables; 18 | 19 | let playbook = path.resolve(this.remotesPath, `bakelets-source/services/neo4j/neo4j${this.version}.yml`); 20 | await this.copy(playbook,`/home/vagrant/baker/${this.name}/neo4j${this.version}.yml`); 21 | } 22 | 23 | async install() 24 | { 25 | var cmd = `neo4j${this.version}.yml`; 26 | await Ansible.runAnsiblePlaybook( 27 | {name: this.name}, cmd, this.ansibleSSHConfig, this.verbose, this.variables 28 | ); 29 | } 30 | } 31 | 32 | module.exports = Neo4j; 33 | -------------------------------------------------------------------------------- /lib/bakelets/start.js: -------------------------------------------------------------------------------- 1 | const Ssh = require('../modules/ssh'); 2 | 3 | async function start(cmd, vmName, ansibleSSHConfig, verbose) { 4 | //await ssh.sshExec(`nohup bash -c '${cmd}' & exit 0`, sshConfig, true); 5 | // await ssh.sshExec(`nohup bash -c "${cmd}" > ~/start.out 2> ~/start.err &`, vmSSHConfig, verbose); 6 | // https://stackoverflow.com/questions/29142/getting-ssh-to-execute-a-command-in-the-background-on-target-machine 7 | // can consider a keepalive option for start if want to see the output without redirecting. 8 | 9 | await Ssh.sshExec(`export ANSIBLE_HOST_KEY_CHECKING=false && cd /home/vagrant/baker/${vmName} && ansible all -m shell -a 'nohup bash -c "${cmd}" > ~/start.out 2> ~/start.err &' -i baker_inventory -v`, ansibleSSHConfig, 20000, verbose); 10 | } 11 | 12 | module.exports = start; 13 | -------------------------------------------------------------------------------- /lib/bakelets/tools/ansible.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const AnsibleHelper = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | 5 | class Ansible extends Bakelet { 6 | 7 | constructor(name,ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | 13 | } 14 | 15 | async load(obj, variables) 16 | { 17 | let playbook = path.resolve(this.remotesPath, `bakelets-source/tools/ansible/ansible${this.version}.yml`); 18 | await this.copy(playbook, `/home/vagrant/baker/${this.name}/ansible${this.version}.yml`); 19 | this.variables = variables; 20 | } 21 | 22 | async install() 23 | { 24 | var cmd = `ansible${this.version}.yml`; 25 | await AnsibleHelper.runAnsiblePlaybook( 26 | {name: this.name}, cmd, this.ansibleSSHConfig, this.verbose, this.variables 27 | ); 28 | } 29 | 30 | 31 | } 32 | 33 | module.exports = Ansible; 34 | -------------------------------------------------------------------------------- /lib/bakelets/tools/dazed.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | 5 | class Dazed extends Bakelet { 6 | 7 | constructor(name,ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | 13 | } 14 | 15 | async load(obj, variables) 16 | { 17 | let playbook = path.resolve(this.remotesPath, `bakelets-source/tools/dazed/dazed${this.version}.yml`); 18 | await this.copy(playbook, `/home/vagrant/baker/${this.name}/dazed${this.version}.yml`); 19 | this.variables = variables; 20 | } 21 | 22 | async install() 23 | { 24 | var cmd = `dazed${this.version}.yml`; 25 | await Ansible.runAnsiblePlaybook( 26 | {name: this.name}, cmd, this.ansibleSSHConfig, this.verbose, this.variables 27 | ); 28 | } 29 | 30 | 31 | } 32 | 33 | module.exports = Dazed; 34 | -------------------------------------------------------------------------------- /lib/bakelets/tools/defects4j.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | 5 | class Defects4J extends Bakelet { 6 | 7 | constructor(name,ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | 13 | } 14 | 15 | async load(obj, variables) 16 | { 17 | let playbook = path.resolve(this.remotesPath, `bakelets-source/tools/defects4j/defects4j${this.version}.yml`); 18 | await this.copy(playbook, `/home/vagrant/baker/${this.name}/defects4j${this.version}.yml`); 19 | this.variables = variables; 20 | } 21 | 22 | async install() 23 | { 24 | var cmd = `defects4j${this.version}.yml`; 25 | await Ansible.runAnsiblePlaybook( 26 | {name: this.name}, cmd, this.ansibleSSHConfig, this.verbose, this.variables 27 | ); 28 | } 29 | 30 | 31 | } 32 | 33 | module.exports = Defects4J; 34 | -------------------------------------------------------------------------------- /lib/bakelets/tools/jekyll.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | 5 | class Jekyll extends Bakelet { 6 | 7 | constructor(name, ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | } 13 | 14 | async load(obj, variables) { 15 | let playbook = path.resolve(this.remotesPath, `bakelets-source/tools/jekyll/jekyll${this.version}.yml`); 16 | await this.copy(playbook, `/home/vagrant/baker/${this.name}/jekyll${this.version}.yml`); 17 | this.variables = variables; 18 | } 19 | 20 | async install() { 21 | var cmd = `jekyll${this.version}.yml`; 22 | await Ansible.runAnsiblePlaybook({ name: this.name }, cmd, this.ansibleSSHConfig, this.verbose, this.variables); 23 | } 24 | } 25 | 26 | module.exports = Jekyll; 27 | -------------------------------------------------------------------------------- /lib/bakelets/tools/jenkins-job-builder.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ottomatica/Baker/3dfe55d6ef58e68a9c89529bc7a5e0d2b0fe4707/lib/bakelets/tools/jenkins-job-builder.js -------------------------------------------------------------------------------- /lib/bakelets/tools/jupyter.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | 5 | class Jupyter extends Bakelet { 6 | 7 | constructor(name,ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | 13 | } 14 | 15 | async load(obj, variables) 16 | { 17 | let playbook = path.resolve(this.remotesPath, `bakelets-source/tools/jupyter/jupyter${this.version}.yml`); 18 | await this.copy(playbook, `/home/vagrant/baker/${this.name}/jupyter${this.version}.yml`); 19 | this.variables = variables; 20 | } 21 | 22 | async install() 23 | { 24 | var cmd = `jupyter${this.version}.yml`; 25 | await Ansible.runAnsiblePlaybook( 26 | {name: this.name}, cmd, this.ansibleSSHConfig, this.verbose, this.variables 27 | ); 28 | } 29 | 30 | 31 | } 32 | 33 | module.exports = Jupyter; 34 | -------------------------------------------------------------------------------- /lib/bakelets/tools/latex.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | const path = require('path'); 4 | 5 | class Latex extends Bakelet { 6 | 7 | constructor(name, ansibleSSHConfig, version) { 8 | super(ansibleSSHConfig); 9 | 10 | this.name = name; 11 | this.version = version; 12 | } 13 | 14 | async load(obj, variables) { 15 | let playbook = path.resolve(this.remotesPath, `bakelets-source/tools/latex/latex${this.version}.yml`); 16 | await this.copy(playbook, `/home/vagrant/baker/${this.name}/latex${this.version}.yml`); 17 | this.variables = variables; 18 | } 19 | 20 | async install() { 21 | var cmd = `latex${this.version}.yml`; 22 | await Ansible.runAnsiblePlaybook({ name: this.name }, cmd, this.ansibleSSHConfig, this.verbose, this.variables); 23 | } 24 | } 25 | 26 | module.exports = Latex; 27 | -------------------------------------------------------------------------------- /lib/bakelets/tools/maven.js: -------------------------------------------------------------------------------- 1 | const Bakelet = require('../bakelet'); 2 | const Ansible = require('../../modules/configuration/ansible'); 3 | 4 | class Maven extends Bakelet { 5 | 6 | constructor(name,ansibleSSHConfig, version) { 7 | super(ansibleSSHConfig); 8 | 9 | this.name = name; 10 | this.version = version; 11 | 12 | } 13 | 14 | async load() 15 | { 16 | } 17 | 18 | async install() 19 | { 20 | await Ansible.runAnsibleAptInstall( 21 | {name: this.name}, "maven", this.ansibleSSHConfig, this.verbose 22 | ); 23 | } 24 | 25 | } 26 | 27 | module.exports = Maven; 28 | -------------------------------------------------------------------------------- /lib/commands/bake.js: -------------------------------------------------------------------------------- 1 | const conf = require('../modules/configstore'); 2 | const spinnerDot = conf.get('spinnerDot'); 3 | const Baker = require('../modules/baker'); 4 | const Git = require('../modules/utils/git'); 5 | const path = require('path'); 6 | const Print = require('../modules/print'); 7 | const Servers = require('../modules/servers'); 8 | const Spinner = require('../modules/spinner'); 9 | const VaultLib = require('../modules/vault'); 10 | 11 | const prompt = require('prompt'); 12 | const _ = require('underscore'); 13 | 14 | const { bakerSSHConfig } = require('../../global-vars'); 15 | 16 | // exports.aliases = ['$0']; 17 | exports.command = 'bake' 18 | exports.desc = 'Bake your VM given local path or repository URL containing the baker.yml'; 19 | exports.builder = (yargs) => { 20 | yargs 21 | .example(`$0 bake`, `Bake baker.yml of current directory`) 22 | .example(`$0 bake --local ~/project`, `Bake baker.yml of ~/project`) 23 | .example(`$0 bake --repo git@github.com:ottomatica/baker-test.git`, `Clone repository in current directory and Bake its baker.yml`); 24 | 25 | yargs.options( 26 | { 27 | local: { 28 | alias: 'l', 29 | describe: `give a local path to where your baker.yml file is located`, 30 | demand: false, 31 | type: 'string' 32 | }, 33 | repo: { 34 | alias: 'r', 35 | describe: `give a git repository URL which has a baker.yml in it's root directory`, 36 | demand: false, 37 | type: 'string' 38 | }, 39 | box: { 40 | alias: 'b', 41 | describe: `give local path to where your baker.yml file is located`, 42 | demand: false, 43 | type: 'string' 44 | }, 45 | remote: { 46 | describe: `give ip address of the remote server`, 47 | demand: false, 48 | type: 'string' 49 | }, 50 | remote_key: { 51 | describe: `give path to the ssh key of the remote server`, 52 | demand: false, 53 | type: 'string' 54 | }, 55 | remote_user: { 56 | describe: `give the ssh username of the remote server`, 57 | demand: false, 58 | type: 'string' 59 | }, 60 | verbose: { 61 | alias: 'v', 62 | describe: `Provide extra output from baking process`, 63 | demand: false, 64 | type: 'boolean' 65 | }, 66 | forceVirtualBox: { 67 | describe: `Force using virtualbox instead of xhyve VM on Mac (no effect on Windows/Linux)`, 68 | hidden: true, // just for debugging for now 69 | demand: false, 70 | type: 'boolean' 71 | }, 72 | useContainer: { 73 | describe: `Override environment type to use container`, 74 | demand: false, 75 | type: 'boolean' 76 | }, 77 | useVM: { 78 | describe: `Override environment type to use vm`, 79 | demand: false, 80 | type: 'boolean' 81 | } 82 | } 83 | ); 84 | }; 85 | 86 | exports.handler = async function(argv) { 87 | const { local, repo, box, remote, remote_key, remote_user, verbose, forceVirtualBox, useContainer, useVM } = argv; 88 | 89 | try{ 90 | let ansibleVM; 91 | let bakePath; 92 | 93 | if( box ){ 94 | bakePath = path.resolve(box); 95 | } 96 | else if (local) { 97 | bakePath = path.resolve(local); 98 | } else if (repo) { 99 | bakePath = path.resolve(await Git.clone(repo)); 100 | } else if (remote) { 101 | bakePath = path.resolve(process.cwd()); 102 | } else { 103 | let cwdVM = await Baker.getCWDBakerYML(); 104 | if(cwdVM){ 105 | bakePath = cwdVM.cwd; 106 | } else { 107 | Print.error( 108 | `Can't find baker.yml in cwd. Use --local to give local path or --repo to give git repository with baker.yml` 109 | ); 110 | process.exit(1); 111 | } 112 | } 113 | 114 | const {provider, BakerObj, doc} = await Baker.chooseProvider(bakePath, useContainer, useVM); 115 | 116 | if( doc.config ) 117 | { 118 | if( doc.config.some(element => element.vault) ) 119 | { 120 | let passphraseKey = `vault:${bakePath}`; 121 | if( !conf.has(passphraseKey) ) 122 | { 123 | let pass = await promptPass(); 124 | let vault = new VaultLib(); 125 | 126 | console.log(passphraseKey, pass); 127 | conf.set(passphraseKey, pass); 128 | } 129 | } 130 | } 131 | 132 | 133 | if(box) 134 | await provider.bakeBox(bakerSSHConfig, ansibleVM, bakePath, verbose); 135 | else if(remote) 136 | await BakerObj.bakeRemote(bakerSSHConfig, remote, remote_key, remote_user, bakePath, verbose); 137 | else{ 138 | await Servers.installBakerServer(forceVirtualBox); 139 | 140 | await BakerObj.bake(bakePath, bakerSSHConfig, verbose); 141 | 142 | // Handle exposure of ports on server if container 143 | await BakerObj.exposePorts(path.join(bakePath, 'baker.yml'), verbose); 144 | 145 | } 146 | 147 | } catch (err) { 148 | Print.error(err); 149 | } 150 | } 151 | 152 | async function promptPass() 153 | { 154 | return new Promise(function(resolve,reject) 155 | { 156 | var properties = [ 157 | { 158 | name: 'password', 159 | hidden: true 160 | } 161 | ]; 162 | 163 | prompt.start(); 164 | 165 | prompt.get(properties, function (err, result) { 166 | if (err) { reject(err); } 167 | else 168 | { 169 | resolve(result.password) 170 | } 171 | }); 172 | }); 173 | } 174 | -------------------------------------------------------------------------------- /lib/commands/boxes.js: -------------------------------------------------------------------------------- 1 | const Baker = require('../modules/baker'); 2 | const conf = require('../../lib/modules/configstore'); 3 | const Print = require('../modules/print'); 4 | const Spinner = require('../modules/spinner'); 5 | const VagrantProvider = require('../modules/providers/vagrant'); 6 | 7 | const spinnerDot = conf.get('spinnerDot'); 8 | 9 | exports.command = 'boxes'; 10 | exports.desc = `list existing Baker boxes`; 11 | exports.handler = async function(argv) { 12 | const { verbose } = argv; 13 | 14 | const provider = new VagrantProvider(); 15 | 16 | try { 17 | await Spinner.spinPromise(provider.bakerBoxes(), `Getting list of Baker boxes`, spinnerDot); 18 | } catch (err) { 19 | Print.error(err); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/commands/cluster.js: -------------------------------------------------------------------------------- 1 | const conf = require('../../lib/modules/configstore'); 2 | const Git = require('../modules/utils/git'); 3 | const path = require('path'); 4 | const Print = require('../modules/print'); 5 | const Spinner = require('../modules/spinner'); 6 | const Servers = require('../modules/servers'); 7 | const Cluster = require('../modules/clusters/cluster'); 8 | 9 | const spinnerDot = conf.get('spinnerDot'); 10 | const { bakerSSHConfig } = require('../../global-vars'); 11 | 12 | exports.command = 'cluster'; 13 | exports.desc = 'Bake your Cluster given local path or repository URL containing the baker.yml'; 14 | 15 | exports.builder = (yargs) => { 16 | // TODO: 17 | // yargs 18 | // .example(`$0 cluster --local`, `This is an example of how to use this command`); 19 | 20 | yargs.options({ 21 | local: { 22 | alias: 'l', 23 | describe: `give a local path to where your baker.yml file is located`, 24 | demand: false, 25 | type: 'string' 26 | }, 27 | repo: { 28 | alias: 'r', 29 | describe: `give a git repository URL which has a baker.yml in it's root directory`, 30 | demand: false, 31 | type: 'string' 32 | }, 33 | verbose: { 34 | alias: 'v', 35 | describe: `Provide extra output from baking process`, 36 | demand: false, 37 | type: 'boolean' 38 | } 39 | }); 40 | }; 41 | 42 | exports.handler = async function(argv) { 43 | const { local, repo, verbose } = argv; 44 | 45 | try{ 46 | let ansibleVM; 47 | let bakePath; 48 | 49 | if (local) { 50 | bakePath = path.resolve(local); 51 | } else if (repo) { 52 | bakePath = path.resolve(await Git.clone(repo)); 53 | } else { 54 | Print.error( 55 | `User --local to give local path or --repo to give git repository with baker.yml` 56 | ); 57 | process.exit(1); 58 | } 59 | 60 | await Servers.installBakerServer(); 61 | 62 | let cluster = new Cluster(); 63 | await cluster.cluster(bakerSSHConfig, ansibleVM, bakePath, verbose); 64 | 65 | } catch (err) { 66 | Print.error(err); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/commands/command.example.js: -------------------------------------------------------------------------------- 1 | exports.command = 'command [not_demand]'; 2 | // exports.aliases = ['$0']; 3 | exports.desc = 'Description of command'; 4 | exports.builder = (yargs) => { 5 | yargs 6 | .example(`$0 command default`, `This is an example of how to use this command`) 7 | .example(`$0 command default default`, `This is another example of how to use this command`); 8 | 9 | yargs 10 | .positional('demand', { 11 | describe: 'You have to specify this', 12 | type: 'string', 13 | default: 'default' 14 | }) 15 | .positional('not_demand', { 16 | describe: 'You can to specify this', 17 | type: 'string' 18 | }); 19 | 20 | yargs.options({ 21 | opt: { 22 | alias: ['o', 'oo'], 23 | describe: `This is an option`, 24 | demand: false, 25 | type: 'string', 26 | default: '.' 27 | } 28 | }); 29 | } 30 | 31 | exports.handler = async function(argv) { 32 | console.log('Running command... '); 33 | } 34 | -------------------------------------------------------------------------------- /lib/commands/destroy.js: -------------------------------------------------------------------------------- 1 | const Baker = require('../modules/baker'); 2 | const conf = require('../../lib/modules/configstore'); 3 | const Print = require('../modules/print'); 4 | const Spinner = require('../modules/spinner'); 5 | const spinnerDot = conf.get('spinnerDot'); 6 | const Servers = require('../modules/servers'); 7 | 8 | exports.command = ['delete [VMName]', 'destroy [VMName]']; 9 | exports.desc = `remove a VM and it's associated files`; 10 | exports.builder = (yargs) => { 11 | yargs 12 | .example(`$0 destroy`, `Destroys the VM build from baker.yml of current directory`) 13 | .example(`$0 destroy baker-test`, `Destroys baker-test VM`); 14 | 15 | // TODO: bakePath is required for finding the envType. 16 | // for now assuming the command is executed in same dir as baker.yml 17 | // yargs.positional('envName', { 18 | // describe: 'Name of the environment to be destroyed', 19 | // type: 'string' 20 | // }); 21 | yargs.options( 22 | { 23 | useContainer: { 24 | describe: `Override environment type to use container`, 25 | demand: false, 26 | type: 'boolean' 27 | }, 28 | useVM: { 29 | describe: `Override environment type to use vm`, 30 | demand: false, 31 | type: 'boolean' 32 | }, 33 | forceVirtualBox: { 34 | describe: `Force using virtualbox instead of xhyve VM on Mac (no effect on Windows/Linux)`, 35 | hidden: true, // just for debugging for now 36 | demand: false, 37 | type: 'boolean' 38 | } 39 | } 40 | ); 41 | 42 | } 43 | 44 | exports.handler = async function(argv) { 45 | let { envName, useContainer, useVM, forceVirtualBox } = argv; 46 | 47 | try { 48 | let bakePath = process.cwd(); 49 | const {envName, BakerObj} = await Baker.chooseProvider(bakePath, useContainer, useVM); 50 | 51 | // ensure baker server is running 52 | await Servers.installBakerServer(forceVirtualBox); 53 | 54 | await Spinner.spinPromise(BakerObj.delete(envName), `Destroying VM: ${envName}`, spinnerDot); 55 | } catch (err) { 56 | Print.error(err); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/commands/docker.js: -------------------------------------------------------------------------------- 1 | const Baker = require('../modules/baker'); 2 | const conf = require('../../lib/modules/configstore'); 3 | const DockerProvider = require('../modules/providers/docker'); 4 | const fs = require('fs-extra'); 5 | const path = require('path'); 6 | const Print = require('../modules/print'); 7 | const Spinner = require('../modules/spinner'); 8 | const spinnerDot = conf.get('spinnerDot'); 9 | const yaml = require('js-yaml'); 10 | 11 | exports.command = 'docker [command]'; 12 | exports.desc = 'Spin up docker containers'; 13 | 14 | exports.builder = (yargs) => { 15 | yargs 16 | .example(`$0 docker start --local .`, `Start a docker container based on baker.yml of current directory`); 17 | 18 | yargs.positional('command', { 19 | describe: 'bake | start | stop | destroy | list | ssh', 20 | type: 'string', 21 | default: 'bake' 22 | }) 23 | 24 | yargs.options({ 25 | local: { 26 | alias: 'l', 27 | describe: `give a local path to where your baker.yml file is located`, 28 | demand: false, 29 | type: 'string' 30 | } 31 | }); 32 | }; 33 | 34 | exports.handler = async function(argv) { 35 | const { local, repo, verbose } = argv; 36 | 37 | const dockerProvider = new DockerProvider({host: '192.168.252.251', port: '2375', protocol: 'http'}); 38 | const BakerObj = new Baker(dockerProvider); 39 | 40 | // Check if command is valid 41 | if(!['bake', 'start', 'stop', 'destroy', 'list', 'ssh', 'images'].includes(argv.command)) { 42 | Print.error(`invalid command: ${argv.command}`); 43 | process.exit(1); 44 | } 45 | 46 | let bakePath = local || process.cwd(); 47 | let doc = yaml.safeLoad(await fs.readFile(path.join(bakePath, 'baker.yml'), 'utf8')); 48 | let name = doc.name; 49 | 50 | await Servers.installBakerServer(); 51 | 52 | switch (argv.command) { 53 | case 'bake': 54 | await BakerObj.bake(bakePath); 55 | break; 56 | 57 | case 'start': 58 | console.log('TODO: just starting a VM only gives you a blank container without running any bakelets') 59 | await BakerObj.start(bakePath); 60 | break; 61 | 62 | case 'stop': 63 | await Spinner.spinPromise(BakerObj.stop(name), `Stopping Docker container`, spinnerDot); 64 | break; 65 | 66 | case 'destroy': 67 | await Spinner.spinPromise(BakerObj.delete(name), `Removing Docker container`, spinnerDot); 68 | break; 69 | 70 | case 'list': 71 | // TODO: Broken 72 | await BakerObj.list(); 73 | break; 74 | 75 | case 'ssh': 76 | await BakerObj.ssh(name); 77 | 78 | case 'images': 79 | await BakerObj.images(); 80 | 81 | default: 82 | break; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/commands/halt.js: -------------------------------------------------------------------------------- 1 | const Baker = require('../modules/baker'); 2 | const conf = require('../../lib/modules/configstore'); 3 | const Print = require('../modules/print'); 4 | const Spinner = require('../modules/spinner'); 5 | const spinnerDot = conf.get('spinnerDot'); 6 | 7 | exports.command = ['stop [VMName]', 'halt [VMName]']; 8 | exports.desc = `shut down a VM`; 9 | 10 | exports.builder = (yargs) => { 11 | yargs 12 | .example(`$0 halt`, `Halts the VM build from baker.yml of current directory`) 13 | .example(`$0 halt baker-test`, `Halts baker-test VM`); 14 | 15 | // TODO: bakePath is required for finding the envType. 16 | // for now assuming the command is executed in same dir as baker.yml 17 | // yargs.positional('envName', { 18 | // describe: 'Name of the environment to stop', 19 | // type: 'string' 20 | // }); 21 | 22 | yargs.options({ 23 | force: { 24 | alias: 'f', 25 | describe: `force shut down`, 26 | demand: false, 27 | type: 'boolean' 28 | } 29 | }); 30 | } 31 | 32 | exports.handler = async function(argv) { 33 | let { envName, force } = argv; 34 | 35 | try { 36 | let bakePath = process.cwd(); 37 | const {envName, BakerObj} = await Baker.chooseProvider(bakePath); 38 | 39 | await Spinner.spinPromise(BakerObj.stop(envName, force), `Stopping VM: ${envName}`, spinnerDot); 40 | } catch(err) { 41 | Print.error(err); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/commands/import.js: -------------------------------------------------------------------------------- 1 | const Baker = require('../modules/baker'); 2 | const conf = require('../../lib/modules/configstore'); 3 | const Print = require('../modules/print'); 4 | const Spinner = require('../modules/spinner'); 5 | const spinnerDot = conf.get('spinnerDot'); 6 | const VagrantProvider = require('../modules/providers/vagrant'); 7 | 8 | exports.command = 'import '; 9 | exports.desc = `Import packaged Baker environment`; 10 | 11 | exports.builder = (yargs) => { 12 | yargs.example(`$0 import ./baker.box`, `Import a Baker Box`) 13 | 14 | yargs.positional('boxPath', { 15 | describe: 'Path to the .box file', 16 | type: 'string' 17 | }); 18 | 19 | yargs.options({ 20 | name: { 21 | alias: 'n', 22 | describe: `Provide name for the imported box`, 23 | demand: false, 24 | type: 'string' 25 | }, 26 | verbose: { 27 | alias: 'v', 28 | describe: `Provide extra output from baking process`, 29 | demand: false, 30 | type: 'boolean' 31 | } 32 | }); 33 | } 34 | 35 | exports.handler = async function(argv) { 36 | const { boxPath, name, verbose } = argv; 37 | 38 | try { 39 | await Spinner.spinPromise(VagrantProvider.import(boxPath, verbose), `Importing box: ${boxPath}`, spinnerDot); 40 | } catch (err) { 41 | Print.error(err); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/commands/info.js: -------------------------------------------------------------------------------- 1 | const Baker = require('../modules/baker'); 2 | 3 | exports.command = 'info '; 4 | exports.desc = 'provides information about a Baker environment'; 5 | exports.builder = (yargs) => { 6 | yargs 7 | .example(`$0 info baker-test`, `Outputs information about 'baker-test' environment`) 8 | .example(`$0 info baker-test --provider digitalocean`, `Provides information about 'baker-test' environment hosted on digitalocean`); 9 | 10 | yargs.positional('envName', { 11 | describe: 'Name of the environment', 12 | type: 'string' 13 | }); 14 | 15 | yargs.options({ 16 | verbose: { 17 | alias: 'v', 18 | describe: `Provide extended information about environment`, 19 | demand: false, 20 | type: 'boolean' 21 | } 22 | }); 23 | 24 | yargs.options({ 25 | provider: { 26 | alias: 'p', 27 | describe: `Provide provider-specific information for given environment`, 28 | demand: false, 29 | type: 'string' 30 | } 31 | }); 32 | 33 | } 34 | exports.handler = async function(argv) { 35 | await Baker.info(argv.envName,argv.provider, argv.verbose); 36 | } 37 | -------------------------------------------------------------------------------- /lib/commands/init.js: -------------------------------------------------------------------------------- 1 | const Interactive = require('../modules/init/interactive'); 2 | 3 | exports.command = 'init'; 4 | exports.desc = 'initializes a new Baker environment by creating a baker.yml file'; 5 | exports.handler = async function(argv) { 6 | await Interactive.initBaker2(); 7 | } 8 | -------------------------------------------------------------------------------- /lib/commands/package.js: -------------------------------------------------------------------------------- 1 | const conf = require('../../lib/modules/configstore'); 2 | const Print = require('../modules/print'); 3 | const Spinner = require('../modules/spinner'); 4 | const spinnerDot = conf.get('spinnerDot'); 5 | const VagrantProvider = require('../modules/providers/vagrant'); 6 | 7 | exports.command = 'package '; 8 | exports.desc = `package a Baker environment`; 9 | 10 | exports.builder = (yargs) => { 11 | yargs.example(`$0 package baker-test`, `Packages 'baker-test' Baker VM`); 12 | 13 | yargs.positional('VMName', { 14 | describe: 'Name of the VM to be packaged', 15 | type: 'string' 16 | }); 17 | 18 | yargs.options({ 19 | verbose: { 20 | alias: 'v', 21 | describe: `Provide extra output from baking process`, 22 | demand: false, 23 | type: 'boolean' 24 | } 25 | }); 26 | } 27 | 28 | exports.handler = async function(argv) { 29 | const { VMName, verbose } = argv; 30 | 31 | try { 32 | await Spinner.spinPromise(VagrantProvider.package(VMName, verbose), `Packaging box: ${VMName}`, spinnerDot); 33 | } catch (err) { 34 | Print.error(err); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/commands/run.js: -------------------------------------------------------------------------------- 1 | const Baker = require('../modules/baker'); 2 | const Print = require('../modules/print'); 3 | const Spinner = require('../modules/spinner'); 4 | const conf = require('../../lib/modules/configstore'); 5 | const yaml = require('js-yaml'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | const chalk = require('chalk'); 9 | 10 | const { bakerSSHConfig } = require('../../global-vars'); 11 | 12 | const spinnerDot = conf.get('spinnerDot'); 13 | 14 | 15 | exports.command = 'run [cmdlet]' 16 | exports.desc = 'Run registered cmdlet in baker environment'; 17 | exports.builder = (yargs) => { 18 | yargs 19 | .example(`$0 run cmdlet`, `Run the cmdlet in the baker environment`) 20 | yargs.options( 21 | { 22 | useContainer: { 23 | describe: `Override environment type to use container`, 24 | demand: false, 25 | type: 'boolean' 26 | }, 27 | useVM: { 28 | describe: `Override environment type to use vm`, 29 | demand: false, 30 | type: 'boolean' 31 | } 32 | } 33 | ); 34 | 35 | yargs.positional('cmdlet', { 36 | describe: 'Command inside baker.yml under commands:', 37 | type: 'string' 38 | }); 39 | 40 | }; 41 | 42 | exports.handler = async function(argv) { 43 | const { cmdlet, useContainer, useVM } = argv; 44 | 45 | try{ 46 | 47 | let bakePath = process.cwd(); 48 | const {envName, provider, BakerObj} = await Baker.chooseProvider(bakePath, useContainer, useVM); 49 | 50 | 51 | let cmd = ""; 52 | if( cmdlet == "hello" ) 53 | { 54 | cmd = "echo 'hello'"; 55 | } 56 | else 57 | { 58 | let content = fs.readFileSync(path.join(bakePath, 'baker.yml'), 'utf8'); 59 | let doc = await yaml.safeLoad(content); 60 | 61 | if( doc.commands && doc.commands.hasOwnProperty(cmdlet) ) 62 | { 63 | let cmdScript = doc.commands[cmdlet]; 64 | 65 | let mount = path.basename(bakePath); 66 | 67 | cmd = `cd /${mount}; ${cmdScript}`; 68 | } 69 | else 70 | { 71 | console.log(`The following cmdlets are available in ${envName} 🍞:`) 72 | for( let c in doc.commands ) 73 | { 74 | console.log(`${chalk.blueBright(c)}\t${doc.commands[c]}`); 75 | } 76 | process.exit(1); 77 | } 78 | } 79 | 80 | console.log(`Running ${cmdlet} in ${envName} 🍞`); 81 | 82 | await provider.ssh(envName, cmd, true, true, {interactive:true, pty:true}).catch( function(err) 83 | { 84 | // Ignore errors caused by manual termination of ssh. 85 | if( err.message.indexOf("Command failed: ssh -q") != 0 ) 86 | { 87 | Print.error(err); 88 | } 89 | }); 90 | 91 | } catch (err) { 92 | Print.error(err); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/commands/server.js: -------------------------------------------------------------------------------- 1 | const Print = require('../modules/print'); 2 | const Ssh = require('../modules/ssh'); 3 | const Servers = require('../modules/servers'); 4 | const Spinner = require('../modules/spinner'); 5 | const conf = require('../modules/configstore'); 6 | const spinnerDot = conf.get('spinnerDot'); 7 | 8 | const { bakerSSHConfig } = require('../../global-vars'); 9 | 10 | 11 | exports.command = 'server [name]'; 12 | // exports.aliases = ['$0']; 13 | exports.desc = 'Control the baker machine'; 14 | exports.builder = (yargs) => { 15 | yargs 16 | .example(`$0 server ssh`, `ssh into the baker machine.`) 17 | .example(`$0 server repair broken-machine`, `Perform fixes, such as repairing a locked dpkg`); 18 | 19 | yargs.positional('cmdlet', { 20 | describe: 'Command to run:', 21 | type: 'string' 22 | }); 23 | 24 | yargs.positional('name', { 25 | describe: 'Optional target of cmdlet:', 26 | type: 'string' 27 | }); 28 | 29 | yargs.options( 30 | { 31 | forceVirtualBox: { 32 | describe: `Force using virtualbox instead of xhyve VM on Mac (no effect on Windows/Linux)`, 33 | hidden: true, // just for debugging for now 34 | demand: false, 35 | type: 'boolean' 36 | } 37 | } 38 | ); 39 | } 40 | 41 | exports.handler = async function(argv) { 42 | const { cmdlet, name, forceVirtualBox } = argv; 43 | 44 | try{ 45 | switch( cmdlet ) 46 | { 47 | case "ssh": 48 | Ssh.SSH_Session(bakerSSHConfig); 49 | break; 50 | case "repair": 51 | if( !name ) 52 | throw new Error("You provide the name of the baker environment you want to repair."); 53 | 54 | let location = `cd /home/vagrant/baker/${name}`; 55 | let ansibleCmd = `ansible all -v -i baker_inventory --become -m shell -a`; 56 | let repairCmd = `rm -f /var/lib/dpkg/lock && dpkg --configure -a`; 57 | 58 | let cmd = `${location} && ${ansibleCmd} "${repairCmd}"`; 59 | 60 | await Ssh.sshExec(cmd, bakerSSHConfig, 20000, true ).catch(e => e); 61 | 62 | break; 63 | case "reload": 64 | await Spinner.spinPromise(Servers.stopBakerServer(forceVirtualBox), `Stopping Baker server`, spinnerDot); 65 | await Spinner.spinPromise(Servers.installBakerServer(forceVirtualBox), `Starting Baker server`, spinnerDot); 66 | break; 67 | case "stop": 68 | await Spinner.spinPromise(Servers.stopBakerServer(forceVirtualBox), `Stopping Baker server`, spinnerDot); 69 | break; 70 | default: 71 | } 72 | 73 | } catch (err) { 74 | Print.error(err); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /lib/commands/setup.js: -------------------------------------------------------------------------------- 1 | const conf = require('../../lib/modules/configstore'); 2 | const path = require('path'); 3 | const Print = require('../modules/print'); 4 | const Spinner = require('../modules/spinner'); 5 | const Validator = require('../modules/validator'); 6 | const Servers = require('../modules/servers'); 7 | const Utils = require('../modules/utils/utils'); 8 | 9 | const spinnerDot = conf.get('spinnerDot'); 10 | const { configPath, ansible } = require('../../global-vars'); 11 | 12 | exports.command = 'setup' 13 | exports.desc = 'create a Baker server which will be used for provisioning yor VMs' 14 | 15 | exports.builder = (yargs) => { 16 | yargs.options({ 17 | force:{ 18 | alias: 'f', 19 | describe: `if Baker server exists, first destroy it and then create a new one. Don't use this unless you know what you want to do.`, 20 | demand: false, 21 | type: 'boolean' 22 | } 23 | }); 24 | } 25 | 26 | exports.handler = async function (argv) { 27 | const { force } = argv 28 | 29 | try { 30 | await Spinner.spinPromise(Validator.validateDependencies(), 'Checking dependencies', spinnerDot); 31 | } catch (err){ 32 | Print.error(err); 33 | process.exit(1); 34 | } 35 | 36 | try { 37 | await Spinner.spinPromise(Servers.installBakerServer(), 'Installing Baker control machine', spinnerDot); 38 | 39 | await Spinner.spinPromise( 40 | Utils.copyFileSync( 41 | path.resolve(configPath, './baker_rsa.pub'), 42 | path.resolve(ansible, 'keys'), 43 | 'baker_rsa.pub' 44 | ), 45 | 'Copying private ssh key', 46 | spinnerDot 47 | ); 48 | 49 | await Spinner.spinPromise( 50 | Utils.copyFileSync( 51 | path.resolve(configPath, './baker_rsa'), 52 | path.resolve(ansible, 'keys'), 53 | 'baker_rsa' 54 | ), 55 | 'Copying public ssh key', 56 | spinnerDot 57 | ); 58 | 59 | } catch (err) { 60 | Print.error(err); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/commands/setupmac.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const path = require('path'); 3 | const Print = require('../modules/print'); 4 | const Servers = require('../modules/servers'); 5 | 6 | const { bakerForMacPath } = require('../../global-vars'); 7 | 8 | exports.command = 'setupmac' 9 | exports.desc = 'create a Baker server which will be used for provisioning yor VMs' 10 | 11 | exports.builder = (yargs) => { 12 | yargs.options({ 13 | force:{ 14 | alias: 'f', 15 | describe: `re-configure Baker for Mac`, 16 | demand: false, 17 | type: 'boolean' 18 | }, 19 | ssh:{ 20 | describe: `ssh`, 21 | demand: false, 22 | type: 'boolean' 23 | } 24 | }); 25 | } 26 | 27 | exports.handler = async function (argv) { 28 | const { force, ssh } = argv 29 | 30 | try { 31 | if(ssh) { 32 | child_process.execSync(`ssh -q -i "${path.join(bakerForMacPath, 'baker_rsa')}" -p 6022 -o StrictHostKeyChecking=no root@localhost`, {stdio: ['inherit', 'inherit', 'inherit']}); 33 | } 34 | else { 35 | await Servers.installBakerServer(force); 36 | } 37 | } catch (err) { 38 | Print.error(err); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/commands/ssh.js: -------------------------------------------------------------------------------- 1 | const Baker = require('../modules/baker'); 2 | const conf = require('../../lib/modules/configstore'); 3 | const Print = require('../modules/print'); 4 | const Spinner = require('../modules/spinner'); 5 | const spinnerDot = conf.get('spinnerDot'); 6 | 7 | exports.command = 'ssh [VMName]'; 8 | exports.desc = 'ssh to a VM'; 9 | 10 | exports.builder = (yargs) => { 11 | yargs 12 | .example(`$0 ssh`, `SSH to Baker environment of current directory`) 13 | .example(`$0 ssh baker-test`, `SSH to 'baker-test' Baker VM`); 14 | 15 | // // TODO: bakePath is required for finding the envType. 16 | // // for now assuming the command is executed in same dir as baker.yml 17 | // yargs.positional('VMName', { 18 | // describe: 'Name of the Baker VM', 19 | // type: 'string' 20 | // }); 21 | 22 | yargs.options( 23 | { 24 | useContainer: { 25 | describe: `Override environment type to use container`, 26 | demand: false, 27 | type: 'boolean' 28 | }, 29 | useVM: { 30 | describe: `Override environment type to use vm`, 31 | demand: false, 32 | type: 'boolean' 33 | } 34 | } 35 | ); 36 | } 37 | 38 | exports.handler = async function(argv) { 39 | let { useContainer, useVM } = argv; 40 | 41 | try { 42 | let bakePath = process.cwd(); 43 | const {envName, BakerObj} = await Baker.chooseProvider(bakePath, useContainer, useVM); 44 | 45 | await BakerObj.ssh(envName); 46 | 47 | //await Spinner.spinPromise(BakerObj.ssh(envName), `SSHing to ${envName}`, spinnerDot); 48 | } catch (err) { 49 | Print.error(err); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/commands/status.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | const child_process = require('child_process'); 3 | const Baker = require('../modules/baker'); 4 | const conf = require('../../lib/modules/configstore') 5 | const Print = require('../modules/print'); 6 | const Spinner = require('../modules/spinner'); 7 | const spinnerDot = conf.get('spinnerDot'); 8 | 9 | exports.command = 'status'; 10 | exports.desc = `Show status for all Baker VMs`; 11 | exports.handler = async function(argv) { 12 | 13 | try { 14 | // await Spinner.spinPromise(Baker.list(), `Getting status of Baker environments`, spinnerDot); 15 | let status = checkVirtualization(); 16 | console.log(`Virtualization support: ${status}`); 17 | if( status != "yes" ) 18 | { 19 | console.log("Please confirm you have virtualization enabled in your BIOS."); 20 | } 21 | await Baker.list(); 22 | } catch (err) { 23 | Print.error(err); 24 | } 25 | } 26 | 27 | function checkVirtualization() 28 | { 29 | let status = "unknown"; 30 | if( os.platform() == 'win32') 31 | { 32 | let output = child_process.execSync('systeminfo'); 33 | if( output && output.toString().indexOf("Virtualization Enabled In Firmware: Yes") != -1) 34 | { 35 | status = "yes"; 36 | } 37 | else { 38 | status = "no"; 39 | } 40 | } 41 | else if( os.platform() == 'darwin' ) 42 | { 43 | let output = child_process.execSync('sysctl -a | grep machdep.cpu.features'); 44 | if( output && output.toString().indexOf("VMX") != -1 ) 45 | { 46 | return "yes"; 47 | } 48 | else { 49 | status = "no"; 50 | } 51 | } 52 | return status; 53 | } 54 | -------------------------------------------------------------------------------- /lib/commands/up.js: -------------------------------------------------------------------------------- 1 | const Baker = require('../modules/baker'); 2 | const conf = require('../../lib/modules/configstore') 3 | const Print = require('../modules/print'); 4 | const Spinner = require('../modules/spinner'); 5 | 6 | const spinnerDot = conf.get('spinnerDot'); 7 | 8 | exports.command = ['start [VMName]', 'up [VMName]']; 9 | exports.desc = `start a VM`; 10 | 11 | exports.builder = (yargs) => { 12 | yargs 13 | .example(`$0 up`, `Start the Baker VM of current directory`) 14 | .example(`$0 up baker-test`, `Start 'baker-test' Baker VM`); 15 | 16 | // TODO: bakePath is required for finding the envType. 17 | // for now assuming the command is executed in same dir as baker.yml 18 | // yargs 19 | // .positional('VMName', { 20 | // describe: 'Name of the Baker VM to Start', 21 | // type: 'string' 22 | // }); 23 | } 24 | 25 | exports.handler = async function(argv) { 26 | let { envName, verbose } = argv; 27 | 28 | try{ 29 | let bakePath = process.cwd(); 30 | const {envName, BakerObj} = await Baker.chooseProvider(bakePath); 31 | 32 | await Spinner.spinPromise(BakerObj.start(envName, verbose), `Starting VM: ${envName}`, spinnerDot); 33 | } catch (err){ 34 | Print.error(err); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/commands/vault.js: -------------------------------------------------------------------------------- 1 | 2 | const Baker = require('../modules/baker'); 3 | const conf = require('../../lib/modules/configstore') 4 | const Print = require('../modules/print'); 5 | const Spinner = require('../modules/spinner'); 6 | 7 | const fs = require('fs'); 8 | const prompt = require('prompt'); 9 | 10 | const VaultLib = require('../modules/vault'); 11 | 12 | const spinnerDot = conf.get('spinnerDot'); 13 | 14 | exports.command = 'vault [file]'; 15 | exports.desc = `encrypt a file`; 16 | 17 | exports.builder = (yargs) => { 18 | yargs 19 | .example(`$0 vault secret.json`, `Encrypt the secret.json file with a passphrase`) 20 | .example(`$0 vault -v secret.json`, `View unencrypted content with passphrase`) 21 | .example(`$0 vault -u secret.json`, `Unencrypt content with passphrase`) 22 | .example(`$0 vault -c`, `Clear vault passphrase`) 23 | yargs 24 | .positional('file', { 25 | describe: 'file to encrypt', 26 | type: 'string' 27 | }); 28 | 29 | yargs.options({ 30 | clear: { 31 | alias: 'c', 32 | describe: `Clear vault passphrase`, 33 | demand: false, 34 | type: 'boolean' 35 | }, 36 | view: { 37 | alias: 'v', 38 | describe: `view unencrypted content with passphrase`, 39 | demand: false, 40 | type: 'boolean' 41 | }, 42 | decrypt: { 43 | alias: 'u', 44 | describe: `Unencrypt content with passphrase`, 45 | demand: false, 46 | type: 'boolean' 47 | }, 48 | }); 49 | 50 | 51 | } 52 | 53 | 54 | async function promptPass() 55 | { 56 | return new Promise(function(resolve,reject) 57 | { 58 | var properties = [ 59 | { 60 | name: 'password', 61 | hidden: true 62 | } 63 | ]; 64 | 65 | prompt.start(); 66 | 67 | prompt.get(properties, function (err, result) { 68 | if (err) { reject(err); } 69 | else 70 | { 71 | resolve(result.password) 72 | } 73 | }); 74 | }); 75 | } 76 | 77 | 78 | exports.handler = async function(argv) { 79 | let { envName, verbose } = argv; 80 | 81 | try{ 82 | // await Spinner.spinPromise(BakerObj.start(envName, verbose), `Starting VM: ${envName}`, spinnerDot); 83 | let passphraseKey = `vault:${process.cwd()}`; 84 | 85 | if( argv.clear ) 86 | { 87 | conf.delete(passphraseKey); 88 | return; 89 | } 90 | 91 | if( !fs.existsSync(argv.file) ) 92 | { 93 | throw new Error(`The provide file does not exist: ${argv.file}`) 94 | } 95 | 96 | if (!conf.has(passphraseKey)) 97 | { 98 | let typedPassphrase = await promptPass(); 99 | conf.set(passphraseKey, typedPassphrase); 100 | } 101 | 102 | let passphrase = conf.get(passphraseKey); 103 | let vault = new VaultLib(); 104 | 105 | if( argv.decrypt) 106 | { 107 | let content = vault.retrieve(argv.file, passphrase); 108 | console.log("Decrypting contents and writing to file.") 109 | fs.writeFileSync(argv.file, content); 110 | } 111 | else 112 | { 113 | if ( argv.view ) 114 | { 115 | let content = vault.retrieve(argv.file, passphrase); 116 | console.log("Viewing decrypted contents:") 117 | console.log(content); 118 | } 119 | else 120 | { 121 | vault.vault(argv.file, passphrase); 122 | } 123 | } 124 | 125 | } catch (err){ 126 | Print.error(err); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /lib/modules/configstore.js: -------------------------------------------------------------------------------- 1 | const Configstore = require('configstore'); 2 | const pkg = require('../../package.json'); 3 | const conf = new Configstore(pkg.name, {} , {globalConfigPath: true}); 4 | 5 | // setting defaults 6 | if (!conf.has('spinnerDot')) 7 | conf.set('spinnerDot', 'dots'); 8 | 9 | module.exports = conf; 10 | -------------------------------------------------------------------------------- /lib/modules/configuration/ansible.js: -------------------------------------------------------------------------------- 1 | const Promise = require('bluebird'); 2 | const Ssh = require('../ssh'); 3 | 4 | class Ansible { 5 | 6 | static async runAnsibleVault(doc, pass, dest, ansibleSSHConfig) { 7 | return new Promise( async (resolve, reject) => { 8 | let key = doc.bake.vault.checkout.key; 9 | await Ssh.sshExec(`cd /home/vagrant/baker/${doc.name} && echo "${pass}" > vault-pwd`, ansibleSSHConfig); 10 | await Ssh.sshExec(`cd /home/vagrant/baker/${doc.name} && ansible-playbook -e "vault=${doc.name}/baker-vault.yml key=${key} dest=${dest}" -i baker_inventory --vault-password-file=vault-pwd ../CheckoutFromVault.yml`, ansibleSSHConfig) 11 | //await sshExec(`cd /home/vagrant/baker/${doc.name} && echo "${pass}" > vault-pwd && ansible-vault view baker-vault.yml --vault-password-file=vault-pwd > checkout.key`, sshConfig); 12 | //await sshExec(`cd /home/vagrant/baker/${doc.name} && ansible all -i baker_inventory --private-key id_rsa -u ${vmSSHConfigUser.user} -m copy -a "src=checkout.key dest=${dest} mode=0600"`, sshConfig) 13 | await Ssh.sshExec(`cd /home/vagrant/baker/${doc.name} && rm vault-pwd`, ansibleSSHConfig) 14 | resolve(); 15 | }); 16 | } 17 | 18 | // TODO: Need to be cleaning cmd so they don't do things like 19 | // ; sudo rm -rf / on our server... 20 | static async runAnsiblePlaybook(doc, cmd, ansibleSSHConfig, verbose, variables) { 21 | let flatVars = {}; 22 | for (var i = 0; i < variables.length; i++) { 23 | for (var key in variables[i]) { 24 | flatVars[key] = variables[i][key]; 25 | } 26 | } 27 | let extravars = JSON.stringify(flatVars); 28 | //let extravars = yaml.dump(variables); 29 | if (verbose) console.log(extravars); 30 | // return Ssh.sshExec(`export ANSIBLE_HOST_KEY_CHECKING=false && cd /home/vagrant/baker/${doc.name} && ansible all -m ping -i baker_inventory`, ansibleSSHConfig, verbose); 31 | let output = await Ssh.sshExec(`export ANSIBLE_HOST_KEY_CHECKING=false && cd /home/vagrant/baker/${doc.name} && echo '${extravars}' > playbook.args.json && ansible-playbook -e @playbook.args.json -i baker_inventory ${cmd} ; rm -f playbook.args.json`, ansibleSSHConfig, 2000, verbose); 32 | // Can do in ansible 2.5 ... 33 | // export ANSIBLE_STDOUT_CALLBACK=yaml && 34 | 35 | // Perform error checking... 36 | let results = output.split('\n').filter(line => line.indexOf('ok=') >= 0 && line.indexOf('failed=') >= 0); 37 | if (results.length > 0) { 38 | let recapString = results[0]; 39 | if( recapString.indexOf("failed=0") == -1) 40 | { 41 | throw new Error(`A bakelet task failed, see output for details: \r\n ${output}`); 42 | } 43 | } 44 | else 45 | { 46 | throw new Error(`Failed to run bakelet, see output for details: \r\n ${output}`); 47 | } 48 | } 49 | 50 | static async runAnsibleAptInstall(doc, cmd, ansibleSSHConfig, verbose) { 51 | return Ssh.sshExec(`export ANSIBLE_HOST_KEY_CHECKING=false && cd /home/vagrant/baker/${doc.name} && ansible all -m apt -a "pkg=${cmd} update_cache=yes cache_valid_time=86400" -i baker_inventory --become`, ansibleSSHConfig, 20000, verbose); 52 | } 53 | 54 | static async runAnsiblePipInstall(doc, requirements, ansibleSSHConfig, verbose) { 55 | return Ssh.sshExec(`export ANSIBLE_HOST_KEY_CHECKING=false && cd /home/vagrant/baker/${doc.name} && ansible all -m pip -a "requirements=${requirements}" -i baker_inventory --become`, ansibleSSHConfig, 20000, verbose); 56 | } 57 | 58 | static async runAnsibleNpmInstall(doc, packagejson, ansibleSSHConfig, verbose) { 59 | return Ssh.sshExec(`export ANSIBLE_HOST_KEY_CHECKING=false && cd /home/vagrant/baker/${doc.name} && ansible all -m npm -a "path=${packagejson}" -i baker_inventory`, ansibleSSHConfig, 20000, verbose); 60 | } 61 | 62 | static async createDirectory(doc, dir, mode, ansibleSSHConfig, verbose) 63 | { 64 | return Ssh.sshExec(`export ANSIBLE_HOST_KEY_CHECKING=false && cd /home/vagrant/baker/${doc.name} && ansible all -m file -a "path=${dir} mode=${mode} state=directory" -i baker_inventory`, ansibleSSHConfig, 20000, verbose); 65 | } 66 | 67 | static async runAnsibleTemplateCmd(doc, src, dest, variables, ansibleSSHConfig, verbose) { 68 | let flatVars = {}; 69 | for( var i =0; i < variables.length; i++ ) 70 | { 71 | for( var key in variables[i] ) 72 | { 73 | flatVars[key] = variables[i][key]; 74 | } 75 | } 76 | let extravars = JSON.stringify(flatVars); 77 | //let extravars = yaml.dump(variables); 78 | return Ssh.sshExec(`export ANSIBLE_HOST_KEY_CHECKING=false && cd /home/vagrant/baker/${doc.name} && echo '${extravars}' > template.args.json && ansible all -m template -a "src=${src} dest=${dest}" -e @template.args.json -i baker_inventory; rm -f template.args.json`, ansibleSSHConfig, 20000, verbose); 79 | } 80 | 81 | } 82 | 83 | module.exports = Ansible; 84 | 85 | -------------------------------------------------------------------------------- /lib/modules/print.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | 3 | /** 4 | * printing cleaner and more uniform output messages 5 | */ 6 | class Print { 7 | constructor() {} 8 | 9 | /** 10 | * Bold red 11 | * @param {String} msg 12 | * @param {Integer} indentationCount number of \t before print 13 | */ 14 | static error(msg, indentationCount = 0) { 15 | console.log( 16 | chalk.bold.red(`${'\t'.repeat(indentationCount)}==> ${msg}`) 17 | ); 18 | }; 19 | 20 | /** 21 | * Amber 22 | * @param {String} msg 23 | * @param {Integer} indentationCount number of \t before print 24 | */ 25 | static warning(msg, indentationCount = 0) { 26 | console.log(chalk.yellow(`${'\t'.repeat(indentationCount)}==> ${msg}`)); 27 | }; 28 | 29 | /** 30 | * Green 31 | * @param {String} msg 32 | * @param {Integer} indentationCount number of \t before print 33 | */ 34 | static success(msg, indentationCount = 0) { 35 | console.log(chalk.green(`${'\t'.repeat(indentationCount)}==> ${msg}`)); 36 | }; 37 | 38 | /** 39 | * No formatting. White. 40 | * @param {String} msg 41 | * @param {Integer} indentationCount number of \t before print 42 | */ 43 | static info(msg, indentationCount = 0) { 44 | console.log(`${'\t'.repeat(indentationCount)}==> ${msg}`); 45 | }; 46 | 47 | /** 48 | * Bold 49 | * @param {String} msg 50 | * @param {Integer} indentationCount number of \t before print 51 | */ 52 | static bold(msg, indentationCount = 0) { 53 | console.log(chalk.bold(`${'\t'.repeat(indentationCount)}==> ${msg}`)); 54 | }; 55 | } 56 | 57 | module.exports = Print; 58 | -------------------------------------------------------------------------------- /lib/modules/providers/digitalocean.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const digitalocean = require('digitalocean'); 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | 6 | class DO_Provider { 7 | constructor(token, clusterDir) { 8 | this.token = token || process.env.DOTOKEN; 9 | if (!token) 10 | throw new Error("Must provide an API token for digital ocean"); 11 | this.client = digitalocean.client(this.token); 12 | 13 | this.clusterDir = clusterDir; 14 | this.clusterName = path.basename(clusterDir); 15 | this.prepareSSHKeyPair(clusterDir); 16 | } 17 | 18 | prepareSSHKeyPair(dir) { 19 | let privatePath = path.resolve(dir, 'id_rsa'); 20 | let publicPath = path.resolve(dir, 'id_rsa.pub'); 21 | if (fs.existsSync(privatePath) && fs.existsSync(publicPath)) 22 | return; 23 | child_process.execSync(`ssh-keygen -q -t rsa -f ${privatePath} -N ''`); 24 | } 25 | 26 | // Used to get facts about cluster. 27 | async info() { 28 | let nodes = await this.getDropletsByTag(this.clusterName); 29 | let privatePath = path.resolve(this.clusterDir, 'id_rsa'); 30 | let facts = []; 31 | for (var node of nodes) { 32 | facts.push({ 33 | host: node.name, 34 | port: '22', 35 | hostname: node.networks.v4[0].ip_address, 36 | user: 'root', 37 | private_key: privatePath 38 | }); 39 | } 40 | return facts; 41 | } 42 | 43 | async create(name) { 44 | var attributes = { 45 | name: name, 46 | region: 'nyc1', 47 | size: '1gb', 48 | image: 'ubuntu-16-04-x64', 49 | tags: [this.clusterName] 50 | }; 51 | 52 | let key = await this.getOrCreateSSHKeyId(); 53 | attributes.ssh_keys = [key.id]; 54 | 55 | let droplet = await this.getDropletFromName(name); 56 | if (droplet == null) 57 | return await this.createDroplet(attributes); 58 | return droplet; 59 | } 60 | 61 | async getDropletFromName(name) { 62 | let droplets = await this.client.droplets.list(); 63 | for (let droplet of droplets) { 64 | if (droplet.name === name) { 65 | return droplet; 66 | } 67 | } 68 | return null; 69 | } 70 | 71 | async getDropletsByTag(tag) { 72 | let droplets = await this.client.droplets.list(); 73 | let list = []; 74 | for (let droplet of droplets) { 75 | if (droplet.tags.includes(tag)) { 76 | list.push(droplet); 77 | } 78 | } 79 | return list; 80 | } 81 | 82 | 83 | async getOrCreateSSHKeyId() { 84 | let publicPath = path.resolve(this.clusterDir, 'id_rsa.pub'); 85 | let key = fs.readFileSync(publicPath).toString(); 86 | 87 | let output = child_process.execSync(`ssh-keygen -E md5 -lf ${publicPath}`).toString(); 88 | // let fingerprint = '2048 MD5:6e:55:af:d4:f4:ad:02:7e:45:0f:a9:03:4e:b6:ae:01 gameweld@cjparnin (RSA)'; 89 | let parts = output.split(/\s+/); 90 | if (parts.length < 2) { 91 | throw new Error(`Invalid ssh fingerprint ${output}`); 92 | } 93 | let fingerprint = parts[1].slice(4); 94 | 95 | console.log(`Looking for fingerprint ${fingerprint}`); 96 | 97 | let storedKey = null; 98 | try { 99 | storedKey = await this.client.account.getSshKey(fingerprint); 100 | } catch (err) { 101 | let attributes = { 102 | name: this.clusterName, 103 | public_key: key, 104 | } 105 | storedKey = await this.client.account.createSshKey(attributes); 106 | } 107 | return storedKey; 108 | } 109 | 110 | async getSSHConfig(nodeName) { 111 | let privatePath = path.resolve(this.clusterDir, 'id_rsa'); 112 | let droplet = await this.getDropletFromName(nodeName); 113 | let ip = droplet.networks.v4[0].ip_address; 114 | return { 115 | host: nodeName, 116 | port: '22', 117 | hostname: ip, 118 | user: 'root', 119 | private_key: privatePath 120 | }; 121 | } 122 | 123 | async createDroplet(attributes) { 124 | var self = this; 125 | // Poll for non-locked state every 10s 126 | let pollUntilDone = function (id, done) { 127 | self.client.droplets.get(id, function (err, droplet) { 128 | if (!err && droplet.locked === false) { 129 | // we're done! 130 | done.call(); 131 | } else if (!err && droplet.locked === true) { 132 | // back off 10s more 133 | setTimeout(function () { 134 | pollUntilDone(id, done); 135 | }, (10 * 1000)); 136 | } else { 137 | pollUntilDone(id, done); 138 | } 139 | }); 140 | } 141 | 142 | return new Promise(function (resolve, reject) { 143 | self.client.droplets.create(attributes, function (err, droplet) { 144 | if (err === null) { 145 | pollUntilDone(droplet.id, function () { 146 | console.log("We have a droplet: " + droplet.id + "!"); 147 | resolve(droplet); 148 | }); 149 | } else { 150 | console.log(err); 151 | reject(); 152 | } 153 | }); 154 | }); 155 | } 156 | 157 | } 158 | 159 | // let foo = async function () 160 | // { 161 | // let token = process.env.DOTOKEN; 162 | // let dir = path.join(require('os').homedir(), '.baker', 'crumbcluster'); 163 | 164 | // let doProvider = new DO_Provider(token,dir); 165 | // //let droplet = await doProvider.create('crumb-test4'); 166 | // //let key = await doProvider.getOrCreateSSHKeyId(); 167 | // //console.log( key.id ); 168 | 169 | // console.log( await doProvider.info() ); 170 | 171 | // }; 172 | // foo(); 173 | 174 | module.exports = DO_Provider; 175 | -------------------------------------------------------------------------------- /lib/modules/providers/provider.js: -------------------------------------------------------------------------------- 1 | const Ssh = require('../ssh'); 2 | 3 | class Provider { 4 | constructor() {} 5 | 6 | async setKnownHosts(ip, sshConfig) { 7 | return Ssh.sshExec(`cd /home/vagrant/baker/ && ansible-playbook -i "localhost," registerhost.yml -e "ip=${ip}" -c local`, sshConfig); 8 | } 9 | 10 | async mkTemplatesDir(doc, ansibleSSHConfig) { 11 | return Ssh.sshExec(`mkdir -p /home/vagrant/baker/${doc.name}/templates`, ansibleSSHConfig); 12 | } 13 | } 14 | 15 | module.exports = Provider; 16 | -------------------------------------------------------------------------------- /lib/modules/providers/remote.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | const path = require('path'); 3 | const Provider = require('./provider'); 4 | const Servers = new (require('../servers'))(); 5 | const Ssh = require('../ssh'); 6 | const Utils = require('../utils/utils'); 7 | const yaml = require('js-yaml'); 8 | 9 | const { bakeletsPath, remotesPath } = require('../../../global-vars'); 10 | 11 | const child_process = require('child_process'); 12 | 13 | class RemoteProvider extends Provider { 14 | /** 15 | * @param {String} username ssh username for the remote host 16 | * @param {String} privateKey ssh key for sshing to the remote host 17 | * @param {String} hostname ip address of the remote host 18 | * @param {String} port=22 ssh port 19 | */ 20 | constructor(user, private_key, hostname, port = 22) { 21 | super(); 22 | this.sshConfig = { 23 | user, 24 | private_key, 25 | hostname, 26 | port 27 | } 28 | } 29 | 30 | async bake(scriptPath, ansibleSSHConfig, verbose) { 31 | let doc = yaml.safeLoad(await fs.readFile(path.join(scriptPath, 'baker.yml'), 'utf8')); 32 | 33 | try { 34 | // TODO: copy the ssh key to ${ip}_rsa instead of id_rsa 35 | await Ssh.copyFromHostToVM( 36 | this.sshConfig.private_key, 37 | `/home/vagrant/baker/${doc.name}/${this.sshConfig.hostname}_rsa`, 38 | ansibleSSHConfig 39 | ); 40 | await Servers.addToAnsibleHosts(this.sshConfig.hostname, doc.name, ansibleSSHConfig, this.sshConfig); 41 | await this.setKnownHosts(this.sshConfig.hostname, ansibleSSHConfig); 42 | await this.mkTemplatesDir(doc, ansibleSSHConfig); 43 | 44 | // prompt for passwords 45 | if (doc.vars) { 46 | await Utils.traverse(doc.vars); 47 | } 48 | 49 | // Installing stuff. 50 | let resolveB = require('../../bakelets/resolve'); 51 | await resolveB.resolveBakelet(bakeletsPath, remotesPath, doc, scriptPath, verbose); 52 | 53 | } catch (err) { 54 | throw err; 55 | } 56 | } 57 | 58 | /** 59 | * ssh to the environment 60 | */ 61 | async ssh() { 62 | try { 63 | child_process.execSync(`ssh -i ${this.sshConfig.private_key} -o IdentitiesOnly=yes ${this.sshConfig.user}@${this.sshConfig.hostname}`, { 64 | stdio: ['inherit', 'inherit', 'inherit'] 65 | }); 66 | } catch (err) { 67 | throw err; 68 | } 69 | } 70 | 71 | /** 72 | * @param {String} bakePath path to the directory of baker.yml 73 | * @returns {Boolean} true if baker.yml is compatible with this provider, otherwise false 74 | */ 75 | static async validateBakerYML(bakePath) { 76 | let doc = yaml.safeLoad(await fs.readFile(path.join(bakePath, 'baker.yml'), 'utf8')); 77 | if (doc.remote && doc.remote.ip && doc.remote.user && doc.remote.private_key) 78 | return true; 79 | else 80 | return false; 81 | } 82 | 83 | getSSHConfig() { 84 | return this.sshConfig; 85 | } 86 | 87 | } 88 | 89 | module.exports = RemoteProvider; 90 | -------------------------------------------------------------------------------- /lib/modules/spinner.js: -------------------------------------------------------------------------------- 1 | const ora = require('ora'); 2 | 3 | class Spinner { 4 | constructor() {} 5 | 6 | static async spinPromise(promise, text, spinner, stream = process.stdout) { 7 | ora.promise(promise, { 8 | text: text, 9 | spinner: spinner, 10 | stream: stream 11 | // color: false, 12 | // enabled: true 13 | }); 14 | return promise; 15 | } 16 | } 17 | 18 | module.exports = Spinner; 19 | -------------------------------------------------------------------------------- /lib/modules/utils/git.js: -------------------------------------------------------------------------------- 1 | const git = require('simple-git'); 2 | const path = require('path'); 3 | 4 | class Git { 5 | constructor() {} 6 | 7 | static async clone(repoURL) { 8 | let name = path.basename(repoURL); 9 | name = name.slice(-4) === '.git' ? name.slice(0, -4) : name; // Removing .git from the end 10 | let dir = path.resolve(process.cwd()); 11 | 12 | return new Promise((resolve, reject) => { 13 | git(dir).silent(true).clone(repoURL, (err, data) => { 14 | if (err) 15 | reject(err); 16 | else 17 | resolve(path.join(dir, name)); 18 | }); 19 | }); 20 | } 21 | } 22 | 23 | module.exports = Git; 24 | -------------------------------------------------------------------------------- /lib/modules/utils/utils.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const Promise = require('bluebird'); 3 | const ping = require('ping') 4 | const prompt = require('prompt'); 5 | const md5File = require('md5-file/promise') 6 | const fs = require('fs-extra'); 7 | const _ = require('underscore'); 8 | const { envIndexPath } = require('../../../global-vars'); 9 | const hasbin = require('hasbin'); 10 | 11 | class Utils { 12 | constructor() {} 13 | 14 | /** 15 | * Private function: 16 | * Traverse yaml and do prompts 17 | */ 18 | static async traverse(o) { 19 | const stack = [{ obj: o, parent: null, parentKey: '' }]; 20 | 21 | while (stack.length) { 22 | const s = stack.shift(); 23 | const obj = s.obj; 24 | const parent = s.parent; 25 | const parentKey = s.parentKey; 26 | 27 | for (var i = 0; i < Object.keys(obj).length; i++) { 28 | let key = Object.keys(obj)[i]; 29 | 30 | //await fn(key, obj[key], obj) 31 | 32 | if (obj[key] instanceof Object) { 33 | stack.unshift({ obj: obj[key], parent: obj, parentKey: key }); 34 | } 35 | 36 | if (key == 'prompt') { 37 | const input = await this.promptValue(parentKey, obj[key]); 38 | // Replace "prompt" with an value provided by user. 39 | parent[parentKey] = input; 40 | } 41 | } 42 | } 43 | return o; 44 | } 45 | 46 | static async promptValue(propertyName, description, hidden=false) { 47 | return new Promise((resolve, reject) => { 48 | prompt.start(); 49 | prompt.get([{ name: propertyName, description: description, hidden:hidden }], function( 50 | err, 51 | result 52 | ) { 53 | if (err) { 54 | print.error(err); 55 | } 56 | //prompt.stop(); 57 | resolve(result[propertyName]); 58 | }); 59 | }); 60 | } 61 | 62 | static async hasbin(bin) 63 | { 64 | return new Promise(function(resolve, reject) 65 | { 66 | hasbin(bin, function(result ) 67 | { 68 | resolve(result); 69 | }); 70 | }); 71 | } 72 | 73 | static async hostIsAccessible(host) { 74 | return (await ping.promise.probe(host, {extra: ['-i 2']})).alive; 75 | } 76 | 77 | static async _ensureDir(path) { 78 | try { 79 | await fs.ensureDir(path); 80 | } catch (err) { 81 | throw `could not create directory: ${path} \n${err}`; 82 | } 83 | } 84 | 85 | static async initIndex(force = false) { 86 | if (!(await fs.pathExists(envIndexPath)) || force) { 87 | let envIndex = [] 88 | 89 | try { 90 | await fs.outputJson(envIndexPath, envIndex, {spaces: 4}); 91 | } catch (err) { 92 | console.error(err); 93 | } 94 | } 95 | } 96 | 97 | /** 98 | * 99 | * @param {String} type vm | container | DO 100 | * @param {Object} env 101 | */ 102 | static async addToIndex(name, path, type, info) { 103 | await this.initIndex(); 104 | try { 105 | let env = {name, path, type, info: _.pick(info, 'host', 'hostname', 'user', 'image', 'private_key', 'port')}; 106 | if(!(await this.FindInIndex(env.name))){ 107 | let envIndex = await fs.readJson(envIndexPath); 108 | envIndex.push(env); 109 | await fs.outputJson(envIndexPath, envIndex, {spaces: 4}); 110 | } 111 | } catch (err) { 112 | console.error(err); 113 | } 114 | } 115 | 116 | /** 117 | * Find and return the env object from index or return null if it doesn't exist 118 | * @param {String} name name of the environment 119 | */ 120 | static async FindInIndex(name) { 121 | await this.initIndex(); 122 | let envIndex = await fs.readJson(envIndexPath); 123 | return envIndex.find(e => e.name === name) || null; 124 | } 125 | 126 | static async removeFromIndex(name) { 127 | await this.initIndex(); 128 | let envIndex = await fs.readJson(envIndexPath); 129 | envIndex = envIndex.filter(e => e.name != name); 130 | await fs.outputJson(envIndexPath, envIndex, {spaces: 4}); 131 | } 132 | 133 | static async setEnvIndexState(name, state) { 134 | await this.initIndex(); 135 | let envIndex = await fs.readJson(envIndexPath); 136 | envIndex.forEach(env => { 137 | if(env.name === name) 138 | env.state = state; 139 | }) 140 | await fs.outputJson(envIndexPath, envIndex, {spaces: 4}); 141 | } 142 | 143 | static async getEnvIndex() { 144 | await this.initIndex(); 145 | return await fs.readJson(envIndexPath); 146 | } 147 | 148 | // adapted from http://procbits.com/2011/11/15/synchronous-file-copy-in-node-js 149 | static async copyFileSync (inFile, outDir, fileName, md5) { 150 | var outFile = path.join(outDir, fileName || path.basename(inFile)); 151 | 152 | if ((await fs.pathExists(outFile)) && (await md5File(outFile)) === md5) 153 | return; 154 | 155 | var BUF_LENGTH = 64 * 1024; 156 | 157 | var read; 158 | var write; 159 | 160 | var buffer = new Buffer.alloc(BUF_LENGTH); // new Buffer(BUF_LENGTH); 161 | 162 | var bytesRead = 1; 163 | var pos = 0; 164 | 165 | await fs.ensureDir(outDir); 166 | read = fs.openSync(inFile, 'r'); 167 | write = fs.openSync(outFile, 'w'); 168 | 169 | while (bytesRead > 0) { 170 | bytesRead = fs.readSync(read, buffer, 0, BUF_LENGTH, pos); 171 | fs.writeSync(write, buffer, 0, bytesRead); 172 | pos += bytesRead; 173 | } 174 | 175 | fs.closeSync(read); 176 | 177 | return fs.closeSync(write); 178 | }; 179 | 180 | } 181 | 182 | module.exports = Utils; 183 | -------------------------------------------------------------------------------- /lib/modules/validator.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | const hasbin = require('hasbin'); 3 | const path = require('path'); 4 | const print = require('./print'); 5 | const validator = require('validator'); 6 | const yaml = require('js-yaml'); 7 | 8 | class Validator { 9 | constructor() {} 10 | 11 | static async validateDependencies () { 12 | let platform = process.platform; 13 | let dependencyNotFound = 'Dependencies not found. Make sure you have installed VirtualBox and Vagrant.'; 14 | 15 | if (platform == 'darwin' || platform === 'linux') { 16 | hasbin.all( ['vagrant', 'virtualbox'], hasDependencies => { 17 | if(hasDependencies) return true; 18 | else{ 19 | // throw dependencyNotFound; 20 | print.warning(dependencyNotFound, 1) 21 | return true; 22 | } 23 | 24 | }); 25 | } 26 | else { 27 | hasbin('vagrant', async function (hasVagrant) { 28 | if(hasVagrant){ 29 | fs.access(path.resolve(path.join(process.env.PROGRAMFILES, `/Oracle/VirtualBox`)), err => { 30 | if (err) { 31 | // throw dependencyNotFound; 32 | print.warning(dependencyNotFound, 1); 33 | return true; 34 | } 35 | }); 36 | } else { 37 | // throw dependencyNotFound; 38 | print.warning(dependencyNotFound, 1) 39 | return true; 40 | } 41 | }); 42 | } 43 | } 44 | 45 | static async validateBakerScript (bakerScriptPath) { 46 | let doc; 47 | try { 48 | doc = yaml.safeLoad( 49 | await fs.readFile(path.join(bakerScriptPath, 'baker.yml'), 'utf8') 50 | ); 51 | } catch (error) { 52 | // print.error(`baker.yml error: Couldn't parse baker.yml:`, 1); 53 | // print.error(error, 1); 54 | // process.exit(1); 55 | throw `baker.yml error: Couldn't parse baker.yml: ${error}` 56 | } 57 | 58 | let passed = true; 59 | 60 | if (!doc.name) { 61 | // print.error( 62 | // 'baker.yml error: You need to provide a name for your VM.', 63 | // 1 64 | // ); 65 | passed = false; 66 | throw 'baker.yml error: You need to provide a name for your VM.'; 67 | } 68 | 69 | if (!doc.vagrant) { 70 | // print.error( 71 | // 'baker.yml error: You need to specify your VM configurations.', 72 | // 1 73 | // ); 74 | passed = false; 75 | throw 'baker.yml error: You need to specify your VM configurations.'; 76 | } 77 | 78 | if (!doc.vagrant.box) { 79 | // print.error( 80 | // `baker.yml error: You need to specify what vagrant box you want Baker to use for your VM.`, 81 | // 1 82 | // ); 83 | // print.error( 84 | // `If you're not sure, we suggest using ubuntu/trusty64`, 85 | // 2 86 | // ); 87 | passed = false; 88 | throw `baker.yml error: You need to specify what vagrant box you want Baker to use for your VM.`; 89 | } 90 | 91 | if (!doc.vagrant.memory) { 92 | // print.error( 93 | // 'baker.yml error: You need to specify how much RAM you want Baker to share with your VM.', 94 | // 1 95 | // ); 96 | passed = false; 97 | throw 'baker.yml error: You need to specify how much RAM you want Baker to share with your VM.'; 98 | } else if (doc.vagrant.memory > 2048) { 99 | print.warning( 100 | `baker.yml warning: Sharing big amounts of RAM with your VM can possibly slow down your computer.`, 101 | 1 102 | ); 103 | //throw `baker.yml warning: Sharing big amounts of RAM with your VM can possibly slow down your computer.`; 104 | } 105 | 106 | if ( 107 | !doc.vagrant.network || 108 | !doc.vagrant.network.some( 109 | network => network.private_network != undefined 110 | ) 111 | ) { 112 | // print.error( 113 | // 'baker.yml error: You need to create a private network for Baker to use for communicating with your VM.', 114 | // 1 115 | // ); 116 | passed = false; 117 | throw 'baker.yml error: You need to create a private network for Baker to use for communicating with your VM.'; 118 | } else if ( 119 | !doc.vagrant.network.some(network => 120 | network.private_network && validator.isIP(network.private_network.ip) 121 | ) 122 | ) { 123 | // print.error( 124 | // `baker.yml error: Private network doesn't have a valid IP address`, 125 | // 1 126 | // ); 127 | passed = false; 128 | throw `baker.yml error: Private network doesn't have a valid IP address`; 129 | } 130 | 131 | if (!passed) { 132 | // print.error( 133 | // 'Use `baker --init` to create a baker.yml which you can then update for your project.', 134 | // 2 135 | // ); 136 | // process.exit(1); 137 | throw 'Use `baker --init` to create a baker.yml which you can then update for your project.'; 138 | } else { 139 | // print.success('baker.yml passed validation', 1); 140 | return; 141 | } 142 | } 143 | } 144 | 145 | module.exports = Validator; 146 | -------------------------------------------------------------------------------- /lib/modules/vault.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const conf = require('./configstore') 5 | 6 | const {version} = require('../../global-vars') 7 | 8 | class VaultLib { 9 | constructor() 10 | { 11 | this.iv = crypto.randomBytes(16); 12 | this.algorithm = 'aes-256-ctr'; 13 | this.salt = Buffer.from('5ebe2294ecd0e0f', 'hex'); 14 | this.headerRegex = /baker-vault:\d+[.]\d+[.]\d+:[0-9A-Fa-f]{15}/g; 15 | } 16 | 17 | setVaultPass(bakePath, pass) 18 | { 19 | let passphraseKey = `vault:${bakePath}`; 20 | conf.set(passphraseKey, pass); 21 | } 22 | 23 | isEncrypted(filePath) 24 | { 25 | let lines = fs.readFileSync(filePath).toString().split(/\r?\n/); 26 | if( lines.length > 0 ) 27 | { 28 | let matches = lines[0].match( this.headerRegex ); 29 | return matches != null; 30 | } 31 | return false; 32 | } 33 | 34 | vault(filePath, passphrase) 35 | { 36 | if( this.isEncrypted(filePath) ) 37 | { 38 | throw new Error(`File is already encrypted: ${filePath}`); 39 | } 40 | 41 | let key = this.generateKeyFromPhrase(passphrase); 42 | let content = fs.readFileSync(filePath); 43 | let shasum = crypto.createHash('sha512'); 44 | shasum.update(content); 45 | let buffer = `baker-vault:${version}:${this.iv.toString('hex')}:${shasum.digest('hex')}\n`; 46 | buffer += this.encryptWithKey(content, key, this.iv); 47 | 48 | fs.writeFileSync(filePath, buffer); 49 | 50 | return key.toString('hex'); 51 | } 52 | 53 | retrieve(filePath, passphrase) 54 | { 55 | if( this.isEncrypted(filePath) ) 56 | { 57 | let lines = fs.readFileSync(filePath).toString().split(/\r?\n/); 58 | let key = this.generateKeyFromPhrase(passphrase); 59 | let iv = Buffer.from(lines[0].split(':')[2],'hex'); 60 | let sha = lines[0].split(':')[3]; 61 | let recovered = this.decryptWithKey(lines[1],key,iv); 62 | 63 | let shasum = crypto.createHash('sha512'); 64 | shasum.update(recovered); 65 | 66 | if( sha == shasum.digest('hex') ) 67 | { 68 | return recovered; 69 | } 70 | throw new Error("Incorrect vault password supplied.") 71 | } 72 | throw new Error(`File is not encrypted: ${filePath}`); 73 | } 74 | 75 | encryptWithKey(text, key, iv) { 76 | let cipher = crypto.createCipheriv(this.algorithm, key, iv ) 77 | let crypted = cipher.update(text,'utf8','hex') 78 | crypted += cipher.final('hex'); 79 | return crypted; 80 | } 81 | 82 | generateKeyFromPhrase(passphrase) 83 | { 84 | return crypto.pbkdf2Sync(passphrase, this.salt, 100000, 32, 'sha512'); 85 | } 86 | 87 | decryptWithKey(text, key, iv) 88 | { 89 | let decipher = crypto.createDecipheriv(this.algorithm, key, iv) 90 | let dec = decipher.update(text,'hex','utf8') 91 | dec += decipher.final('utf8'); 92 | return dec; 93 | } 94 | } 95 | 96 | module.exports = VaultLib; 97 | 98 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baker", 3 | "version": "0.7.2", 4 | "description": "baker creates ansible powered virtual machines", 5 | "engines": { 6 | "node": ">=7.10.0" 7 | }, 8 | "main": "baker.js", 9 | "scripts": { 10 | "test": "mocha test/bake/*.js", 11 | "int-test": "mocha test/integration/*.js", 12 | "commit": "git-cz", 13 | "release": "standard-version", 14 | "build-macos": "pkg --targets node10-macos-x64 --output ./installers/macos/bin/baker ./package.json", 15 | "build-win": "pkg --targets node10-win-x64 --output ./installers/win/bin/baker.exe ./package.json", 16 | "build-linux": "pkg --targets node10-linux-x64 --output ./installers/linux/executable/baker ./package.json", 17 | "package-macos": "npm run build-macos && ./installers/macos/package.sh", 18 | "package-linux": "npm run build-linux && cp ./installers/linux/executable/baker ./installers/linux/deb-template/baker/usr/bin/baker && dpkg --build installers/linux/deb-template/baker && mv ./installers/linux/deb-template/baker.deb ./installers/linux/deb/" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/ottomatica/Baker.git" 23 | }, 24 | "keywords": [ 25 | "baker", 26 | "ansible", 27 | "configuration" 28 | ], 29 | "author": "Ottomatica", 30 | "license": "Apache-2.0", 31 | "bugs": { 32 | "url": "https://github.com/ottomatica/Baker/issues" 33 | }, 34 | "homepage": "https://getbaker.io/", 35 | "dependencies": { 36 | "bluebird": "^3.7.2", 37 | "chalk": "^3.0.0", 38 | "configstore": "^5.0.1", 39 | "console.table": "^0.10.0", 40 | "digitalocean": "^1.1.1", 41 | "dockerode": "^3.1.0", 42 | "download": "^7.1.0", 43 | "fs-extra": "^8.1.0", 44 | "hasbin": "^1.2.3", 45 | "inquirer": "^7.0.4", 46 | "js-yaml": "^3.13.1", 47 | "jsonfile": "^5.0.0", 48 | "md5-file": "^4.0.0", 49 | "mustache": "^4.0.0", 50 | "netaddr": "^1.1.0", 51 | "node-powershell": "^4.0.0", 52 | "node-vagrant": "^1.4.0", 53 | "node-virtualbox": "^0.2.3", 54 | "ora": "^4.0.3", 55 | "ping": "^0.2.2", 56 | "prompt": "^1.0.0", 57 | "request": "^2.88.2", 58 | "scp2": "^0.5.0", 59 | "simple-git": "^1.131.0", 60 | "slash": "^3.0.0", 61 | "ssh2": "^0.8.7", 62 | "underscore": "^1.9.2", 63 | "validator": "^12.2.0", 64 | "yargs": "^15.1.0" 65 | }, 66 | "pkg": { 67 | "assets": [ 68 | "config/**", 69 | "remotes", 70 | "node_modules/node-virtualbox/config/**" 71 | ], 72 | "scripts": "lib/**" 73 | }, 74 | "bin": "baker.js", 75 | "devDependencies": { 76 | "chai": "^4.1.2", 77 | "commitizen": "^4.0.3", 78 | "cz-conventional-changelog": "^3.1.0", 79 | "grunt": "^1.0.4", 80 | "innosetup-compiler": "^5.6.1", 81 | "mocha": "^7.0.1", 82 | "pkg": "^4.4.3", 83 | "standard-version": "^7.1.0" 84 | }, 85 | "config": { 86 | "commitizen": { 87 | "path": "./node_modules/cz-conventional-changelog" 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /remotes/bakelets-source/README.md: -------------------------------------------------------------------------------- 1 | # Bakelets 2 | 3 | Repository for storing scripts, roles, and playbooks 4 | 5 | 6 | ### Development 7 | 8 | To add as a subtree to baker. 9 | 10 | ``` 11 | git remote add bakelets-source https://github.com/ottomatica/bakelets-source.git 12 | ``` 13 | 14 | To update the subtree. 15 | ``` 16 | git subtree pull --prefix src/remotes/bakelets-source/ bakelets-source master 17 | ``` 18 | 19 | If there is no subtree present (e.g. first time): 20 | ``` 21 | git subtree add --prefix src/remotes/bakelets-source/ bakelets-source master 22 | ``` 23 | -------------------------------------------------------------------------------- /remotes/bakelets-source/config/keys.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | 4 | tasks: 5 | - name: ensure keys directory exists 6 | file: 7 | path: /keys 8 | owner: "{{ansible_user}}" 9 | mode: 0700 10 | state: directory 11 | become: yes 12 | 13 | # Passed in from extra-vars 14 | - name: copy client keys 15 | copy: 16 | src: "{{item}}" 17 | dest: "/keys/{{item}}" 18 | mode: 0600 19 | with_items: "{{baker_client_keys}}" 20 | -------------------------------------------------------------------------------- /remotes/bakelets-source/env/env.yml.mustache: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: yes 4 | 5 | tasks: 6 | {{#env}} 7 | - name: Adding the path in the bashrc files 8 | lineinfile: 9 | dest: /etc/environment 10 | line: 'export {{KEY}}={{VALUE}}' 11 | insertafter: 'EOF' 12 | state: present 13 | 14 | {{/env}} 15 | -------------------------------------------------------------------------------- /remotes/bakelets-source/lang/R/r.yml.mustache: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: yes 4 | 5 | tasks: 6 | - name: Ensure apt-transport-https is installed. 7 | apt: name=apt-transport-https state=present 8 | 9 | - name: Add R deb package 10 | apt_repository: 11 | repo: "deb https://cran.rstudio.com/bin/linux/ubuntu {{=<% %>=}}{{ ansible_distribution_release }}<%={{ }}=%>/" 12 | state: present 13 | become: yes 14 | 15 | - name: Ensure the R apt repository key is present 16 | apt_key: 17 | id=E084DAB9 18 | keyserver=keyserver.ubuntu.com 19 | state=present 20 | become: yes 21 | 22 | - name: Ensure r-base is installed. 23 | apt: 24 | pkg: r-base 25 | force: yes 26 | state: latest 27 | cache_valid_time: 3600 28 | update_cache: yes 29 | become: yes 30 | 31 | - name: Build-essentials often needed for r-packages 32 | apt: pkg=build-essential state=present 33 | become: yes 34 | 35 | {{#cran}} 36 | - name: Install some r packages 37 | command: Rscript -e "install.packages(c({{{packages}}}), repos='https://cran.rstudio.com/')" 38 | become: yes 39 | {{/cran}} 40 | -------------------------------------------------------------------------------- /remotes/bakelets-source/lang/java/java8.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: yes 4 | 5 | tasks: 6 | - name: Add public key of ppa.launchpand.net 7 | command: apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C2518248EEA14886 8 | 9 | - name: add repo for java 8 10 | apt_repository: repo='ppa:webupd8team/java' state=present 11 | 12 | - name: agree to license 13 | debconf: name='oracle-java8-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select' 14 | 15 | - name: install java 8 16 | apt: name=oracle-java8-installer state=latest update-cache=yes force=yes 17 | -------------------------------------------------------------------------------- /remotes/bakelets-source/lang/nodejs/nodejs13.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: yes 4 | 5 | tasks: 6 | - name: Ensure apt-transport-https is installed. 7 | apt: name=apt-transport-https state=present 8 | 9 | - name: Add Nodesource apt key. 10 | apt_key: 11 | url: https://deb.nodesource.com/gpgkey/nodesource.gpg.key 12 | state: present 13 | 14 | - name: Add NodeSource repositories for Node.js. 15 | apt_repository: 16 | repo: "{{ item }}" 17 | state: present 18 | with_items: 19 | - "deb https://deb.nodesource.com/node_13.x {{ ansible_distribution_release }} main" 20 | - "deb-src https://deb.nodesource.com/node_13.x {{ ansible_distribution_release }} main" 21 | 22 | - name: Install Node.js 23 | become: yes 24 | apt: 25 | pkg: "{{item}}" 26 | state: latest 27 | update_cache: yes 28 | with_items: 29 | - nodejs 30 | - build-essential 31 | -------------------------------------------------------------------------------- /remotes/bakelets-source/lang/nodejs/nodejs9.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: yes 4 | 5 | tasks: 6 | - name: Ensure apt-transport-https is installed. 7 | apt: name=apt-transport-https state=present 8 | 9 | - name: Add Nodesource apt key. 10 | apt_key: 11 | url: https://deb.nodesource.com/gpgkey/nodesource.gpg.key 12 | state: present 13 | 14 | - name: Add NodeSource repositories for Node.js. 15 | apt_repository: 16 | repo: "{{ item }}" 17 | state: present 18 | with_items: 19 | - "deb https://deb.nodesource.com/node_9.x {{ ansible_distribution_release }} main" 20 | - "deb-src https://deb.nodesource.com/node_9.x {{ ansible_distribution_release }} main" 21 | 22 | - name: Install Node.js 23 | become: yes 24 | apt: 25 | pkg: "{{item}}" 26 | state: latest 27 | update_cache: yes 28 | with_items: 29 | - nodejs 30 | - build-essential 31 | -------------------------------------------------------------------------------- /remotes/bakelets-source/lang/python/python2.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | tasks: 3 | 4 | - name: Install basic utils and build envs. 5 | apt: pkg={{ item }} state=present 6 | with_items: 7 | - git 8 | - unzip 9 | - vim 10 | - build-essential 11 | become: yes 12 | 13 | - name: Install required system packages. 14 | apt: pkg={{ item }} state=present 15 | with_items: 16 | - python-dev 17 | - python-pip 18 | - python-setuptools 19 | become: yes 20 | 21 | - name: Set python as default python using alternatives 22 | alternatives: 23 | name: python 24 | link: /usr/bin/python 25 | path: /usr/bin/python2 26 | become: yes 27 | 28 | # - name: Upgrade pip 29 | # pip: 30 | # name: pip 31 | # executable: pip2 32 | # extra_args: --upgrade --user 33 | # version: 18 34 | 35 | # # long story: https://github.com/pypa/pip/issues/5240 36 | # - name: Remove old pip 37 | # file: 38 | # state: absent 39 | # path: "/usr/bin/pip" 40 | # become: yes 41 | 42 | # - name: Create symbolic link 43 | # file: 44 | # src: "{{ansible_env.HOME}}/.local/bin/pip" 45 | # dest: /usr/bin/pip 46 | # state: link 47 | # become: yes 48 | 49 | # - name: Set pip as default pip using alternatives 50 | # alternatives: 51 | # name: pip 52 | # link: /usr/bin/pip 53 | # path: "{{ansible_env.HOME}}/.local/bin/pip" 54 | # priority: 1000 55 | # become: yes 56 | 57 | - name: fetch fix pip script 58 | get_url: 59 | url: https://bootstrap.pypa.io/get-pip.py 60 | dest: /tmp/get-pip.py 61 | 62 | - name: fix pip 63 | shell: python /tmp/get-pip.py --force-reinstall 64 | become: yes 65 | 66 | - stat: path="{{BAKER_SHARE_DIR}}/requirements.txt" 67 | register: file_exists 68 | 69 | - name: Install the project requirements 70 | pip: 71 | state: present 72 | executable: /usr/local/bin/pip 73 | requirements: "{{BAKER_SHARE_DIR}}/requirements.txt" 74 | when: file_exists.stat.exists == True 75 | become: yes 76 | -------------------------------------------------------------------------------- /remotes/bakelets-source/lang/python/python3.6.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | become: yes 3 | tasks: 4 | 5 | - name: Install basic utils and build envs. 6 | apt: pkg={{ item }} state=present 7 | with_items: 8 | - git 9 | - unzip 10 | - vim 11 | - build-essential 12 | 13 | - name: add ppa for python 3.6 14 | apt_repository: repo='ppa:deadsnakes/ppa' state=present 15 | 16 | - name: Install required system packages. 17 | apt: pkg={{ item }} state=present 18 | with_items: 19 | - python3.6 20 | - python3.6-dev 21 | - python3.6-venv 22 | 23 | - name: Set python3.6 as default python using alternatives 24 | alternatives: 25 | name: python 26 | link: /usr/bin/python 27 | path: /usr/bin/python3.6 28 | 29 | - name: Get pip 30 | get_url: 31 | url: https://bootstrap.pypa.io/get-pip.py 32 | dest: /tmp/get-pip.py 33 | 34 | - name: Install pip3.6 35 | become: yes 36 | command: python3.6 /tmp/get-pip.py 37 | 38 | - name: Set pip3.6 as default pip using alternatives 39 | alternatives: 40 | name: pip 41 | link: /usr/bin/pip 42 | path: /usr/local/bin/pip3.6 43 | 44 | - name: Upgrade pip 45 | pip: 46 | name: pip 47 | executable: pip3.6 48 | extra_args: --upgrade 49 | 50 | - stat: path="{{BAKER_SHARE_DIR}}/requirements.txt" 51 | register: file_exists 52 | 53 | - name: Install the project requirements 54 | pip: 55 | state: present 56 | executable: pip3.6 57 | requirements: "{{BAKER_SHARE_DIR}}/requirements.txt" 58 | when: file_exists.stat.exists == True 59 | -------------------------------------------------------------------------------- /remotes/bakelets-source/lang/python/python3.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | become: yes 3 | tasks: 4 | 5 | - name: Install basic utils and build envs. 6 | apt: pkg={{ item }} state=present 7 | with_items: 8 | - git 9 | - unzip 10 | - vim 11 | - build-essential 12 | 13 | - name: Install required system packages. 14 | apt: pkg={{ item }} state=present 15 | with_items: 16 | - python3-dev 17 | - python3-pip 18 | - python3-setuptools 19 | 20 | - name: Set python3 as default python using alternatives 21 | alternatives: 22 | name: python 23 | link: /usr/bin/python 24 | path: /usr/bin/python3 25 | 26 | - name: Set pip3 as default pip using alternatives 27 | alternatives: 28 | name: pip 29 | link: /usr/bin/pip 30 | path: /usr/bin/pip3 31 | 32 | - name: Upgrade pip 33 | pip: 34 | name: pip 35 | executable: pip3 36 | extra_args: --upgrade 37 | 38 | - stat: path="{{BAKER_SHARE_DIR}}/requirements.txt" 39 | register: file_exists 40 | 41 | - name: Install the project requirements 42 | pip: 43 | state: present 44 | executable: pip3 45 | requirements: "{{BAKER_SHARE_DIR}}/requirements.txt" 46 | when: file_exists.stat.exists == True 47 | -------------------------------------------------------------------------------- /remotes/bakelets-source/packages/apt.yml.mustache: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: yes 4 | 5 | tasks: 6 | {{#packages.default}} 7 | - name: Ensure {{{name}}} is installed. 8 | apt: 9 | pkg: {{{name}}} 10 | force: yes 11 | state: latest 12 | cache_valid_time: 3600 13 | update_cache: yes 14 | become: yes 15 | 16 | {{/packages.default}} 17 | {{#packages.deb}} 18 | - name: Ensure {{{name}}} is installed 19 | apt: 20 | deb: {{{deb}}} 21 | 22 | {{/packages.deb}} 23 | 24 | {{#packages.ppa}} 25 | {{/packages.ppa}} 26 | -------------------------------------------------------------------------------- /remotes/bakelets-source/services/docker/docker.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: yes 4 | 5 | tasks: 6 | - name: Disable Firewall 7 | service: name=ufw state=stopped 8 | 9 | - name: Install HTTPS Apt Packages 10 | apt: name={{ item }} update_cache=yes 11 | with_items: 12 | - apt-transport-https 13 | - ca-certificates 14 | - curl 15 | - software-properties-common 16 | 17 | - name: Add Docker GPG Key 18 | apt_key: url=https://download.docker.com/linux/ubuntu/gpg state=present 19 | 20 | - name: Add Docker Repository 21 | apt_repository: 22 | repo="deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" 23 | state=present 24 | 25 | - name: Install Docker CE 26 | apt: name=docker-ce state=present update_cache=yes 27 | 28 | - name: Enable Docker at Startup 29 | service: name=docker state=started enabled=yes 30 | 31 | - name: add user mod to docker 32 | command: usermod -aG docker {{ ansible_user }} -------------------------------------------------------------------------------- /remotes/bakelets-source/services/mongodb/mongodb3.6.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | 4 | tasks: 5 | - name: add an apt key of MongoDB 6 | become: yes 7 | apt_key: 8 | keyserver: keyserver.ubuntu.com 9 | # url: https://www.mongodb.org/static/pgp/server-3.6.asc 10 | id: 91FA4AD5 11 | state: present 12 | 13 | # - name: create list file for MongoDB 14 | # command: echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.6 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.6.list 15 | 16 | - name: create list file for MongoDB 17 | become: yes 18 | apt_repository: 19 | repo: deb https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.6 multiverse 20 | state: present 21 | 22 | - name: Install mongodb 23 | become: yes 24 | apt: 25 | pkg: "{{item}}" 26 | state: latest 27 | update_cache: yes 28 | with_items: 29 | - libssl1.0.0 30 | - mongodb-org-server 31 | 32 | - name: ensure mongodb is running and starts on boot 33 | service: name=mongod state=restarted enabled=true 34 | become: yes 35 | 36 | - name: Installing Python-Pip 37 | apt: 38 | pkg: python-pip 39 | state: latest 40 | 41 | - name: Install the latest pymongo package 42 | pip: name=pymongo state=latest use_mirrors=no 43 | -------------------------------------------------------------------------------- /remotes/bakelets-source/services/mysql/mysql5.7.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | vars: 4 | - root_db_password: "{{mysql_password}}" 5 | 6 | tasks: 7 | - name: Try to specify preference for mysql 8 | shell: echo mysql-apt-config mysql-apt-config/select-server select mysql-5.7 | debconf-set-selections 9 | become: yes 10 | 11 | # Download mysql debian package 12 | - name: Add mysql apt-config debian 13 | apt: deb=http://dev.mysql.com/get/mysql-apt-config_0.8.1-1_all.deb update-cache=yes cache_valid_time=86400 14 | become: yes 15 | 16 | # Basic nice dev stuff 17 | - name: Install required system packages. 18 | apt: pkg={{ item }} state=present 19 | with_items: 20 | - python-dev 21 | - python-pip 22 | - debconf-utils 23 | become: yes 24 | 25 | # For 5.7, password is required during install. Normally, this is prompted by an interactive script. 26 | # But by populating the debconf database, we can setup a password that gets asked during install. 27 | - name: Mysql | Set root password 28 | shell: echo mysql-server mysql-server/root_password password {{root_db_password}} | debconf-set-selections 29 | become: yes 30 | 31 | - name: Mysql | Set root repassword 32 | shell: echo mysql-server mysql-server/root_password_again password {{root_db_password}} | debconf-set-selections 33 | become: yes 34 | 35 | # There is a module that also allows this to work. 36 | # Doing a different set of question keys, which seems to be the updated question key. 37 | # https://gist.github.com/fideloper/e774cb62d8be28da8a93 38 | - name: Set root Password 39 | debconf: 40 | name: mysql-community-server 41 | question: 'mysql-community-server/root-pass' 42 | value: '{{ root_db_password }}' # Set as a variable 43 | vtype: password 44 | become: yes 45 | 46 | - name: Set root Password Again 47 | debconf: 48 | name: mysql-community-server 49 | question: 'mysql-community-server/re-root-pass' 50 | value: '{{ root_db_password }}' # Set as a variable 51 | vtype: password 52 | become: yes 53 | 54 | # https://bugs.mysql.com/bug.php?id=85029 55 | - name: Update mysql key 56 | command: apt-key adv --keyserver pgp.mit.edu --recv-keys 5072E1F5 57 | become: yes 58 | 59 | # Test to see if we should skip next step (optimization for rebaking) 60 | - stat: path=/usr/bin/mysql 61 | register: file_exists 62 | 63 | # Install mysql 64 | #dpkg_options="force-confnew" 65 | - name: Install mysql components 66 | apt: pkg={{ item }} state=latest allow_unauthenticated=yes update_cache=true cache_valid_time=86400 67 | with_items: 68 | - mysql-server 69 | - mysql-client 70 | - libmysqlclient-dev 71 | - python3-mysqldb 72 | become: yes 73 | when: file_exists.stat.exists == False 74 | 75 | - name: Copy my.cnf settings 76 | template: src=templates/mysql.cfg dest=/etc/mysql/mysql.conf.d/mysqld.cnf 77 | become: yes 78 | 79 | # https://stackoverflow.com/questions/14087598/python-3-importerror-no-module-named-configparser 80 | # - name: Install the Python MySQLB module (needed for mysql_user) 81 | # # pip: name=MySQL-python 82 | # pip: name=mysqlclient executable=pip3 83 | # become: yes 84 | 85 | - name: Install the Python MySQLB module 86 | pip: name=MySQL-python executable=pip 87 | become: yes 88 | 89 | - name: ensure mysql is running and starts on boot 90 | service: name=mysql state=restarted enabled=true 91 | become: yes 92 | 93 | - name: For chroot, start a service manually since systemd will perform NOP. 94 | shell: /etc/init.d/mysql start 95 | become: yes 96 | 97 | - name: update mysql root password for all root accounts 98 | mysql_user: name=root 99 | password="{{ root_db_password }}" 100 | check_implicit_admin=yes 101 | login_user=root 102 | login_password="{{root_db_password}}" 103 | state=present 104 | 105 | # Need to do this for idempotency, see 106 | # http://ansible.cc/docs/modules.html#mysql-user 107 | - name: copy .my.cnf file with mysql root password credentials 108 | #template: src=templates/root/.my.cnf dest=/root/.my.cnf owner=root mode=0600 109 | template: src=templates/my.cnf dest={{ ansible_env.HOME}}/.my.cnf mode=0600 110 | 111 | - name: update mysql root password for all root accounts on {{ inventory_hostname }} 112 | mysql_user: name=root host={{ item }} password={{ root_db_password }} priv=*.*:ALL login_user=root login_password={{root_db_password}} 113 | with_items: 114 | # - localhost 115 | # IPV6 localhost 116 | - ::1 117 | # IP address of server 118 | - "{{ inventory_hostname }}" 119 | - '%' 120 | 121 | # - name: update mysql root password for all root accounts on {{ inventory_hostname }} 122 | # mysql_user: 123 | # name: root 124 | # host: '%' 125 | # password: "{{ root_db_password }}" 126 | # login_user: root 127 | # login_password: "{{root_db_password}}" 128 | 129 | - name: ensure anonymous users are not in the database 130 | mysql_user: name='' host={{ item }} state=absent 131 | with_items: 132 | - localhost 133 | - ::1 134 | - "{{ inventory_hostname }}" 135 | 136 | - name: remove the test database 137 | mysql_db: name=test state=absent 138 | -------------------------------------------------------------------------------- /remotes/bakelets-source/services/neo4j/neo4j.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | 4 | vars: 5 | - neo4j_initial_password: "{{neo4j_password}}" 6 | 7 | handlers: 8 | 9 | - name: Restart Neo4J 10 | become: yes 11 | service: name=neo4j state=restarted enabled=yes 12 | 13 | tasks: 14 | 15 | - name: Check for Neo4J 16 | stat: 17 | path: /usr/bin/neo4j 18 | register: neo4j_check 19 | 20 | - name: Add Neo4J Key 21 | become: yes 22 | apt_key: 23 | url: http://debian.neo4j.org/neotechnology.gpg.key 24 | state: present 25 | 26 | - name: Add Neo4J Repo 27 | become: yes 28 | apt_repository: 29 | repo: deb http://debian.neo4j.org/repo stable/ 30 | state: present 31 | filename: neo4j 32 | 33 | - name: Install Packages 34 | become: yes 35 | apt: name="{{ item.key }}={{ item.value }}" state=present update_cache=yes 36 | with_dict: 37 | neo4j: 3.3.0 38 | 39 | - name: Ensure Neo4J Listens on All Devices 40 | become: yes 41 | lineinfile: 42 | path: /etc/neo4j/neo4j.conf 43 | regexp: "{{ item.key }}" 44 | line: "{{ item.key }}={{ item.value }}" 45 | with_dict: 46 | dbms.connector.bolt.listen_address: 0.0.0.0:7687 47 | dbms.connector.http.listen_address: 0.0.0.0:7474 48 | dbms.connector.https.listen_address: 0.0.0.0:7473 49 | notify: 50 | - Restart Neo4J 51 | 52 | - name: Set Initial Neo4J Password 53 | become: yes 54 | command: "neo4j-admin set-initial-password '{{ neo4j_initial_password }}'" 55 | when: not neo4j_check.stat.exists 56 | 57 | - name: Properly Set Neo4J Directory Permissions # Executing sudo neo4j-admin overrides them 58 | become: yes 59 | file: 60 | path: /var/lib/neo4j 61 | owner: neo4j 62 | group: adm 63 | recurse: yes 64 | state: directory 65 | 66 | - name: Start Neo4J 67 | become: yes 68 | service: name=neo4j state=started enabled=yes 69 | -------------------------------------------------------------------------------- /remotes/bakelets-source/tools/ansible/ansible.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | become: yes 3 | tasks: 4 | 5 | - name: Install basic tools 6 | apt: pkg={{ item }} state=present 7 | with_items: 8 | - git 9 | - vim 10 | - build-essential 11 | - python-dev 12 | 13 | - name: Add ansible repository. 14 | apt_repository: 15 | repo: 'ppa:ansible/ansible' 16 | 17 | - name: Install required system packages. 18 | apt: pkg={{ item }} state=present update_cache=yes 19 | with_items: 20 | - ansible 21 | 22 | -------------------------------------------------------------------------------- /remotes/bakelets-source/tools/dazed/dazed.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | vars: 3 | #aruco: aruco-3.0.10 4 | aruco: aruco-2.0.19 5 | tasks: 6 | - name: Install basic utils and build envs. 7 | apt: pkg={{ item }} state=present 8 | with_items: 9 | - git 10 | - unzip 11 | - vim 12 | - gcc 13 | - cmake 14 | - build-essential 15 | become: yes 16 | 17 | - name: Install required system packages. 18 | apt: pkg={{ item }} state=present 19 | with_items: 20 | - python-dev 21 | - python-pip 22 | - python-setuptools 23 | - python-numpy 24 | - python-scipy 25 | - python-matplotlib 26 | - libgtk2.0-dev 27 | become: yes 28 | 29 | - name: Install OpenCV 30 | apt: pkg={{ item }} state=present 31 | with_items: 32 | - libopencv-dev 33 | - python-opencv 34 | become: yes 35 | # - name: Install OpenCV 36 | # pip: name=opencv-contrib-python 37 | # become: yes 38 | 39 | - name: Install swig and libeigen3 40 | apt: pkg={{ item }} state=present 41 | with_items: 42 | - libeigen3-dev 43 | - swig3.0 44 | become: yes 45 | 46 | - name: Set swig3.0 as default swig using alternatives 47 | alternatives: 48 | name: swig 49 | link: /usr/bin/swig 50 | path: /usr/bin/swig3.0 51 | become: yes 52 | 53 | - name: Download aruco 54 | get_url: 55 | url: https://sourceforge.net/projects/aruco/files/2.0.19/aruco-2.0.19.zip/download?use_mirror=svwh 56 | # url: https://sourceforge.net/projects/aruco/files/3.0.0/aruco-3.0.10.zip/download?use_mirror=svwh 57 | dest: "/tmp/{{aruco}}.zip" 58 | 59 | - unarchive: 60 | src: "/tmp/{{aruco}}.zip" 61 | dest: /tmp 62 | remote_src: yes 63 | 64 | - file: 65 | path: "/tmp/{{aruco}}/build" 66 | state: directory 67 | mode: 0755 68 | 69 | - name: run cmake to create make files 70 | shell: "cd /tmp/{{aruco}}/build && cmake .." 71 | 72 | - name: Build aruco 73 | make: 74 | chdir: "/tmp/{{aruco}}/build" 75 | 76 | - name: Build install for aruco 77 | make: 78 | chdir: "/tmp/{{aruco}}/build" 79 | target: install 80 | become: yes 81 | 82 | - name: git clone aruco-python 83 | git: 84 | repo: https://github.com/fehlfarbe/python-aruco 85 | dest: /tmp/python-aruco 86 | version: b8feb03d9049acce08159b411301993130386168 87 | force: yes 88 | 89 | - name: run swig command 90 | shell: cd /tmp/python-aruco && ./swigbuild.sh 91 | 92 | - name: install libs 93 | shell: cd /tmp/python-aruco && python setup.py install 94 | become: yes 95 | 96 | - name: register libs 97 | shell: ldconfig 98 | become: yes 99 | -------------------------------------------------------------------------------- /remotes/bakelets-source/tools/defects4j/defects4j.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | tasks: 3 | 4 | # - name: register java 7 ppa 5 | # apt_repository: repo="ppa:openjdk-r/ppa" 6 | 7 | # - name: Add JRE ppa 8 | # apt_repository: repo=ppa:webupd8team/java state=present 9 | 10 | - name: Install basic utils and build envs. 11 | apt: pkg={{ item }} state=present update_cache=true cache_valid_time=3600 12 | with_items: 13 | # - openjdk-7-jdk 14 | - git 15 | - subversion 16 | - perl 17 | - unzip 18 | - libdbi-perl 19 | - libtext-csv-perl 20 | - libdbd-csv-perl 21 | become: yes 22 | # perl -MCPAN -e'install Text::CSV' 23 | 24 | - name: Download "public mirror" file 25 | get_url: 26 | url: http://ftp.osuosl.org/pub/funtoo/distfiles/oracle-java/jdk-7u80-linux-x64.tar.gz 27 | dest: /tmp/jdk-7u80-linux-x64.tar.gz 28 | 29 | - name: Prepare /opt/jdk directory 30 | file: 31 | path: /opt/jdk 32 | state: directory 33 | become: yes 34 | 35 | - name: Unarchive tar 36 | unarchive: 37 | src: /tmp/jdk-7u80-linux-x64.tar.gz 38 | dest: /opt/jdk 39 | remote_src: yes 40 | become: yes 41 | 42 | - name: Update alternatives for java 43 | alternatives: 44 | name: java 45 | link: /usr/bin/java 46 | path: /opt/jdk/jdk1.7.0_80/bin/java 47 | priority: 5000 48 | become: yes 49 | 50 | - name: Update alternatives for javac 51 | alternatives: 52 | name: javac 53 | link: /usr/bin/javac 54 | path: /opt/jdk/jdk1.7.0_80/bin/javac 55 | priority: 5000 56 | become: yes 57 | 58 | # - name: point to download 59 | # shell: echo oracle-java7-installer oracle-java7-installer/local select /tmp | sudo /usr/bin/debconf-set-selections 60 | # become: yes 61 | 62 | # - name: Automatically select the Oracle License 63 | # #shell: echo debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections 64 | # debconf: name='oracle-java7-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select' 65 | # become: yes 66 | 67 | # - name: Install JRE 68 | # apt: pkg=oracle-java7-installer state=latest update-cache=yes force=yes 69 | # become: yes 70 | 71 | - name: git clone defects4j 72 | git: 73 | repo: https://github.com/rjust/defects4j 74 | dest: ~/defects4j 75 | 76 | - name: Run init.sh 77 | shell: cd ~/defects4j && ./init.sh 78 | 79 | - name: Add d4j_home var to env 80 | lineinfile: 81 | dest: ~/.bashrc 82 | line: export D4J_HOME="~/defects4j" 83 | state: present 84 | 85 | - name: Add d4j_editor var to env 86 | lineinfile: 87 | dest: ~/.bashrc 88 | line: export D4J_EDITOR="diff -y -W $(( $(tput cols) - 2 ))" 89 | state: present 90 | 91 | - name: Add defects4j to path 92 | lineinfile: 93 | dest: ~/.bashrc 94 | line: export PATH="$D4J_HOME/framework/bin:$PATH" -------------------------------------------------------------------------------- /remotes/bakelets-source/tools/jekyll/jekyll.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | tasks: 3 | 4 | - name: Install basic utils and build envs. 5 | apt: pkg={{ item }} state=present 6 | with_items: 7 | - build-essential 8 | - make 9 | - ruby 10 | - ruby-dev 11 | - zlib1g-dev 12 | - tree 13 | become: yes 14 | 15 | - name: install gem with proper $PATH 16 | gem: 17 | name: "{{item}}" 18 | user_install: no 19 | with_items: 20 | - bundler 21 | - jekyll 22 | become: yes 23 | 24 | - name: Install the gemfile 25 | bundler: 26 | state: present 27 | gemfile: "{{BAKER_SHARE_DIR}}/Gemfile" 28 | -------------------------------------------------------------------------------- /remotes/bakelets-source/tools/jupyter/jupyter.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | become: yes 3 | tasks: 4 | 5 | # - name: Install basic utils and build envs. 6 | # apt: pkg={{ item }} state=present 7 | # with_items: 8 | 9 | - name: check python version 10 | command: python --version 11 | register: python_version 12 | 13 | - debug: 14 | msg: "Python Version output: {{python_version}}" 15 | # https://stackoverflow.com/questions/26028416/why-does-python-print-version-info-to-stderr 16 | # Python version outputs to stdout or stderr depending on version. 17 | 18 | - name: Install required system packages. 19 | apt: pkg={{ item }} state=present 20 | with_items: 21 | # - python-numpy 22 | - python-scipy 23 | - python-matplotlib 24 | - python-pandas 25 | when: python_version.stdout.startswith('Python 2') or python_version.stderr.startswith('Python 2') 26 | 27 | - name: Install numpy 28 | pip: name=numpy extra_args=--user executable=pip 29 | when: python_version.stdout.startswith('Python 2') or python_version.stderr.startswith('Python 2') 30 | 31 | - name: Install Jupyter 32 | pip: name=jupyter executable=pip 33 | when: python_version.stdout.startswith('Python 2') or python_version.stderr.startswith('Python 2') 34 | become: yes 35 | 36 | - name: Install required system packages. 37 | apt: pkg={{ item }} state=present 38 | with_items: 39 | # - python3-numpy 40 | - python3-scipy 41 | - python3-matplotlib 42 | - python3-pandas 43 | - python3-pip 44 | when: python_version.stdout.startswith('Python 3') or python_version.stderr.startswith('Python 3') 45 | 46 | - name: Install numpy 47 | pip: name=numpy extra_args=--user 48 | when: python_version.stdout.startswith('Python 3') or python_version.stderr.startswith('Python 3') 49 | 50 | - name: Install Jupyter 51 | pip: name=jupyter 52 | when: python_version.stdout.startswith('Python 3') or python_version.stderr.startswith('Python 3') 53 | become: yes 54 | -------------------------------------------------------------------------------- /remotes/bakelets-source/tools/latex/latex.yml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | vars: 3 | - package_names: 4 | - texlive-latex-base 5 | - texlive-latex-base-doc 6 | - texlive-latex-extra 7 | - texlive-latex-extra-doc 8 | - texlive-generic-extra 9 | - texlive-latex-recommended 10 | - texlive-latex-recommended-doc 11 | - texlive-science 12 | - texlive-fonts-recommended 13 | - texlive-fonts-extra 14 | - latexmk 15 | 16 | tasks: 17 | 18 | - stat: path=/usr/bin/pdflatex 19 | register: file_exists 20 | 21 | - name: install latex packages 22 | apt: pkg="{{item}}" state="present" 23 | with_items: "{{package_names}}" 24 | become: yes 25 | when: file_exists.stat.exists == False 26 | 27 | - name: install basics 28 | apt: pkg="{{item}}" state="present" 29 | with_items: 30 | - git 31 | - vim 32 | - build-essential 33 | - python-pip 34 | become: yes 35 | 36 | - name: Upgrade pip 37 | pip: 38 | name: pip 39 | extra_args: --upgrade 40 | become: yes 41 | 42 | - name: install pygments 43 | pip: 44 | name: pygments 45 | executable: pip2 46 | become: yes 47 | -------------------------------------------------------------------------------- /test/bake/test-326.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const request = require('request'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | 6 | const resolve = require('../../lib/bakelets/resolve'); 7 | 8 | describe('Baker 2 tests', function() { 9 | 10 | }); 11 | -------------------------------------------------------------------------------- /test/integration/bake-326-onboard.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const request = require('request'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const os = require('os'); 6 | const path = require('path'); 7 | const fs = require('fs-extra'); 8 | 9 | describe('baker should create coffeemaker, run it, and destroy it', function() { 10 | this.timeout(1000000); 11 | 12 | // https://github.ncsu.edu/engr-csc326-staff/Onboarding 13 | const tstDir = path.join(os.homedir(), 'Library', 'Baker', 'int-test'); 14 | const onboarding = path.join(tstDir, 'Onboarding'); 15 | 16 | it('should run coffeemaker project', function(done) { 17 | 18 | fs.mkdirpSync(tstDir); 19 | fs.removeSync(onboarding); 20 | 21 | // echo value for prompt input for password. 22 | var child = child_process.exec('echo 326 | baker bake --repo git@github.ncsu.edu:engr-csc326-staff/Onboarding.git -v', 23 | {cwd: tstDir }, function(error, stdout, stderr) { 24 | 25 | expect(stdout).to.not.include("Host key verification failed", "You need to add ssh key to github.ncsu.edu in order to run this test."); 26 | 27 | setTimeout( function() 28 | { 29 | 30 | var options = { 31 | url: "http://192.168.8.8:8080/api/v1/inventory", 32 | method: 'GET' 33 | }; 34 | 35 | request(options, function (error, response, body) 36 | { 37 | console.log(error || body); 38 | done(); 39 | }); 40 | 41 | },180000); 42 | 43 | console.log(`Waiting 180 seconds for coffeemaker to start springboot:run`); 44 | 45 | }); 46 | child.stdout.pipe(process.stdout); 47 | }); 48 | 49 | it('should destroy coffeemaker VM', function(done) { 50 | var child = child_process.exec(`cd ${onboarding} && baker destroy`, function(error, stdout, stderr) 51 | { 52 | console.log(stderr); 53 | expect(stderr).to.be.empty; 54 | done(); 55 | }); 56 | child.stdout.pipe(process.stdout); 57 | }); 58 | 59 | }); 60 | -------------------------------------------------------------------------------- /test/integration/baker-test-repo.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const request = require('request'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | 6 | 7 | describe('Command line tests', function() { 8 | }); 9 | 10 | /* 11 | describe('baker should create VM and destroy it', function() { 12 | this.timeout(600000); 13 | 14 | it('should have running node server', function(done) { 15 | var child = child_process.exec('node cmd.js bake --local test/resources/baker-test', function(error, stdout, stderr){ 16 | 17 | var options = { 18 | url: "http://localhost:3333/", 19 | method: 'GET' 20 | }; 21 | 22 | // Send a http request to url and specify a callback that will be called upon its return. 23 | request(options, function (error, response, body) 24 | { 25 | expect(body).to.equal('Hi there!'); 26 | done(); 27 | }); 28 | 29 | }); 30 | child.stdout.pipe(process.stdout); 31 | }); 32 | 33 | it('should destroy VM', function(done) { 34 | var child = child_process.exec('node cmd.js destroy baker-test', function(error, stdout, stderr) 35 | { 36 | console.log(stderr); 37 | expect(stderr).to.be.empty; 38 | done(); 39 | }); 40 | child.stdout.pipe(process.stdout); 41 | }); 42 | 43 | }); 44 | */ -------------------------------------------------------------------------------- /test/integration/test-neo4j.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const request = require('request'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const os = require('os'); 6 | const path = require('path'); 7 | const fs = require('fs-extra'); 8 | 9 | describe('baker should create neo4j vm', function() { 10 | this.timeout(2000000); 11 | 12 | // https://github.ncsu.edu/engr-csc326-staff/Onboarding 13 | 14 | it('should setup neo4j', function(done) { 15 | const tstDir = path.join(os.tmpdir(), 'neo4j'); 16 | fs.mkdirpSync(tstDir); 17 | fs.copySync('test/resources/baker2/neo4j.yml', path.join(tstDir,'baker.yml')); 18 | // echo value for prompt input for password. 19 | var child = child_process.exec(`echo neo | baker bake -v --local ${tstDir}`, 20 | {cwd: os.tmpdir() }, function(error, stdout, stderr) 21 | { 22 | console.log(stderr || stdout); 23 | done(); 24 | }); 25 | child.stdout.pipe(process.stdout); 26 | }); 27 | }); 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/integration/test-python-nb.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const request = require('request'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const os = require('os'); 6 | const path = require('path'); 7 | const fs = require('fs-extra'); 8 | 9 | describe('baker should create python notebook', function() { 10 | this.timeout(1000000); 11 | 12 | // https://github.ncsu.edu/engr-csc326-staff/Onboarding 13 | 14 | it('should setup python notebook', function(done) { 15 | const tstDir = path.join(os.tmpdir(), 'python-nb'); 16 | fs.mkdirpSync(tstDir); 17 | fs.copySync('test/resources/baker2/python-notebook.yml', path.join(tstDir,'baker.yml')); 18 | // echo value for prompt input for password. 19 | var child = child_process.exec(`baker bake --local ${tstDir}`, 20 | {cwd: os.tmpdir() }, function(error, stdout, stderr) 21 | { 22 | console.log(stderr || stdout); 23 | done(); 24 | }); 25 | child.stdout.pipe(process.stdout); 26 | }); 27 | }); 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/integration/test-r-tidy.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const request = require('request'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const os = require('os'); 6 | const path = require('path'); 7 | const fs = require('fs-extra'); 8 | 9 | describe('baker should create r tidy vm', function() { 10 | this.timeout(2000000); 11 | 12 | // https://github.ncsu.edu/engr-csc326-staff/Onboarding 13 | 14 | it('should setup tidyverse', function(done) { 15 | const tstDir = path.join(os.tmpdir(), 'r-tidy'); 16 | fs.mkdirpSync(tstDir); 17 | fs.copySync('test/resources/baker2/r-tidy.yml', path.join(tstDir,'baker.yml')); 18 | // echo value for prompt input for password. 19 | var child = child_process.exec(`baker bake --local ${tstDir}`, 20 | {cwd: os.tmpdir() }, function(error, stdout, stderr) 21 | { 22 | console.log(stderr || stdout); 23 | done(); 24 | }); 25 | child.stdout.pipe(process.stdout); 26 | }); 27 | }); 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/integration/test-runc.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const request = require('request'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const os = require('os'); 6 | const path = require('path'); 7 | const fs = require('fs-extra'); 8 | 9 | describe('baker should create runc baker container', function() { 10 | this.timeout(1000000); 11 | 12 | // https://github.ncsu.edu/engr-csc326-staff/Onboarding 13 | const tstDir = path.join(os.homedir(), 'Library', 'Baker', 'int-test'); 14 | const containerDir = path.join(tstDir, 'test-runc'); 15 | 16 | it('should make baker container', function(done) { 17 | 18 | fs.mkdirpSync(containerDir); 19 | fs.copyFileSync('test/resources/container/baker.yml', `${containerDir}/baker.yml`); 20 | 21 | // echo value for prompt input for password. 22 | var child = child_process.exec('baker bake -v', 23 | {cwd: containerDir }, function(error, stdout, stderr) { 24 | 25 | expect(stdout).to.not.include("\"failed\": true"); 26 | done(); 27 | }); 28 | child.stdout.pipe(process.stdout); 29 | }); 30 | 31 | it('should destroy chroot', function(done) { 32 | var child = child_process.exec(`cd ${containerDir} && baker destroy`, function(error, stdout, stderr) 33 | { 34 | console.log(stderr); 35 | expect(stderr).to.be.empty; 36 | done(); 37 | }); 38 | child.stdout.pipe(process.stdout); 39 | }); 40 | 41 | }); 42 | -------------------------------------------------------------------------------- /test/mustache.js: -------------------------------------------------------------------------------- 1 | const mustache = require('mustache'); 2 | const yaml = require('js-yaml'); 3 | const fs = require('fs'); 4 | const prompt = require("prompt"); 5 | 6 | async function promptValue(propertyName, description) 7 | { 8 | return new Promise((resolve, reject) => { 9 | prompt.start(); 10 | prompt.get([{name: propertyName, description: description }], function (err, result) 11 | { 12 | if (err) { console.log(err); } 13 | //prompt.stop(); 14 | resolve(result[propertyName]); 15 | }); 16 | }); 17 | } 18 | 19 | async function traverse(o) { 20 | const stack = [{obj: o, parent: null, parentKey:""}] 21 | 22 | while (stack.length) { 23 | const s = stack.shift() 24 | const obj = s.obj; 25 | const parent = s.parent; 26 | const parentKey = s.parentKey; 27 | 28 | for( var i = 0; i < Object.keys(obj).length; i++ ) 29 | { 30 | let key = Object.keys(obj)[i]; 31 | 32 | //await fn(key, obj[key], obj) 33 | 34 | if (obj[key] instanceof Object) { 35 | stack.unshift({obj: obj[key], parent: obj, parentKey: key}) 36 | } 37 | 38 | if( key == "prompt") 39 | { 40 | const input = await promptValue(parentKey, obj[key]); 41 | // Replace "prompt" with an value provided by user. 42 | parent[parentKey] = input; 43 | } 44 | 45 | } 46 | } 47 | return o; 48 | } 49 | 50 | ( async() => 51 | { 52 | template = fs.readFileSync( "../config/BaseVM.mustache" ).toString(); 53 | let doc = yaml.safeLoad(fs.readFileSync("resources/baker.yml", 'utf8')); 54 | 55 | const vagrant = doc.vagrant; 56 | const x = await traverse(vagrant); 57 | const output = mustache.render(template, doc); 58 | 59 | console.log(output); 60 | })(); 61 | 62 | -------------------------------------------------------------------------------- /test/resources/baker-test/README.md: -------------------------------------------------------------------------------- 1 | # baker-test 2 | A repository of scripts to try baker functionality 3 | -------------------------------------------------------------------------------- /test/resources/baker-test/baker.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: baker-test 3 | vagrant: 4 | box: "ubuntu/trusty64" 5 | memory: 512 6 | network: 7 | - forwarded_port: 8 | guest: 3000 9 | host: 3333 10 | - private_network: 11 | ip: 192.168.22.22 12 | bake: 13 | ansible: 14 | source: deployment/ 15 | playbooks: 16 | - node.yml 17 | - python.yml 18 | -------------------------------------------------------------------------------- /test/resources/baker-test/deployment/express/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var app = express() 3 | 4 | ///////////// WEB ROUTES 5 | app.get('/', function (req, res) { 6 | res.send('Hi there!') 7 | }) 8 | 9 | // HTTP SERVER 10 | var server = app.listen(3000, function () { 11 | console.log('Example app listening at port 3000'); 12 | }) 13 | -------------------------------------------------------------------------------- /test/resources/baker-test/deployment/express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baker-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "forever": "forever start index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.15.3", 14 | "forever": "^0.15.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/resources/baker-test/deployment/node.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: baker-test 3 | gather_facts: no 4 | 5 | tasks: 6 | - name: Installing dependencies 7 | become: yes 8 | apt: 9 | pkg: "{{item}}" 10 | state: latest 11 | update_cache: true 12 | cache_valid_time: 86400 13 | with_items: 14 | - build-essential 15 | - git 16 | - curl 17 | 18 | - name: Ensure the system can use the HTTPS transport for APT 19 | stat: path=/usr/lib/apt/methods/https 20 | register: apt_https_transport 21 | 22 | - name: Install HTTPS transport for APT 23 | become: yes 24 | apt: pkg=apt-transport-https state=installed 25 | when: not apt_https_transport.stat.exists 26 | 27 | - name: Import the NodeSource GPG key into apt 28 | become: yes 29 | apt_key: > 30 | id=68576280 31 | url="https://keyserver.ubuntu.com/pks/lookup?op=get&fingerprint=on&search=0x1655A0AB68576280" 32 | validate_certs=False 33 | - name: Add NodeSource deb repository 34 | become: yes 35 | apt_repository: repo='deb https://deb.nodesource.com/node_6.x trusty main' state=present 36 | 37 | - name: Install Node.js 38 | become: yes 39 | apt: pkg=nodejs state=installed update_cache=yes 40 | 41 | - name: Copy express server files 42 | copy: 43 | src: express/ 44 | dest: "/home/{{ansible_user}}/express" 45 | mode: 0700 46 | 47 | - name: Install dependencies 48 | shell: "cd /home/{{ansible_user}}/express/ && npm install" 49 | 50 | - name: Start express server 51 | shell: "cd /home/{{ansible_user}}/express/ && npm run forever" 52 | -------------------------------------------------------------------------------- /test/resources/baker-test/deployment/python.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: baker-test 3 | gather_facts: no 4 | 5 | # Python 2 is missing by default in ubuntu 16. 6 | # https://stackoverflow.com/questions/32429259/ansible-fails-with-bin-sh-1-usr-bin-python-not-found 7 | tasks: 8 | - name: install python 2 9 | raw: test -e /usr/bin/python || (sudo apt -y update && sudo apt install -y python-minimal) -------------------------------------------------------------------------------- /test/resources/baker.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: dazed16 3 | #vagrant: env/Vagrantfile 4 | vagrant: 5 | box: "ubuntu/xenial64" 6 | memory: 7 | prompt: "How much memory?" 8 | network: 9 | - forwarded_port: 10 | guest: 8888 11 | host: 8888 12 | - forwarded_port: 13 | guest: 80 14 | host: 15 | prompt: "What web port?" 16 | - private_network: 17 | ip: 192.168.3.39 18 | synced_folders: 19 | - folder: 20 | src: 21 | prompt: "What host folder to sync for projects?" 22 | dest: "/code" 23 | # - folder: 24 | # src: "C:/" 25 | # dest: "/cdrive" 26 | 27 | 28 | bake: 29 | ansible: 30 | source: env/ 31 | run: 32 | - ansible-playbook bootstrap.yml -i inventory 33 | - ansible-playbook configure.yml -i inventory -s 34 | - ansible-playbook aruco.yml -i inventory 35 | -------------------------------------------------------------------------------- /test/resources/baker2/jenkins.yml: -------------------------------------------------------------------------------- 1 | tools: 2 | - jenkins-job-builder 3 | services: 4 | - jenkins 5 | -------------------------------------------------------------------------------- /test/resources/baker2/neo4j.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: neo4j-test 3 | vm: 4 | ip: 192.168.88.4 5 | ports: 7687, 7474, 7473 6 | vars: 7 | - neo4j_password: 8 | prompt: Please type initial neo4j password 9 | lang: 10 | - nodejs9 11 | services: 12 | - neo4j 13 | 14 | -------------------------------------------------------------------------------- /test/resources/baker2/python-notebook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: python-nb-test 3 | vmß: 4 | ip: "192.168.88.2" 5 | tools: 6 | - jupyter 7 | lang: 8 | - python2 9 | start: jupyter notebook --no-browser --ip 0.0.0.0 --NotebookApp.token='' -------------------------------------------------------------------------------- /test/resources/baker2/r-tidy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: r-tidy-test 3 | vm: 4 | ip: "192.168.88.3" 5 | 6 | lang: 7 | - R: 8 | packages: tidyverse, xml, ggplot2 -------------------------------------------------------------------------------- /test/resources/cluster/plain.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: plain-cluster 3 | cluster: 4 | plain: 5 | nodes[3]: 6 | ip: 192.168.55.254 7 | lang: 8 | - nodejs9 9 | -------------------------------------------------------------------------------- /test/resources/container/baker.yml: -------------------------------------------------------------------------------- 1 | name: runc-test 2 | container: 3 | ip: 192.168.77.40 4 | lang: 5 | - nodejs9 6 | -------------------------------------------------------------------------------- /test/resources/docker-host/baker.yml: -------------------------------------------------------------------------------- 1 | name: docker-host 2 | vm: 3 | ip: 192.168.0.10 4 | memory: 4096 5 | services: 6 | - docker 7 | -------------------------------------------------------------------------------- /test/resources/prompt.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: dazed16 3 | #vagrant: env/Vagrantfile 4 | vagrant: 5 | box: "ubuntu/xenial64" 6 | memory: 7 | prompt: "How much memory do you want for VM (in Megabytes)" 8 | 9 | bake: 10 | ansible: 11 | source: env/ 12 | run: 13 | - ansible-playbook bootstrap.yml -i inventory 14 | - ansible-playbook configure.yml -i inventory -s 15 | - ansible-playbook aruco.yml -i inventory 16 | --------------------------------------------------------------------------------