vagrant-niftycloud 0.1.0.dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. data/.gitignore +18 -0
  2. data/CHANGELOG.md +1 -0
  3. data/Gemfile +10 -0
  4. data/LICENSE +8 -0
  5. data/README.md +256 -0
  6. data/Rakefile +21 -0
  7. data/dummy.box +0 -0
  8. data/example_box/README.md +13 -0
  9. data/example_box/metadata.json +3 -0
  10. data/lib/vagrant-niftycloud.rb +18 -0
  11. data/lib/vagrant-niftycloud/action.rb +178 -0
  12. data/lib/vagrant-niftycloud/action/connect_niftycloud.rb +56 -0
  13. data/lib/vagrant-niftycloud/action/is_created.rb +18 -0
  14. data/lib/vagrant-niftycloud/action/message_already_created.rb +16 -0
  15. data/lib/vagrant-niftycloud/action/message_not_created.rb +16 -0
  16. data/lib/vagrant-niftycloud/action/message_will_not_destroy.rb +16 -0
  17. data/lib/vagrant-niftycloud/action/read_ssh_info.rb +52 -0
  18. data/lib/vagrant-niftycloud/action/read_state.rb +56 -0
  19. data/lib/vagrant-niftycloud/action/resume_instance.rb +56 -0
  20. data/lib/vagrant-niftycloud/action/run_instance.rb +131 -0
  21. data/lib/vagrant-niftycloud/action/suspend_instance.rb +56 -0
  22. data/lib/vagrant-niftycloud/action/sync_folders.rb +67 -0
  23. data/lib/vagrant-niftycloud/action/terminate_instance.rb +61 -0
  24. data/lib/vagrant-niftycloud/action/timed_provision.rb +21 -0
  25. data/lib/vagrant-niftycloud/config.rb +210 -0
  26. data/lib/vagrant-niftycloud/errors.rb +35 -0
  27. data/lib/vagrant-niftycloud/plugin.rb +73 -0
  28. data/lib/vagrant-niftycloud/provider.rb +50 -0
  29. data/lib/vagrant-niftycloud/util/timer.rb +17 -0
  30. data/lib/vagrant-niftycloud/version.rb +5 -0
  31. data/locales/en.yml +91 -0
  32. data/spec/vagrant-niftycloud/config_spec.rb +154 -0
  33. data/vagrant-niftycloud.gemspec +57 -0
  34. metadata +157 -0
