kitchen-google 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4085522e906870ad6ced21e1324fd139ffb2f454
4
+ data.tar.gz: e0337e83aa1ae41006264dfe93c0ddd2739f63f8
5
+ SHA512:
6
+ metadata.gz: b0b0e34c10fa46f788a8e36a11d637a2fe6d5e6729f7c023481a5fae135d4df1eab74ee7cf2c9a877bda863ceb3e46a9df27734ebb4857acb60aaa4669ef7c2a
7
+ data.tar.gz: a683597a6f9cd2eac0d90cf34bd2b7e4ab7c6612558781c52a78ed646c778b353b513603f9d9b215eb5534a7a6f810d248a27c6e2ca1f790b9953dc3355e5c08
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *~
2
+ *#
3
+ .ruby-version
4
+ *.gem
5
+ Gemfile.lock
data/.rubocop.yml ADDED
@@ -0,0 +1 @@
1
+ inherit_from: .rubocop_todo.yml
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,11 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2014-09-20 08:00:47 -0700 using RuboCop version 0.26.0.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 1
9
+ # Configuration parameters: CountComments.
10
+ Metrics/ClassLength:
11
+ Max: 102
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.0
7
+
8
+ before_install:
9
+ - gem update bundler
data/CHANGELOG.md ADDED
@@ -0,0 +1,76 @@
1
+ ## 0.3.0 / 2016-01-23
2
+
3
+ ### New Features
4
+
5
+ * #14: Support service_accounts option in Fog
6
+ * #22: Add JSON credential file and Preemptible VM support
7
+
8
+ ### Improvements
9
+
10
+ * Move to test-kitchen GitHub org
11
+ * Fixes to tests
12
+
13
+ ## 0.2.0 / 2014-09-20
14
+
15
+ ### Improvements
16
+
17
+ * #10: Deprecate "area" in configuration for "region"
18
+ * #11: Fix name length, via @pdunnavant
19
+ * #12: Generate instance names that are valid for GCE
20
+
21
+ ## 0.1.2 / 2014-04-16
22
+
23
+ ### New Features
24
+
25
+ * Add documentation for new asia-east1 region.
26
+
27
+ ### Improvements
28
+
29
+ * #9: Dependency updates: Remove faraday version constraint; require newer
30
+ ridley gem.
31
+
32
+ ## 0.1.0 / 2014-03-29
33
+
34
+ ### New Features
35
+
36
+ * PR #7: Add support for specifying SSH keys in public_key_path, via @someara
37
+ * Add support for setting username
38
+ * Support GCE v1 API, including persistent disks.
39
+
40
+ ### Improvements
41
+
42
+ * Add rspec tests and Travis support.
43
+
44
+ ## 0.0.6 / 2014-02-23:
45
+
46
+ * Require Ruby 1.9 or greater.
47
+
48
+ ### Improvements
49
+
50
+ * Add support for specifying GCE network and tags.
51
+
52
+ ### Bug fixes
53
+
54
+ * Temporarily pin Fog version to 1.19.0 until 1.20.0 support is added.
55
+ * Require Faraday Gem version to be ~> 0.8.9; 0.9.0 breaks test-kitchen.
56
+
57
+ ## 0.0.4 / 2013-12-28
58
+
59
+ ### Bug fixes
60
+
61
+ * In GCE, instance names must be unique; derive by default from
62
+ `<suite>-<platform>` and a UUID.
63
+ * Fix bug where running `kitchen create` multiple times would create
64
+ duplicate instances.
65
+ * Require version of Fog with exponential backoff in GCE API queries.
66
+
67
+ ### Improvements
68
+
69
+ * README formatting and clarity fixes.
70
+ * Add concept of an "area" (us, europe, any) to automatically select
71
+ an availability zone from those that are up within the requested
72
+ area for each instance.
73
+
74
+ ## 0.0.1 / 2013-10-20
75
+
76
+ ### Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify dependencies in gemspec:
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ Author:: Andrew Leonard (<andy@hurricane-ridge.com>)
2
+
3
+ Copyright (C) 2013-2014, Andrew Leonard
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,192 @@
1
+ # Kitchen::Gce - A Test Kitchen Driver for Google Compute Engine
2
+
3
+ [![Build Status](https://travis-ci.org/test-kitchen/kitchen-google.png?branch=master)](https://travis-ci.org/test-kitchen/kitchen-google)
4
+ [![Code Climate](https://codeclimate.com/github/test-kitchen/kitchen-google.png)](https://codeclimate.com/github/test-kitchen/kitchen-google)
5
+
6
+ This is a [Test Kitchen](https://github.com/opscode/test-kitchen/)
7
+ driver for Google Compute Engine. While similar to EC2 and other IaaS
8
+ providers, GCE has a couple of advantages for Chef cookbook testing:
9
+
10
+ * (Subjectively) faster instance launch times; and
11
+ * Sub-hour billing.
12
+
13
+ ## Requirements
14
+
15
+ Ruby 1.9 or greater.
16
+
17
+ A [Google Cloud Platform](https://cloud.google.com) account is
18
+ required. If you do not already have an appropriate "project" in
19
+ which to run your test-kitchen instances, create one, noting the
20
+ "project id". Then, within the [Google API
21
+ Console](https://code.google.com/apis/console/), create a "service
22
+ account" for the project under the "API Access" tab. Save the key
23
+ file, and note the email address associated with the service account
24
+ (e.g. 123456789012@developer.gserviceaccount.com - not the project
25
+ owner's email address).
26
+
27
+ If you are not using the `public_key_path` setting (see below) and
28
+ have not [set up SSH keys for your GCE
29
+ environment](https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys),
30
+ you must also do that prior to using kitchen-gce. Also, you will
31
+ likely want to add your SSH keys to ssh-agent prior to converging any
32
+ instances.
33
+
34
+ ## Installation
35
+
36
+ Assuming you are using Bundler, ensure the Gemfile within your Chef
37
+ cookbook contains at least the following:
38
+
39
+ ```ruby
40
+ source 'https://rubygems.org'
41
+
42
+ gem 'berkshelf'
43
+
44
+ group :integration do
45
+ gem 'kitchen-gce'
46
+ end
47
+ ```
48
+
49
+ Then, execute `bundle install`.
50
+
51
+ ## Configuration
52
+
53
+ ### `area`
54
+
55
+ Deprecated - use equivalent [`region`](#region) instead. If both `area` and
56
+ `region` are set, the value of `region` will be used.
57
+
58
+ ### `autodelete_disk`
59
+
60
+ Boolean specifying whether or not to automatically delete boot disk
61
+ for test instance. Default: `true`
62
+
63
+ ### `disk_size`
64
+
65
+ Size, in gigabytes, of boot disk. Default: `10`.
66
+
67
+ ### `google_client_email`
68
+
69
+ **Required** Email address associated with your GCE service account.
70
+ (N.B. - this is not the same as the Google Cloud Platform user's email
71
+ account; should be in the form
72
+ "123456789012@developer.gserviceaccount.com".)
73
+
74
+ ### `google_key_location`
75
+
76
+ **Required** Path to GCE service account key file.
77
+
78
+ ### `google_project`
79
+
80
+ **Required** Project ID of the GCE project into which test-kitchen
81
+ instances will be launched.
82
+
83
+ ### `image_name`
84
+
85
+ **Required** Operating system image to deploy.
86
+
87
+ ### `inst_name`
88
+
89
+ Name to give to instance; unlike EC2's "Name" tag, this is used as an
90
+ instance identifier and must be unique. If none is specified, a unique
91
+ name will be auto-generated; note that auto-generated names must be
92
+ used if there is more than one test suite. Default:
93
+ `<suite>-<platform>-<UUID>`
94
+
95
+ ### `machine_type`
96
+
97
+ GCE instance type (size) to launch; default: `n1-standard-1`
98
+
99
+ ### `network`
100
+
101
+ GCE network that instance will be attached to; default: `default`
102
+
103
+ ### `preemptible`
104
+
105
+ If set to `true`, GCE instance will be brought up as a [preemptible](https://cloud.google.com/compute/docs/instances/preemptible) virtual machine,
106
+ that runs at a much lower price than normal instances. However, Compute
107
+ Engine might terminate (preempt) these instances if it requires access
108
+ to those resources for other tasks; default: `false`
109
+
110
+ ### `public_key_path`
111
+
112
+ Path to the public half of the ssh key that will be deployed to
113
+ `~username/.ssh/authorized_keys`; see also [`username`](#username) below.
114
+
115
+ ### `region`
116
+
117
+ Region in which to launch instances. `region` is defined as the part
118
+ prior to the second hyphen in an availability zone's name; e.g. in
119
+ `us-central1-b`, the region is `us-central1`. Specifying region but
120
+ not `zone_name` allows kitchen-gce to avoid launching instances into a
121
+ zone that is down for maintenance. If `any` is specified, kitchen-gce
122
+ will select a zone from all regions. Default: `us-central1` (lowest
123
+ cost region); valid values: `any`, `asia-east1`, `europe-west1`,
124
+ `us-central1`
125
+
126
+ ### `tags`
127
+
128
+ Array of tags to associate with instance; default: `[]`
129
+
130
+ ### `username`
131
+
132
+ Username test-kitchen will log into instance as; default: `ENV['USER']`
133
+
134
+ ### `zone_name`
135
+
136
+ Location into which instances will be launched. If not specified, a
137
+ zone is chosen from available zones within the [`region`](#region).
138
+
139
+ ## Example
140
+
141
+ An example `.kitchen.yml` file using kitchen-gce might look something
142
+ like this:
143
+
144
+ ```ruby
145
+ ---
146
+ driver_plugin: gce
147
+ driver_config:
148
+ google_client_email: "123456789012@developer.gserviceaccount.com"
149
+ google_key_location: "<%= ENV['HOME']%>/gce/1234567890abcdef1234567890abcdef12345678-privatekey.p12"
150
+ google_project: "alpha-bravo-123"
151
+ network: "kitchenci"
152
+ region: any
153
+
154
+ platforms:
155
+ - name: debian-7
156
+ driver_config:
157
+ image_name: debian-7-wheezy-v20151104
158
+ require_chef_omnibus: true
159
+ public_key_path: '/home/alice/.ssh/google_compute_engine.pub'
160
+ tags: ["somerole"]
161
+
162
+ suites:
163
+ - name: default
164
+ run_list: ["recipe[somecookbook]"]
165
+ attributes: {}
166
+ ```
167
+
168
+ ## Development
169
+
170
+ Source is hosted on [GitHub](https://github.com/anl/kitchen-gce).
171
+
172
+ * Pull requests are welcome, using topic branches if possible:
173
+
174
+ 1. Fork the repo.
175
+ 2. Create a feature branch, commit changes to it and push them.
176
+ 3. Submit a pull request.
177
+
178
+ * Report issues or submit feature requests on [GitHub](https://github.com/anl/kitchen-gce/issues)
179
+
180
+ ## Author, Acknowledgements, Etc.
181
+
182
+ Created and maintained by [Andrew Leonard](http://andyleonard.com)
183
+ ([andy@hurricane-ridge.com](mailto:andy@hurricane-ridge.com)).
184
+
185
+ The initial release drew heavily on the
186
+ [kitchen-ec2](https://github.com/opscode/kitchen-ec2/) gem for both
187
+ inspiration and implementation details. Any bugs, however, are solely
188
+ the author's own doing.
189
+
190
+ ## License
191
+
192
+ Licensed under Apache 2.0.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ desc 'Run RSpec unit tests'
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: [:spec]
@@ -0,0 +1,26 @@
1
+ # -*- coding: utf-8 -*-
2
+ Gem::Specification.new do |s|
3
+ s.name = 'kitchen-google'
4
+ s.version = '0.3.0'
5
+ s.date = '2016-01-23'
6
+ s.summary = 'Kitchen::Driver::Gce'
7
+ s.description = 'A Test-Kitchen driver for Google Compute Engine'
8
+ s.authors = ['Andrew Leonard']
9
+ s.email = 'andy@hurricane-ridge.com'
10
+ s.files = `git ls-files`.split($/) # rubocop:disable SpecialGlobalVars
11
+ s.homepage = 'https://github.com/test-kitchen/kitchen-google'
12
+ s.license = 'Apache 2.0'
13
+
14
+ s.add_dependency 'fog', '>= 1.31.0'
15
+ s.add_dependency 'google-api-client'
16
+ s.add_dependency 'ridley', '>= 3.0.0' # See GH issue RiotGames/ridley#239
17
+ s.add_dependency 'test-kitchen'
18
+
19
+ s.add_development_dependency 'bundler'
20
+ s.add_development_dependency 'pry'
21
+ s.add_development_dependency 'rake'
22
+ s.add_development_dependency 'rspec'
23
+ s.add_development_dependency 'rubocop'
24
+
25
+ s.required_ruby_version = '>= 1.9'
26
+ end
@@ -0,0 +1,170 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Author:: Andrew Leonard (<andy@hurricane-ridge.com>)
4
+ #
5
+ # Copyright (C) 2013-2014, Andrew Leonard
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'fog'
20
+ require 'securerandom'
21
+
22
+ require 'kitchen'
23
+
24
+ module Kitchen
25
+ module Driver
26
+ # Google Compute Engine driver for Test Kitchen
27
+ #
28
+ # @author Andrew Leonard <andy@hurricane-ridge.com>
29
+ class Gce < Kitchen::Driver::SSHBase
30
+ default_config :area, 'us-central1'
31
+ default_config :autodelete_disk, true
32
+ default_config :disk_size, 10
33
+ default_config :machine_type, 'n1-standard-1'
34
+ default_config :network, 'default'
35
+ default_config :inst_name, nil
36
+ default_config :service_accounts, nil
37
+ default_config :tags, []
38
+ default_config :username, ENV['USER']
39
+ default_config :zone_name, nil
40
+ default_config :google_key_location, nil
41
+ default_config :google_json_key_location, nil
42
+ default_config :preemptible, false
43
+ default_config :auto_restart, false
44
+
45
+ required_config :google_client_email
46
+ required_config :google_project
47
+ required_config :image_name
48
+
49
+ def create(state)
50
+ return if state[:server_id]
51
+
52
+ instance = create_instance
53
+ state[:server_id] = instance.identity
54
+
55
+ info("GCE instance <#{state[:server_id]}> created.")
56
+
57
+ wait_for_up_instance(instance, state)
58
+
59
+ rescue Fog::Errors::Error, Excon::Errors::Error => ex
60
+ raise ActionFailed, ex.message
61
+ end
62
+
63
+ def destroy(state)
64
+ return if state[:server_id].nil?
65
+
66
+ instance = connection.servers.get(state[:server_id])
67
+ instance.destroy unless instance.nil?
68
+ info("GCE instance <#{state[:server_id]}> destroyed.")
69
+ state.delete(:server_id)
70
+ state.delete(:hostname)
71
+ end
72
+
73
+ private
74
+
75
+ def connection
76
+ options = {
77
+ provider: 'google',
78
+ google_client_email: config[:google_client_email],
79
+ google_project: config[:google_project]
80
+ }
81
+
82
+ [
83
+ :google_key_location,
84
+ :google_json_key_location
85
+ ].each do |k|
86
+ options[k] = config[k] unless config[k].nil?
87
+ end
88
+
89
+ Fog::Compute.new(options)
90
+ end
91
+
92
+ def create_disk
93
+ disk = connection.disks.create(
94
+ name: config[:inst_name],
95
+ size_gb: config[:disk_size],
96
+ zone_name: config[:zone_name],
97
+ source_image: config[:image_name]
98
+ )
99
+
100
+ disk.wait_for { disk.ready? }
101
+ disk
102
+ end
103
+
104
+ def create_instance
105
+ config[:region] ||= config[:area]
106
+
107
+ config[:inst_name] ||= generate_inst_name
108
+ config[:zone_name] ||= select_zone
109
+
110
+ disk = create_disk
111
+ create_server(disk)
112
+ end
113
+
114
+ def create_server(disk)
115
+ connection.servers.create(
116
+ name: config[:inst_name],
117
+ disks: [disk.get_as_boot_disk(true, config[:autodelete_disk])],
118
+ machine_type: config[:machine_type],
119
+ network: config[:network],
120
+ service_accounts: config[:service_accounts],
121
+ tags: config[:tags],
122
+ zone_name: config[:zone_name],
123
+ public_key_path: config[:public_key_path],
124
+ username: config[:username],
125
+ preemptible: config[:preemptible],
126
+ on_host_maintenance: config[:preemptible] ? 'TERMINATE': 'MIGRATE',
127
+ auto_restart: config[:auto_restart]
128
+ )
129
+ end
130
+
131
+ def generate_inst_name
132
+ # Inspired by generate_name from kitchen-rackspace
133
+ name = instance.name.downcase
134
+ name.gsub!(/([^-a-z0-9])/, '-')
135
+ name = 't' + name unless name =~ /^[a-z]/
136
+ base_name = name[0..25] # UUID is 36 chars, max name length 63
137
+ gen_name = "#{base_name}-#{SecureRandom.uuid}"
138
+ unless gen_name =~ /^[a-z]([-a-z0-9]*[a-z0-9])?$/
139
+ fail "Invalid generated instance name: #{gen_name}"
140
+ end
141
+ gen_name
142
+ end
143
+
144
+ def select_zone
145
+ if config[:region] == 'any'
146
+ zone_regexp = /^[a-z]+\-/
147
+ else
148
+ zone_regexp = /^#{config[:region]}\-/
149
+ end
150
+ zones = connection.zones.select do |z|
151
+ z.status == 'UP' && z.name.match(zone_regexp)
152
+ end
153
+ fail 'No up zones in region' unless zones.length >= 1
154
+ zones.sample.name
155
+ end
156
+
157
+ def wait_for_up_instance(instance, state)
158
+ instance.wait_for do
159
+ print '.'
160
+ ready?
161
+ end
162
+ print '(server ready)'
163
+ state[:hostname] = instance.public_ip_address ||
164
+ instance.private_ip_address
165
+ wait_for_sshd(state[:hostname], config[:username])
166
+ puts '(ssh ready)'
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,398 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Author:: Andrew Leonard (<andy@hurricane-ridge.com>)
4
+ #
5
+ # Copyright (C) 2013-2014, Andrew Leonard
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require_relative '../../spec_helper.rb'
20
+
21
+ require 'resolv'
22
+
23
+ describe Kitchen::Driver::Gce do
24
+
25
+ let(:config) do
26
+ { google_client_email: '123456789012@developer.gserviceaccount.com',
27
+ google_project: 'alpha-bravo-123'
28
+ }
29
+ end
30
+
31
+ let(:state) { Hash.new }
32
+
33
+ let(:logged_output) { StringIO.new }
34
+ let(:logger) { Logger.new(logged_output) }
35
+
36
+ let(:instance) do
37
+ double(
38
+ logger: logger,
39
+ name: 'default-distro-12'
40
+ )
41
+ end
42
+
43
+ let(:driver) do
44
+ d = Kitchen::Driver::Gce.new(config)
45
+ allow(d).to receive(:instance) { instance }
46
+ allow(d).to receive(:wait_for_sshd) { true }
47
+ d
48
+ end
49
+
50
+ let(:fog) do
51
+ Fog::Compute::Google::Mock.new({})
52
+ end
53
+
54
+ let(:disk) do
55
+ fog.disks.create(
56
+ name: 'rspec-test-disk',
57
+ size_gb: 10,
58
+ zone_name: 'us-central1-b',
59
+ source_image: 'debian-7-wheezy-v20130816'
60
+ )
61
+ end
62
+
63
+ let(:server) do
64
+ fog.servers.create(
65
+ name: 'rspec-test-instance',
66
+ disks: [disk],
67
+ machine_type: 'n1-standard-1',
68
+ zone_name: 'us-central1-b'
69
+ )
70
+ end
71
+
72
+ before(:each) do
73
+ Fog.mock!
74
+ Fog::Mock.reset
75
+ Fog::Mock.delay = 0
76
+ end
77
+
78
+ describe '#initialize' do
79
+ context 'with default options' do
80
+
81
+ defaults = {
82
+ area: 'us-central1',
83
+ autodelete_disk: true,
84
+ disk_size: 10,
85
+ inst_name: nil,
86
+ machine_type: 'n1-standard-1',
87
+ network: 'default',
88
+ region: nil,
89
+ service_accounts: nil,
90
+ tags: [],
91
+ username: ENV['USER'],
92
+ zone_name: nil,
93
+ google_key_location: nil,
94
+ google_json_key_location: nil,
95
+ preemptible: false,
96
+ auto_restart: false
97
+ }
98
+
99
+ defaults.each do |k, v|
100
+ it "sets the correct default for #{k}" do
101
+ expect(driver[k]).to eq(v)
102
+ end
103
+ end
104
+ end
105
+
106
+ context 'with overriden options' do
107
+ overrides = {
108
+ area: 'europe-west',
109
+ autodelete_disk: false,
110
+ disk_size: 15,
111
+ inst_name: 'ci-instance',
112
+ machine_type: 'n1-highmem-8',
113
+ network: 'dev-net',
114
+ region: 'asia-east1',
115
+ service_accounts: %w(userdata.email compute.readonly),
116
+ tags: %w(qa integration),
117
+ username: 'root',
118
+ zone_name: 'europe-west1-a',
119
+ google_key_location: '/path/to/foo.p12',
120
+ google_json_key_location: '/path/to/bar.json',
121
+ preemptible: true,
122
+ auto_restart: false # because of preemptible, see kitchen-google/pull/22
123
+ }
124
+
125
+ let(:config) { overrides }
126
+
127
+ overrides.each do |k, v|
128
+ it "overrides the default value for #{k}" do
129
+ expect(driver[k]).to eq(v)
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ describe '#connection' do
136
+ context 'with required variables set' do
137
+ it 'returns a Fog Compute object' do
138
+ expect(driver.send(:connection)).to be_a(Fog::Compute::Google::Mock)
139
+ end
140
+
141
+ it 'uses the v1 api version' do
142
+ conn = driver.send(:connection)
143
+ expect(conn.api_version).to eq('v1')
144
+ end
145
+ end
146
+
147
+ context 'without required variables set' do
148
+ let(:config) { Hash.new }
149
+
150
+ it 'raises an error' do
151
+ expect { driver.send(:connection) }.to raise_error(ArgumentError)
152
+ end
153
+ end
154
+ end
155
+
156
+ describe '#create' do
157
+ context 'with an existing server' do
158
+ let(:state) do
159
+ s = Hash.new
160
+ s[:server_id] = 'default-distro-12345678'
161
+ s
162
+ end
163
+
164
+ it 'returns if server_id already exists' do
165
+ expect(driver.create(state)).to equal nil
166
+ end
167
+ end
168
+
169
+ context 'when an instance is successfully created' do
170
+
171
+ let(:driver) do
172
+ d = Kitchen::Driver::Gce.new(config)
173
+ allow(d).to receive(:create_instance) { server }
174
+ allow(d).to receive(:wait_for_up_instance) { nil }
175
+ d
176
+ end
177
+
178
+ it 'sets a value for server_id in the state hash' do
179
+ driver.send(:create, state)
180
+ expect(state[:server_id]).to eq('rspec-test-instance')
181
+ end
182
+
183
+ it 'returns nil' do
184
+ expect(driver.send(:create, state)).to equal(nil)
185
+ end
186
+ end
187
+ end
188
+
189
+ describe '#create_disk' do
190
+ context 'with defaults and required options' do
191
+ it 'returns a Google Disk object' do
192
+ config[:image_name] = 'debian-7-wheezy-v20130816'
193
+ config[:inst_name] = 'rspec-disk'
194
+ config[:zone_name] = 'us-central1-a'
195
+ expect(driver.send(:create_disk)).to be_a(Fog::Compute::Google::Disk)
196
+ end
197
+ end
198
+
199
+ context 'without required options' do
200
+ it 'returns a Fog NotFound Error' do
201
+ expect { driver.send(:create_disk) }.to raise_error(
202
+ Fog::Errors::NotFound)
203
+ end
204
+ end
205
+ end
206
+
207
+ describe '#create_instance' do
208
+ context 'with default options' do
209
+ it 'returns a Fog Compute Server object' do
210
+ expect(driver.send(:create_instance)).to be_a(
211
+ Fog::Compute::Google::Server)
212
+ end
213
+
214
+ it 'sets the region to the default "us-central1"' do
215
+ driver.send(:create_instance)
216
+ expect(config[:region]).to eq('us-central1')
217
+ end
218
+ end
219
+
220
+ context 'area set, region unset' do
221
+ let(:config) do
222
+ { area: 'europe-west1',
223
+ google_client_email: '123456789012@developer.gserviceaccount.com',
224
+ google_key_location: '/home/user/gce/123456-privatekey.p12',
225
+ google_project: 'alpha-bravo-123'
226
+ }
227
+ end
228
+
229
+ it 'sets region to the area value' do
230
+ driver.send(:create_instance)
231
+ expect(config[:region]).to eq(config[:area])
232
+ end
233
+ end
234
+
235
+ context 'area set, region set' do
236
+ let(:config) do
237
+ { area: 'fugazi',
238
+ google_client_email: '123456789012@developer.gserviceaccount.com',
239
+ google_key_location: '/home/user/gce/123456-privatekey.p12',
240
+ google_project: 'alpha-bravo-123',
241
+ region: 'europe-west1'
242
+ }
243
+ end
244
+
245
+ it 'sets the region independent of the area value' do
246
+ driver.send(:create_instance)
247
+ expect(config[:region]).to eq('europe-west1')
248
+ end
249
+
250
+ end
251
+ end
252
+
253
+ describe '#create_server' do
254
+ context 'with default options' do
255
+ it 'returns a Fog Compute Server object' do
256
+ expect(driver.send(:create_instance)).to be_a(
257
+ Fog::Compute::Google::Server)
258
+ end
259
+ end
260
+ end
261
+
262
+ describe '#destroy' do
263
+ let(:state) do
264
+ s = Hash.new
265
+ s[:server_id] = 'rspec-test-instance'
266
+ s[:hostname] = '198.51.100.17'
267
+ s
268
+ end
269
+
270
+ it 'returns if server_id does not exist' do
271
+ expect(driver.destroy({})).to equal nil
272
+ end
273
+
274
+ it 'removes the server state information' do
275
+ driver.destroy(state)
276
+ expect(state[:hostname]).to equal(nil)
277
+ expect(state[:server_id]).to equal(nil)
278
+ end
279
+ end
280
+
281
+ describe '#generate_inst_name' do
282
+ context 'with a name less than 28 characters' do
283
+ it 'concatenates the name and a UUID' do
284
+ expect(driver.send(:generate_inst_name)).to match(
285
+ /^default-distro-12-[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$/)
286
+ end
287
+ end
288
+
289
+ context 'with a name 27 characters or longer' do
290
+ let(:instance) do
291
+ double(name: 'a23456789012345678901234567')
292
+ end
293
+
294
+ it 'shortens the base name and appends a UUID' do
295
+ expect(driver.send(:generate_inst_name).length).to eq 63
296
+ expect(driver.send(:generate_inst_name)).to match(
297
+ /^a2345678901234567890123456
298
+ -[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$/x)
299
+ end
300
+ end
301
+
302
+ context 'with a "name" value containing an invalid leading character' do
303
+ let(:instance) do
304
+ double(name: '12345')
305
+ end
306
+
307
+ it 'adds a leading "t"' do
308
+ expect(driver.send(:generate_inst_name)).to match(
309
+ /^t12345
310
+ -[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$/x)
311
+ end
312
+ end
313
+
314
+ context 'with a "name" value containing uppercase letters' do
315
+ let(:instance) do
316
+ double(name: 'AbCdEf')
317
+ end
318
+
319
+ it 'downcases the "name" characters in the instance name' do
320
+ expect(driver.send(:generate_inst_name)).to match(
321
+ /^abcdef
322
+ -[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$/x)
323
+ end
324
+ end
325
+
326
+ context 'with a name value containing invalid characters' do
327
+ let(:instance) do
328
+ double(name: 'a!b@c#d$e%f^g&h*i(j)')
329
+ end
330
+
331
+ it 'replaces the invalid characters with dashes' do
332
+ expect(driver.send(:generate_inst_name)).to match(
333
+ /^a-b-c-d-e-f-g-h-i-j-
334
+ -[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$/x)
335
+ end
336
+ end
337
+ end
338
+
339
+ describe '#select_zone' do
340
+ context 'when choosing from any region' do
341
+ let(:config) do
342
+ { region: 'any',
343
+ google_client_email: '123456789012@developer.gserviceaccount.com',
344
+ google_key_location: '/home/user/gce/123456-privatekey.p12',
345
+ google_project: 'alpha-bravo-123'
346
+ }
347
+ end
348
+
349
+ it 'chooses from all zones' do
350
+ expect(driver.send(:select_zone)).to satisfy do |zone|
351
+ %w(europe-west1-a us-central1-a us-central1-b
352
+ us-central2-a).include?(zone)
353
+ end
354
+ end
355
+ end
356
+
357
+ context 'when choosing from the "europe-west1" region' do
358
+ let(:config) do
359
+ { region: 'europe-west1',
360
+ google_client_email: '123456789012@developer.gserviceaccount.com',
361
+ google_key_location: '/home/user/gce/123456-privatekey.p12',
362
+ google_project: 'alpha-bravo-123'
363
+ }
364
+ end
365
+
366
+ it 'chooses a zone in europe-west1' do
367
+ expect(driver.send(:select_zone)).to satisfy do |zone|
368
+ %w(europe-west1-a).include?(zone)
369
+ end
370
+ end
371
+ end
372
+
373
+ context 'when choosing from the default "us-central1" region' do
374
+ let(:config) do
375
+ { region: 'us-central1',
376
+ google_client_email: '123456789012@developer.gserviceaccount.com',
377
+ google_key_location: '/home/user/gce/123456-privatekey.p12',
378
+ google_project: 'alpha-bravo-123'
379
+ }
380
+ end
381
+
382
+ it 'chooses a zone in us-central1' do
383
+ expect(driver.send(:select_zone)).to satisfy do |zone|
384
+ %w(us-central1-a us-central1-b us-central2-a).include?(zone)
385
+ end
386
+
387
+ end
388
+ end
389
+ end
390
+
391
+ describe '#wait_for_up_instance' do
392
+ it 'sets the hostname' do
393
+ driver.send(:wait_for_up_instance, server, state)
394
+ # Mock instance gives us a random IP each time:
395
+ expect(state[:hostname]).to match(Resolv::IPv4::Regex)
396
+ end
397
+ end
398
+ end
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Author:: Andrew Leonard (<andy@hurricane-ridge.com>)
4
+ #
5
+ # Copyright (C) 2013-2014, Andrew Leonard
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'rspec'
20
+
21
+ require_relative '../lib/kitchen/driver/gce'
metadata ADDED
@@ -0,0 +1,182 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kitchen-google
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Leonard
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fog
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.31.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.31.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: google-api-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ridley
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: 3.0.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-kitchen
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: A Test-Kitchen driver for Google Compute Engine
140
+ email: andy@hurricane-ridge.com
141
+ executables: []
142
+ extensions: []
143
+ extra_rdoc_files: []
144
+ files:
145
+ - .gitignore
146
+ - .rubocop.yml
147
+ - .rubocop_todo.yml
148
+ - .travis.yml
149
+ - CHANGELOG.md
150
+ - Gemfile
151
+ - LICENSE
152
+ - README.md
153
+ - Rakefile
154
+ - kitchen-google.gemspec
155
+ - lib/kitchen/driver/gce.rb
156
+ - spec/kitchen/driver/gce_spec.rb
157
+ - spec/spec_helper.rb
158
+ homepage: https://github.com/test-kitchen/kitchen-google
159
+ licenses:
160
+ - Apache 2.0
161
+ metadata: {}
162
+ post_install_message:
163
+ rdoc_options: []
164
+ require_paths:
165
+ - lib
166
+ required_ruby_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - '>='
169
+ - !ruby/object:Gem::Version
170
+ version: '1.9'
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - '>='
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ requirements: []
177
+ rubyforge_project:
178
+ rubygems_version: 2.0.14
179
+ signing_key:
180
+ specification_version: 4
181
+ summary: Kitchen::Driver::Gce
182
+ test_files: []