vagrant-google 0.1.3

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,140 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ require "vagrant/action/builder"
15
+
16
+ module VagrantPlugins
17
+ module Google
18
+ module Action
19
+ # Include the built-in modules so we can use them as top-level things.
20
+ include Vagrant::Action::Builtin
21
+
22
+ # This action is called to terminate the remote machine.
23
+ def self.action_destroy
24
+ Vagrant::Action::Builder.new.tap do |b|
25
+ b.use Call, DestroyConfirm do |env, b2|
26
+ if env[:result]
27
+ b2.use ConfigValidate
28
+ b2.use ConnectGoogle
29
+ b2.use TerminateInstance
30
+ else
31
+ b2.use MessageWillNotDestroy
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ # This action is called when `vagrant provision` is called.
38
+ def self.action_provision
39
+ Vagrant::Action::Builder.new.tap do |b|
40
+ b.use ConfigValidate
41
+ b.use Call, IsCreated do |env, b2|
42
+ if !env[:result]
43
+ b2.use MessageNotCreated
44
+ next
45
+ end
46
+
47
+ b2.use Provision
48
+ b2.use SyncFolders
49
+ end
50
+ end
51
+ end
52
+
53
+ # This action is called to read the SSH info of the machine. The
54
+ # resulting state is expected to be put into the `:machine_ssh_info`
55
+ # key.
56
+ def self.action_read_ssh_info
57
+ Vagrant::Action::Builder.new.tap do |b|
58
+ b.use ConfigValidate
59
+ b.use ConnectGoogle
60
+ b.use ReadSSHInfo
61
+ end
62
+ end
63
+
64
+ # This action is called to read the state of the machine. The
65
+ # resulting state is expected to be put into the `:machine_state_id`
66
+ # key.
67
+ def self.action_read_state
68
+ Vagrant::Action::Builder.new.tap do |b|
69
+ b.use ConfigValidate
70
+ b.use ConnectGoogle
71
+ b.use ReadState
72
+ end
73
+ end
74
+
75
+ # This action is called to SSH into the machine.
76
+ def self.action_ssh
77
+ Vagrant::Action::Builder.new.tap do |b|
78
+ b.use ConfigValidate
79
+ b.use Call, IsCreated do |env, b2|
80
+ if !env[:result]
81
+ b2.use MessageNotCreated
82
+ next
83
+ end
84
+
85
+ b2.use SSHExec
86
+ end
87
+ end
88
+ end
89
+
90
+ def self.action_ssh_run
91
+ Vagrant::Action::Builder.new.tap do |b|
92
+ b.use ConfigValidate
93
+ b.use Call, IsCreated do |env, b2|
94
+ if !env[:result]
95
+ b2.use MessageNotCreated
96
+ next
97
+ end
98
+
99
+ b2.use SSHRun
100
+ end
101
+ end
102
+ end
103
+
104
+ # This action is called to bring the box up from nothing.
105
+ def self.action_up
106
+ Vagrant::Action::Builder.new.tap do |b|
107
+ b.use HandleBoxUrl
108
+ b.use ConfigValidate
109
+ b.use ConnectGoogle
110
+ b.use Call, IsCreated do |env, b2|
111
+ if env[:result]
112
+ b2.use MessageAlreadyCreated
113
+ next
114
+ end
115
+
116
+ b2.use Provision
117
+ b2.use SyncFolders
118
+ b2.use WarnNetworks
119
+ b2.use RunInstance
120
+ end
121
+ end
122
+ end
123
+
124
+ # The autoload farm
125
+ action_root = Pathname.new(File.expand_path("../action", __FILE__))
126
+ autoload :ConnectGoogle, action_root.join("connect_google")
127
+ autoload :IsCreated, action_root.join("is_created")
128
+ autoload :MessageAlreadyCreated, action_root.join("message_already_created")
129
+ autoload :MessageNotCreated, action_root.join("message_not_created")
130
+ autoload :MessageWillNotDestroy, action_root.join("message_will_not_destroy")
131
+ autoload :ReadSSHInfo, action_root.join("read_ssh_info")
132
+ autoload :ReadState, action_root.join("read_state")
133
+ autoload :RunInstance, action_root.join("run_instance")
134
+ autoload :SyncFolders, action_root.join("sync_folders")
135
+ autoload :TimedProvision, action_root.join("timed_provision")
136
+ autoload :WarnNetworks, action_root.join("warn_networks")
137
+ autoload :TerminateInstance, action_root.join("terminate_instance")
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,241 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ require "vagrant"
15
+
16
+ module VagrantPlugins
17
+ module Google
18
+ class Config < Vagrant.plugin("2", :config)
19
+ # The Service Account Client ID Email address
20
+ #
21
+ # @return [String]
22
+ attr_accessor :google_client_email
23
+
24
+ # The path to the Service Account private key
25
+ #
26
+ # @return [String]
27
+ attr_accessor :google_key_location
28
+
29
+ # The Google Cloud Project ID (not name or number)
30
+ #
31
+ # @return [String]
32
+ attr_accessor :google_project_id
33
+
34
+ # The image name of the instance to use.
35
+ #
36
+ # @return [String]
37
+ attr_accessor :image
38
+
39
+ # The type of machine to launch, such as "n1-standard-1"
40
+ #
41
+ # @return [String]
42
+ attr_accessor :machine_type
43
+
44
+ # The user metadata string
45
+ #
46
+ # @return [Hash<String, String>]
47
+ attr_accessor :metadata
48
+
49
+ # The name of the instance
50
+ #
51
+ # @return [String]
52
+ attr_accessor :name
53
+
54
+ # The name of the network
55
+ #
56
+ # @return [String]
57
+ attr_accessor :network
58
+
59
+ # The timeout value waiting for instance ready
60
+ #
61
+ # @return [Int]
62
+ attr_accessor :instance_ready_timeout
63
+
64
+ # The tags for the machine.
65
+ # TODO(erjohnso): not supported in fog
66
+ #
67
+ # @return [Hash<String, String>]
68
+ #attr_accessor :tags
69
+
70
+ # The zone to launch the instance into. If nil, it will
71
+ # use the default us-central1-a.
72
+ #
73
+ # @return [String]
74
+ attr_accessor :zone
75
+
76
+ def initialize(zone_specific=false)
77
+ @google_client_email = UNSET_VALUE
78
+ @google_key_location = UNSET_VALUE
79
+ @google_project_id = UNSET_VALUE
80
+ @image = UNSET_VALUE
81
+ @machine_type = UNSET_VALUE
82
+ @metadata = {}
83
+ @name = UNSET_VALUE
84
+ @network = UNSET_VALUE
85
+ @instance_ready_timeout = UNSET_VALUE
86
+ @zone = UNSET_VALUE
87
+
88
+ # Internal state (prefix with __ so they aren't automatically
89
+ # merged)
90
+ @__compiled_zone_configs = {}
91
+ @__finalized = false
92
+ @__zone_config = {}
93
+ @__zone_specific = zone_specific
94
+ end
95
+
96
+ # Allows zone-specific overrides of any of the settings on this
97
+ # configuration object. This allows the user to override things like
98
+ # image and machine type name for zones. Example:
99
+ #
100
+ # google.zone_config "us-central1-a" do |zone|
101
+ # zone.image = "debian-7-wheezy-v20140619"
102
+ # zone.machine_type = "n1-standard-4"
103
+ # end
104
+ #
105
+ # @param [String] zone The zone name to configure.
106
+ # @param [Hash] attributes Direct attributes to set on the configuration
107
+ # as a shortcut instead of specifying a full block.
108
+ # @yield [config] Yields a new Google configuration.
109
+ def zone_config(zone, attributes=nil, &block)
110
+ # Append the block to the list of zone configs for that zone.
111
+ # We'll evaluate these upon finalization.
112
+ @__zone_config[zone] ||= []
113
+
114
+ # Append a block that sets attributes if we got one
115
+ if attributes
116
+ attr_block = lambda do |config|
117
+ config.set_options(attributes)
118
+ end
119
+
120
+ @__zone_config[zone] << attr_block
121
+ end
122
+
123
+ # Append a block if we got one
124
+ @__zone_config[zone] << block if block_given?
125
+ end
126
+
127
+ #-------------------------------------------------------------------
128
+ # Internal methods.
129
+ #-------------------------------------------------------------------
130
+
131
+ def merge(other)
132
+ super.tap do |result|
133
+ # Copy over the zone specific flag. "True" is retained if either
134
+ # has it.
135
+ new_zone_specific = other.instance_variable_get(:@__zone_specific)
136
+ result.instance_variable_set(
137
+ :@__zone_specific, new_zone_specific || @__zone_specific)
138
+
139
+ # Go through all the zone configs and prepend ours onto
140
+ # theirs.
141
+ new_zone_config = other.instance_variable_get(:@__zone_config)
142
+ @__zone_config.each do |key, value|
143
+ new_zone_config[key] ||= []
144
+ new_zone_config[key] = value + new_zone_config[key]
145
+ end
146
+
147
+ # Set it
148
+ result.instance_variable_set(:@__zone_config, new_zone_config)
149
+
150
+ # Merge in the metadata
151
+ result.metadata.merge!(self.metadata)
152
+ result.metadata.merge!(other.metadata)
153
+ end
154
+ end
155
+
156
+ def finalize!
157
+ # Try to get access keys from standard Google environment variables; they
158
+ # will default to nil if the environment variables are not present.
159
+ @google_client_email = ENV['GOOGLE_CLIENT_EMAIL'] if @google_client_email == UNSET_VALUE
160
+ @google_key_location = ENV['GOOGLE_KEY_LOCATION'] if @google_key_location == UNSET_VALUE
161
+ @google_project_id = ENV['GOOGLE_PROJECT_ID'] if @google_project_id == UNSET_VALUE
162
+
163
+ # Image must be nil, since we can't default that
164
+ @image = "debian-7-wheezy-v20140619" if @image == UNSET_VALUE
165
+
166
+ # Default instance type is an n1-standard-1
167
+ @machine_type = "n1-standard-1" if @machine_type == UNSET_VALUE
168
+
169
+ # Instance name defaults to a new datetime value (hour granularity)
170
+ t = Time.now
171
+ @name = "i-#{t.year}#{t.month.to_s.rjust(2,'0')}#{t.day.to_s.rjust(2,'0')}#{t.hour.to_s.rjust(2,'0')}" if @name == UNSET_VALUE
172
+
173
+ # Network defaults to 'default'
174
+ @network = "default" if @network == UNSET_VALUE
175
+
176
+ # Default zone is us-central1-a.
177
+ @zone = "us-central1-a" if @zone == UNSET_VALUE
178
+
179
+ # Default instance_ready_timeout
180
+ @instance_ready_timeout = 20 if @instance_ready_timeout == UNSET_VALUE
181
+
182
+ # Compile our zone specific configurations only within
183
+ # NON-zone-SPECIFIC configurations.
184
+ if !@__zone_specific
185
+ @__zone_config.each do |zone, blocks|
186
+ config = self.class.new(true).merge(self)
187
+
188
+ # Execute the configuration for each block
189
+ blocks.each { |b| b.call(config) }
190
+
191
+ # The zone name of the configuration always equals the
192
+ # zone config name:
193
+ config.zone = zone
194
+
195
+ # Finalize the configuration
196
+ config.finalize!
197
+
198
+ # Store it for retrieval
199
+ @__compiled_zone_configs[zone] = config
200
+ end
201
+ end
202
+
203
+ # Mark that we finalized
204
+ @__finalized = true
205
+ end
206
+
207
+ def validate(machine)
208
+ errors = _detected_errors
209
+
210
+ errors << I18n.t("vagrant_google.config.zone_required") if @zone.nil?
211
+
212
+ if @zone
213
+ config = get_zone_config(@zone)
214
+
215
+ errors << I18n.t("vagrant_google.config.google_project_id_required") if \
216
+ config.google_project_id.nil?
217
+ errors << I18n.t("vagrant_google.config.google_client_email_required") if \
218
+ config.google_client_email.nil?
219
+ errors << I18n.t("vagrant_google.config.google_key_location_required") if \
220
+ config.google_key_location.nil?
221
+ end
222
+
223
+ errors << I18n.t("vagrant_google.config.image_required") if config.image.nil?
224
+ errors << I18n.t("vagrant_google.config.name_required") if @name.nil?
225
+
226
+ { "Google Provider" => errors }
227
+ end
228
+
229
+ # This gets the configuration for a specific zone. It shouldn't
230
+ # be called by the general public and is only used internally.
231
+ def get_zone_config(name)
232
+ if !@__finalized
233
+ raise "Configuration must be finalized before calling this method."
234
+ end
235
+
236
+ # Return the compiled zone config
237
+ @__compiled_zone_configs[name] || self
238
+ end
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,32 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ require "vagrant"
15
+
16
+ module VagrantPlugins
17
+ module Google
18
+ module Errors
19
+ class VagrantGoogleError < Vagrant::Errors::VagrantError
20
+ error_namespace("vagrant_google.errors")
21
+ end
22
+
23
+ class FogError < VagrantGoogleError
24
+ error_key(:fog_error)
25
+ end
26
+
27
+ class RsyncError < VagrantGoogleError
28
+ error_key(:rsync_error)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,86 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ begin
15
+ require "vagrant"
16
+ rescue LoadError
17
+ raise "The Vagrant Google plugin must be run within Vagrant."
18
+ end
19
+
20
+ # This is a sanity check to make sure no one is attempting to install
21
+ # this into an early Vagrant version.
22
+ if Vagrant::VERSION < "1.2.0"
23
+ raise "The Vagrant Google plugin is only compatible with Vagrant 1.2+"
24
+ end
25
+
26
+ module VagrantPlugins
27
+ module Google
28
+ class Plugin < Vagrant.plugin("2")
29
+ name "Google"
30
+ description <<-DESC
31
+ This plugin installs a provider that allows Vagrant to manage
32
+ Google Compute Engine instances.
33
+ DESC
34
+
35
+ config(:google, :provider) do
36
+ require_relative "config"
37
+ Config
38
+ end
39
+
40
+ provider(:google, parallel: true) do
41
+ # Setup logging and i18n
42
+ setup_logging
43
+ setup_i18n
44
+
45
+ # Return the provider
46
+ require_relative "provider"
47
+ Provider
48
+ end
49
+
50
+ # This initializes the internationalization strings.
51
+ def self.setup_i18n
52
+ I18n.load_path << File.expand_path("locales/en.yml", Google.source_root)
53
+ I18n.reload!
54
+ end
55
+
56
+ # This sets up our log level to be whatever VAGRANT_LOG is.
57
+ def self.setup_logging
58
+ require "log4r"
59
+
60
+ level = nil
61
+ begin
62
+ level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
63
+ rescue NameError
64
+ # This means that the logging constant wasn't found,
65
+ # which is fine. We just keep `level` as `nil`. But
66
+ # we tell the user.
67
+ level = nil
68
+ end
69
+
70
+ # Some constants, such as "true" resolve to booleans, so the
71
+ # above error checking doesn't catch it. This will check to make
72
+ # sure that the log level is an integer, as Log4r requires.
73
+ level = nil if !level.is_a?(Integer)
74
+
75
+ # Set the logging level on all "vagrant" namespaced
76
+ # logs as long as we have a valid level.
77
+ if level
78
+ logger = Log4r::Logger.new("vagrant_google")
79
+ logger.outputters = Log4r::Outputter.stderr
80
+ logger.level = level
81
+ logger = nil
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,63 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ require "log4r"
15
+ require "vagrant"
16
+
17
+ module VagrantPlugins
18
+ module Google
19
+ class Provider < Vagrant.plugin("2", :provider)
20
+ def initialize(machine)
21
+ @machine = machine
22
+ end
23
+
24
+ def action(name)
25
+ # Attempt to get the action method from the Action class if it
26
+ # exists, otherwise return nil to show that we don't support the
27
+ # given action.
28
+ action_method = "action_#{name}"
29
+ return Action.send(action_method) if Action.respond_to?(action_method)
30
+ nil
31
+ end
32
+
33
+ def ssh_info
34
+ # Run a custom action called "read_ssh_info" which does what it
35
+ # says and puts the resulting SSH info into the `:machine_ssh_info`
36
+ # key in the environment.
37
+ env = @machine.action("read_ssh_info")
38
+ env[:machine_ssh_info]
39
+ end
40
+
41
+ def state
42
+ # Run a custom action we define called "read_state" which does
43
+ # what it says. It puts the state in the `:machine_state_id`
44
+ # key in the environment.
45
+ env = @machine.action("read_state")
46
+
47
+ state_id = env[:machine_state_id]
48
+
49
+ # Get the short and long description
50
+ short = I18n.t("vagrant_google.states.short_#{state_id}")
51
+ long = I18n.t("vagrant_google.states.long_#{state_id}")
52
+
53
+ # Return the MachineState object
54
+ Vagrant::MachineState.new(state_id, short, long)
55
+ end
56
+
57
+ def to_s
58
+ id = @machine.id.nil? ? "new" : @machine.id
59
+ "Google (#{id})"
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,30 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ module VagrantPlugins
15
+ module Google
16
+ module Util
17
+ class Timer
18
+ # A basic utility method that times the execution of the given
19
+ # block and returns it.
20
+ def self.time
21
+ start_time = Time.now.to_f
22
+ yield
23
+ end_time = Time.now.to_f
24
+
25
+ end_time - start_time
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ module VagrantPlugins
15
+ module Google
16
+ VERSION = "0.1.3"
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "pathname"
16
+ require "vagrant-google/plugin"
17
+
18
+ module VagrantPlugins
19
+ module Google
20
+ lib_path = Pathname.new(File.expand_path("../vagrant-google", __FILE__))
21
+ autoload :Action, lib_path.join("action")
22
+ autoload :Errors, lib_path.join("errors")
23
+
24
+ # This returns the path to the source of this plugin.
25
+ #
26
+ # @return [Pathname]
27
+ def self.source_root
28
+ @source_root ||= Pathname.new(File.expand_path("../../", __FILE__))
29
+ end
30
+ end
31
+ end