@@ -0,0 +1,67 @@
1
+ require "log4r"
2
+
3
+ require "vagrant/util/subprocess"
4
+
5
+ module VagrantPlugins
6
+ module NiftyCloud
7
+ module Action
8
+ # This middleware uses `rsync` to sync the folders over to the
9
+ # NiftyCloud instance.
10
+ class SyncFolders
11
+ def initialize(app, env)
12
+ @app = app
13
+ @logger = Log4r::Logger.new("vagrant_niftycloud::action::sync_folders")
14
+ end
15
+
16
+ def call(env)
17
+ @app.call(env)
18
+
19
+ ssh_info = env[:machine].ssh_info
20
+ env[:machine].config.vm.synced_folders.each do |id, data|
21
+ begin
22
+ # Ignore disabled shared folders
23
+ next if data[:disabled]
24
+
25
+ hostpath = File.expand_path(data[:hostpath], env[:root_path])
26
+ guestpath = data[:guestpath]
27
+
28
+ # Make sure there is a trailing slash on the host path to
29
+ # avoid creating an additional directory with rsync
30
+ hostpath = "#{hostpath}/" if hostpath !~ /\/$/
31
+
32
+ env[:ui].info(I18n.t("vagrant_niftycloud.rsync_folder",
33
+ :hostpath => hostpath,
34
+ :guestpath => guestpath))
35
+
36
+ # Create the guest path
37
+ env[:machine].communicate.sudo("mkdir -p '#{guestpath}'")
38
+ env[:machine].communicate.sudo(
39
+ "chown #{ssh_info[:username]} '#{guestpath}'")
40
+
41
+ # Rsync over to the guest path using the SSH info
42
+ command = [
43
+ "rsync", "--verbose", "--archive", "-z",
44
+ "--exclude", ".vagrant/",
45
+ "-e", "ssh -p #{ssh_info[:port]} -o StrictHostKeyChecking=no -i '#{ssh_info[:private_key_path]}'",
46
+ hostpath,
47
+ "#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}"]
48
+
49
+ r = Vagrant::Util::Subprocess.execute(*command)
50
+ if r.exit_code != 0
51
+ raise Errors::RsyncError,
52
+ :guestpath => guestpath,
53
+ :hostpath => hostpath,
54
+ :stderr => r.stderr
55
+ end
56
+ rescue => e
57
+ raise Errors::RsyncError,
58
+ :guestpath => guestpath,
59
+ :hostpath => hostpath,
60
+ :stderr => e.message
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,61 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "log4r"
3
+
4
+ module VagrantPlugins
5
+ module NiftyCloud
6
+ module Action
7
+ # This terminates the running instance.
8
+ class TerminateInstance
9
+ def initialize(app, env)
10
+ @app = app
11
+ @logger = Log4r::Logger.new("vagrant_niftycloud::action::terminate_instance")
12
+ end
13
+
14
+ def call(env)
15
+
16
+ # 例外の定義は以下参照
17
+ # http://cloud.nifty.com/api/sdk/rdoc/
18
+ begin
19
+ env[:ui].info(I18n.t("vagrant_niftycloud.terminating"))
20
+
21
+ # 起動直後等、terminate処理できないステータスの場合一旦待つ
22
+ server = env[:niftycloud_compute].describe_instances(:instance_id => env[:machine].id).reservationSet.item.first.instancesSet.item.first
23
+ while server.instanceState.name == 'pending'
24
+ sleep 5
25
+ server = env[:niftycloud_compute].describe_instances(:instance_id => env[:machine].id).reservationSet.item.first.instancesSet.item.first
26
+ end
27
+
28
+ attribute = env[:niftycloud_compute].describe_instance_attribute(:instance_id => env[:machine].id, :attribute => 'disableApiTermination')
29
+ if attribute.disableApiTermination.value == 'false'
30
+ # AWSのように即terminateができないため念のため一旦stopする
31
+ # TODO API経由でのterminate不可の場合を考慮する必要があるか
32
+ server = env[:niftycloud_compute].describe_instances(:instance_id => env[:machine].id).reservationSet.item.first.instancesSet.item.first
33
+ if server.instanceState.name != 'stopped'
34
+ env[:niftycloud_compute].stop_instances(:instance_id => env[:machine].id, :force => true)
35
+ while server.instanceState.name != 'stopped'
36
+ sleep 5
37
+ server = env[:niftycloud_compute].describe_instances(:instance_id => env[:machine].id).reservationSet.item.first.instancesSet.item.first
38
+ end
39
+ end
40
+ end
41
+
42
+ # terminate処理
43
+ server = env[:niftycloud_compute].describe_instances(:instance_id => env[:machine].id).reservationSet.item.first.instancesSet.item.first
44
+ if server.instanceState.name == 'stopped'
45
+ response = env[:niftycloud_compute].terminate_instances(:instance_id => env[:machine].id)
46
+ env[:machine].id = nil
47
+
48
+ @app.call(env)
49
+ end
50
+ rescue NIFTY::ConfigurationError => e
51
+ raise VagrantPlugins::NiftyCloud::Errors::NiftyCloudConfigurationError,
52
+ :message => e.message
53
+ rescue NIFTY::ArgumentError => e
54
+ raise VagrantPlugins::NiftyCloud::Errors::NiftyCloudArgumentError,
55
+ :message => e.message
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,21 @@
1
+ require "vagrant-niftycloud/util/timer"
2
+
3
+ module VagrantPlugins
4
+ module NiftyCloud
5
+ module Action
6
+ # This is the same as the builtin provision except it times the
7
+ # provisioner runs.
8
+ class TimedProvision < Vagrant::Action::Builtin::Provision
9
+ def run_provisioner(env, name, p)
10
+ timer = Util::Timer.time do
11
+ super
12
+ end
13
+
14
+ env[:metrics] ||= {}
15
+ env[:metrics]["provisioner_times"] ||= []
16
+ env[:metrics]["provisioner_times"] << [name, timer]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,210 @@
1
+ require "vagrant"
2
+
3
+ module VagrantPlugins
4
+ module NiftyCloud
5
+ class Config < Vagrant.plugin("2", :config)
6
+ # The access key ID for accessing NiftyCloud.
7
+ #
8
+ # @return [String]
9
+ attr_accessor :access_key_id
10
+
11
+ # The ID of the AMI to use.
12
+ #
13
+ # @return [String]
14
+ attr_accessor :image_id
15
+
16
+ # The zone to launch the instance into. If nil, it will
17
+ # use the default for your account.
18
+ #
19
+ # @return [String]
20
+ attr_accessor :zone
21
+
22
+ # The timeout to wait for an instance to become ready.
23
+ #
24
+ # @return [Fixnum]
25
+ attr_accessor :instance_ready_timeout
26
+
27
+ # The type of instance to launch, such as "m1.small"
28
+ #
29
+ # @return [String]
30
+ attr_accessor :instance_type
31
+
32
+ # The name of the keypair to use.
33
+ #
34
+ # @return [String]
35
+ attr_accessor :key_name
36
+
37
+ # The secret access key for accessing NiftyCloud.
38
+ #
39
+ # @return [String]
40
+ attr_accessor :secret_access_key
41
+
42
+ # The firewall to set on the instance.
43
+ # be a list of IDs. For NiftyCloud, it can be either.
44
+ #
45
+ # @return [Array<String>]
46
+ attr_accessor :firewall
47
+
48
+ # The user data string
49
+ #
50
+ # @return [String]
51
+ attr_accessor :user_data
52
+
53
+ def initialize(zone_specific=false)
54
+ @access_key_id = UNSET_VALUE
55
+ @image_id = UNSET_VALUE
56
+ @zone = UNSET_VALUE
57
+ @instance_ready_timeout = UNSET_VALUE
58
+ @instance_type = UNSET_VALUE
59
+ @key_name = UNSET_VALUE
60
+ @secret_access_key = UNSET_VALUE
61
+ @firewall = UNSET_VALUE
62
+ @user_data = UNSET_VALUE
63
+
64
+ # Internal state (prefix with __ so they aren't automatically
65
+ # merged)
66
+ @__compiled_zone_configs = {}
67
+ @__finalized = false
68
+ @__zone_config = {}
69
+ @__zone_specific = zone_specific
70
+ end
71
+
72
+ # Allows zone-specific overrides of any of the settings on this
73
+ # configuration object. This allows the user to override things like
74
+ # image_id and key name for zones. Example:
75
+ #
76
+ # niftycloud.zone_config "east-12" do |zone|
77
+ # zone.image_id = 21
78
+ # zone.key_name = "company-east12"
79
+ # end
80
+ #
81
+ # @param [String] zone The zone name to configure.
82
+ # @param [Hash] attributes Direct attributes to set on the configuration
83
+ # as a shortcut instead of specifying a full block.
84
+ # @yield [config] Yields a new Nifty Cloud configuration.
85
+ def zone_config(zone, attributes=nil, &block)
86
+ # Append the block to the list of zone configs for that zone.
87
+ # We'll evaluate these upon finalization.
88
+ @__zone_config[zone] ||= []
89
+
90
+ # Append a block that sets attributes if we got one
91
+ if attributes
92
+ attr_block = lambda do |config|
93
+ config.set_options(attributes)
94
+ end
95
+
96
+ @__zone_config[zone] << attr_block
97
+ end
98
+
99
+ # Append a block if we got one
100
+ @__zone_config[zone] << block if block_given?
101
+ end
102
+
103
+ #-------------------------------------------------------------------
104
+ # Internal methods.
105
+ #-------------------------------------------------------------------
106
+
107
+ def merge(other)
108
+ super.tap do |result|
109
+ # Copy over the zone specific flag. "True" is retained if either
110
+ # has it.
111
+ new_zone_specific = other.instance_variable_get(:@__zone_specific)
112
+ result.instance_variable_set(
113
+ :@__zone_specific, new_zone_specific || @__zone_specific)
114
+
115
+ # Go through all the zone configs and prepend ours onto
116
+ # theirs.
117
+ new_zone_config = other.instance_variable_get(:@__zone_config)
118
+ @__zone_config.each do |key, value|
119
+ new_zone_config[key] ||= []
120
+ new_zone_config[key] = value + new_zone_config[key]
121
+ end
122
+
123
+ # Set it
124
+ result.instance_variable_set(:@__zone_config, new_zone_config)
125
+ end
126
+ end
127
+
128
+ def finalize!
129
+ # Try to get access keys from standard NiftyCloud environment variables; they
130
+ # will default to nil if the environment variables are not present.
131
+ @access_key_id = ENV['NIFTY_ACCESS_KEY'] if @access_key_id == UNSET_VALUE
132
+ @secret_access_key = ENV['NIFTY_SECRET_KEY'] if @secret_access_key == UNSET_VALUE
133
+
134
+ # AMI must be nil, since we can't default that
135
+ @image_id = nil if @image_id == UNSET_VALUE
136
+
137
+ # Set the default timeout for waiting for an instance to be ready
138
+ @instance_ready_timeout = 300 if @instance_ready_timeout == UNSET_VALUE
139
+
140
+ # Default instance type is an mini
141
+ @instance_type = "mini" if @instance_type == UNSET_VALUE
142
+
143
+ # Keypair defaults to nil
144
+ @key_name = nil if @key_name == UNSET_VALUE
145
+
146
+ @zone = nil if @zone == UNSET_VALUE
147
+
148
+ # The firewall are empty by default.
149
+ @firewall = [] if @firewall == UNSET_VALUE
150
+
151
+ # User Data is nil by default
152
+ @user_data = nil if @user_data == UNSET_VALUE
153
+
154
+ if !@__zone_specific
155
+ @__zone_config.each do |zone, blocks|
156
+ config = self.class.new(true).merge(self)
157
+
158
+ # Execute the configuration for each block
159
+ blocks.each { |b| b.call(config) }
160
+
161
+ # The zone name of the configuration always equals the
162
+ # zone config name:
163
+ config.zone = zone
164
+
165
+ # Finalize the configuration
166
+ config.finalize!
167
+
168
+ # Store it for retrieval
169
+ @__compiled_zone_configs[zone] = config
170
+ end
171
+ end
172
+
173
+ # Mark that we finalized
174
+ @__finalized = true
175
+ end
176
+
177
+ def validate(machine)
178
+ errors = _detected_errors
179
+
180
+ errors << I18n.t("vagrant_niftycloud.config.zone_required") if @zone.nil?
181
+
182
+ if @zone
183
+ # Get the configuration for the zone we're using and validate only
184
+ # that zone.
185
+ config = get_zone_config(@zone)
186
+
187
+ errors << I18n.t("vagrant_niftycloud.config.access_key_id_required") if \
188
+ config.access_key_id.nil?
189
+ errors << I18n.t("vagrant_niftycloud.config.secret_access_key_required") if \
190
+ config.secret_access_key.nil?
191
+
192
+ errors << I18n.t("vagrant_niftycloud.config.image_id_required") if config.image_id.nil?
193
+ end
194
+
195
+ { "NiftyCloud Provider" => errors }
196
+ end
197
+
198
+ # This gets the configuration for a specific zone. It shouldn't
199
+ # be called by the general public and is only used internally.
200
+ def get_zone_config(name)
201
+ if !@__finalized
202
+ raise "Configuration must be finalized before calling this method."
203
+ end
204
+
205
+ # Return the compiled zone config
206
+ @__compiled_zone_configs[name] || self
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,35 @@
1
+ require "vagrant"
2
+
3
+ module VagrantPlugins
4
+ module NiftyCloud
5
+ module Errors
6
+ class VagrantNiftyCloudError < Vagrant::Errors::VagrantError
7
+ error_namespace("vagrant_niftycloud.errors")
8
+ end
9
+
10
+ class NiftyCloudConfigurationError < VagrantNiftyCloudError
11
+ error_key(:niftycloud_configuration_error)
12
+ end
13
+
14
+ class NiftyCloudArgumentError < VagrantNiftyCloudError
15
+ error_key(:niftycloud_argument_error)
16
+ end
17
+
18
+ class NiftyCloudResponseError < VagrantNiftyCloudError
19
+ error_key(:niftycloud_response_error)
20
+ end
21
+
22
+ class NiftyCloudResponseFormatError < VagrantNiftyCloudError
23
+ error_key(:niftycloud_response_format_error)
24
+ end
25
+
26
+ class InstanceReadyTimeout < VagrantNiftyCloudError
27
+ error_key(:instance_ready_timeout)
28
+ end
29
+
30
+ class RsyncError < VagrantNiftyCloudError
31
+ error_key(:rsync_error)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,73 @@
1
+ begin
2
+ require "vagrant"
3
+ rescue LoadError
4
+ raise "The Vagrant NiftyCloud 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 NiftyCloud plugin is only compatible with Vagrant 1.2+"
11
+ end
12
+
13
+ module VagrantPlugins
14
+ module NiftyCloud
15
+ class Plugin < Vagrant.plugin("2")
16
+ name "NiftyCloud"
17
+ description <<-DESC
18
+ This plugin installs a provider that allows Vagrant to manage
19
+ machines in NiftyCloud.
20
+ DESC
21
+
22
+ config(:niftycloud, :provider) do
23
+ require_relative "config"
24
+ Config
25
+ end
26
+
27
+ provider(:niftycloud, parallel: true) do
28
+ # Setup logging and i18n
29
+ setup_logging
30
+ setup_i18n
31
+
32
+ # Return the provider
33
+ require_relative "provider"
34
+ Provider
35
+ end
36
+
37
+ # This initializes the internationalization strings.
38
+ def self.setup_i18n
39
+ I18n.load_path << File.expand_path("locales/en.yml", NiftyCloud.source_root)
40
+ I18n.reload!
41
+ end
42
+
43
+ # This sets up our log level to be whatever VAGRANT_LOG is.
44
+ def self.setup_logging
45
+ require "log4r"
46
+
47
+ level = nil
48
+ begin
49
+ level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
50
+ rescue NameError
51
+ # This means that the logging constant wasn't found,
52
+ # which is fine. We just keep `level` as `nil`. But
53
+ # we tell the user.
54
+ level = nil
55
+ end
56
+
57
+ # Some constants, such as "true" resolve to booleans, so the
58
+ # above error checking doesn't catch it. This will check to make
59
+ # sure that the log level is an integer, as Log4r requires.
60
+ level = nil if !level.is_a?(Integer)
61
+
62
+ # Set the logging level on all "vagrant" namespaced
63
+ # logs as long as we have a valid level.
64
+ if level
65
+ logger = Log4r::Logger.new("vagrant_niftycloud")
66
+ logger.outputters = Log4r::Outputter.stderr
67
+ logger.level = level
68
+ logger = nil
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end