vagrant-cloudstack 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ require "vagrant-cloudstack/util/timer"
2
+
3
+ module VagrantPlugins
4
+ module Cloudstack
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, pname, 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"] << [p.class.to_s, timer]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ module VagrantPlugins
2
+ module Cloudstack
3
+ module Action
4
+ class WarnNetworks
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ if env[:machine].config.vm.networks.length > 0
11
+ env[:ui].warn(I18n.t("vagrant_cloudstack.warn_networks"))
12
+ end
13
+
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,253 @@
1
+ require "vagrant"
2
+
3
+ module VagrantPlugins
4
+ module Cloudstack
5
+ class Config < Vagrant.plugin("2", :config)
6
+ # Cloudstack api host.
7
+ #
8
+ # @return [String]
9
+ attr_accessor :host
10
+
11
+ # Cloudstack api path.
12
+ #
13
+ # @return [String]
14
+ attr_accessor :path
15
+
16
+ # Cloudstack api port.
17
+ #
18
+ # @return [String]
19
+ attr_accessor :port
20
+
21
+ # Cloudstack api scheme
22
+ #
23
+ # @return [String]
24
+ attr_accessor :scheme
25
+
26
+ # The API key for accessing Cloudstack.
27
+ #
28
+ # @return [String]
29
+ attr_accessor :api_key
30
+
31
+ # The secret key for accessing Cloudstack.
32
+ #
33
+ # @return [String]
34
+ attr_accessor :secret_key
35
+
36
+ # The timeout to wait for an instance to become ready.
37
+ #
38
+ # @return [Fixnum]
39
+ attr_accessor :instance_ready_timeout
40
+
41
+ # Domain id to launch the instance into.
42
+ #
43
+ # @return [String]
44
+ attr_accessor :domain_id
45
+
46
+ # Network uuid that the instance should use
47
+ #
48
+ # @return [String]
49
+ attr_accessor :network_id
50
+
51
+ # Project uuid that the instance should belong to
52
+ #
53
+ # @return [String]
54
+ attr_accessor :project_id
55
+
56
+ # Service offering uuid to use for the instance
57
+ #
58
+ # @return [String]
59
+ attr_accessor :service_offering_id
60
+
61
+ # Template uuid to use for the instance
62
+ #
63
+ # @return [String]
64
+ attr_accessor :template_id
65
+
66
+ # Zone uuid to launch the instance into. If nil, it will
67
+ # launch in default project.
68
+ #
69
+ # @return [String]
70
+ attr_accessor :zone_id
71
+
72
+ def initialize(domain_specific=false)
73
+ @host = UNSET_VALUE
74
+ @path = UNSET_VALUE
75
+ @port = UNSET_VALUE
76
+ @scheme = UNSET_VALUE
77
+ @api_key = UNSET_VALUE
78
+ @secret_key = UNSET_VALUE
79
+ @instance_ready_timeout = UNSET_VALUE
80
+ @domain_id = UNSET_VALUE
81
+ @network_id = UNSET_VALUE
82
+ @project_id = UNSET_VALUE
83
+ @service_offering_id = UNSET_VALUE
84
+ @template_id = UNSET_VALUE
85
+ @zone_id = UNSET_VALUE
86
+
87
+ # Internal state (prefix with __ so they aren't automatically
88
+ # merged)
89
+ @__compiled_domain_configs = {}
90
+ @__finalized = false
91
+ @__domain_config = {}
92
+ @__domain_specific = domain_specific
93
+ end
94
+
95
+ # Allows domain-specific overrides of any of the settings on this
96
+ # configuration object. This allows the user to override things like
97
+ # template and keypair name for domains. Example:
98
+ #
99
+ # cloudstack.domain_config "abcd-ef01-2345-6789" do |domain|
100
+ # domain.template_id = "1234-5678-90ab-cdef"
101
+ # domain.keypair_name = "company-east"
102
+ # end
103
+ #
104
+ # @param [String] domain The Domain name to configure.
105
+ # @param [Hash] attributes Direct attributes to set on the configuration
106
+ # as a shortcut instead of specifying a full block.
107
+ # @yield [config] Yields a new domain configuration.
108
+ def domain_config(domain, attributes=nil, &block)
109
+ # Append the block to the list of domain configs for that domain.
110
+ # We'll evaluate these upon finalization.
111
+ @__domain_config[domain] ||= []
112
+
113
+ # Append a block that sets attributes if we got one
114
+ if attributes
115
+ attr_block = lambda do |config|
116
+ config.set_options(attributes)
117
+ end
118
+
119
+ @__domain_config[domain] << attr_block
120
+ end
121
+
122
+ # Append a block if we got one
123
+ @__domain_config[domain] << block if block_given?
124
+ end
125
+
126
+ #-------------------------------------------------------------------
127
+ # Internal methods.
128
+ #-------------------------------------------------------------------
129
+
130
+ def merge(other)
131
+ super.tap do |result|
132
+ # Copy over the domain specific flag. "True" is retained if either
133
+ # has it.
134
+ new_domain_specific = other.instance_variable_get(:@__domain_specific)
135
+ result.instance_variable_set(
136
+ :@__domain_specific, new_domain_specific || @__domain_specific)
137
+
138
+ # Go through all the domain configs and prepend ours onto
139
+ # theirs.
140
+ new_domain_config = other.instance_variable_get(:@__domain_config)
141
+ @__domain_config.each do |key, value|
142
+ new_domain_config[key] ||= []
143
+ new_domain_config[key] = value + new_domain_config[key]
144
+ end
145
+
146
+ # Set it
147
+ result.instance_variable_set(:@__domain_config, new_domain_config)
148
+
149
+ # Merge in the tags
150
+ result.tags.merge!(self.tags)
151
+ result.tags.merge!(other.tags)
152
+ end
153
+ end
154
+
155
+ def finalize!
156
+ # Domain_id must be nil, since we can't default that
157
+ @host = nil if @host == UNSET_VALUE
158
+
159
+ # Path must be nil, since we can't default that
160
+ @path = nil if @path == UNSET_VALUE
161
+
162
+ # Port must be nil, since we can't default that
163
+ @port = nil if @port == UNSET_VALUE
164
+
165
+ # Scheme is 'http' by default
166
+ @scheme = "http" if @scheme == UNSET_VALUE
167
+
168
+ # Api key must be nil, since we can't default that
169
+ @api_key = nil if @api_key == UNSET_VALUE
170
+
171
+ # Secret key must be nil, since we can't default that
172
+ @secret_key = nil if @secret_key == UNSET_VALUE
173
+
174
+ # Set the default timeout for waiting for an instance to be ready
175
+ @instance_ready_timeout = 120 if @instance_ready_timeout == UNSET_VALUE
176
+
177
+ # Domain id must be nil, since we can't default that
178
+ @domain_id = nil if @domain_id == UNSET_VALUE
179
+
180
+ # Network uuid must be nil, since we can't default that
181
+ @network_id = nil if @network_id == UNSET_VALUE
182
+
183
+ # Project uuid must be nil, since we can't default that
184
+ @project_id = nil if @project_id == UNSET_VALUE
185
+
186
+ # Service offering uuid must be nil, since we can't default that
187
+ @service_offering_id = nil if @service_offering_id == UNSET_VALUE
188
+
189
+ # Template uuid must be nil, since we can't default that
190
+ @template_id = nil if @template_id == UNSET_VALUE
191
+
192
+ # Zone uuid must be nil, since we can't default that
193
+ @zone_id = nil if @zone_id == UNSET_VALUE
194
+
195
+ # Compile our domain specific configurations only within
196
+ # NON-DOMAIN-SPECIFIC configurations.
197
+ if !@__domain_specific
198
+ @__domain_config.each do |domain, blocks|
199
+ config = self.class.new(true).merge(self)
200
+
201
+ # Execute the configuration for each block
202
+ blocks.each { |b| b.call(config) }
203
+
204
+ # The domain name of the configuration always equals the
205
+ # domain config name:
206
+ config.domain = domain
207
+
208
+ # Finalize the configuration
209
+ config.finalize!
210
+
211
+ # Store it for retrieval
212
+ @__compiled_domain_configs[domain] = config
213
+ end
214
+ end
215
+
216
+ # Mark that we finalized
217
+ @__finalized = true
218
+ end
219
+
220
+ def validate(machine)
221
+ errors = []
222
+
223
+ if @domain
224
+ # Get the configuration for the domain we're using and validate only
225
+ # that domain.
226
+ config = get_domain_config(@domain)
227
+
228
+ if !config.use_fog_profile
229
+ errors << I18n.t("vagrant_cloudstack.config.api_key_required") if \
230
+ config.access_key_id.nil?
231
+ errors << I18n.t("vagrant_cloudstack.config.secret_key_required") if \
232
+ config.secret_access_key.nil?
233
+ end
234
+
235
+ errors << I18n.t("vagrant_cloudstack.config.ami_required") if config.ami.nil?
236
+ end
237
+
238
+ { "Cloudstack Provider" => errors }
239
+ end
240
+
241
+ # This gets the configuration for a specific domain. It shouldn't
242
+ # be called by the general public and is only used internally.
243
+ def get_domain_config(name)
244
+ if !@__finalized
245
+ raise "Configuration must be finalized before calling this method."
246
+ end
247
+
248
+ # Return the compiled domain config
249
+ @__compiled_domain_configs[name] || self
250
+ end
251
+ end
252
+ end
253
+ end
@@ -0,0 +1,23 @@
1
+ require "vagrant"
2
+
3
+ module VagrantPlugins
4
+ module Cloudstack
5
+ module Errors
6
+ class VagrantCloudstackError < Vagrant::Errors::VagrantError
7
+ error_namespace("vagrant_cloudstack.errors")
8
+ end
9
+
10
+ class FogError < VagrantCloudstackError
11
+ error_key(:fog_error)
12
+ end
13
+
14
+ class InstanceReadyTimeout < VagrantCloudstackError
15
+ error_key(:instance_ready_timeout)
16
+ end
17
+
18
+ class RsyncError < VagrantCloudstackError
19
+ error_key(:rsync_error)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,73 @@
1
+ begin
2
+ require "vagrant"
3
+ rescue LoadError
4
+ raise "The Vagrant Cloudstack 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 Cloudstack plugin is only compatible with Vagrant 1.2+"
11
+ end
12
+
13
+ module VagrantPlugins
14
+ module Cloudstack
15
+ class Plugin < Vagrant.plugin("2")
16
+ name "Cloudstack"
17
+ description <<-DESC
18
+ This plugin installs a provider that allows Vagrant to manage
19
+ machines in Cloudstack.
20
+ DESC
21
+
22
+ config(:cloudstack, :provider) do
23
+ require_relative "config"
24
+ Config
25
+ end
26
+
27
+ provider(:cloudstack) 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", Cloudstack.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_cloudstack")
66
+ logger.outputters = Log4r::Outputter.stderr
67
+ logger.level = level
68
+ logger = nil
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,50 @@
1
+ require "log4r"
2
+ require "vagrant"
3
+
4
+ module VagrantPlugins
5
+ module Cloudstack
6
+ class Provider < Vagrant.plugin("2", :provider)
7
+ def initialize(machine)
8
+ @machine = machine
9
+ end
10
+
11
+ def action(name)
12
+ # Attempt to get the action method from the Action class if it
13
+ # exists, otherwise return nil to show that we don't support the
14
+ # given action.
15
+ action_method = "action_#{name}"
16
+ return Action.send(action_method) if Action.respond_to?(action_method)
17
+ nil
18
+ end
19
+
20
+ def ssh_info
21
+ # Run a custom action called "read_ssh_info" which does what it
22
+ # says and puts the resulting SSH info into the `:machine_ssh_info`
23
+ # key in the environment.
24
+ env = @machine.action("read_ssh_info")
25
+ env[:machine_ssh_info]
26
+ end
27
+
28
+ def state
29
+ # Run a custom action we define called "read_state" which does
30
+ # what it says. It puts the state in the `:machine_state_id`
31
+ # key in the environment.
32
+ env = @machine.action("read_state")
33
+
34
+ state_id = env[:machine_state_id]
35
+
36
+ # Get the short and long description
37
+ short = I18n.t("vagrant_cloudstack.states.short_#{state_id}")
38
+ long = I18n.t("vagrant_cloudstack.states.long_#{state_id}")
39
+
40
+ # Return the MachineState object
41
+ Vagrant::MachineState.new(state_id, short, long)
42
+ end
43
+
44
+ def to_s
45
+ id = @machine.id.nil? ? "new" : @machine.id
46
+ "Cloudstack (#{id})"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,17 @@
1
+ module VagrantPlugins
2
+ module Cloudstack
3
+ module Util
4
+ class Timer
5
+ # A basic utility method that times the execution of the given
6
+ # block and returns it.
7
+ def self.time
8
+ start_time = Time.now.to_f
9
+ yield
10
+ end_time = Time.now.to_f
11
+
12
+ end_time - start_time
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end