beaker-google 1.2.0 → 1.3.0
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.
- checksums.yaml +4 -4
- data/.github/release.yml +41 -0
- data/.github/workflows/ci.yml +11 -8
- data/.github/workflows/release.yml +91 -17
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +20 -0
- data/CHANGELOG.md +32 -0
- data/Gemfile +8 -0
- data/README.md +2 -2
- data/Rakefile +7 -0
- data/beaker-google.gemspec +9 -6
- data/lib/beaker/hypervisor/google_compute.rb +4 -4
- data/lib/beaker/hypervisor/google_compute_helper.rb +15 -5
- data/lib/beaker-google/version.rb +1 -1
- data/spec/classes/beaker/google_compute_constants_and_defaults_spec.rb +141 -0
- data/spec/classes/beaker/google_compute_helper_api_version_spec.rb +37 -0
- data/spec/classes/beaker/google_compute_helper_configuration_validation_spec.rb +100 -0
- data/spec/classes/beaker/google_compute_helper_constants_and_defaults_spec.rb +66 -0
- data/spec/classes/beaker/google_compute_helper_edge_cases_spec.rb +173 -0
- data/spec/classes/beaker/google_compute_helper_error_handling_spec.rb +105 -0
- data/spec/classes/beaker/google_compute_helper_spec.rb +368 -0
- data/spec/classes/beaker/google_compute_helper_utilities_spec.rb +95 -0
- data/spec/classes/beaker/google_compute_initialization_spec.rb +52 -0
- data/spec/classes/beaker/google_compute_provision_spec.rb +68 -0
- data/spec/classes/beaker/google_compute_spec.rb +95 -0
- data/spec/classes/beaker/google_compute_ssh_key_management_spec.rb +115 -0
- data/spec/classes/beaker/google_spec.rb +68 -0
- data/spec/classes/beaker-google/beaker_google_version_spec.rb +19 -0
- data/spec/classes/beaker_integration_spec.rb +67 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/support/google_compute_shared_setup.rb +138 -0
- data/spec/support/shared_mocks.rb +89 -0
- metadata +59 -15
- data/.github/workflows/codeql-analysis.yml +0 -70
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad1087b2a3feb7c707d5e76d9a7290c1aee3c7b7d70d976f547547332bf759c2
|
|
4
|
+
data.tar.gz: 0545ab3de6ddcf6ff30e5a40185acdeb8c840bd89656af1b8cd257b46e67e0a0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3b0be0f5e35f3810a556687d6fb4724b0e40890f920b8c410fe9d87a57c13a51371156c694cedde8313f0b5263ec087ac90c1eb8aaed8b5ed67682dd827d4028
|
|
7
|
+
data.tar.gz: 8332beb8864b708e07a613f84b06ae82dcce3c505059d7a374af5434a1bf51a0e35b06178b7eafaaf431aa0eb270847c7ed87994e73644faf7256517104d2386
|
data/.github/release.yml
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes
|
|
3
|
+
|
|
4
|
+
changelog:
|
|
5
|
+
exclude:
|
|
6
|
+
labels:
|
|
7
|
+
- duplicate
|
|
8
|
+
- invalid
|
|
9
|
+
- modulesync
|
|
10
|
+
- question
|
|
11
|
+
- skip-changelog
|
|
12
|
+
- wont-fix
|
|
13
|
+
- wontfix
|
|
14
|
+
- github_actions
|
|
15
|
+
|
|
16
|
+
categories:
|
|
17
|
+
- title: Breaking Changes 🛠
|
|
18
|
+
labels:
|
|
19
|
+
- backwards-incompatible
|
|
20
|
+
|
|
21
|
+
- title: New Features 🎉
|
|
22
|
+
labels:
|
|
23
|
+
- enhancement
|
|
24
|
+
|
|
25
|
+
- title: Bug Fixes 🐛
|
|
26
|
+
labels:
|
|
27
|
+
- bug
|
|
28
|
+
- bugfix
|
|
29
|
+
|
|
30
|
+
- title: Documentation Updates 📚
|
|
31
|
+
labels:
|
|
32
|
+
- documentation
|
|
33
|
+
- docs
|
|
34
|
+
|
|
35
|
+
- title: Dependency Updates ⬆️
|
|
36
|
+
labels:
|
|
37
|
+
- dependencies
|
|
38
|
+
|
|
39
|
+
- title: Other Changes
|
|
40
|
+
labels:
|
|
41
|
+
- "*"
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -3,6 +3,9 @@ name: Test
|
|
|
3
3
|
on:
|
|
4
4
|
- pull_request
|
|
5
5
|
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
|
|
6
9
|
env:
|
|
7
10
|
BUNDLE_WITHOUT: release
|
|
8
11
|
|
|
@@ -10,11 +13,11 @@ jobs:
|
|
|
10
13
|
rubocop:
|
|
11
14
|
runs-on: ubuntu-latest
|
|
12
15
|
steps:
|
|
13
|
-
- uses: actions/checkout@
|
|
14
|
-
- name: Install Ruby 3.
|
|
16
|
+
- uses: actions/checkout@v7
|
|
17
|
+
- name: Install Ruby 3.4
|
|
15
18
|
uses: ruby/setup-ruby@v1
|
|
16
19
|
with:
|
|
17
|
-
ruby-version: "3.
|
|
20
|
+
ruby-version: "3.4"
|
|
18
21
|
bundler-cache: true
|
|
19
22
|
- name: Run rubocop
|
|
20
23
|
run: bundle exec rake rubocop
|
|
@@ -27,14 +30,15 @@ jobs:
|
|
|
27
30
|
- ruby: "2.7"
|
|
28
31
|
- ruby: "3.0"
|
|
29
32
|
- ruby: "3.1"
|
|
30
|
-
coverage: "yes"
|
|
31
33
|
- ruby: "3.2"
|
|
32
34
|
- ruby: "3.3"
|
|
35
|
+
- ruby: "3.4"
|
|
36
|
+
coverage: "yes"
|
|
33
37
|
env:
|
|
34
38
|
COVERAGE: ${{ matrix.coverage }}
|
|
35
39
|
name: Ruby ${{ matrix.ruby }}
|
|
36
40
|
steps:
|
|
37
|
-
- uses: actions/checkout@
|
|
41
|
+
- uses: actions/checkout@v7
|
|
38
42
|
- name: Install Ruby ${{ matrix.ruby }}
|
|
39
43
|
uses: ruby/setup-ruby@v1
|
|
40
44
|
with:
|
|
@@ -42,9 +46,8 @@ jobs:
|
|
|
42
46
|
bundler-cache: true
|
|
43
47
|
- name: Verify gem builds
|
|
44
48
|
run: gem build --strict --verbose *.gemspec
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
# run: bundle exec rake
|
|
49
|
+
- name: Run spec tests
|
|
50
|
+
run: bundle exec rake
|
|
48
51
|
|
|
49
52
|
tests:
|
|
50
53
|
needs:
|
|
@@ -1,32 +1,106 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
name: Gem Release
|
|
2
3
|
|
|
3
4
|
on:
|
|
4
5
|
push:
|
|
5
6
|
tags:
|
|
6
7
|
- '*'
|
|
7
8
|
|
|
9
|
+
permissions: {}
|
|
10
|
+
|
|
8
11
|
jobs:
|
|
9
|
-
release:
|
|
10
|
-
|
|
12
|
+
build-release:
|
|
13
|
+
# Prevent releases from forked repositories
|
|
11
14
|
if: github.repository_owner == 'voxpupuli'
|
|
15
|
+
name: Build the gem
|
|
16
|
+
runs-on: ubuntu-24.04
|
|
12
17
|
steps:
|
|
13
|
-
- uses: actions/checkout@
|
|
14
|
-
- name: Install Ruby
|
|
18
|
+
- uses: actions/checkout@v7
|
|
19
|
+
- name: Install Ruby
|
|
15
20
|
uses: ruby/setup-ruby@v1
|
|
16
21
|
with:
|
|
17
|
-
ruby-version: '
|
|
18
|
-
env:
|
|
19
|
-
BUNDLE_WITHOUT: release
|
|
22
|
+
ruby-version: 'ruby'
|
|
20
23
|
- name: Build gem
|
|
21
|
-
|
|
24
|
+
shell: bash
|
|
25
|
+
run: gem build --verbose *.gemspec
|
|
26
|
+
- name: Upload gem to GitHub cache
|
|
27
|
+
uses: actions/upload-artifact@v7
|
|
28
|
+
with:
|
|
29
|
+
name: gem-artifact
|
|
30
|
+
path: '*.gem'
|
|
31
|
+
retention-days: 1
|
|
32
|
+
compression-level: 0
|
|
33
|
+
|
|
34
|
+
create-github-release:
|
|
35
|
+
needs: build-release
|
|
36
|
+
name: Create GitHub release
|
|
37
|
+
runs-on: ubuntu-24.04
|
|
38
|
+
permissions:
|
|
39
|
+
contents: write # clone repo and create release
|
|
40
|
+
steps:
|
|
41
|
+
- name: Download gem from GitHub cache
|
|
42
|
+
uses: actions/download-artifact@v8
|
|
43
|
+
with:
|
|
44
|
+
name: gem-artifact
|
|
45
|
+
- name: Create Release
|
|
46
|
+
shell: bash
|
|
47
|
+
env:
|
|
48
|
+
GH_TOKEN: ${{ github.token }}
|
|
49
|
+
run: gh release create --repo ${{ github.repository }} ${{ github.ref_name }} --generate-notes *.gem
|
|
50
|
+
|
|
51
|
+
release-to-github:
|
|
52
|
+
needs: build-release
|
|
53
|
+
name: Release to GitHub
|
|
54
|
+
runs-on: ubuntu-24.04
|
|
55
|
+
permissions:
|
|
56
|
+
packages: write # publish to rubygems.pkg.github.com
|
|
57
|
+
steps:
|
|
58
|
+
- name: Download gem from GitHub cache
|
|
59
|
+
uses: actions/download-artifact@v8
|
|
60
|
+
with:
|
|
61
|
+
name: gem-artifact
|
|
62
|
+
- name: Publish gem to GitHub packages
|
|
63
|
+
run: gem push --host https://rubygems.pkg.github.com/${{ github.repository_owner }} *.gem
|
|
64
|
+
env:
|
|
65
|
+
GEM_HOST_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
|
66
|
+
|
|
67
|
+
release-to-rubygems:
|
|
68
|
+
needs: build-release
|
|
69
|
+
name: Release gem to rubygems.org
|
|
70
|
+
runs-on: ubuntu-24.04
|
|
71
|
+
environment: release # recommended by rubygems.org
|
|
72
|
+
permissions:
|
|
73
|
+
id-token: write # rubygems.org authentication
|
|
74
|
+
steps:
|
|
75
|
+
- name: Download gem from GitHub cache
|
|
76
|
+
uses: actions/download-artifact@v8
|
|
77
|
+
with:
|
|
78
|
+
name: gem-artifact
|
|
79
|
+
- uses: rubygems/configure-rubygems-credentials@v2.1.0
|
|
22
80
|
- name: Publish gem to rubygems.org
|
|
81
|
+
shell: bash
|
|
23
82
|
run: gem push *.gem
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
83
|
+
|
|
84
|
+
release-verification:
|
|
85
|
+
name: Check that all releases are done
|
|
86
|
+
runs-on: ubuntu-24.04
|
|
87
|
+
permissions:
|
|
88
|
+
contents: read # minimal permissions that we have to grant
|
|
89
|
+
needs:
|
|
90
|
+
- create-github-release
|
|
91
|
+
- release-to-github
|
|
92
|
+
- release-to-rubygems
|
|
93
|
+
steps:
|
|
94
|
+
- name: Download gem from GitHub cache
|
|
95
|
+
uses: actions/download-artifact@v8
|
|
96
|
+
with:
|
|
97
|
+
name: gem-artifact
|
|
98
|
+
- name: Install Ruby
|
|
99
|
+
uses: ruby/setup-ruby@v1
|
|
100
|
+
with:
|
|
101
|
+
ruby-version: 'ruby'
|
|
102
|
+
- name: Wait for release to propagate
|
|
103
|
+
shell: bash
|
|
27
104
|
run: |
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
chmod 0600 ~/.gem/credentials
|
|
31
|
-
- name: Publish gem to GitHub packages
|
|
32
|
-
run: gem push --key github --host https://rubygems.pkg.github.com/voxpupuli *.gem
|
|
105
|
+
gem install rubygems-await
|
|
106
|
+
gem await *.gem
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config --no-auto-gen-timestamp`
|
|
3
|
+
# using RuboCop version 1.75.8.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 1
|
|
10
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
11
|
+
# Configuration parameters: AutoCorrect, CheckForMethodsWithNoSideEffects.
|
|
12
|
+
Lint/Void:
|
|
13
|
+
Exclude:
|
|
14
|
+
- 'lib/beaker/hypervisor/google_compute_helper.rb'
|
|
15
|
+
|
|
16
|
+
# Offense count: 2
|
|
17
|
+
# Configuration parameters: MinSize.
|
|
18
|
+
Performance/CollectionLiteralInLoop:
|
|
19
|
+
Exclude:
|
|
20
|
+
- 'lib/beaker/hypervisor/google_compute_helper.rb'
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.2.0](https://github.com/voxpupuli/beaker-google/tree/1.2.0) (2026-11-03)
|
|
4
|
+
|
|
5
|
+
[Full Changelog](https://github.com/voxpupuli/beaker-google/compare/1.2.0...1.2.0)
|
|
6
|
+
|
|
7
|
+
**Fixed bugs:**
|
|
8
|
+
|
|
9
|
+
- Let a non-empty BEAKER\_gce\_ports replace configured gce\_ports [\#74](https://github.com/voxpupuli/beaker-google/pull/74) ([jaevans](https://github.com/jaevans))
|
|
10
|
+
|
|
11
|
+
**Closed issues:**
|
|
12
|
+
|
|
13
|
+
- Compute calls fail with "Invalid API version '2026-11-01'" since google-apis-compute\_v1 0.157.0 [\#76](https://github.com/voxpupuli/beaker-google/issues/76)
|
|
14
|
+
|
|
15
|
+
**Merged pull requests:**
|
|
16
|
+
|
|
17
|
+
- Pin the Compute API version sent to Compute Engine [\#77](https://github.com/voxpupuli/beaker-google/pull/77) ([michael-riddle](https://github.com/michael-riddle))
|
|
18
|
+
- Remove CodeQL workflow in favor of default setup [\#75](https://github.com/voxpupuli/beaker-google/pull/75) ([jaevans](https://github.com/jaevans))
|
|
19
|
+
- Bump actions/checkout from 6 to 7 [\#71](https://github.com/voxpupuli/beaker-google/pull/71) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
20
|
+
- Bump rubygems/configure-rubygems-credentials from 1.0.0 to 2.1.0 [\#70](https://github.com/voxpupuli/beaker-google/pull/70) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
21
|
+
- Bump actions/download-artifact from 7 to 8 [\#68](https://github.com/voxpupuli/beaker-google/pull/68) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
22
|
+
- Bump actions/upload-artifact from 6 to 7 [\#67](https://github.com/voxpupuli/beaker-google/pull/67) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
23
|
+
- Bump actions/upload-artifact from 5 to 6 [\#66](https://github.com/voxpupuli/beaker-google/pull/66) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
24
|
+
- Bump actions/download-artifact from 6 to 7 [\#65](https://github.com/voxpupuli/beaker-google/pull/65) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
25
|
+
- Bump actions/checkout from 5 to 6 [\#64](https://github.com/voxpupuli/beaker-google/pull/64) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
26
|
+
- Bump actions/upload-artifact from 4 to 5 [\#63](https://github.com/voxpupuli/beaker-google/pull/63) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
27
|
+
- Bump actions/download-artifact from 5 to 6 [\#62](https://github.com/voxpupuli/beaker-google/pull/62) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
28
|
+
- Bump github/codeql-action from 3 to 4 [\#61](https://github.com/voxpupuli/beaker-google/pull/61) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
29
|
+
- Bump actions/checkout from 4 to 5 [\#60](https://github.com/voxpupuli/beaker-google/pull/60) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
30
|
+
- Update thin requirement from ~\> 1.8, \>= 1.8.2 to \>= 1.8.2, \< 3 [\#59](https://github.com/voxpupuli/beaker-google/pull/59) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
31
|
+
- Add rspec tests [\#57](https://github.com/voxpupuli/beaker-google/pull/57) ([silug](https://github.com/silug))
|
|
32
|
+
- Update voxpupuli-rubocop requirement from ~\> 2.8.0 to ~\> 3.1.0 [\#56](https://github.com/voxpupuli/beaker-google/pull/56) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
33
|
+
- Update voxpupuli-rubocop requirement from ~\> 2.7.0 to ~\> 2.8.0 [\#55](https://github.com/voxpupuli/beaker-google/pull/55) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
34
|
+
|
|
3
35
|
## [1.2.0](https://github.com/voxpupuli/beaker-google/tree/1.2.0) (2024-06-07)
|
|
4
36
|
|
|
5
37
|
[Full Changelog](https://github.com/voxpupuli/beaker-google/compare/1.1.0...1.2.0)
|
data/Gemfile
CHANGED
|
@@ -20,6 +20,14 @@ group :acceptance_testing do
|
|
|
20
20
|
gem 'beaker', *location_for(ENV.fetch('BEAKER_VERSION', '~> 4.0'))
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
# For Ruby 3.4 compatibility
|
|
24
|
+
group :development, :test do
|
|
25
|
+
gem 'benchmark', '~> 0.1'
|
|
26
|
+
gem 'irb', '~> 1.2'
|
|
27
|
+
gem 'mutex_m', '~> 0.1'
|
|
28
|
+
gem 'pstore', '~> 0.1'
|
|
29
|
+
end
|
|
30
|
+
|
|
23
31
|
group :release, optional: true do
|
|
24
32
|
gem 'faraday-retry', '~> 2.1', require: false
|
|
25
33
|
gem 'github_changelog_generator', '~> 1.16.4', require: false
|
data/README.md
CHANGED
|
@@ -46,7 +46,7 @@ The behavior of this library can be configured using either the beaker host conf
|
|
|
46
46
|
| gce_zone | true | | The zone to place compute instances in. The region is calculated from the zone name. |
|
|
47
47
|
| gce_network | false | Default | The name of the network to attach to instances. If the project uses the default network, this and `gce_subnetwork` can be left empty. |
|
|
48
48
|
| gce_subnetwork | false | Default | The name of the subnetwork to attach to the instances network interface. If the Default network is not used, this must be supplied. |
|
|
49
|
-
| gce_ports | false | `[ ]` | A comma separated
|
|
49
|
+
| gce_ports | false | `[ ]` | A list, or a comma separated string, of ports to add to the external firewall. A non-empty `BEAKER_gce_ports` replaces it. Each port is specified in the format `number/protocol` where protocol is one of `tcp`, `udp`, `icmp`, `esp`, `ah`, `ipip`, or `sctp`. **NOTE:** Port `22/tcp` is required for beaker to function and is automatically added to the firewall. |
|
|
50
50
|
| gce_ssh_private_key | false | $HOME/.ssh/google_compute_engine | The file path of the private key to use to connect to instances. If using the key created by the gcloud tool, this can be left blank. |
|
|
51
51
|
| gce_ssh_public_key | false | <gce_ssh_private_key>.pub | The file path of the public key to upload to the instance. If left blank, attempt to use the file at `gce_ssh_private_key` with a `.pub` extension. |
|
|
52
52
|
| gce_machine_type | false | e2-standard-4 | The machine type to use for the instance. If the `BEAKER_gce_machine_type` environment variable is set, it will be used for all hosts. |
|
|
@@ -62,7 +62,7 @@ Each run of beaker creates a pair of firewalls to protect the hosts, and interna
|
|
|
62
62
|
|
|
63
63
|
The internal firewall allows all communication between hosts in the node set, while keeping them isolated from any other Beaker jobs that may be running in the same environment. This firewall is attached to all hosts in the test set, and allows all `tcp`, `udp`, and `icmp` traffic.
|
|
64
64
|
|
|
65
|
-
The external firewall allows outside communication from the internet into the hosts in the test. Due to constrains of the Beaker system, the firewall accepts any source IP (`0.0.0.0/0`) and the SSH port (`22/tcp`) is always allowed. Other ports may be
|
|
65
|
+
The external firewall allows outside communication from the internet into the hosts in the test. Due to constrains of the Beaker system, the firewall accepts any source IP (`0.0.0.0/0`) and the SSH port (`22/tcp`) is always allowed. Other ports may be opened with the `gce_ports` configuration option, or with the `BEAKER_gce_ports` environment variable, which takes the place of `gce_ports` when both are set. Either takes a list, or a comma separated string, of `port/proto` values where `port` is the port number or range, and proto is one of `tcp`, `udp`, `icmp`, `esp`, `ah`, `ipip`, or `sctp`. The port number is only used for `tcp`, `udp`, and `sctp` protocols. Any value, such as `-1` can be used for the other protocols. A non-empty `BEAKER_gce_ports` replaces the configured list rather than adding to it, so it must name every port the run needs besides `22/tcp`.
|
|
66
66
|
|
|
67
67
|
VM Instances created during this process will by default use the automatically-generated instance name as the hostname in the VM OS. Set the `BEAKER_set_gce_hostname` environment variable to `1` to override this behavior and configure the VM OS with the name defined in the nodeset as the hostname.
|
|
68
68
|
|
data/Rakefile
CHANGED
|
@@ -8,6 +8,13 @@ rescue LoadError
|
|
|
8
8
|
# the voxpupuli-rubocop gem is optional
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
12
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Also make spec part of the default task
|
|
16
|
+
task default: [:spec]
|
|
17
|
+
|
|
11
18
|
###########################################################
|
|
12
19
|
#
|
|
13
20
|
# Documentation Tasks
|
data/beaker-google.gemspec
CHANGED
|
@@ -26,16 +26,19 @@ Gem::Specification.new do |s|
|
|
|
26
26
|
s.add_development_dependency 'rspec', '~> 3.0'
|
|
27
27
|
s.add_development_dependency 'rspec-its', '~> 1.3'
|
|
28
28
|
s.add_development_dependency 'simplecov', '~> 0.22.0'
|
|
29
|
-
s.add_development_dependency 'voxpupuli-rubocop', '~>
|
|
29
|
+
s.add_development_dependency 'voxpupuli-rubocop', '~> 3.1.0'
|
|
30
30
|
|
|
31
31
|
# Documentation dependencies
|
|
32
|
-
s.add_development_dependency 'thin', '
|
|
32
|
+
s.add_development_dependency 'thin', '>= 1.8.2', '< 3'
|
|
33
33
|
s.add_development_dependency 'yard', '~> 0.9.36'
|
|
34
34
|
|
|
35
35
|
# Run time dependencies
|
|
36
|
-
s.
|
|
36
|
+
s.add_dependency 'stringify-hash', '~> 0.0.0'
|
|
37
37
|
|
|
38
|
-
s.
|
|
39
|
-
s.
|
|
40
|
-
s.
|
|
38
|
+
s.add_dependency 'google-apis-compute_v1', '~> 0.1'
|
|
39
|
+
s.add_dependency 'google-apis-oslogin_v1', '~> 0.1'
|
|
40
|
+
s.add_dependency 'googleauth', '~> 1.2'
|
|
41
|
+
|
|
42
|
+
s.add_dependency 'logger', '~> 1.4'
|
|
43
|
+
s.add_dependency 'ostruct', '~> 0.2'
|
|
41
44
|
end
|
|
@@ -18,12 +18,12 @@ module Beaker
|
|
|
18
18
|
#
|
|
19
19
|
# @raise [Error] if the private key can not be found
|
|
20
20
|
def find_google_ssh_private_key
|
|
21
|
-
private_keyfile = ENV.fetch('
|
|
21
|
+
private_keyfile = ENV.fetch('BEAKER_gce_ssh_private_key',
|
|
22
22
|
File.join(Dir.home, '.ssh', 'google_compute_engine'))
|
|
23
23
|
if @options[:gce_ssh_private_key] && !File.exist?(private_keyfile)
|
|
24
24
|
private_keyfile = @options[:gce_ssh_private_key]
|
|
25
25
|
end
|
|
26
|
-
raise("Could not find GCE Private SSH key at '#{
|
|
26
|
+
raise("Could not find GCE Private SSH key at '#{private_keyfile}'") unless File.exist?(private_keyfile)
|
|
27
27
|
|
|
28
28
|
@options[:gce_ssh_private_key] = private_keyfile
|
|
29
29
|
private_keyfile
|
|
@@ -37,9 +37,9 @@ module Beaker
|
|
|
37
37
|
# @raise [Error] if the public key can not be found
|
|
38
38
|
def find_google_ssh_public_key
|
|
39
39
|
private_keyfile = find_google_ssh_private_key
|
|
40
|
-
public_keyfile = private_keyfile
|
|
40
|
+
public_keyfile = "#{private_keyfile}.pub"
|
|
41
41
|
public_keyfile = @options[:gce_ssh_public_key] if @options[:gce_ssh_public_key] && !File.exist?(public_keyfile)
|
|
42
|
-
raise("Could not find GCE Public SSH key at '#{
|
|
42
|
+
raise("Could not find GCE Public SSH key at '#{public_keyfile}'") unless File.exist?(public_keyfile)
|
|
43
43
|
|
|
44
44
|
@options[:gce_ssh_public_key] = public_keyfile
|
|
45
45
|
public_keyfile
|
|
@@ -16,6 +16,8 @@ module Beaker
|
|
|
16
16
|
class GoogleComputeError < StandardError
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
attr_reader :options
|
|
20
|
+
|
|
19
21
|
SLEEPWAIT = 5
|
|
20
22
|
|
|
21
23
|
AUTH_URL = 'https://www.googleapis.com/auth/compute'
|
|
@@ -51,9 +53,12 @@ module Beaker
|
|
|
51
53
|
@options[:gce_network] = ENV.fetch('BEAKER_gce_network', DEFAULT_NETWORK_NAME)
|
|
52
54
|
@options[:gce_subnetwork] = ENV.fetch('BEAKER_gce_subnetwork', nil)
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
|
|
56
|
+
# A non-empty BEAKER_gce_ports replaces gce_ports from the hosts file, as
|
|
57
|
+
# BEAKER_gce_project and BEAKER_gce_machine_type replace theirs. Either
|
|
58
|
+
# source may be a comma-separated string or a list.
|
|
59
|
+
env_ports = ENV.fetch('BEAKER_gce_ports', '').strip
|
|
60
|
+
ports = env_ports.empty? ? @options[:gce_ports] : env_ports
|
|
61
|
+
@options[:gce_ports] = Array(ports).flat_map { |entry| entry.to_s.split(',') }.map(&:strip).reject(&:empty?)
|
|
57
62
|
|
|
58
63
|
raise 'You must specify a gce_project for Google Compute Engine instances!' unless @options[:gce_project]
|
|
59
64
|
|
|
@@ -69,6 +74,11 @@ module Beaker
|
|
|
69
74
|
authorizer = authenticate
|
|
70
75
|
@compute = ::Google::Apis::ComputeV1::ComputeService.new
|
|
71
76
|
@compute.authorization = authorizer
|
|
77
|
+
# google-apis-compute_v1 sends a dated X-Goog-Api-Version header on every
|
|
78
|
+
# call, and a release can name a version Compute Engine doesn't accept yet
|
|
79
|
+
# (0.157.0 sends 2026-11-01, which is rejected). Request options are
|
|
80
|
+
# applied after that header, so pin the API version this helper targets.
|
|
81
|
+
@compute.request_options.header = { 'X-Goog-Api-Version' => API_VERSION }
|
|
72
82
|
|
|
73
83
|
# Find the appropriate username to log into created instances
|
|
74
84
|
@cloudoslogin = ::Google::Apis::OsloginV1::CloudOSLoginService.new
|
|
@@ -332,7 +342,7 @@ module Beaker
|
|
|
332
342
|
allowed = []
|
|
333
343
|
allow.each do |port|
|
|
334
344
|
parts = port.split('/', 2)
|
|
335
|
-
allowed << if
|
|
345
|
+
allowed << if %w[tcp udp sctp].include?(parts[1])
|
|
336
346
|
::Google::Apis::ComputeV1::Firewall::Allowed.new(ip_protocol: parts[1], ports: [parts[0]])
|
|
337
347
|
else
|
|
338
348
|
::Google::Apis::ComputeV1::Firewall::Allowed.new(ip_protocol: parts[1])
|
|
@@ -341,7 +351,7 @@ module Beaker
|
|
|
341
351
|
denied = []
|
|
342
352
|
deny.each do |port|
|
|
343
353
|
parts = port.split('/', 2)
|
|
344
|
-
denied << if
|
|
354
|
+
denied << if %w[tcp udp sctp].include?(parts[1])
|
|
345
355
|
::Google::Apis::ComputeV1::Firewall::Denied.new(ip_protocol: parts[1], ports: [parts[0]])
|
|
346
356
|
else
|
|
347
357
|
::Google::Apis::ComputeV1::Firewall::Denied.new(ip_protocol: parts[1])
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Beaker::GoogleCompute do
|
|
6
|
+
context 'when testing constants and defaults' do
|
|
7
|
+
let(:base_options) do
|
|
8
|
+
{
|
|
9
|
+
gce_project: 'test-project',
|
|
10
|
+
gce_zone: 'us-central1-a',
|
|
11
|
+
gce_network: 'default',
|
|
12
|
+
gce_ports: ['80/tcp', '443/tcp'],
|
|
13
|
+
logger: instance_double(Beaker::Logger),
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
before do
|
|
18
|
+
# Mock the authentication and service initialization
|
|
19
|
+
allow(Google::Auth).to receive(:get_application_default).and_return(double)
|
|
20
|
+
|
|
21
|
+
compute_service = double
|
|
22
|
+
allow(compute_service).to receive(:authorization=)
|
|
23
|
+
allow(compute_service).to receive(:request_options).and_return(Google::Apis::RequestOptions.new)
|
|
24
|
+
allow(Google::Apis::ComputeV1::ComputeService).to receive(:new).and_return(compute_service)
|
|
25
|
+
|
|
26
|
+
oslogin_service = double
|
|
27
|
+
allow(oslogin_service).to receive(:authorization=)
|
|
28
|
+
allow(Google::Apis::OsloginV1::CloudOSLoginService).to receive(:new).and_return(oslogin_service)
|
|
29
|
+
|
|
30
|
+
client_options = double
|
|
31
|
+
allow(client_options).to receive(:application_name=)
|
|
32
|
+
allow(client_options).to receive(:application_version=)
|
|
33
|
+
allow(Google::Apis::ClientOptions).to receive(:default).and_return(client_options)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe 'environment variable handling' do
|
|
37
|
+
it 'uses default zone constant when environment variable is not set' do
|
|
38
|
+
# Test that the gem uses the default zone constant when no environment variable is set
|
|
39
|
+
expect(Beaker::GoogleComputeHelper::DEFAULT_ZONE_NAME).to eq('us-central1-a')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'uses default zone from options when initialized' do
|
|
43
|
+
# Test that the helper uses the default zone from options when initialized
|
|
44
|
+
helper = Beaker::GoogleComputeHelper.new(base_options)
|
|
45
|
+
expect(helper.default_zone).to eq('us-central1-a')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'uses default network constant when environment variable is not set' do
|
|
49
|
+
# Test that the gem uses the default network constant when no environment variable is set
|
|
50
|
+
expect(Beaker::GoogleComputeHelper::DEFAULT_NETWORK_NAME).to eq('default')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'uses default network from options when initialized' do
|
|
54
|
+
# Test that the helper uses the default network from options when initialized
|
|
55
|
+
helper = Beaker::GoogleComputeHelper.new(base_options)
|
|
56
|
+
expect(helper.default_network).to eq('default')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'processes port configuration through actual gem logic' do
|
|
60
|
+
# Test that the gem processes port configuration correctly
|
|
61
|
+
helper_with_ports = Beaker::GoogleComputeHelper.new(base_options.merge(gce_ports: ['80/tcp', '443/tcp',
|
|
62
|
+
'22/tcp',]))
|
|
63
|
+
expect(helper_with_ports.options[:gce_ports]).to eq(['80/tcp', '443/tcp', '22/tcp'])
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe 'zone and region utilities' do
|
|
68
|
+
let(:zone_test_cases) do
|
|
69
|
+
{
|
|
70
|
+
'us-central1-a' => 'us-central1',
|
|
71
|
+
'us-west1-b' => 'us-west1',
|
|
72
|
+
'europe-west1-c' => 'europe-west1',
|
|
73
|
+
'asia-east1-a' => 'asia-east1',
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
before do
|
|
78
|
+
allow(ENV).to receive(:fetch).with('BEAKER_gce_network', anything).and_return('default')
|
|
79
|
+
allow(ENV).to receive(:fetch).with('BEAKER_gce_subnetwork', anything).and_return(nil)
|
|
80
|
+
allow(ENV).to receive(:fetch).with('BEAKER_gce_ports', anything).and_return('')
|
|
81
|
+
allow(ENV).to receive(:[]).with('BEAKER_gce_project').and_return(nil)
|
|
82
|
+
allow(ENV).to receive(:[]).with('GOOGLE_APPLICATION_CREDENTIALS').and_return(nil)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'extracts region from zone using default_region method' do
|
|
86
|
+
allow(ENV).to receive(:fetch).with('BEAKER_gce_zone', anything).and_return('us-central1-a')
|
|
87
|
+
|
|
88
|
+
# Test the actual default_region method from the gem
|
|
89
|
+
helper = Beaker::GoogleComputeHelper.new(base_options.merge(gce_zone: 'us-central1-a'))
|
|
90
|
+
expect(helper.default_region).to eq('us-central1')
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'handles different zone formats' do
|
|
94
|
+
zone_test_cases.each do |zone, expected_region|
|
|
95
|
+
allow(ENV).to receive(:fetch).with('BEAKER_gce_zone', anything).and_return(zone)
|
|
96
|
+
helper = Beaker::GoogleComputeHelper.new(base_options.merge(gce_zone: zone))
|
|
97
|
+
expect(helper.default_region).to eq(expected_region)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe 'connection preferences' do
|
|
103
|
+
it 'prefers IP connections' do
|
|
104
|
+
# Test the actual connection_preference method from the gem
|
|
105
|
+
google_compute = described_class.new([], base_options)
|
|
106
|
+
expect(google_compute.connection_preference(nil)).to eq([:ip])
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe 'Windows image detection' do
|
|
111
|
+
it 'uses Windows image project constants' do
|
|
112
|
+
# Test the actual Windows image project constants from the gem
|
|
113
|
+
expect(Beaker::GoogleCompute::WINDOWS_IMAGE_PROJECT).to include('windows-cloud')
|
|
114
|
+
.and include('windows-sql-cloud')
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
private
|
|
119
|
+
|
|
120
|
+
def mock_google_services
|
|
121
|
+
compute = instance_double(Google::Apis::ComputeV1::ComputeService)
|
|
122
|
+
oslogin = instance_double(Google::Apis::OsloginV1::CloudOSLoginService)
|
|
123
|
+
auth = instance_double(Google::Auth::ServiceAccountCredentials)
|
|
124
|
+
client_options = instance_double(Google::Apis::ClientOptions)
|
|
125
|
+
|
|
126
|
+
allow(Google::Apis::ComputeV1::ComputeService).to receive(:new).and_return(compute)
|
|
127
|
+
allow(Google::Apis::OsloginV1::CloudOSLoginService).to receive(:new).and_return(oslogin)
|
|
128
|
+
allow(Google::Auth::ServiceAccountCredentials).to receive(:make_creds).and_return(auth)
|
|
129
|
+
allow(Google::Auth::UserRefreshCredentials).to receive(:make_creds).and_return(auth)
|
|
130
|
+
allow(Google::Auth).to receive(:get_application_default).and_return(auth)
|
|
131
|
+
|
|
132
|
+
allow(compute).to receive(:authorization=)
|
|
133
|
+
allow(compute).to receive(:request_options).and_return(Google::Apis::RequestOptions.new)
|
|
134
|
+
allow(oslogin).to receive(:authorization=)
|
|
135
|
+
|
|
136
|
+
allow(client_options).to receive(:application_name=)
|
|
137
|
+
allow(client_options).to receive(:application_version=)
|
|
138
|
+
allow(Google::Apis::ClientOptions).to receive(:default).and_return(client_options)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
# Uses the real ComputeService, so the request is built by the installed
|
|
6
|
+
# google-apis-compute_v1, including whatever X-Goog-Api-Version it sets.
|
|
7
|
+
RSpec.describe Beaker::GoogleComputeHelper do
|
|
8
|
+
subject(:helper) { described_class.new(options) }
|
|
9
|
+
|
|
10
|
+
let(:options) do
|
|
11
|
+
{
|
|
12
|
+
gce_project: 'test-project',
|
|
13
|
+
gce_zone: 'us-central1-a',
|
|
14
|
+
gce_ports: [],
|
|
15
|
+
logger: instance_double(Beaker::Logger, debug: nil, info: nil, warn: nil, error: nil),
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
before do
|
|
20
|
+
allow(Google::Auth::ServiceAccountCredentials).to receive(:from_env).and_return(nil)
|
|
21
|
+
allow(Google::Auth).to receive(:get_application_default).and_return(nil)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe 'Compute API version' do
|
|
25
|
+
# The request as it is sent: prepare! runs just before execution.
|
|
26
|
+
let(:prepared_command) do
|
|
27
|
+
command = nil
|
|
28
|
+
allow(helper.instance_variable_get(:@compute)).to receive(:execute_or_queue_command) { |cmd| command = cmd }
|
|
29
|
+
helper.get_machine_type
|
|
30
|
+
command.tap(&:prepare!)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'sends the API version the helper targets, not the client library default' do
|
|
34
|
+
expect(prepared_command.header['X-Goog-Api-Version']).to eq(described_class::API_VERSION)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|