├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── Rakefile ├── build └── .gitignore ├── example ├── README.md ├── Vagrantfile └── ops │ └── dna │ ├── db-master.json │ ├── php-app.json │ └── stack.json ├── opsworks ├── Vagrantfile.template ├── client.yml ├── opsworks ├── opsworks.rb └── pre_config.yml ├── preseed └── preseed.cfg ├── provision ├── cleanup.sh ├── minimize.sh ├── network.sh ├── opsworks.sh ├── update.sh ├── vagrant.sh └── vmtools.sh └── template ├── ubuntu1204.json └── ubuntu1404.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | packer_cache/ 3 | .vagrant/ 4 | *.box 5 | *.iso 6 | *.tar.gz 7 | output-* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "example/cookbooks"] 2 | path = example/ops/cookbooks 3 | url = https://github.com/amazonwebservices/opsworks-example-cookbooks.git 4 | branch = version2 5 | [submodule "example/dev/simple-php"] 6 | path = example/dev/simple-php 7 | url = https://github.com/amazonwebservices/opsworks-demo-php-simple-app.git 8 | branch = master 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 PixelCog Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Packer templates for AWS OpsWorks 2 | ================================= 3 | 4 | > **Note:** this Packer template is for use with the legacy AWS OpsWorks "Stacks" 5 | > operating in Chef 11 mode. There are no plans to update this to work with 6 | > Chef 12 or OpsWorks Chef Automate modes. A vanilla Chef plugin for Vagrant 7 | > may serve you better in these cases. 8 | 9 | This repository contains a [Packer](https://www.packer.io) templates for Ubuntu 10 | pre-loaded with the `opsworks-agent` software utilized by Amazon Web Services, 11 | allowing [OpsWorks](http://aws.amazon.com/opsworks/) stacks to be virtualized 12 | for local testing and development. 13 | 14 | This Packer configuration will install the `opsworks-agent-cli` command and 15 | daemon and bundle the resulting Vagrant box with a custom shell script 16 | provisioner to interface with it, manage dependencies, and simplify deployments. 17 | 18 | ## Building and Installation 19 | 20 | ```bash 21 | $ rake build # create a 'ubuntu1404-opsworks' box 22 | $ rake install # install a compiled box via 'vagrant box add' 23 | $ rake remove # remove an installed box via 'vagrant box remove' 24 | ``` 25 | 26 | By default, these will build a VirtualBox compatible Vagrant image. If you wish 27 | to create a box for VMWare, you can prefix the commands like so: 28 | 29 | ```bash 30 | $ rake vmware:build 31 | ``` 32 | 33 | Rake will build a Ubuntu 14.04 LTS "*Trusty Tahr*" box by default, but you can 34 | also specify Ubuntu 12.04 LTS "*Precise Pangolin*" like so: 35 | 36 | ```bash 37 | $ rake build[ubuntu1204] install[ubuntu1204] 38 | ``` 39 | 40 | _**Note:** Amazon Linux is not supported as it cannot be run outside of 41 | Amazon EC2._ 42 | 43 | 44 | ## Using the Box 45 | 46 | The compiled box will be named `ubuntu1404-opsworks` or `ubuntu1204-opsworks`. 47 | To utilize this box in your project, create a new Vagrantfile and include 48 | the following: 49 | 50 | ```ruby 51 | Vagrant.configure("2") do |config| 52 | config.vm.box = "ubuntu1404-opsworks" 53 | config.vm.provision "opsworks", type:"shell", args:"path/to/dna.json" 54 | end 55 | ``` 56 | 57 | The argument passed to the _opsworks_ provisioner should be a path relative to 58 | the Vagrantfile which contains the JSON to be used by chef-zero. If multiple 59 | arguments are provided, the JSON documents will be merged with the entries in 60 | the later files overriding the earlier ones. This can be useful when 61 | provisioning a multi-machine stack where parts of the configuration are shared 62 | between machines. You can see an example of this in the [_example_](example/) 63 | directory. 64 | 65 | An example JSON file might look like the following: 66 | 67 | ```json 68 | { 69 | "deploy": { 70 | "my-app": { 71 | "application_type": "php", 72 | "scm": { 73 | "scm_type": "git", 74 | "repository": "path/to/my-app" 75 | } 76 | } 77 | }, 78 | "opsworks_custom_cookbooks": { 79 | "enabled": true, 80 | "scm": { 81 | "repository": "path/to/my-cookbooks" 82 | }, 83 | "recipes": [ 84 | "recipe[opsworks_initial_setup]", 85 | "recipe[dependencies]", 86 | "recipe[mod_php5_apache2]", 87 | "recipe[deploy::default]", 88 | "recipe[deploy::php]", 89 | "recipe[my_custom_cookbook::configure]" 90 | ] 91 | } 92 | } 93 | ``` 94 | 95 | Where `path/to/my-app` and `path/to/my-cookbooks` are paths relative to the 96 | Vagrantfile. These will be copied into the vm and deployed as though they 97 | were remote git repositories. If you include a _Berksfile_ in your custom 98 | cookbooks then berkshelf will be enabled automatically. 99 | 100 | 101 | LICENSE 102 | ======= 103 | 104 | The MIT License (MIT) 105 | 106 | Copyright (c) 2017 PixelCog Inc. 107 | 108 | Permission is hereby granted, free of charge, to any person obtaining a copy 109 | of this software and associated documentation files (the "Software"), to deal 110 | in the Software without restriction, including without limitation the rights 111 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 112 | copies of the Software, and to permit persons to whom the Software is 113 | furnished to do so, subject to the following conditions: 114 | 115 | The above copyright notice and this permission notice shall be included in all 116 | copies or substantial portions of the Software. 117 | 118 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 119 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 120 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 121 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 122 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 123 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 124 | SOFTWARE. 125 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | 2 | # first is default 3 | BOXES = %w( ubuntu1404 ubuntu1204 ).freeze 4 | 5 | # namespace for each provider 6 | provider_builder = lambda do |provider| 7 | namespace provider do 8 | desc "Build a box for #{provider} using packer (default: #{BOXES.first})" 9 | task :build, [:box] do | t, args| build_box box_arg(args), provider; end 10 | 11 | desc "Install a #{provider} box with vagrant (default: #{BOXES.first})" 12 | task :install, [:box] do | t, args| install_box box_arg(args), provider; end 13 | 14 | desc "Remove an installed vagrant box for #{provider} (default: #{BOXES.first})" 15 | task :remove, [:box] do | t, args| remove_box box_arg(args), provider; end 16 | 17 | desc "Build all boxes for #{provider} using packer" 18 | task 'build-all' do BOXES.each { |box| build_box box, provider }; end 19 | 20 | desc "Install all #{provider} boxes with vagrant" 21 | task 'install-all' do BOXES.each { |box| install_box box, provider }; end 22 | 23 | desc "Remove all #{provider} boxes from vagrant" 24 | task 'remove-all' do BOXES.each { |box| remove_box box, provider }; end 25 | end 26 | end 27 | 28 | provider_builder.call(:virtualbox) 29 | provider_builder.call(:vmware) 30 | 31 | desc "Remove compiled assets and cached files" 32 | task :clean do 33 | sh 'rm -f build/*.box' 34 | end 35 | task :clear do 36 | sh 'rm -rf packer_cache' 37 | end 38 | 39 | # shortcuts to virtualbox tasks with no namespace 40 | task :build, [:box] => 'virtualbox:build' 41 | task :install, [:box] => 'virtualbox:install' 42 | task :remove, [:box] => 'virtualbox:remove' 43 | 44 | # build a box for the specified provider 45 | def build_box(box, provider) 46 | log "Building #{box} for #{provider}" 47 | sh "rm -f build/#{box}-opsworks-#{provider}.box && packer build -only=#{provider}-iso template/#{box}.json" 48 | end 49 | 50 | # build a box with vagrant 51 | def install_box(box, provider) 52 | file = "build/#{box}-opsworks-#{provider}.box" 53 | build_box(box, provider) unless File.exists?(file) 54 | 55 | log "Installing #{box}-opsworks for #{provider} with vagrant" 56 | sh "vagrant box add #{file} --force --name=#{box}-opsworks" 57 | end 58 | 59 | # remove a box from vagrant 60 | def remove_box(box, provider) 61 | log "Removing #{box} for #{provider}" 62 | provider = 'vmware_desktop' if provider.to_s == 'vmware' 63 | sh "vagrant box remove #{box} --provider=#{provider}" 64 | end 65 | 66 | # validate input for tasks with optional parameters 67 | def box_arg(args) 68 | abort "Invalid box provided" if args[:box] && !BOXES.include?(args[:box]) 69 | args[:box] || BOXES.first 70 | end 71 | 72 | def log(msg) 73 | puts "==> Rake: #{msg}" 74 | end 75 | -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | *.box -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | AWS OpsWorks "Getting Started" Example 2 | ====================================== 3 | 4 | This example implements the AWS OpsWorks "Getting Started" sample PHP application found [here](http://docs.aws.amazon.com/opsworks/latest/userguide/gettingstarted-db.html) 5 | 6 | This example depends on the `ubuntu1404-opsworks` box which must be compiled and installed: 7 | 8 | $ rake build install # assuming you are using virtualbox 9 | 10 | To run this example, first ensure that git submodules have been checked out: 11 | 12 | $ git submodule init 13 | $ git submodule update 14 | 15 | Then simply type `vagrant up` and wait for it to provision the app. You can view the results by opening up a browser and pointing it to [localhost:8080](http://localhost:8080/) -------------------------------------------------------------------------------- /example/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # This Vagrantfile configuration emulates the AWS OpsWorks example project found 5 | # in their "Getting Started" guide: 6 | # http://docs.aws.amazon.com/opsworks/latest/userguide/gettingstarted-db.html 7 | 8 | Vagrant.configure("2") do |config| 9 | 10 | config.vm.box = "ubuntu1404-opsworks" 11 | 12 | # Create the php-app layer 13 | config.vm.define "app" do |layer| 14 | 15 | layer.vm.provision "opsworks", type:"shell", args:[ 16 | 'ops/dna/stack.json', 17 | 'ops/dna/php-app.json' 18 | ] 19 | 20 | # Forward port 80 so we can see our work 21 | layer.vm.network "forwarded_port", guest: 80, host: 8080 22 | layer.vm.network "private_network", ip: "10.10.10.10" 23 | end 24 | 25 | # Create the db-master layer 26 | config.vm.define "db" do |layer| 27 | 28 | layer.vm.provision "opsworks", type:"shell", args:[ 29 | 'ops/dna/stack.json', 30 | 'ops/dna/db-master.json' 31 | ] 32 | 33 | layer.vm.network "private_network", ip: "10.10.10.20" 34 | end 35 | end -------------------------------------------------------------------------------- /example/ops/dna/db-master.json: -------------------------------------------------------------------------------- 1 | { 2 | "opsworks_custom_cookbooks": { 3 | "recipes": [ 4 | "recipe[opsworks_initial_setup]", 5 | "recipe[ssh_host_keys]", 6 | "recipe[ssh_users]", 7 | "recipe[mysql::client]", 8 | "recipe[dependencies]", 9 | "recipe[ebs]", 10 | "recipe[opsworks_ganglia::client]", 11 | "recipe[mysql::server]", 12 | "recipe[deploy::mysql]", 13 | "recipe[phpapp::dbsetup]", 14 | "recipe[opsworks_ganglia::configure-client]", 15 | "recipe[agent_version]" 16 | ] 17 | } 18 | } -------------------------------------------------------------------------------- /example/ops/dna/php-app.json: -------------------------------------------------------------------------------- 1 | { 2 | "opsworks_custom_cookbooks": { 3 | "recipes": [ 4 | "recipe[opsworks_initial_setup]", 5 | "recipe[ssh_host_keys]", 6 | "recipe[ssh_users]", 7 | "recipe[mysql::client]", 8 | "recipe[dependencies]", 9 | "recipe[ebs]", 10 | "recipe[opsworks_ganglia::client]", 11 | "recipe[mod_php5_apache2]", 12 | "recipe[deploy::default]", 13 | "recipe[deploy::php]", 14 | "recipe[phpapp::appsetup]", 15 | "recipe[opsworks_ganglia::configure-client]", 16 | "recipe[agent_version]", 17 | "recipe[php::configure]" 18 | ] 19 | } 20 | } -------------------------------------------------------------------------------- /example/ops/dna/stack.json: -------------------------------------------------------------------------------- 1 | { 2 | "opsworks": { 3 | "layers": { 4 | "php-app": { 5 | "instances": { 6 | "php-app1": {"private-ip": "10.10.10.10"} 7 | } 8 | }, 9 | "db-master": { 10 | "instances": { 11 | "db-master1": {"private-ip": "10.10.10.20"} 12 | } 13 | } 14 | } 15 | }, 16 | "deploy": { 17 | "simple-php": { 18 | "application_type": "php", 19 | "document_root": "web", 20 | "scm": { 21 | "scm_type": "git", 22 | "repository": "dev/simple-php" 23 | }, 24 | "memcached": {}, 25 | "database": { 26 | "host": "10.10.10.20", 27 | "database": "simple-php", 28 | "username": "root", 29 | "password": "correcthorsebatterystaple", 30 | "reconnect": true 31 | } 32 | } 33 | }, 34 | "mysql": { 35 | "server_root_password": "correcthorsebatterystaple", 36 | "tunable": {"innodb_buffer_pool_size": "256M"} 37 | }, 38 | "opsworks_custom_cookbooks": { 39 | "enabled": true, 40 | "scm": { 41 | "repository": "ops/cookbooks" 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /opsworks/Vagrantfile.template: -------------------------------------------------------------------------------- 1 | 2 | # require vagrant version 1.7.0 to allow for the named provisioners syntax 3 | Vagrant.require_version(">= 1.7.0") 4 | box_root = File.dirname(__FILE__) 5 | 6 | Vagrant.configure("2") do |config| 7 | config.vm.synced_folder box_root, '/tmp/vagrant-opsworks' 8 | config.vm.provision 'opsworks', type: 'shell' do |shell| 9 | shell.inline = '/bin/bash /tmp/vagrant-opsworks/opsworks "$@"' 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /opsworks/client.yml: -------------------------------------------------------------------------------- 1 | # opsworks chef client config file 2 | # /var/lib/aws/opsworks/client.yml 3 | --- 4 | 5 | :local_mode: true 6 | :log_level: :info 7 | :ohai_plugin_path: /opt/aws/opsworks/current/plugins 8 | :cookbook_path: ["/opt/aws/opsworks/current/merged-cookbooks"] 9 | :default_cookbooks_path: /opt/aws/opsworks/current/cookbooks 10 | :site_cookbooks_path: /opt/aws/opsworks/current/site-cookbooks 11 | :merged_cookbooks_path: /opt/aws/opsworks/current/merged-cookbooks 12 | :berkshelf_cookbooks_path: /opt/aws/opsworks/current/berkshelf-cookbooks 13 | :berkshelf_cache_path: /var/lib/aws/opsworks/berkshelf_cache 14 | :file_cache_path: /var/lib/aws/opsworks/cache 15 | :search_nodes_path: /var/lib/aws/opsworks/data/nodes 16 | :data_bag_path: /var/lib/aws/opsworks/data/data_bags 17 | -------------------------------------------------------------------------------- /opsworks/opsworks: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit if no arguments provided 4 | if [[ $# -eq 0 ]]; then 5 | echo "Nothing to do..." 6 | exit 7 | fi 8 | 9 | # install opsworks agent if not already available 10 | if [[ ! -f /opt/aws/opsworks/current/VERSION ]]; then 11 | 12 | # decide which agent version to install 13 | if [[ -z $OPSWORKS_AGENT_VERSION ]]; then 14 | OPSWORKS_AGENT_VERSION='3432-20160120135248' 15 | fi 16 | 17 | # install dependencies 18 | echo "Installing OpsWorks agent dependencies" 19 | apt-get -yq update 20 | apt-get -yq install curl libxml2-dev libxslt-dev libyaml-dev 21 | 22 | # create expected directories and populate them with expected config files 23 | mkdir -p /{etc,opt,var/{log,lib}}/aws/opsworks/ /var/lib/cloud/ 24 | cp $(dirname "${BASH_SOURCE[0]}")/{client.yml,pre_config.yml} /var/lib/aws/opsworks/ 25 | 26 | # create a temporary directory to work in 27 | TMP_DIR=$(mktemp -d "opsworks-installer.XXXXXXXX") 28 | trap 'rm -rf "$TMP_DIR"' EXIT 29 | pushd $TMP_DIR 30 | 31 | # download and install the requested opsworks agent 32 | echo "Installing OpsWorks agent version $OPSWORKS_AGENT_VERSION" 33 | wget -nv -O opsworks-agent-installer.tgz https://opsworks-instance-agent.s3.amazonaws.com/$OPSWORKS_AGENT_VERSION/opsworks-agent-installer.tgz 34 | tar -xzpof opsworks-agent-installer.tgz 35 | cd opsworks-agent-installer/opsworks-agent/bin/ 36 | ./installer_wrapper.sh -R opsworks-instance-assets.s3.amazonaws.com 37 | 38 | # return to our previous location and destroy our temporary directory 39 | popd > /dev/null 40 | rm -rf "$TMP_DIR" 41 | trap - EXIT 42 | 43 | # ensure we can access the opsworks chef gem 44 | echo "export PATH=\$PATH:/opt/aws/opsworks/current/bin" > /etc/profile.d/opsworks_path.sh 45 | fi 46 | 47 | # set the vagrant shared directory as cwd if available 48 | [ -d /vagrant ] && cd /vagrant 49 | 50 | # run our provisioner 51 | env /opt/aws/opsworks/local/bin/ruby $(dirname "${BASH_SOURCE[0]}")/opsworks.rb "$@" 52 | -------------------------------------------------------------------------------- /opsworks/opsworks.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # OpsWorks provisioner for Vagrant 4 | # -------------------------------- 5 | # Copyright (c) 2016 PixelCog Inc. 6 | # Licensed under MIT (see LICENSE) 7 | 8 | require 'date' 9 | require 'json' 10 | require 'tmpdir' 11 | require 'fileutils' 12 | 13 | module OpsWorks 14 | 15 | class OpsWorksError < StandardError; end 16 | 17 | DNA_BASE = { 18 | "ssh_users" => { 19 | "1000" => { 20 | "name" => "vagrant", 21 | "public_key" => nil, 22 | "sudoer" => true 23 | } 24 | }, 25 | "dependencies" => { 26 | "gem_binary" => "/usr/local/bin/gem", 27 | "gems" => {}, 28 | "debs" => {} 29 | }, 30 | "ec2" => { 31 | "instance_type" => "vm.vagrant" 32 | }, 33 | "opsworks_initial_setup" => { 34 | "swapfile_instancetypes" => ["vm.vagrant"] 35 | }, 36 | "ebs" => { 37 | "devices" => {}, 38 | "raids" => {} 39 | }, 40 | "opsworks" => { 41 | "activity" => "setup", 42 | "valid_client_activities" => ["setup"], 43 | "agent_version" => 0, 44 | "ruby_version" => "2.0.0", 45 | "ruby_stack" => "ruby", 46 | "rails_stack" => { 47 | "name" => nil 48 | }, 49 | "stack" => { 50 | "name" => "Vagrant Stack", 51 | "elb-load-balancers" => [], 52 | "rds_instances" => [] 53 | }, 54 | "layers" => {}, 55 | "instance" => { 56 | "infrastructure_class" => "ec2", 57 | "ip" => "127.0.0.1", 58 | "private_ip" => "127.0.0.1", 59 | "layers" => [] 60 | } 61 | }, 62 | "deploy" => {}, 63 | "opsworks_rubygems" => { 64 | "version" => "2.2.2" 65 | }, 66 | "opsworks_bundler" => { 67 | "version" => "1.5.3", 68 | "manage_package" => nil 69 | }, 70 | "opsworks_custom_cookbooks" => { 71 | "enabled" => false, 72 | "scm" => { 73 | "type" => "git", 74 | "repository" => nil, 75 | "user" => nil, 76 | "password" => nil, 77 | "revision" => nil, 78 | "ssh_key" => nil 79 | }, 80 | "manage_berkshelf" => nil, 81 | "recipes" => [] 82 | }, 83 | "chef_environment" => "_default", 84 | "recipes" => [ 85 | "opsworks_custom_cookbooks::load", 86 | "opsworks_custom_cookbooks::execute" 87 | ] 88 | } 89 | 90 | DNA_DEPLOY_BASE = { 91 | "deploy_to" => nil, 92 | "application" => nil, 93 | "deploying_user" => nil, 94 | "domains" => [], 95 | "application_type" => nil, 96 | "mounted_at" => nil, 97 | "rails_env" => nil, 98 | "ssl_support" => false, 99 | "ssl_certificate" => nil, 100 | "ssl_certificate_key" => nil, 101 | "ssl_certificate_ca" => nil, 102 | "document_root" => nil, 103 | "restart_command" => "echo 'restarting app'", 104 | "sleep_before_restart" => 0, 105 | "symlink_before_migrate" => {}, 106 | "symlinks" => {}, 107 | "database" => {}, 108 | "migrate" => false, 109 | "auto_bundle_on_deploy" => true, 110 | "scm" => { 111 | "scm_type" => "git", 112 | "repository" => nil, 113 | "revision" => nil, 114 | "ssh_key" => nil, 115 | "user" => nil, 116 | "password" => nil 117 | } 118 | } 119 | 120 | def self.provision(*args) 121 | if agent_revision < Date.today.prev_month(4) 122 | warn "Warning: OpsWorks agent version #{agent_version} is over four months old, consider updating..." 123 | end 124 | 125 | log "Checking dependencies..." 126 | check_dependencies 127 | 128 | log "Reading input..." 129 | dna = compile_json expand_paths(args) 130 | 131 | log "Parsing deployments..." 132 | dna['deploy'].each do |name, app| 133 | 134 | # if repo points to a local path, trick opsworks into receiving it as a git repo 135 | if app['scm']['repository'] && app['scm']['repository'] !~ /^(?:[A-Za-z0-9]+@|http(|s)\:\/\/)/i 136 | if !Dir.exist?(app['scm']['repository']) 137 | raise OpsWorksError, "Local app '#{name}' could not be found at '#{app['scm']['repository']}'" 138 | end 139 | app['scm']['repository'] = prepare_deployment(app['scm']['repository']) 140 | end 141 | end 142 | 143 | log "Parsing custom cookbooks..." 144 | if dna['opsworks_custom_cookbooks']['enabled'] 145 | cookbooks = dna['opsworks_custom_cookbooks'] 146 | 147 | # if repo points to a local path, trick opsworks into receiving it as a git repo 148 | if cookbooks['scm']['repository'] && cookbooks['scm']['repository'] !~ /^(?:[A-Za-z0-9]+@|http(|s)\:\/\/)/i 149 | if !Dir.exist?(cookbooks['scm']['repository']) 150 | raise OpsWorksError, "Local custom cookbooks could not be found at '#{cookbooks['scm']['repository']}'" 151 | end 152 | cookbooks['scm']['repository'] = prepare_deployment(cookbooks['scm']['repository']) 153 | 154 | # autodetect berkshelf support 155 | if cookbooks['manage_berkshelf'].nil? 156 | berksfile = cookbooks['scm']['repository'].sub(/[\/\\]+$/,'') + '/Berksfile' 157 | cookbooks['manage_berkshelf'] = File.exist?(berksfile) 158 | end 159 | end 160 | 161 | # remove the local cache to force opsworks to update custom cookbooks 162 | log "Purging local cookbooks cache from '/opt/aws/opsworks/current/site-cookbooks'..." 163 | FileUtils.rm_rf('/opt/aws/opsworks/current/site-cookbooks/') 164 | end 165 | 166 | if dna['opsworks']['instance']['hostname'] 167 | log "Setting instance hostname..." 168 | set_hostname dna['opsworks']['instance']['hostname'] 169 | end 170 | 171 | # run some base recipes if none explicitly provided 172 | if dna['opsworks_custom_cookbooks']['recipes'].empty? 173 | dna['opsworks_custom_cookbooks']['recipes']= %w( 174 | recipe[opsworks_initial_setup] 175 | recipe[ssh_host_keys] 176 | recipe[ssh_users] 177 | recipe[dependencies] 178 | recipe[ebs] 179 | recipe[agent_version] 180 | recipe[opsworks_stack_state_sync] 181 | recipe[opsworks_cleanup] 182 | ) 183 | end 184 | 185 | log "Generating dna.json..." 186 | dna_file = save_json_tempfile dna, 'dna.json' 187 | 188 | log "Running opsworks agent..." 189 | 190 | # AWS currently does not set UTF-8 as default encoding 191 | system({"LANG" => "POSIX"}, "opsworks-agent-cli run_command -f #{dna_file}") 192 | 193 | rescue OpsWorksError => e 194 | warn "Error: #{e}" 195 | exit false 196 | end 197 | 198 | def self.save_json_tempfile(data, name) 199 | tmp_dir = Dir.mktmpdir('vagrant-opsworks') 200 | File.chmod(0755, tmp_dir) 201 | 202 | tmp_file = "#{tmp_dir}/#{name}" 203 | File.open(tmp_file, 'w') { |f| f.write JSON.pretty_generate(data) } 204 | File.chmod(0755, tmp_file) 205 | 206 | tmp_file 207 | end 208 | 209 | def self.log(msg) 210 | puts msg 211 | end 212 | 213 | def self.check_dependencies 214 | `apt-get -yq install git 2>&1` if `which git`.empty? 215 | end 216 | 217 | def self.set_hostname(hostname) 218 | if !File.readlines('/etc/hosts').grep(/(?=[^\.\w-]|$)#{hostname}(?=[^\.\w-]|$)/).any? 219 | File.open('/etc/hosts', 'a') do |f| 220 | f.puts "\n127.0.0.1\t#{hostname}.localdomain #{hostname}\n" 221 | end 222 | end 223 | File.write('/etc/hostname', hostname) 224 | system('hostname', hostname) 225 | end 226 | 227 | def self.expand_paths(args) 228 | files = [] 229 | args.each do |file| 230 | if File.exist?(file) 231 | files << file 232 | elsif file.include? '*' 233 | files += Dir.glob(file) 234 | else 235 | raise OpsWorksError, "The file '#{file}' does not appear to exist." 236 | end 237 | end 238 | files 239 | end 240 | 241 | def self.compile_json(files) 242 | # combine all json files into one hash, starting with our base hash to 243 | # provide some sensible defaults 244 | dna = files.reduce(DNA_BASE) do |dna, file| 245 | log "Processing '#{file}'..." 246 | begin 247 | json = File.read(file).strip || '{}' 248 | json = JSON.parse(json) 249 | rescue JSON::ParserError => e 250 | raise OpsWorksError, "The file '#{file}' does not appear to be valid JSON. (error: #{e})" 251 | end 252 | deep_merge(dna, json) 253 | end 254 | 255 | # ensure each layer has some required fields including instances with both 256 | # private and public ip addresses 257 | dna['opsworks']['layers'].each do |name, layer| 258 | next unless Hash === layer 259 | layer['name'] ||= name 260 | layer['elb-load-balancers'] ||= [] 261 | layer['instances'] ||= {} 262 | 263 | next unless Hash === layer['instances'] 264 | layer['instances'].each do |name, instance| 265 | next unless Hash === instance 266 | instance['private_ip'] ||= instance['ip'] 267 | instance['ip'] ||= instance['private_ip'] 268 | end 269 | end 270 | 271 | # merge some default values into each app definition 272 | dna['deploy'].each do |name, app| 273 | app.replace deep_merge(DNA_DEPLOY_BASE, app) 274 | app['application'] ||= name 275 | app['domains'] << name if app['domains'].empty? 276 | end 277 | 278 | dna 279 | end 280 | 281 | def self.prepare_deployment(path) 282 | tmp_dir = Dir.mktmpdir('vagrant-opsworks') 283 | File.chmod(0755, tmp_dir) 284 | FileUtils.cp_r("#{path}/.", tmp_dir) 285 | Dir.chdir(tmp_dir) do 286 | `find . -name '.git*' -exec rm -rf {} \\; 2>&1; git init; git add .; git -c user.name='Vagrant' -c user.email=none commit -m 'Create temporary repository for deployment.'` 287 | end 288 | tmp_dir 289 | end 290 | 291 | def self.deep_merge(a, b) 292 | a.merge(b) { |_, a, b| Hash === a && Hash === b ? deep_merge(a, b) : b } 293 | end 294 | 295 | def self.agent_version 296 | File.read('/opt/aws/opsworks/current/REVISION')[/\d\d\d\d\-\d\d-\d\d-\d\d:\d\d:\d\d (\d+)/, 1].to_i 297 | end 298 | 299 | def self.agent_revision 300 | date_string = File.read('/opt/aws/opsworks/current/REVISION')[/(\d\d\d\d\-\d\d-\d\d-\d\d:\d\d:\d\d)/, 1] 301 | raise OpsWorksError, 'Unable to parse agent revision' unless date_string 302 | DateTime.strptime date_string, '%Y-%m-%d-%H:%M:%S' 303 | end 304 | end 305 | 306 | # automatically run provisioner 307 | if __FILE__ == $0 308 | STDOUT.sync = true 309 | OpsWorks.provision *ARGV 310 | end 311 | -------------------------------------------------------------------------------- /opsworks/pre_config.yml: -------------------------------------------------------------------------------- 1 | # opsworks-agent pre-config file 2 | # /var/lib/aws/opsworks/pre_config.yml 3 | --- 4 | 5 | :hostname: opsworks-vagrant 6 | :identity: ffffffff-ffff-ffff-ffff-ffffffffffff 7 | :agent_installer_base_url: opsworks-instance-agent.s3.amazonaws.com 8 | :agent_installer_tgz: opsworks-agent-installer.tgz 9 | :verbose: false 10 | :instance_service_region: us-east-1 11 | :instance_service_endpoint: localhost 12 | :instance_service_port: '65535' 13 | :instance_public_key: | 14 | -----BEGIN PUBLIC KEY----- 15 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA30W1qY/kuT3H0QJAWaOs 16 | 0tLI8E64OKKCsK6908NL8ReroxsYHZHjzl5+ZNw7YE4QENBZ4eWR4gbC2z/YT/5b 17 | U6LrZZUCuIdSL+9cMyBUUOTEV1W1Z5EtZkB8PgoDm2+SSDnL9F6Tww+oiD27kA4n 18 | xa68i6Y0+tGARAkC11tX7z7Yg0cfkLYXcY3weueXagbIdF+esxuVFXj+Jz/oyBwP 19 | qU1lVWQ1b3ZYv2XPnmMuJPfdENI/0YHkXm1JMhdseEUPS3TuZalqpDIbG/9m1ZMB 20 | GiH5UUshMm2GldDjjEnVV024K+WFi7ww76+pJcdZ8NcyLXVzLEH/CiwhnQigFzw3 21 | xQIDAQAB 22 | -----END PUBLIC KEY----- 23 | :instance_private_key: | 24 | -----BEGIN RSA PRIVATE KEY----- 25 | MIIEpAIBAAKCAQEA30W1qY/kuT3H0QJAWaOs0tLI8E64OKKCsK6908NL8ReroxsY 26 | HZHjzl5+ZNw7YE4QENBZ4eWR4gbC2z/YT/5bU6LrZZUCuIdSL+9cMyBUUOTEV1W1 27 | Z5EtZkB8PgoDm2+SSDnL9F6Tww+oiD27kA4nxa68i6Y0+tGARAkC11tX7z7Yg0cf 28 | kLYXcY3weueXagbIdF+esxuVFXj+Jz/oyBwPqU1lVWQ1b3ZYv2XPnmMuJPfdENI/ 29 | 0YHkXm1JMhdseEUPS3TuZalqpDIbG/9m1ZMBGiH5UUshMm2GldDjjEnVV024K+WF 30 | i7ww76+pJcdZ8NcyLXVzLEH/CiwhnQigFzw3xQIDAQABAoIBAQDF6Ji6kJ4BxU2V 31 | axV3X6oVxlnvCRgqu4J08q+5QefS8VRm4+FgdK0lhIUtCjpnh0qeXNEPd9r0K2IV 32 | zmYDokd5v3RBOvCKeQjVDKsBdqrGecHAWGzQPNOtS4PVyjKgWSmlc/XhyuPXh82v 33 | 1minrKR8igL/Fnjny0STChnGo2Uy3y3X089VIWlkKskSTLe73jTN7EeI47+LHJul 34 | ULiV8Oh7YbEHf4w6Fz+1LNxcCJg8rNYeJKrGbCBq/ImygiJp14+oTU2nCDQSBJqF 35 | bdUPhtpQDlDsAsfgBavYb3fHc0ZBVbCwM84VSdktKz9QbINI2Ugh+lI201woORlZ 36 | MCqClgwRAoGBAPs1vapbsNbb+zRIxKRKfOLcay3O9efPyUqOPIMmn3pbpxk0GEBg 37 | KQXO5PZmDP25oLA3bLvowVMMgShY1WRAr7ReloIRHaARVo+If8c7G83nePycYZ3f 38 | C/ztfzsKpBO2SVzUkQIzh6rogK/rKUa/FCwZ/Gnf93v/j5RyUmLWXoZrAoGBAOOH 39 | l/yCaxdY5khc1uEbCQDzT9lqWKcgFjoVuWO7o4vallNIDnCDd7olGbR2oIWbJAtB 40 | mKpXLIWVjcRPXGp9Kr07mvkL+/mO2m6tG/vFJDh5Jge/qoOK4d1KEb2y+PwK+XRK 41 | /SkAEcT6qpLMdz5W/Oy/wBc8b/BeBJkSoF1/weaPAoGAZ3eGDBHB720htTI3k/d+ 42 | Iq5okrCIhhcGMGgPMnGJBAuV8oKLbpBstRC3K2ly9lorfgkGBwth/QPMesLD+YvP 43 | ErpWwXGtQw2BGpM9FeEZnaA2K815Q13oASAM5FOIqvnMk6iVpVN2EIW84zg3gwUW 44 | mOeHGFCADZmAGMNRfZYPzssCgYAnCWB+JjIRc2MvDx6eyHCnBReyCZjkM5EcrhV8 45 | kvjgScR4zWgMzcGA4lSiraekxJVOiRaUQxiUYrBL+gG1E3x9svhHulKk4ml/i5u9 46 | enlYZxCrS6sJno5Z1RduIIKvW4Ko/SSqICTsUsVpIkNjIrGKPOvMEMZzyu2nBZcV 47 | 85Fk6QKBgQDLfvbS010HhYuEoW9NtSgeSxaJaCTU82EURBoL3F1umPcc1+EmtvnE 48 | WbjdSwiVT7tb8F/yM6wIGjHEaNdIPdIakHEPU4MfJFDe/+aPwk2M1MCCpbERgyJR 49 | m4SlK1pWQsPZ6Em0C+bw+dnkThEXXb3kfWSxnuh0d7JjfX+Fd/8F6Q== 50 | -----END RSA PRIVATE KEY----- 51 | :charlie_public_key: | 52 | -----BEGIN PUBLIC KEY----- 53 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAni7eKdm34oaCvGiw96Fk 54 | lyLX+aPfInYzilkk+AY3pXF6nijpQ2cm3ZeM2EoqZFTv3a/meosNBAs3Q3Sy1e4G 55 | 7Ibn/xwMof+iSBvimx3PGKFzNP0BhY9yS6AMEMxtmqksHb0glwmFeJcomdhxZV1F 56 | ziWTtL6ZEyvCg0I7rxGm1ceQmD25eK90VcZVh4LJtNfnwcZRM4eC+KK9Qllxw5hW 57 | vB4Z52JMMZbEG9MYCLydWSY9rnVkAyQ0ngJUaJ3q7JsbkBV/J5BcrGgcbioR1k+h 58 | INRoHwBQU9WnT/x8W+N6vwJb4o6v2hBR1H2GSDLwyZ7wC8EVH+XafWYpU1g/nSEe 59 | aQIDAQAB 60 | -----END PUBLIC KEY----- 61 | :wait_between_runs: '60' 62 | -------------------------------------------------------------------------------- /preseed/preseed.cfg: -------------------------------------------------------------------------------- 1 | choose-mirror-bin mirror/http/proxy string 2 | d-i base-installer/kernel/override-image string linux-server 3 | d-i clock-setup/utc boolean true 4 | d-i clock-setup/utc-auto boolean true 5 | d-i finish-install/reboot_in_progress note 6 | d-i grub-installer/only_debian boolean true 7 | d-i grub-installer/with_other_os boolean true 8 | d-i partman-auto-lvm/guided_size string max 9 | d-i partman-auto/choose_recipe select atomic 10 | d-i partman-auto/method string lvm 11 | d-i partman-lvm/confirm boolean true 12 | d-i partman-lvm/confirm boolean true 13 | d-i partman-lvm/confirm_nooverwrite boolean true 14 | d-i partman-lvm/device_remove_lvm boolean true 15 | d-i partman/choose_partition select finish 16 | d-i partman/confirm boolean true 17 | d-i partman/confirm_nooverwrite boolean true 18 | d-i partman/confirm_write_new_label boolean true 19 | d-i passwd/user-fullname string vagrant 20 | d-i passwd/user-uid string 900 21 | d-i passwd/user-password password vagrant 22 | d-i passwd/user-password-again password vagrant 23 | d-i passwd/username string vagrant 24 | d-i pkgsel/include string openssh-server ntp curl nfs-common linux-headers-$(uname -r) build-essential perl dkms 25 | d-i pkgsel/install-language-support boolean false 26 | d-i pkgsel/update-policy select unattended-upgrades 27 | d-i pkgsel/upgrade select full-upgrade 28 | d-i time/zone string UTC 29 | d-i user-setup/allow-password-weak boolean true 30 | d-i user-setup/encrypt-home boolean false 31 | tasksel tasksel/first multiselect standard, ubuntu-server -------------------------------------------------------------------------------- /provision/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | 3 | # Force grub to boot without user interation 4 | echo "GRUB_RECORDFAIL_TIMEOUT=10" >> /etc/default/grub 5 | update-grub 6 | 7 | echo "==> Cleaning up tmp" 8 | rm -rf /tmp/* 9 | 10 | # Remove Bash history 11 | unset HISTFILE 12 | rm -f /root/.bash_history 13 | rm -f /home/vagrant/.bash_history 14 | 15 | # Clean up log files 16 | find /var/log -type f | while read f; do echo -ne '' > $f; done; 17 | 18 | echo "==> Clearing last login information" 19 | >/var/log/lastlog 20 | >/var/log/wtmp 21 | >/var/log/btmp 22 | 23 | # Whiteout root 24 | count=$(df --sync -kP / | tail -n1 | awk -F ' ' '{print $4}') 25 | let count-- 26 | dd if=/dev/zero of=/tmp/whitespace bs=1024 count=$count 27 | rm /tmp/whitespace 28 | 29 | # Whiteout /boot 30 | count=$(df --sync -kP /boot | tail -n1 | awk -F ' ' '{print $4}') 31 | let count-- 32 | dd if=/dev/zero of=/boot/whitespace bs=1024 count=$count 33 | rm /boot/whitespace 34 | 35 | # Zero out the free space to save space in the final image 36 | dd if=/dev/zero of=/EMPTY bs=1M 37 | rm -f /EMPTY 38 | 39 | # Make sure we wait until all the data is written to disk, otherwise 40 | # Packer might quite too early before the large files are deleted 41 | sync -------------------------------------------------------------------------------- /provision/minimize.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | 3 | echo "==> Installed packages before cleanup" 4 | dpkg --get-selections | grep -v deinstall 5 | 6 | # Remove some packages to get a minimal install 7 | echo "==> Removing all linux kernels except the currrent one" 8 | dpkg --list | awk '{ print $2 }' | grep 'linux-image-3.*-generic' | grep -v $(uname -r) | xargs apt-get -y purge 9 | echo "==> Removing linux source" 10 | dpkg --list | awk '{ print $2 }' | grep linux-source | xargs apt-get -y purge 11 | # echo "==> Removing development packages" 12 | # dpkg --list | awk '{ print $2 }' | grep -- '-dev$' | xargs apt-get -y purge 13 | echo "==> Removing documentation" 14 | dpkg --list | awk '{ print $2 }' | grep -- '-doc$' | xargs apt-get -y purge 15 | echo "==> Removing X11 libraries" 16 | apt-get -y purge libx11-data xauth libxmuu1 libxcb1 libx11-6 libxext6 17 | echo "==> Removing obsolete networking components" 18 | apt-get -y purge ppp pppconfig pppoeconf 19 | echo "==> Removing other oddities" 20 | apt-get -y purge popularity-contest installation-report landscape-common wireless-tools wpasupplicant ubuntu-serverguide 21 | 22 | # Clean up the apt cache 23 | apt-get -y autoremove --purge 24 | apt-get -y autoclean 25 | apt-get -y clean 26 | 27 | # Clean up orphaned packages with deborphan 28 | apt-get -y install deborphan 29 | while [ -n "$(deborphan --guess-all --libdevel)" ]; do 30 | deborphan --guess-all --libdevel | xargs apt-get -y purge 31 | done 32 | apt-get -y purge deborphan dialog 33 | 34 | # echo "==> Removing man pages" 35 | # rm -rf /usr/share/man/* 36 | # echo "==> Removing APT files" 37 | # find /var/lib/apt -type f | xargs rm -f 38 | echo "==> Removing anything in /usr/src" 39 | rm -rf /usr/src/* 40 | echo "==> Removing any docs" 41 | rm -rf /usr/share/doc/* 42 | echo "==> Removing caches" 43 | find /var/cache -type f -exec rm -rf {} \; -------------------------------------------------------------------------------- /provision/network.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | 3 | # Make sure udev does not block our network - http://6.ptmc.org/?p=164 4 | echo "==> Cleaning up udev rules" 5 | rm -rf /dev/.udev/ 6 | rm /lib/udev/rules.d/75-persistent-net-generator.rules 7 | 8 | if [ -d "/var/lib/dhcp" ]; then 9 | echo "==> Cleaning up leftover dhcp leases" 10 | rm /var/lib/dhcp/* 11 | fi 12 | 13 | # Add delay to prevent "vagrant reload" from failing 14 | echo "pre-up sleep 2" >> /etc/network/interfaces 15 | 16 | # Disable DNS reverse lookup 17 | echo "UseDNS no" >> /etc/ssh/sshd_config -------------------------------------------------------------------------------- /provision/opsworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | 3 | # set the agent version to be installed 4 | AGENT_VERSION="3432-20160120135248" 5 | 6 | echo "==> Generating chef json for first OpsWorks run" 7 | TMPDIR=$(mktemp -d) && trap 'rm -rf "$TMPDIR"' EXIT 8 | mkdir -p $TMPDIR/cookbooks 9 | 10 | # Create a base json file to execute some default recipes 11 | cat < $TMPDIR/dna.json 12 | { 13 | "opsworks_initial_setup": { 14 | "swapfile_instancetypes": null 15 | }, 16 | "opsworks_custom_cookbooks": { 17 | "enabled": true, 18 | "scm": { 19 | "repository": "$TMPDIR/cookbooks" 20 | }, 21 | "manage_berkshelf": true, 22 | "recipes": [ 23 | "recipe[opsworks_initial_setup]", 24 | "recipe[ssh_host_keys]", 25 | "recipe[ssh_users]", 26 | "recipe[dependencies]", 27 | "recipe[apt]", 28 | "recipe[deploy::default]", 29 | "recipe[agent_version]", 30 | "recipe[opsworks_stack_state_sync]", 31 | "recipe[opsworks_cleanup]" 32 | ] 33 | } 34 | } 35 | EOT 36 | 37 | # Use Berkshelf to pre-load some commonly-used community cookbooks 38 | cat <> $TMPDIR/cookbooks/Berksfile 39 | source "https://supermarket.getchef.com" 40 | 41 | # pre-load some opscode community cookbooks 42 | cookbook "apt", "~> 2.7.0" 43 | # cookbook "apache2" 44 | # cookbook "aws" 45 | cookbook "bluepill", "~> 2.3.1" 46 | cookbook "build-essential", "~> 2.2.3" 47 | # cookbook "couchdb" 48 | # cookbook "cron" 49 | # cookbook "git" 50 | # cookbook "haproxy" 51 | # cookbook "memcached" 52 | cookbook "mongodb", "~> 0.16.2" 53 | # cookbook "mysql" 54 | # cookbook "newrelic" 55 | # cookbook "nginx" 56 | # cookbook "nodejs" 57 | cookbook "ohai", "~> 2.0.1" 58 | # cookbook "postgresql" 59 | # cookbook "php" 60 | cookbook "php-fpm", "~> 0.7.4" 61 | cookbook "python", "~> 1.4.6" 62 | cookbook "redisio", "~> 2.3.0" 63 | cookbook "rsyslog", "~> 2.0.0" 64 | cookbook "runit", "~> 1.6.0" 65 | # cookbook "sysctl" 66 | cookbook "yum", "~> 3.6.0" 67 | cookbook "yum-epel", "~> 0.6.0" 68 | EOT 69 | 70 | echo "==> Installing and running OpsWorks agent" 71 | chmod +x /tmp/opsworks/opsworks 72 | env OPSWORKS_AGENT_VERSION="$AGENT_VERSION" /tmp/opsworks/opsworks $TMPDIR/dna.json 73 | -------------------------------------------------------------------------------- /provision/update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | 3 | echo "==> Updating packages" 4 | 5 | sudo find /var/lib/apt/lists -type f -exec rm -v {} \; 6 | apt-get -y update 7 | apt-get -y upgrade -------------------------------------------------------------------------------- /provision/vagrant.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | 3 | # https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub 4 | VAGRANT_INSECURE_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key" 5 | 6 | # Store build time 7 | date > /etc/vagrant_box_build_time 8 | 9 | # Create Vagrant user (if not already present) 10 | if ! id -u vagrant >/dev/null 2>&1; then 11 | echo "==> Creating vagrant user" 12 | /usr/sbin/groupadd vagrant 13 | /usr/sbin/useradd vagrant -g vagrant -G sudo -d /home/vagrant --create-home 14 | echo "vagrant:vagrant" | chpasswd 15 | fi 16 | 17 | echo "==> Giving vagrant sudo powers" 18 | echo "vagrant ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers 19 | 20 | echo "==> Installing vagrant key" 21 | mkdir -p /home/vagrant/.ssh 22 | chmod 700 /home/vagrant/.ssh 23 | echo "${VAGRANT_INSECURE_KEY}" > /home/vagrant/.ssh/authorized_keys 24 | chmod 600 /home/vagrant/.ssh/authorized_keys 25 | chown -R vagrant:vagrant /home/vagrant/.ssh 26 | 27 | # Remove those annoying "stdin: is not a tty" messages when running vagrant 28 | sed -i "s/mesg n/tty -s \&\& mesg n/g" /root/.profile -------------------------------------------------------------------------------- /provision/vmtools.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eux 2 | 3 | if [ -f /home/vagrant/.vbox_version ]; then 4 | echo "==> Installing VirtualBox guest additions" 5 | # Assuming the following packages are installed 6 | # apt-get install -y linux-headers-$(uname -r) build-essential perl 7 | # apt-get install -y dkms 8 | 9 | VBOX_VERSION=$(cat /home/vagrant/.vbox_version) 10 | mount -o loop /home/vagrant/VBoxGuestAdditions_$VBOX_VERSION.iso /mnt 11 | sh /mnt/VBoxLinuxAdditions.run 12 | umount /mnt 13 | rm /home/vagrant/VBoxGuestAdditions_$VBOX_VERSION.iso 14 | rm /home/vagrant/.vbox_version 15 | 16 | if [[ $VBOX_VERSION = "4.3.10" ]]; then 17 | ln -s /opt/VBoxGuestAdditions-4.3.10/lib/VBoxGuestAdditions /usr/lib/VBoxGuestAdditions 18 | fi 19 | fi 20 | 21 | if [ -f /home/vagrant/vmware_tools.iso ]; then 22 | echo "==> Installing VMware Tools" 23 | # Assuming the following packages are installed 24 | # apt-get install -y linux-headers-$(uname -r) build-essential perl 25 | 26 | cd /tmp 27 | mkdir -p /mnt/cdrom 28 | mount -o loop /home/vagrant/vmware_tools.iso /mnt/cdrom 29 | tar zxf /mnt/cdrom/VMwareTools-*.tar.gz -C /tmp/ 30 | 31 | /tmp/vmware-tools-distrib/vmware-install.pl -d 32 | 33 | rm /home/vagrant/vmware_tools.iso 34 | umount /mnt/cdrom 35 | rmdir /mnt/cdrom 36 | rm -rf /tmp/VMwareTools-* 37 | fi -------------------------------------------------------------------------------- /template/ubuntu1204.json: -------------------------------------------------------------------------------- 1 | { 2 | "builders": [ 3 | { 4 | "vm_name": "ubuntu1204-opsworks", 5 | "type": "virtualbox-iso", 6 | "guest_os_type": "Ubuntu_64", 7 | "guest_additions_path": "VBoxGuestAdditions_{{.Version}}.iso", 8 | "virtualbox_version_file": ".vbox_version", 9 | "iso_urls": [ 10 | "http://releases.ubuntu.com/12.04/ubuntu-12.04.5-server-amd64.iso", 11 | "http://nl.releases.ubuntu.com/12.04/ubuntu-12.04.5-server-amd64.iso" 12 | ], 13 | "iso_checksum": "7540ace2d6cdee264432f5ed987236d32edef798", 14 | "iso_checksum_type": "sha1", 15 | "ssh_username": "vagrant", 16 | "ssh_password": "vagrant", 17 | "ssh_timeout": "10m", 18 | "http_directory": "preseed", 19 | "headless": true, 20 | "boot_wait": "5s", 21 | "boot_command": [ 22 | "", 23 | "/install/vmlinuz ", 24 | "preseed/url=http://{{.HTTPIP}}:{{.HTTPPort}}/preseed.cfg ", 25 | "debian-installer=en_US auto locale=en_US kbd-chooser/method=us ", 26 | "hostname={{.Name}} ", 27 | "fb=false debconf/frontend=noninteractive ", 28 | "keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ", 29 | "keyboard-configuration/variant=USA console-setup/ask_detect=false ", 30 | "initrd=/install/initrd.gz -- " 31 | ], 32 | "shutdown_command": "echo 'vagrant' | sudo -S -E shutdown -P now", 33 | "hard_drive_interface": "sata" 34 | }, 35 | { 36 | "vm_name": "ubuntu1204-opsworks", 37 | "type": "vmware-iso", 38 | "guest_os_type": "ubuntu-64", 39 | "iso_urls": [ 40 | "http://releases.ubuntu.com/12.04/ubuntu-12.04.5-server-amd64.iso", 41 | "http://nl.releases.ubuntu.com/12.04/ubuntu-12.04.5-server-amd64.iso" 42 | ], 43 | "iso_checksum": "7540ace2d6cdee264432f5ed987236d32edef798", 44 | "iso_checksum_type": "sha1", 45 | "ssh_username": "vagrant", 46 | "ssh_password": "vagrant", 47 | "ssh_timeout": "10m", 48 | "http_directory": "preseed", 49 | "headless": true, 50 | "boot_wait": "5s", 51 | "boot_command": [ 52 | "", 53 | "/install/vmlinuz ", 54 | "preseed/url=http://{{.HTTPIP}}:{{.HTTPPort}}/preseed.cfg ", 55 | "debian-installer=en_US auto locale=en_US kbd-chooser/method=us ", 56 | "hostname={{.Name}} ", 57 | "fb=false debconf/frontend=noninteractive ", 58 | "keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ", 59 | "keyboard-configuration/variant=USA console-setup/ask_detect=false ", 60 | "initrd=/install/initrd.gz -- " 61 | ], 62 | "shutdown_command": "echo 'vagrant' | sudo -S -E shutdown -P now", 63 | "tools_upload_flavor": "linux", 64 | "tools_upload_path": "vmware_tools.iso", 65 | "vmdk_name": "disk", 66 | "disk_type_id": "0", 67 | "vmx_data": { 68 | "MemTrimRate": "0", 69 | "sched.mem.pshare.enable": "FALSE", 70 | "mainMem.useNamedFile": "FALSE", 71 | "prefvmx.minVmMemPct": "100" 72 | } 73 | } 74 | ], 75 | "provisioners": [ 76 | { 77 | "type": "file", 78 | "source": "opsworks", 79 | "destination": "/tmp" 80 | }, 81 | { 82 | "type": "shell", 83 | "execute_command": "echo 'vagrant' | sudo -S -E bash '{{.Path}}'", 84 | "scripts": [ 85 | "provision/update.sh", 86 | "provision/network.sh", 87 | "provision/vagrant.sh", 88 | "provision/vmtools.sh", 89 | "provision/minimize.sh", 90 | "provision/opsworks.sh", 91 | "provision/cleanup.sh" 92 | ] 93 | } 94 | ], 95 | "post-processors": [ 96 | { 97 | "type": "vagrant", 98 | "output": "build/ubuntu1204-opsworks-{{.Provider}}.box", 99 | "include": [ 100 | "opsworks/opsworks", 101 | "opsworks/opsworks.rb", 102 | "opsworks/pre_config.yml", 103 | "opsworks/client.yml" 104 | ], 105 | "vagrantfile_template": "opsworks/Vagrantfile.template" 106 | } 107 | ] 108 | } 109 | -------------------------------------------------------------------------------- /template/ubuntu1404.json: -------------------------------------------------------------------------------- 1 | { 2 | "builders": [ 3 | { 4 | "vm_name": "ubuntu1404-opsworks", 5 | "type": "virtualbox-iso", 6 | "guest_os_type": "Ubuntu_64", 7 | "guest_additions_path": "VBoxGuestAdditions_{{.Version}}.iso", 8 | "virtualbox_version_file": ".vbox_version", 9 | "iso_urls": [ 10 | "http://releases.ubuntu.com/14.04/ubuntu-14.04.5-server-amd64.iso", 11 | "http://nl.releases.ubuntu.com/14.04/ubuntu-14.04.5-server-amd64.iso" 12 | ], 13 | "iso_checksum": "5e567024c385cc8f90c83d6763c6e4f1cd5deb6f", 14 | "iso_checksum_type": "sha1", 15 | "ssh_username": "vagrant", 16 | "ssh_password": "vagrant", 17 | "ssh_timeout": "10m", 18 | "http_directory": "preseed", 19 | "headless": true, 20 | "boot_wait": "5s", 21 | "boot_command": [ 22 | "", 23 | "/install/vmlinuz ", 24 | "preseed/url=http://{{.HTTPIP}}:{{.HTTPPort}}/preseed.cfg ", 25 | "debian-installer=en_US auto locale=en_US kbd-chooser/method=us ", 26 | "hostname={{.Name}} ", 27 | "fb=false debconf/frontend=noninteractive ", 28 | "keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ", 29 | "keyboard-configuration/variant=USA console-setup/ask_detect=false ", 30 | "initrd=/install/initrd.gz -- " 31 | ], 32 | "shutdown_command": "echo 'vagrant' | sudo -S -E shutdown -P now", 33 | "hard_drive_interface": "sata" 34 | }, 35 | { 36 | "vm_name": "ubuntu1404-opsworks", 37 | "type": "vmware-iso", 38 | "guest_os_type": "ubuntu-64", 39 | "iso_urls": [ 40 | "http://releases.ubuntu.com/14.04/ubuntu-14.04.5-server-amd64.iso", 41 | "http://nl.releases.ubuntu.com/14.04/ubuntu-14.04.5-server-amd64.iso" 42 | ], 43 | "iso_checksum": "5e567024c385cc8f90c83d6763c6e4f1cd5deb6f", 44 | "iso_checksum_type": "sha1", 45 | "ssh_username": "vagrant", 46 | "ssh_password": "vagrant", 47 | "ssh_timeout": "10m", 48 | "http_directory": "preseed", 49 | "headless": true, 50 | "boot_wait": "5s", 51 | "boot_command": [ 52 | "", 53 | "/install/vmlinuz ", 54 | "preseed/url=http://{{.HTTPIP}}:{{.HTTPPort}}/preseed.cfg ", 55 | "debian-installer=en_US auto locale=en_US kbd-chooser/method=us ", 56 | "hostname={{.Name}} ", 57 | "fb=false debconf/frontend=noninteractive ", 58 | "keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ", 59 | "keyboard-configuration/variant=USA console-setup/ask_detect=false ", 60 | "initrd=/install/initrd.gz -- " 61 | ], 62 | "shutdown_command": "echo 'vagrant' | sudo -S -E shutdown -P now", 63 | "tools_upload_flavor": "linux", 64 | "tools_upload_path": "vmware_tools.iso", 65 | "vmdk_name": "disk", 66 | "disk_type_id": "0", 67 | "vmx_data": { 68 | "MemTrimRate": "0", 69 | "sched.mem.pshare.enable": "FALSE", 70 | "mainMem.useNamedFile": "FALSE", 71 | "prefvmx.minVmMemPct": "100" 72 | } 73 | } 74 | ], 75 | "provisioners": [ 76 | { 77 | "type": "file", 78 | "source": "opsworks", 79 | "destination": "/tmp" 80 | }, 81 | { 82 | "type": "shell", 83 | "execute_command": "echo 'vagrant' | sudo -S -E bash '{{.Path}}'", 84 | "scripts": [ 85 | "provision/update.sh", 86 | "provision/network.sh", 87 | "provision/vagrant.sh", 88 | "provision/vmtools.sh", 89 | "provision/minimize.sh", 90 | "provision/opsworks.sh", 91 | "provision/cleanup.sh" 92 | ] 93 | } 94 | ], 95 | "post-processors": [ 96 | { 97 | "type": "vagrant", 98 | "output": "build/ubuntu1404-opsworks-{{.Provider}}.box", 99 | "include": [ 100 | "opsworks/opsworks", 101 | "opsworks/opsworks.rb", 102 | "opsworks/pre_config.yml", 103 | "opsworks/client.yml" 104 | ], 105 | "vagrantfile_template": "opsworks/Vagrantfile.template" 106 | } 107 | ] 108 | } 109 | --------------------------------------------------------------------------------