vagrant-cloudstack 0.0.5

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.
@@ -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