├── .gitignore ├── LICENSE ├── README.md ├── bower.json ├── defaults └── main.yml ├── examples ├── packaged │ ├── README.md │ ├── Vagrantfile │ ├── hosts │ ├── playbook.yml │ ├── roles │ │ ├── install-ruby │ │ │ └── tasks │ │ │ │ └── main.yml │ │ ├── setup-db │ │ │ └── tasks │ │ │ │ └── main.yml │ │ └── verify │ │ │ └── tasks │ │ │ └── main.yml │ └── templates │ │ └── database.j2 ├── rbenv │ ├── README.md │ ├── Vagrantfile │ ├── hosts │ ├── playbook.yml │ ├── roles │ │ ├── rbenv │ │ │ └── tasks │ │ │ │ └── main.yml │ │ └── verify │ │ │ └── tasks │ │ │ └── main.yml │ └── templates │ │ └── database.j2 └── rvm │ ├── README.md │ ├── Vagrantfile │ ├── hosts │ ├── playbook.yml │ ├── roles │ ├── rvm │ │ └── tasks │ │ │ └── main.yml │ └── verify │ │ └── tasks │ │ └── main.yml │ └── templates │ └── database.j2 ├── library ├── diff └── merge ├── meta └── main.yml └── tasks └── main.yml /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components/* 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Raphael Randschau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rails-deployment 2 | 3 | A role that executes common tasks when deploying ruby on rails applications. 4 | 5 | Depends on [prepare-release][1] and [finalize-release][2] roles to checkout a new 6 | version from your git versioned application. 7 | 8 | example usage: 9 | 10 | --- 11 | - hosts: server 12 | user: app 13 | gather_facts: False 14 | vars: 15 | user: app 16 | home_directory: "/home/{{ user }}" 17 | rails_env: "staging" 18 | deploy_to: "{{ home_directory }}" 19 | 20 | roles: 21 | - 22 | role: nicolai86.prepare-release 23 | 24 | repo: git@example.com:app 25 | branch: develop 26 | 27 | symlinks: 28 | - { src: "{{ shared_path }}/vendor/bundle", dest: "{{ build_path }}/vendor/bundle" } 29 | - { src: "{{ shared_path }}/public/assets", dest: "{{ build_path }}/public/assets" } 30 | - { src: "{{ shared_path }}/log", dest: "{{ build_path }}/log" } 31 | - { src: "{{ shared_path }}/.env", dest: "{{ build_path }}/.env" } 32 | - { src: "{{ shared_path }}/config/database.yml", dest: "{{ build_path }}/config/database.yml" } 33 | 34 | directories: 35 | - "{{ shared_path }}/config" 36 | 37 | templates: 38 | - { src: "templates/env.js", dest: "{{ shared_path }}/.env" } 39 | 40 | tags: deploy 41 | 42 | - 43 | role: nicolai86.rails-deployment 44 | 45 | migrate: yes 46 | compile_assets: yes 47 | force_migrate: no 48 | force_asset_compilation: no 49 | 50 | tags: deploy 51 | 52 | - 53 | role: nicolai86.finalize-release 54 | 55 | tags: deploy 56 | 57 | - 58 | role: restart 59 | 60 | service: application:* 61 | 62 | tags: 63 | - deploy 64 | - rollback 65 | 66 | 67 | #### configuration 68 | 69 | Most parts of the role can be configured using variables. For example, if you are using rails but using SQL for schema management, 70 | you can easily configure rails-deployment to compare the structure.sql files instead of schema.rb like this: 71 | 72 | - 73 | role: nicolai86.rails-deployment 74 | 75 | migrate: yes 76 | 77 | migrate_diff_paths: 78 | - { current: "{{ current_path }}/db/structure.sql", next: "{{ build_path }}/db/structure.sql" } 79 | 80 | See defaults/main.yml for details about available variables. 81 | 82 | #### requirements 83 | 84 | - all gem binaries (e.g. bundle, rake, rails) need to be locateable using the $PATH. Make sure to setup properly 85 | 86 | If you are using rbenv to manage your ruby version make sure to properly set the environment using 87 | something like this: 88 | 89 | ``` 90 | environment: 91 | PATH: '~/.rbenv/shims:~/.rbenv/bin:"$PATH"' 92 | ``` 93 | 94 | #### important features: 95 | 96 | - it can be reused multiple times inside a single playbook for separate deployments. 97 | - works with rvm, rbenv or system ruby installations. 98 | - it's using a bare copy of the repository to deploy. 99 | - migration and asset compilation can be de-activated as needed. 100 | - only keeps 5 most recent deployments per default 101 | 102 | #### limitations 103 | 104 | - you need to write your own restart handling 105 | 106 | [1]:https://github.com/nicolai86/ansible-prepare-release 107 | [2]:https://github.com/nicolai86/ansible-finalize-release 108 | [3]:https://github.com/nicolai86/ansible-rails 109 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Ansible Rails Deployment", 3 | "version": "0.8.3", 4 | "homepage": "https://github.com/nicolai86/ansible-rails-deployment", 5 | "authors": [ 6 | "Raphael Randschau" 7 | ], 8 | "description": "A role that executes common tasks when deploying ruby on rails applications.", 9 | "license": "MIT", 10 | "dependencies": { 11 | "nicolai86.deployment-facts": "nicolai86/ansible-deployment-facts#v0.1.2", 12 | "nicolai86.prepare-release": "nicolai86/ansible-prepare-release#v0.4.0", 13 | "nicolai86.finalize-release": "nicolai86/ansible-finalize-release#v0.2.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | # migrate database by default 2 | migrate: yes 3 | 4 | # compile new assets by default 5 | compile_assets: yes 6 | 7 | # force migration even if no differences are found 8 | force_migrate: no 9 | 10 | # force asset compilation even if no differences are found 11 | force_asset_compilation: no 12 | 13 | # paths to check by default for changes when running migrations 14 | migrate_diff_paths: 15 | - 16 | current: "{{ current_path }}/db/schema.rb" 17 | next: "{{ build_path }}/db/schema.rb" 18 | - 19 | current: "{{ current_path }}/db/structure.sql" 20 | next: "{{ build_path }}/db/structure.sql" 21 | - 22 | current: "{{ current_path }}/db/migrate" 23 | next: "{{ build_path }}/db/migrate" 24 | 25 | # paths to check by defualt for changes when compiling assets 26 | asset_precompile_diff_paths: 27 | - 28 | current: "{{ current_path }}/app/assets" 29 | next: "{{ build_path }}/app/assets" 30 | - 31 | current: "{{ current_path }}/vendor/assets" 32 | next: "{{ build_path }}/vendor/assets" 33 | - 34 | current: "{{ current_path }}/Gemfile.lock" 35 | next: "{{ build_path }}/Gemfile.lock" 36 | 37 | # assumptions about the ruby setup. 38 | gem_home: "{{ home_directory }}/.gem" 39 | 40 | # custom paths necessary to locate bundler, rake, ... (e.g. your rbenv shims directory) 41 | rails_bin_paths: [] 42 | 43 | # rails environment used to invoke commands in 44 | rails_env: production 45 | 46 | # default environment for running tasks. 47 | default_environment: 48 | RAILS_ENV: "{{ rails_env }}" 49 | PATH: "{{ gem_home }}/bin:{{ rails_bin_paths | union([ansible_env.PATH]) | join(':') }}" 50 | GEM_HOME: "{{ gem_home }}" 51 | 52 | # you can add custom variables to the command environment here 53 | custom_environment: {} 54 | 55 | shared_bundle_path: "{{ shared_path }}/vendor/bundle" 56 | 57 | # you can overwrite the options used to bundle install by setting 58 | # bundle_install_options: 59 | 60 | # default options for bundle_install_options 61 | default_bundle_install_options: "--gemfile='./Gemfile' --deployment --binstubs='./bin'" -------------------------------------------------------------------------------- /examples/packaged/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | ``` 4 | vagrant up 5 | ansible-playbook -i ./hosts playbook.yml --private-key=~/.vagrant.d/insecure_private_key -u vagrant 6 | ``` -------------------------------------------------------------------------------- /examples/packaged/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! 5 | VAGRANTFILE_API_VERSION = "2" 6 | 7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 8 | # All Vagrant configuration is done here. The most common configuration 9 | # options are documented and commented below. For a complete reference, 10 | # please see the online documentation at vagrantup.com. 11 | 12 | # Every Vagrant virtual environment requires a box to build off of. 13 | config.vm.box = "precise64" 14 | 15 | # The url from where the 'config.vm.box' box will be fetched if it 16 | # doesn't already exist on the user's system. 17 | config.vm.box_url = "http://files.vagrantup.com/precise64.box" 18 | 19 | # Create a forwarded port mapping which allows access to a specific port 20 | # within the machine from a port on the host machine. In the example below, 21 | # accessing "localhost:8080" will access port 80 on the guest machine. 22 | 23 | # Create a private network, which allows host-only access to the machine 24 | # using a specific IP. 25 | config.vm.network :private_network, ip: "10.0.0.199" 26 | 27 | # Create a public network, which generally matched to bridged network. 28 | # Bridged networks make the machine appear as another physical device on 29 | # your network. 30 | # config.vm.network :public_network 31 | 32 | # If true, then any SSH connections made will enable agent forwarding. 33 | # Default value: false 34 | config.ssh.forward_agent = true 35 | 36 | # Share an additional folder to the guest VM. The first argument is 37 | # the path on the host to the actual folder. The second argument is 38 | # the path on the guest to mount the folder. And the optional third 39 | # argument is a set of non-required options. 40 | # config.vm.synced_folder "../data", "/vagrant_data" 41 | 42 | # Provider-specific configuration so you can fine-tune various 43 | # backing providers for Vagrant. These expose provider-specific options. 44 | # Example for VirtualBox: 45 | # 46 | config.vm.provider :virtualbox do |vb| 47 | vb.gui = false 48 | 49 | vb.customize ["modifyvm", :id, "--memory", "1024"] 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /examples/packaged/hosts: -------------------------------------------------------------------------------- 1 | [vm] 2 | 10.0.0.199 -------------------------------------------------------------------------------- /examples/packaged/playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: vm 2 | remote_user: vagrant 3 | sudo: true 4 | gather_facts: yes 5 | vars: 6 | user: vagrant 7 | home_directory: "/home/{{ user }}" 8 | deploy_to: "{{ home_directory }}" 9 | 10 | rails_env: development 11 | 12 | gem_home: "{{ home_directory }}/.gem" 13 | asset_precompile_diff_paths: 14 | - { current: "{{ current_path }}/app/assets", next: "{{ build_path }}/app/assets" } 15 | - { current: "{{ current_path }}/vendor/assets", next: "{{ build_path }}/vendor/assets" } 16 | 17 | roles: 18 | - install-ruby 19 | - 20 | role: nicolai86.prepare-release 21 | 22 | repo: https://github.com/nicolai86/pattern-manager.git 23 | branch: master 24 | 25 | symlinks: 26 | - { src: "{{ shared_path }}/config/database.yml", dest: "{{ build_path }}/config/database.yml" } 27 | - { src: "{{ shared_path }}/_db", dest: "{{ build_path }}/_db" } 28 | 29 | directories: 30 | - "{{ shared_path }}/config" 31 | - "{{ shared_path }}/_db" 32 | 33 | templates: 34 | - { src: "templates/database.j2", dest: "{{ shared_path }}/config/database.yml" } 35 | 36 | - setup-db 37 | 38 | - 39 | role: nicolai86.rails-deployment 40 | 41 | migrate: yes 42 | compile_assets: yes 43 | force_migrate: no 44 | force_asset_compilation: no 45 | 46 | - nicolai86.finalize-release 47 | - verify -------------------------------------------------------------------------------- /examples/packaged/roles/install-ruby/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - apt: 3 | name: "{{ item }}" 4 | state: present 5 | update_cache: yes 6 | with_items: 7 | - git-core 8 | - curl 9 | - build-essential 10 | - libssl-dev 11 | - libpq-dev 12 | - nodejs 13 | - libsqlite3-dev 14 | 15 | - name: add brightbox ppa for ruby 2.1 16 | apt_repository: 17 | repo: 'ppa:brightbox/ruby-ng-experimental' 18 | 19 | - name: install ruby 2.1 20 | apt: 21 | pkg: "{{item}}" 22 | state: installed 23 | update-cache: yes 24 | with_items: 25 | - ruby2.1 26 | - ruby2.1-dev 27 | - ruby2.1-doc 28 | - ruby-switch 29 | 30 | - name: set ruby 2.1 as default 31 | shell: ruby-switch --set ruby2.1 32 | 33 | - gem: 34 | name: bundler 35 | state: present 36 | user_install: no -------------------------------------------------------------------------------- /examples/packaged/roles/setup-db/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - lineinfile: 3 | dest: "{{ build_path }}/Gemfile" 4 | line: "gem 'pg'" 5 | insertbefore: EOF 6 | state: absent 7 | 8 | - lineinfile: 9 | dest: "{{ build_path }}/Gemfile" 10 | regexp: "sqlite3" 11 | line: "gem 'sqlite3'" 12 | insertbefore: BOF 13 | state: present 14 | 15 | - name: execute bundler 16 | command: chdir="{{ build_path }}" bundle install --path='{{ shared_path }}/vendor/bundle' --gemfile='./Gemfile' --binstubs='./bin' 17 | environment: 18 | GEM_HOME: "{{ gem_home }}" 19 | PATH: "{{ gem_home }}/bin:{{ ansible_env.PATH }}" 20 | RAILS_ENV: "{{ rails_env }}" 21 | 22 | - command: chdir="{{ build_path }}" bundle exec rake db:create 23 | environment: 24 | RAILS_ENV: "{{ rails_env }}" 25 | PATH: "{{ gem_home }}/bin:{{ ansible_env.PATH }}" 26 | GEM_HOME: "{{ gem_home }}" -------------------------------------------------------------------------------- /examples/packaged/roles/verify/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - file: 3 | path: "{{ build_path }}" 4 | state: directory 5 | owner: "{{ user }}" 6 | group: "{{ user }}" 7 | 8 | - file: 9 | path: "{{ current_path }}" 10 | state: directory 11 | owner: "{{ user }}" 12 | group: "{{ user }}" -------------------------------------------------------------------------------- /examples/packaged/templates/database.j2: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: sqlite3 3 | encoding: unicode 4 | pool: 5 5 | 6 | development: 7 | <<: *default 8 | database: _db/development.sqlite3 -------------------------------------------------------------------------------- /examples/rbenv/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | ``` 4 | vagrant up 5 | ansible-playbook -i ./hosts playbook.yml --private-key=~/.vagrant.d/insecure_private_key -u vagrant 6 | ``` -------------------------------------------------------------------------------- /examples/rbenv/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! 5 | VAGRANTFILE_API_VERSION = "2" 6 | 7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 8 | # All Vagrant configuration is done here. The most common configuration 9 | # options are documented and commented below. For a complete reference, 10 | # please see the online documentation at vagrantup.com. 11 | 12 | # Every Vagrant virtual environment requires a box to build off of. 13 | config.vm.box = "precise64" 14 | 15 | # The url from where the 'config.vm.box' box will be fetched if it 16 | # doesn't already exist on the user's system. 17 | config.vm.box_url = "http://files.vagrantup.com/precise64.box" 18 | 19 | # Create a forwarded port mapping which allows access to a specific port 20 | # within the machine from a port on the host machine. In the example below, 21 | # accessing "localhost:8080" will access port 80 on the guest machine. 22 | 23 | # Create a private network, which allows host-only access to the machine 24 | # using a specific IP. 25 | config.vm.network :private_network, ip: "10.0.0.199" 26 | 27 | # Create a public network, which generally matched to bridged network. 28 | # Bridged networks make the machine appear as another physical device on 29 | # your network. 30 | # config.vm.network :public_network 31 | 32 | # If true, then any SSH connections made will enable agent forwarding. 33 | # Default value: false 34 | config.ssh.forward_agent = true 35 | 36 | # Share an additional folder to the guest VM. The first argument is 37 | # the path on the host to the actual folder. The second argument is 38 | # the path on the guest to mount the folder. And the optional third 39 | # argument is a set of non-required options. 40 | # config.vm.synced_folder "../data", "/vagrant_data" 41 | 42 | # Provider-specific configuration so you can fine-tune various 43 | # backing providers for Vagrant. These expose provider-specific options. 44 | # Example for VirtualBox: 45 | # 46 | config.vm.provider :virtualbox do |vb| 47 | vb.gui = false 48 | 49 | vb.customize ["modifyvm", :id, "--memory", "1024"] 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /examples/rbenv/hosts: -------------------------------------------------------------------------------- 1 | [vm] 2 | 10.0.0.199 -------------------------------------------------------------------------------- /examples/rbenv/playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: vm 2 | remote_user: vagrant 3 | gather_facts: no 4 | sudo: true 5 | vars: 6 | user: vagrant 7 | home_directory: "/home/{{ user }}" 8 | deploy_to: "{{ home_directory }}" 9 | rails_env: development 10 | 11 | roles: 12 | - rbenv 13 | - 14 | role: nicolai86.prepare-release 15 | 16 | repo: https://github.com/nicolai86/pattern-manager.git 17 | branch: master 18 | 19 | symlinks: 20 | - { src: "{{ shared_path }}/config/database.yml", dest: "{{ build_path }}/config/database.yml" } 21 | 22 | directories: 23 | - "{{ shared_path }}/config" 24 | 25 | templates: 26 | - { src: "templates/database.j2", dest: "{{ shared_path }}/config/database.yml" } 27 | 28 | - 29 | role: nicolai86.rails-deployment 30 | 31 | migrate: no 32 | compile_assets: no 33 | force_migrate: no 34 | force_asset_compilation: no 35 | 36 | - nicolai86.finalize-release 37 | - verify -------------------------------------------------------------------------------- /examples/rbenv/roles/rbenv/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - apt: 2 | name: "{{ item }}" 3 | state: present 4 | update_cache: yes 5 | with_items: 6 | - git-core 7 | - curl 8 | - build-essential 9 | - libssl-dev 10 | - libpq-dev 11 | - nodejs 12 | 13 | # TODO RBENV install 14 | # TODO ruby install 15 | # TODO RBENV_ROOT 16 | 17 | - name: "adjust GEM HOME for user" 18 | lineinfile: 19 | dest: "/home/vagrant/.bashrc" 20 | regexp: "^export GEM_HOME" 21 | line: "export GEM_HOME=$HOME/.gem" 22 | insertbefore: BOF 23 | state: present 24 | 25 | - name: "add gem paths to path" 26 | lineinfile: 27 | dest: "/home/vagrant/.bashrc" 28 | regexp: "^export PATH=.GEM_HOME" 29 | line: "export PATH=$GEM_HOME/bin:$PATH" 30 | insertafter: "GEM_HOME" 31 | state: present 32 | 33 | - name: "adjust GEM HOME for user" 34 | lineinfile: 35 | dest: "/home/vagrant/.bashrc" 36 | regexp: "^source /usr/local/rvm/scripts/rvm" 37 | line: "source /usr/local/rvm/scripts/rvm" 38 | insertbefore: BOF 39 | 40 | - name: install bundler 41 | shell: gem install bundler -------------------------------------------------------------------------------- /examples/rbenv/roles/verify/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - file: 3 | path: "{{ build_path }}" 4 | state: directory 5 | owner: "{{ user }}" 6 | group: "{{ user }}" 7 | 8 | - file: 9 | path: "{{ current_path }}" 10 | state: directory 11 | owner: "{{ user }}" 12 | group: "{{ user }}" -------------------------------------------------------------------------------- /examples/rbenv/templates/database.j2: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: sqlite 3 | encoding: unicode 4 | pool: 5 5 | 6 | development: 7 | <<: *default 8 | database: pattern-manager_development -------------------------------------------------------------------------------- /examples/rvm/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | ``` 4 | vagrant up 5 | ansible-playbook -i ./hosts playbook.yml --private-key=~/.vagrant.d/insecure_private_key -u vagrant 6 | ``` -------------------------------------------------------------------------------- /examples/rvm/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! 5 | VAGRANTFILE_API_VERSION = "2" 6 | 7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 8 | # All Vagrant configuration is done here. The most common configuration 9 | # options are documented and commented below. For a complete reference, 10 | # please see the online documentation at vagrantup.com. 11 | 12 | # Every Vagrant virtual environment requires a box to build off of. 13 | config.vm.box = "precise64" 14 | 15 | # The url from where the 'config.vm.box' box will be fetched if it 16 | # doesn't already exist on the user's system. 17 | config.vm.box_url = "http://files.vagrantup.com/precise64.box" 18 | 19 | # Create a forwarded port mapping which allows access to a specific port 20 | # within the machine from a port on the host machine. In the example below, 21 | # accessing "localhost:8080" will access port 80 on the guest machine. 22 | 23 | # Create a private network, which allows host-only access to the machine 24 | # using a specific IP. 25 | config.vm.network :private_network, ip: "10.0.0.199" 26 | 27 | # Create a public network, which generally matched to bridged network. 28 | # Bridged networks make the machine appear as another physical device on 29 | # your network. 30 | # config.vm.network :public_network 31 | 32 | # If true, then any SSH connections made will enable agent forwarding. 33 | # Default value: false 34 | config.ssh.forward_agent = true 35 | 36 | # Share an additional folder to the guest VM. The first argument is 37 | # the path on the host to the actual folder. The second argument is 38 | # the path on the guest to mount the folder. And the optional third 39 | # argument is a set of non-required options. 40 | # config.vm.synced_folder "../data", "/vagrant_data" 41 | 42 | # Provider-specific configuration so you can fine-tune various 43 | # backing providers for Vagrant. These expose provider-specific options. 44 | # Example for VirtualBox: 45 | # 46 | config.vm.provider :virtualbox do |vb| 47 | vb.gui = false 48 | 49 | vb.customize ["modifyvm", :id, "--memory", "1024"] 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /examples/rvm/hosts: -------------------------------------------------------------------------------- 1 | [vm] 2 | 10.0.0.199 -------------------------------------------------------------------------------- /examples/rvm/playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: vm 2 | remote_user: vagrant 3 | gather_facts: yes 4 | sudo: true 5 | vars: 6 | user: vagrant 7 | home_directory: "/home/{{ user }}" 8 | deploy_to: "{{ home_directory }}" 9 | rails_env: development 10 | rails_bin_paths: 11 | - /usr/local/rvm/gems/ruby-2.1.2@global/bin 12 | - /usr/local/rvm/bin 13 | - /usr/local/rvm/gems/ruby-2.1.2/bin 14 | - /usr/local/rvm/rubies/ruby-2.1.2/bin 15 | 16 | roles: 17 | - rvm 18 | - 19 | role: nicolai86.prepare-release 20 | 21 | repo: https://github.com/nicolai86/pattern-manager.git 22 | branch: master 23 | 24 | symlinks: 25 | - { src: "{{ shared_path }}/config/database.yml", dest: "{{ build_path }}/config/database.yml" } 26 | 27 | directories: 28 | - "{{ shared_path }}/config" 29 | 30 | templates: 31 | - { src: "templates/database.j2", dest: "{{ shared_path }}/config/database.yml" } 32 | 33 | - 34 | role: nicolai86.rails-deployment 35 | 36 | migrate: no 37 | compile_assets: no 38 | force_migrate: no 39 | force_asset_compilation: no 40 | 41 | - nicolai86.finalize-release 42 | - verify -------------------------------------------------------------------------------- /examples/rvm/roles/rvm/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - apt: 2 | name: "{{ item }}" 3 | state: present 4 | update_cache: yes 5 | with_items: 6 | - git-core 7 | - curl 8 | - build-essential 9 | - libssl-dev 10 | - libpq-dev 11 | - nodejs 12 | 13 | - stat: path=/etc/profile.d/rvm.sh 14 | register: rvm_folder 15 | 16 | - name: install rvm 17 | shell: "curl -sSL https://get.rvm.io | bash -s stable --ruby=2.1.2" 18 | when: rvm_folder.stat.isdir is not defined 19 | 20 | - file: 21 | src: /usr/local/rvm/environments/ruby-2.1.2 22 | dest: /usr/local/rvm/environments/default 23 | state: link 24 | 25 | - lineinfile: 26 | dest: "/home/vagrant/.bashrc" 27 | regexp: "^export PATH=/usr/local/rvm/bin" 28 | line: "export PATH=/usr/local/rvm/bin:$PATH" 29 | insertafter: BOF 30 | state: present 31 | 32 | - name: "adjust GEM HOME for user" 33 | lineinfile: 34 | dest: "/home/vagrant/.bashrc" 35 | regexp: "^export GEM_HOME" 36 | line: "export GEM_HOME=$HOME/.gem" 37 | insertbefore: BOF 38 | state: present 39 | 40 | - name: "add gem paths to path" 41 | lineinfile: 42 | dest: "/home/vagrant/.bashrc" 43 | regexp: "^export PATH=.GEM_HOME" 44 | line: "export PATH=$GEM_HOME/bin:$PATH" 45 | insertafter: "GEM_HOME" 46 | state: present 47 | 48 | - name: "adjust GEM HOME for user" 49 | lineinfile: 50 | dest: "/home/vagrant/.bashrc" 51 | regexp: "^source /usr/local/rvm/scripts/rvm" 52 | line: "source /usr/local/rvm/scripts/rvm" 53 | insertbefore: BOF 54 | 55 | - name: install bundler 56 | shell: gem install bundler -------------------------------------------------------------------------------- /examples/rvm/roles/verify/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - file: 3 | path: "{{ build_path }}" 4 | state: directory 5 | owner: "{{ user }}" 6 | group: "{{ user }}" 7 | 8 | - file: 9 | path: "{{ current_path }}" 10 | state: directory 11 | owner: "{{ user }}" 12 | group: "{{ user }}" -------------------------------------------------------------------------------- /examples/rvm/templates/database.j2: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: sqlite 3 | encoding: unicode 4 | pool: 5 5 | 6 | development: 7 | <<: *default 8 | database: pattern-manager_development -------------------------------------------------------------------------------- /library/diff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # (c) 2014-2015, Raphael Randschau 5 | 6 | DOCUMENTATION = ''' 7 | --- 8 | module: diff 9 | short_description: diffs directories and files 10 | version_added: "1.0" 11 | author: Raphael Randschau 12 | options: 13 | paths: 14 | description: 15 | - paths to check for diffs. Format expected is { next: "/bar" ,current: "/foo" } 16 | required: yes 17 | ''' 18 | 19 | EXAMPLES = ''' 20 | # check paths for diffs 21 | diff: paths=[{ next: "/bar", current: "/foo" }] 22 | ''' 23 | 24 | import re 25 | import filecmp 26 | import os 27 | import sys 28 | import subprocess 29 | from subprocess import check_output 30 | 31 | def flatten(items, seqtypes=(list, tuple)): 32 | for i, x in enumerate(items): 33 | while isinstance(items[i], seqtypes): 34 | items[i:i+1] = items[i] 35 | return items 36 | 37 | class DiffModule(object): 38 | diffs = [] 39 | def __init__(self): 40 | self.diffs = [] 41 | 42 | def _diff(self, path_a, path_b): 43 | """returns 0 if both paths are the same, otherwise 1""" 44 | if not os.path.exists(path_a) and not os.path.exists(path_b): 45 | return 0 46 | 47 | rc = subprocess.call(['diff', '-r', '-q', path_a, path_b]) 48 | return rc 49 | 50 | def check(self, paths): 51 | has_diffs = False 52 | if paths != None and len(paths) > 0: 53 | for path in flatten(paths): 54 | if isinstance(path, list) or isinstance(path, tuple): 55 | path = path[0] 56 | 57 | if not isinstance(path, dict): 58 | raise Exception('''all paths must be dict({'current': '/some/path', 'next': '/other/path'}). Got ''' + type(path).__name__) 59 | 60 | path['current'] = os.path.realpath(path['current']) 61 | path['next'] = os.path.realpath(path['next']) 62 | 63 | diff_rc = self._diff(path['current'], path['next']) 64 | if diff_rc != 0: 65 | path['rc'] = diff_rc 66 | self.diffs.append(path) 67 | has_diffs = has_diffs or (diff_rc != 0) 68 | return has_diffs 69 | 70 | def main(): 71 | module = AnsibleModule( 72 | argument_spec = dict( 73 | paths = dict(required=False, type='list') 74 | ), 75 | supports_check_mode = True, 76 | mutually_exclusive = [ ], 77 | ) 78 | 79 | diff = DiffModule() 80 | 81 | paths = module.params['paths'] 82 | has_diffs = diff.check(paths) 83 | module.exit_json(paths=paths, changed=has_diffs, diffs=diff.diffs) 84 | 85 | from ansible.module_utils.basic import * 86 | 87 | main() 88 | -------------------------------------------------------------------------------- /library/merge: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # (c) 2015, Raphael Randschau 5 | 6 | DOCUMENTATION = ''' 7 | --- 8 | module: merge 9 | short_description: merge dictionaries, export as ansible variable 10 | version_added: "1.0" 11 | author: Raphael Randschau 12 | options: 13 | var: 14 | description: 15 | - variable to export as 16 | dicts: 17 | description: 18 | - dicts to merge 19 | required: yes 20 | ''' 21 | 22 | EXAMPLES = ''' 23 | # merge dicts, exports as foo 24 | merge: dicts=[{ 'next': "/bar" },{'current': "/foo" }] var=blubb 25 | ''' 26 | 27 | def main(): 28 | module = AnsibleModule( 29 | argument_spec = dict( 30 | dicts = dict(required=True, type='list'), 31 | var = dict(required=True, type='str') 32 | ), 33 | supports_check_mode = True 34 | ) 35 | 36 | dicts = module.params['dicts'] 37 | 38 | # merge all dictionaries 39 | merged_dicts= {} 40 | for d in dicts: 41 | # NOTE this will fail if d is no dict. This is on purpose! 42 | merged_dicts.update(d) 43 | 44 | # export as provided var 45 | merged = {} 46 | merged[module.params['var']] = merged_dicts 47 | 48 | result = {} 49 | result['ansible_facts'] = merged 50 | 51 | module.exit_json(**result) 52 | 53 | from ansible.module_utils.basic import * 54 | 55 | main() 56 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: "Raphael Randschau" 4 | description: "deploys rails application like capistrano or mina do" 5 | license: MIT 6 | min_ansible_version: 1.4 7 | platforms: 8 | - name: Ubuntu 9 | versions: 10 | - precise 11 | - quantal 12 | - raring 13 | - saucy 14 | categories: 15 | - web 16 | dependencies: [] -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - merge: 3 | dicts: 4 | - "{{ default_environment }}" 5 | - "{{ custom_environment }}" 6 | var: command_environment 7 | 8 | # note: mostly for convenience when ssh'ing to your server so you can run ruby related commands properly 9 | - name: add GEM_HOME to .bashrc 10 | lineinfile: 11 | dest: "{{ home_directory }}/.bashrc" 12 | insertafter: BOF 13 | regexp: ^export.GEM_HOME 14 | line: "export GEM_HOME={{ gem_home }}" 15 | state: present 16 | 17 | - name: update PATH with $GEM_HOME/bin 18 | lineinfile: 19 | dest: "{{ home_directory }}/.bashrc" 20 | insertafter: ^export.GEM_HOME 21 | regexp: ^export.PATH=.GEM_HOME 22 | line: "export PATH=$GEM_HOME/bin:$PATH" 23 | state: present 24 | 25 | - name: execute bundler 26 | command: chdir="{{ build_path }}" bundle install --path='{{ shared_bundle_path }}' {{ bundle_install_options|default(default_bundle_install_options) }} 27 | register: bundler 28 | changed_when: "'Installing' in bundler or 'Updating' in bundler or 'upgrade' in bundler" 29 | environment: "{{ command_environment }}" 30 | 31 | - name: check schema for diffs 32 | diff: 33 | paths: "{{ migrate_diff_paths }}" 34 | when: migrate 35 | register: rails_schema 36 | 37 | - debug: var=rails_schema 38 | 39 | - name: migrate the database 40 | command: chdir="{{ build_path }}" bundle exec rake db:migrate 41 | environment: "{{ command_environment }}" 42 | when: migrate and (force_migrate or rails_schema|changed) 43 | 44 | - name: check assets for diffs 45 | diff: 46 | paths: "{{ asset_precompile_diff_paths }}" 47 | when: compile_assets 48 | register: assets 49 | 50 | - name: precompile asset files if necessary 51 | command: chdir="{{ build_path }}" bundle exec rake assets:precompile 52 | environment: "{{ command_environment }}" 53 | when: compile_assets and (assets|changed or force_asset_compilation) 54 | 55 | - name: copy asset files when not changed 56 | shell: "cp -R {{ current_path }}/public/assets {{ build_path }}/public/assets" 57 | when: compile_assets and assets is defined and not assets.changed 58 | --------------------------------------------------------------------------------