tcr-vagrant-google 0.1.4

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,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.4"
17
+ end
18
+ end
@@ -0,0 +1,105 @@
1
+ en:
2
+ vagrant_google:
3
+ already_created: |-
4
+ The machine is already created.
5
+ launching_instance: |-
6
+ Launching an instance with the following settings...
7
+ launch_vpc_warning: |-
8
+ Warning! You're launching this instance into a VPC without an
9
+ elastic IP. Please verify you're properly connected to a VPN so
10
+ you can access this machine, otherwise Vagrant will not be able
11
+ to SSH into it.
12
+ not_created: |-
13
+ Instance is not created. Please run `vagrant up` first.
14
+ ready: |-
15
+ Machine is booted and ready for use!
16
+ ready_ssh: |-
17
+ Machine is ready for SSH access!
18
+ rsync_folder: |-
19
+ Rsyncing folder: %{hostpath} => %{guestpath}
20
+ terminating: |-
21
+ Terminating the instance...
22
+ waiting_for_ready: |-
23
+ Waiting for instance to become "ready"...
24
+ waiting_for_ssh: |-
25
+ Waiting for SSH to become available...
26
+ warn_networks: |-
27
+ Warning! The Google provider doesn't support any of the Vagrant
28
+ high-level network configurations (`config.vm.network`). They
29
+ will be silently ignored.
30
+ will_not_destroy: |-
31
+ The instance '%{name}' will not be destroyed, since the confirmation
32
+ was declined.
33
+
34
+ config:
35
+ google_client_email_required: |-
36
+ A Google Service Account client email is required via "google_client_email"
37
+ machine_required: |-
38
+ An MACHINE_TYPE must be configured via "machine"
39
+ private_key_missing: |-
40
+ The specified private key for Google could not be found
41
+ zone_required: |-
42
+ A zone must be specified via "zone"
43
+ name_required: |-
44
+ An instance name must be specified via "name"
45
+ google_key_location_required: |-
46
+ A private key pathname is required via "google_key_location"
47
+ google_project_id_required: |-
48
+ A Google Cloud Project ID is required via "google_project_id"
49
+
50
+ errors:
51
+ fog_error: |-
52
+ There was an error talking to Google. The error message is shown
53
+ below:
54
+
55
+ %{message}
56
+ instance_ready_timeout: |-
57
+ The instance never became "ready" in Google. The timeout currently
58
+ set waiting for the instance to become ready is %{timeout} seconds.
59
+ Please verify that the machine properly boots. If you need more time
60
+ set the `instance_ready_timeout` configuration on the Google provider.
61
+ rsync_error: |-
62
+ There was an error when attemping to rsync a share folder.
63
+ Please inspect the error message below for more info.
64
+
65
+ Host path: %{hostpath}
66
+ Guest path: %{guestpath}
67
+ Error: %{stderr}
68
+
69
+ states:
70
+ short_not_created: |-
71
+ not created
72
+ long_not_created: |-
73
+ The Google instance is not created. Run `vagrant up` to create it.
74
+
75
+ short_PROVISIONING: |-
76
+ provsioning
77
+ long_PROVISIONING: |-
78
+ Resources are being reserved for this instance. This instance is
79
+ not yet running.
80
+
81
+ short_STAGING: |-
82
+ staging
83
+ long_STAGING: |-
84
+ Resources have been acquired and the instance is being prepared for
85
+ launch and should be in the RUNNING state soon.
86
+
87
+ short_RUNNING: |-
88
+ running
89
+ long_RUNNING: |-
90
+ The Google instance is running. To stop this machine, you can run
91
+ `vagrant halt`. To destroy the machine, you can run `vagrant destroy`.
92
+
93
+ short_STOPPED: |-
94
+ stopped
95
+ long_STOPPED: |-
96
+ The Google instance is not currently running, either due to a failure
97
+ , or the instance is being shut down. This is a temporary status;
98
+ the instance will move to either PROVISIONING or TERMINATED.
99
+
100
+ short_TERMINATED: |-
101
+ terminated
102
+ long_TERMINATED: |-
103
+ The Google instance failed for some reason or was shutdown. This is
104
+ a permanent status, and the only way to repair the instance is to
105
+ delete it with `vagrant destroy`.
@@ -0,0 +1,202 @@
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-google/config"
15
+
16
+ describe VagrantPlugins::Google::Config do
17
+ let(:instance) { described_class.new }
18
+
19
+ # Ensure tests are not affected by Google credential environment variables
20
+ before :each do
21
+ ENV.stub(:[] => nil)
22
+ end
23
+
24
+ describe "defaults" do
25
+ subject do
26
+ instance.tap do |o|
27
+ o.finalize!
28
+ end
29
+ end
30
+ t = Time.now
31
+
32
+ its("name") { should == "i-#{t.year}#{t.month.to_s.rjust(2,'0')}#{t.day.to_s.rjust(2,'0')}#{t.hour.to_s.rjust(2,'0')}" }
33
+ its("image") { should == "debian-7-wheezy-v20140926" }
34
+ its("zone") { should == "us-central1-f" }
35
+ its("network") { should == "default" }
36
+ its("machine_type") { should == "n1-standard-1" }
37
+ its("disk_size") { should == 10 }
38
+ its("instance_ready_timeout") { should == 20 }
39
+ its("metadata") { should == {} }
40
+ its("tags") { should == [] }
41
+ its("service_accounts") { should == nil }
42
+ end
43
+
44
+ describe "overriding defaults" do
45
+ # I typically don't meta-program in tests, but this is a very
46
+ # simple boilerplate test, so I cut corners here. It just sets
47
+ # each of these attributes to "foo" in isolation, and reads the value
48
+ # and asserts the proper result comes back out.
49
+ [:name, :image, :zone, :instance_ready_timeout, :machine_type, :disk_size,
50
+ :network, :metadata].each do |attribute|
51
+
52
+ it "should not default #{attribute} if overridden" do
53
+ instance.send("#{attribute}=".to_sym, "foo")
54
+ instance.finalize!
55
+ instance.send(attribute).should == "foo"
56
+ end
57
+ end
58
+ end
59
+
60
+ describe "getting credentials from environment" do
61
+ context "without Google credential environment variables" do
62
+ subject do
63
+ instance.tap do |o|
64
+ o.finalize!
65
+ end
66
+ end
67
+
68
+ its("google_client_email") { should be_nil }
69
+ its("google_key_location") { should be_nil }
70
+ end
71
+
72
+ context "with Google credential environment variables" do
73
+ before :each do
74
+ ENV.stub(:[]).with("GOOGLE_CLIENT_EMAIL").and_return("client_id_email")
75
+ ENV.stub(:[]).with("GOOGLE_KEY_LOCATION").and_return("/path/to/key")
76
+ end
77
+
78
+ subject do
79
+ instance.tap do |o|
80
+ o.finalize!
81
+ end
82
+ end
83
+
84
+ its("google_client_email") { should == "client_id_email" }
85
+ its("google_key_location") { should == "/path/to/key" }
86
+ end
87
+ end
88
+
89
+ describe "zone config" do
90
+ let(:config_image) { "foo" }
91
+ let(:config_machine_type) { "foo" }
92
+ let(:config_disk_size) { 99 }
93
+ let(:config_name) { "foo" }
94
+ let(:config_zone) { "foo" }
95
+ let(:config_network) { "foo" }
96
+
97
+ def set_test_values(instance)
98
+ instance.name = config_name
99
+ instance.network = config_network
100
+ instance.image = config_image
101
+ instance.machine_type = config_machine_type
102
+ instance.disk_size = config_disk_size
103
+ instance.zone = config_zone
104
+ end
105
+
106
+ it "should raise an exception if not finalized" do
107
+ expect { instance.get_zone_config("us-central1-f") }.
108
+ to raise_error
109
+ end
110
+
111
+ context "with no specific config set" do
112
+ subject do
113
+ # Set the values on the top-level object
114
+ set_test_values(instance)
115
+
116
+ # Finalize so we can get the zone config
117
+ instance.finalize!
118
+
119
+ # Get a lower level zone
120
+ instance.get_zone_config("us-central1-f")
121
+ end
122
+
123
+ its("name") { should == config_name }
124
+ its("image") { should == config_image }
125
+ its("machine_type") { should == config_machine_type }
126
+ its("disk_size") { should == config_disk_size }
127
+ its("network") { should == config_network }
128
+ its("zone") { should == config_zone }
129
+ end
130
+
131
+ context "with a specific config set" do
132
+ let(:zone_name) { "hashi-zone" }
133
+
134
+ subject do
135
+ # Set the values on a specific zone
136
+ instance.zone_config zone_name do |config|
137
+ set_test_values(config)
138
+ end
139
+
140
+ # Finalize so we can get the zone config
141
+ instance.finalize!
142
+
143
+ # Get the zone
144
+ instance.get_zone_config(zone_name)
145
+ end
146
+
147
+ its("name") { should == config_name }
148
+ its("image") { should == config_image }
149
+ its("machine_type") { should == config_machine_type }
150
+ its("disk_size") { should == config_disk_size }
151
+ its("network") { should == config_network }
152
+ its("zone") { should == zone_name }
153
+ end
154
+
155
+ describe "inheritance of parent config" do
156
+ let(:zone) { "hashi-zone" }
157
+
158
+ subject do
159
+ # Set the values on a specific zone
160
+ instance.zone_config zone do |config|
161
+ config.image = "child"
162
+ end
163
+
164
+ # Set some top-level values
165
+ instance.image = "parent"
166
+
167
+ # Finalize and get the zone
168
+ instance.finalize!
169
+ instance.get_zone_config(zone)
170
+ end
171
+
172
+ its("image") { should == "child" }
173
+ end
174
+
175
+ describe "shortcut configuration" do
176
+ subject do
177
+ # Use the shortcut configuration to set some values
178
+ instance.zone_config "us-central1-f", :image => "child"
179
+ instance.finalize!
180
+ instance.get_zone_config("us-central1-f")
181
+ end
182
+
183
+ its("image") { should == "child" }
184
+ end
185
+
186
+ describe "merging" do
187
+ let(:first) { described_class.new }
188
+ let(:second) { described_class.new }
189
+
190
+ it "should merge the metadata" do
191
+ first.metadata["one"] = "foo"
192
+ second.metadata["two"] = "bar"
193
+
194
+ third = first.merge(second)
195
+ third.metadata.should == {
196
+ "one" => "foo",
197
+ "two" => "bar"
198
+ }
199
+ end
200
+ end
201
+ end
202
+ end