vagrant-google 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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