vagrant-ami 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ Vagrantfile
19
+ .vagrant
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in vagrant-ami.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ # We depend on Vagrant for development, but we don't add it as a
8
+ # gem dependency because we expect to be installed within the
9
+ # Vagrant environment itself using `vagrant plugin`.
10
+ gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git"
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Mike Ryan
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # Create AMIs from Vagrant EC2 boxes
2
+
3
+ This is a [Vagrant](http://www.vagrantup.com) 1.2+ plugin that adds a command
4
+ to create [AWS](http://aws.amazon.com) AMIs.
5
+
6
+ This plugin has a very short lifespan in terms of usefulness.
7
+
8
+ Technically this plugin is already superseded by [Packer](http://packer.io) which
9
+ is a more general solution for creating various types of machine images.
10
+
11
+ However, Packer does not yet have the same level of provisioner support enjoyed
12
+ by Vagrant. Until then, I need a simple way to make AMIs based on Vagrant EC2 boxes
13
+ provisioned with Puppet and Chef, which can be called easily from Jenkins.
14
+
15
+ **NOTE:** This plugin requires Vagrant 1.2+,
16
+
17
+
18
+ ## Features
19
+
20
+ * Create AMIs from Vagrant-managed EC2 instances
21
+ * Assign tags to newly-created AMIs
22
+
23
+
24
+ ## Usage
25
+
26
+ Install using standard Vagrant 1.1+ plugin installation methods. After
27
+ bringing up an AwS instance issue the command to create the AMI as shown
28
+ below.
29
+
30
+ ```
31
+ $ vagrant plugin install vagrant-ami
32
+ ...
33
+ $ vagrant up --provider=aws
34
+ ...
35
+ $ vagrant create_ami --name my-ami --desc "My AMI" --tags role=test,environment=dev
36
+ ...
37
+ $ vagrant destroy
38
+ ```
39
+
40
+ vagrant-ami relies heavily on vagrant-aws, and reuses all of its configuration settings.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rspec/core/rake_task'
4
+
5
+ # Immediately sync all stdout so that tools like buildbot can
6
+ # immediately load in the output.
7
+ $stdout.sync = true
8
+ $stderr.sync = true
9
+
10
+ # Change to the directory of this file.
11
+ Dir.chdir(File.expand_path("../", __FILE__))
12
+
13
+ # This installs the tasks that help with gem creation and
14
+ # publishing.
15
+ Bundler::GemHelper.install_tasks
16
+
17
+ # Install the `spec` task so that we can run tests.
18
+ RSpec::Core::RakeTask.new
19
+
20
+ # Default task is to run the unit tests
21
+ task :default => "spec"
@@ -0,0 +1,18 @@
1
+ require "pathname"
2
+
3
+ require "vagrant-ami/plugin"
4
+
5
+ module VagrantPlugins
6
+ module AMI
7
+ lib_path = Pathname.new(File.expand_path("../vagrant-ami", __FILE__))
8
+ autoload :Action, lib_path.join("action")
9
+ autoload :Errors, lib_path.join("errors")
10
+
11
+ # This returns the path to the source of this plugin.
12
+ #
13
+ # @return [Pathname]
14
+ def self.source_root
15
+ @source_root ||= Pathname.new(File.expand_path("../../", __FILE__))
16
+ end
17
+ end
18
+ end
Binary file
@@ -0,0 +1,27 @@
1
+ require "pathname"
2
+
3
+ require "vagrant/action/builder"
4
+ require "vagrant-aws/action"
5
+
6
+ module VagrantPlugins
7
+ module AMI
8
+ module Action
9
+ # Include the built-in modules so we can use them as top-level things.
10
+ include Vagrant::Action::Builtin
11
+
12
+ # This action is called to create EC2 AMIs.
13
+ def self.action_create_ami
14
+ Vagrant::Action::Builder.new.tap do |b|
15
+ b.use ConfigValidate
16
+ b.use VagrantPlugins::AWS::Action::ConnectAWS
17
+ b.use CreateAMI
18
+ end
19
+ end
20
+
21
+
22
+ # The autoload farm
23
+ action_root = Pathname.new(File.expand_path("../action", __FILE__))
24
+ autoload :CreateAMI, action_root.join("create_ami")
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,74 @@
1
+ require 'date'
2
+ require 'vagrant-aws/util/timer'
3
+ require 'vagrant-aws/errors'
4
+ require 'vagrant/util/retryable'
5
+
6
+ module VagrantPlugins
7
+ module AMI
8
+ module Action
9
+ # This runs the configured instance.
10
+ class CreateAMI
11
+ include Vagrant::Util::Retryable
12
+
13
+ def initialize(app, env)
14
+ @app = app
15
+ @logger = Log4r::Logger.new("vagrant_ami::action::create_ami")
16
+ end
17
+
18
+ def call(env)
19
+ if env[:machine].state.id != :running
20
+ puts "Skipping #{env[:machine].name}: not running"
21
+ else
22
+ _create_ami(env)
23
+ end
24
+
25
+ end
26
+
27
+ protected
28
+
29
+ def _create_ami(env)
30
+ env[:ui].info("Creating AMI named '#{env[:name]}'for #{env[:machine].name} (#{env[:machine].id})")
31
+
32
+ # TODO this isn't getting logged
33
+ @logger.info("Description: #{env[:desc]} Tags: #{env[:tags]}")
34
+
35
+ # TODO error handling on create_image/tags
36
+ # this raises an error if AMI name already exists
37
+ # see this for error handling examples
38
+ # https://github.com/mitchellh/vagrant-aws/blob/master/lib/vagrant-aws/action/run_instance.rb#L79
39
+ server = env[:aws_compute].servers.get(env[:machine].id)
40
+ begin
41
+ data = env[:aws_compute].create_image(server.identity, env[:name], env[:desc])
42
+ rescue Excon::Errors::BadRequest => e
43
+ if e.response.body =~ /InvalidAMIName.Duplicate/
44
+ raise VagrantPlugins::AWS::Errors::FogError,
45
+ :message => "An AMI named #{env[:name]} already exists"
46
+ end
47
+ raise
48
+ end
49
+
50
+ image_id = data.body["imageId"]
51
+
52
+ image = env[:aws_compute].images.get(image_id)
53
+ env[:ui].info("Creating #{image_id}")
54
+
55
+ # Wait for the image to be ready
56
+ # TODO should have a configurable timeout for this
57
+ while true
58
+ # If we're interrupted then just back out
59
+ break if env[:interrupted]
60
+ image = env[:aws_compute].images.get(image_id)
61
+ break if image.ready?
62
+ sleep 2
63
+ end
64
+
65
+ unless env[:tags].empty?
66
+ env[:ui].info("Adding tags to AMI")
67
+ env[:aws_compute].create_tags(image_id, env[:tags])
68
+ end
69
+ env[:ui].info("Created #{image_id}")
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,54 @@
1
+ require 'optparse'
2
+
3
+ module VagrantPlugins
4
+ module AMI
5
+ class Command < Vagrant.plugin("2", :command)
6
+ def execute
7
+
8
+ options = {
9
+ :tags => {}
10
+ }
11
+
12
+ opts = OptionParser.new do |o|
13
+ o.banner = "Usage: vagrant create_ami [vm-name]"
14
+ o.separator ""
15
+
16
+ o.on("-n", "--name NAME", "AMI Name") do |n|
17
+ options[:name] = n
18
+ end
19
+
20
+ o.on("-d", "--desc DESCRIPTION", "AMI Description.") do |d|
21
+ options[:desc] = d
22
+ end
23
+
24
+ o.on("-t", "--tags key1=val1,keyN=valN", Array, "Optional tags to assign to the AMI.") do |t|
25
+ options[:tags] = Hash[t.map {|kv| kv.split("=")}]
26
+ end
27
+
28
+ # TODO add option to wait until AMI creation is complete?
29
+ # TODO does this work if the instance is terminated immediately after hte create_ami call
30
+ # is issues?
31
+
32
+ end
33
+
34
+ # Parse the options
35
+ argv = parse_options(opts)
36
+ return if !argv
37
+
38
+ if options[:name].nil? or options[:desc].nil?
39
+ raise Vagrant::Errors::CLIInvalidOptions, :help => opts.help.chomp
40
+ end
41
+
42
+ with_target_vms(argv, :reverse => true) do |machine|
43
+ @env.action_runner.run(VagrantPlugins::AMI::Action.action_create_ami, {
44
+ :machine => machine,
45
+ :name => options[:name],
46
+ :desc => options[:desc],
47
+ :tags => options[:tags]
48
+ })
49
+ end
50
+ 0
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,50 @@
1
+ require "vagrant"
2
+
3
+ module VagrantPlugins
4
+ module AMI
5
+ class Config < Vagrant.plugin("2", :config)
6
+ # The tags for created AMIs.
7
+ #
8
+ # @return [Hash<String, String>]
9
+ attr_accessor :tags
10
+
11
+ def initialize(region_specific=false)
12
+ @tags = {}
13
+ end
14
+
15
+ def validate(machine)
16
+ errors = _detected_errors
17
+
18
+ errors << I18n.t("vagrant_aws.config.region_required") if @region.nil?
19
+
20
+ if @region
21
+ # Get the configuration for the region we're using and validate only
22
+ # that region.
23
+ config = get_region_config(@region)
24
+
25
+ if !config.use_iam_profile
26
+ errors << I18n.t("vagrant_aws.config.access_key_id_required") if \
27
+ config.access_key_id.nil?
28
+ errors << I18n.t("vagrant_aws.config.secret_access_key_required") if \
29
+ config.secret_access_key.nil?
30
+ end
31
+
32
+ errors << I18n.t("vagrant_aws.config.ami_required") if config.ami.nil?
33
+ end
34
+
35
+ { "AWS Provider" => errors }
36
+ end
37
+
38
+ # This gets the configuration for a specific region. It shouldn't
39
+ # be called by the general public and is only used internally.
40
+ def get_region_config(name)
41
+ if !@__finalized
42
+ raise "Configuration must be finalized before calling this method."
43
+ end
44
+
45
+ # Return the compiled region config
46
+ @__compiled_region_configs[name] || self
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,61 @@
1
+ begin
2
+ require "vagrant"
3
+ rescue LoadError
4
+ raise "The Vagrant AMI plugin must be run within Vagrant."
5
+ end
6
+
7
+ # This is a sanity check to make sure no one is attempting to install
8
+ # this into an early Vagrant version.
9
+ if Vagrant::VERSION < "1.2.0"
10
+ raise "The Vagrant AMI plugin is only compatible with Vagrant 1.2+"
11
+ end
12
+
13
+ module VagrantPlugins
14
+ module AMI
15
+ class Plugin < Vagrant.plugin("2")
16
+ name "AMI"
17
+ description <<-DESC
18
+ This plugin allows Vagrant to create EC2 AMIs.
19
+ DESC
20
+
21
+ #config(:ami, :provider) do
22
+ # require_relative "config"
23
+ # Config
24
+ #end
25
+
26
+ command("create-ami") do
27
+ require File.expand_path("../commands/create_ami.rb", __FILE__)
28
+ Command
29
+ end
30
+
31
+ # This sets up our log level to be whatever VAGRANT_LOG is.
32
+ def self.setup_logging
33
+ require "log4r"
34
+
35
+ level = nil
36
+ begin
37
+ level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
38
+ rescue NameError
39
+ # This means that the logging constant wasn't found,
40
+ # which is fine. We just keep `level` as `nil`. But
41
+ # we tell the user.
42
+ level = nil
43
+ end
44
+
45
+ # Some constants, such as "true" resolve to booleans, so the
46
+ # above error checking doesn't catch it. This will check to make
47
+ # sure that the log level is an integer, as Log4r requires.
48
+ level = nil if !level.is_a?(Integer)
49
+
50
+ # Set the logging level on all "vagrant" namespaced
51
+ # logs as long as we have a valid level.
52
+ if level
53
+ logger = Log4r::Logger.new("vagrant_ami")
54
+ logger.outputters = Log4r::Outputter.stderr
55
+ logger.level = level
56
+ logger = nil
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,5 @@
1
+ module Vagrant
2
+ module Ami
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'vagrant-ami/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "vagrant-ami"
8
+ spec.version = Vagrant::Ami::VERSION
9
+ spec.authors = "Mike Ryan"
10
+ spec.email = "mike@epitech.nl"
11
+ spec.description = "Enables Vagrant to create EC2 AMIs."
12
+ spec.summary = "Enables Vagrant to create EC2 AMIs."
13
+ spec.homepage = "http://www.epitech.nl"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_runtime_dependency "vagrant-aws"
24
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vagrant-ami
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mike Ryan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &12417060 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *12417060
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &12416600 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *12416600
36
+ - !ruby/object:Gem::Dependency
37
+ name: vagrant-aws
38
+ requirement: &12416120 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *12416120
47
+ description: Enables Vagrant to create EC2 AMIs.
48
+ email: mike@epitech.nl
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - LICENSE.txt
56
+ - README.md
57
+ - Rakefile
58
+ - lib/vagrant-ami.rb
59
+ - lib/vagrant-ami/.plugin.rb.swp
60
+ - lib/vagrant-ami/action.rb
61
+ - lib/vagrant-ami/action/.create_ami.rb.swp
62
+ - lib/vagrant-ami/action/create_ami.rb
63
+ - lib/vagrant-ami/commands/.create_ami.rb.swp
64
+ - lib/vagrant-ami/commands/create_ami.rb
65
+ - lib/vagrant-ami/config.rb
66
+ - lib/vagrant-ami/plugin.rb
67
+ - lib/vagrant-ami/version.rb
68
+ - vagrant-ami.gemspec
69
+ homepage: http://www.epitech.nl
70
+ licenses:
71
+ - MIT
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ segments:
83
+ - 0
84
+ hash: 1894379412045326636
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ segments:
92
+ - 0
93
+ hash: 1894379412045326636
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 1.8.11
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: Enables Vagrant to create EC2 AMIs.
100
+ test_files: []