beaker-hcloud 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/dependabot.yml +18 -0
- data/.github/workflows/ci.yml +57 -0
- data/.github/workflows/codeql-analysis.yml +70 -0
- data/.github/workflows/release.yml +32 -0
- data/.gitignore +7 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +20 -0
- data/CHANGELOG.md +37 -0
- data/Gemfile +15 -0
- data/LICENSE +661 -0
- data/README.md +53 -0
- data/Rakefile +26 -0
- data/beaker-hcloud.gemspec +29 -0
- data/lib/beaker/hypervisor/hcloud.rb +95 -0
- data/lib/beaker-hcloud/ssh_data_patches.rb +66 -0
- data/lib/beaker-hcloud/version.rb +5 -0
- data/spec/beaker/hypervisor/hcloud_spec.rb +168 -0
- data/spec/spec_helper.rb +29 -0
- metadata +185 -0
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# beaker-hcloud
|
2
|
+
|
3
|
+
[![License](https://img.shields.io/github/license/voxpupuli/beaker-hcloud.svg)](https://github.com/voxpupuli/beaker-hcloud/blob/master/LICENSE)
|
4
|
+
[![Test](https://github.com/voxpupuli/beaker-hcloud/actions/workflows/test.yml/badge.svg)](https://github.com/voxpupuli/beaker-hcloud/actions/workflows/test.yml)
|
5
|
+
[![Release](https://github.com/voxpupuli/beaker-hcloud/actions/workflows/release.yml/badge.svg)](https://github.com/voxpupuli/beaker-hcloud/actions/workflows/release.yml)
|
6
|
+
[![RubyGem Version](https://img.shields.io/gem/v/beaker-hcloud.svg)](https://rubygems.org/gems/beaker-hcloud)
|
7
|
+
[![RubyGem Downloads](https://img.shields.io/gem/dt/beaker-hcloud.svg)](https://rubygems.org/gems/beaker-hcloud)
|
8
|
+
|
9
|
+
A [beaker](https://github.com/voxpupuli/beaker) extension for provision Hetzner Cloud instances.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Include this gem alongside Beaker in your Gemfile or project.gemspec. E.g.
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
# Gemfile
|
17
|
+
gem 'beaker', '~> 5.0'
|
18
|
+
gem 'beaker-hcloud'
|
19
|
+
|
20
|
+
# project.gemspec
|
21
|
+
s.add_runtime_dependency 'beaker', '~> 5.0'
|
22
|
+
s.add_runtime_dependency 'beaker-hcloud'
|
23
|
+
```
|
24
|
+
|
25
|
+
## Authentication
|
26
|
+
|
27
|
+
You need to create an API token using Hetzner's cloud console. Make
|
28
|
+
sure to create the token in the correct project.
|
29
|
+
|
30
|
+
`beaker-hcloud` expects the token to be in the `BEAKER_HCLOUD_TOKEN`
|
31
|
+
environment variable.
|
32
|
+
|
33
|
+
## Configuration
|
34
|
+
|
35
|
+
Some options can be set to influence how and where server instances
|
36
|
+
are being created:
|
37
|
+
|
38
|
+
|
39
|
+
| configuration option | required | default | description |
|
40
|
+
| -------------------- | -------- | ------- | ----------- |
|
41
|
+
| `image` | true | | The name of one of Hetzner's provided images, e.g. `ubuntu-20.04`, or a custom one, i.e. a snapshot in your account. |
|
42
|
+
| `server_type` | false | `cx11` | Hetzner cloud server type |
|
43
|
+
| `location` | false | `nbg1` | One of Hetzner's datacenter locations |
|
44
|
+
|
45
|
+
# Cleanup
|
46
|
+
|
47
|
+
In cases where the beaker process is killed before finishing, it may leave resources in Hetzner cloud. These will need to be manually deleted.
|
48
|
+
|
49
|
+
Look for servers in your project named exactly as the ones in your beaker host configuration and SSH keys with names beginning with `Beaker-`.
|
50
|
+
|
51
|
+
# Contributing
|
52
|
+
|
53
|
+
Please refer to voxpupuli/beaker's [contributing](https://github.com/voxpupuli/beaker/blob/master/CONTRIBUTING.md) guide.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'voxpupuli/rubocop/rake'
|
7
|
+
rescue LoadError
|
8
|
+
# the voxpupuli-rubocop gem is optional
|
9
|
+
end
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'rubygems'
|
13
|
+
require 'github_changelog_generator/task'
|
14
|
+
|
15
|
+
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
16
|
+
config.header = "# Changelog\n\nAll notable changes to this project will be documented in this file."
|
17
|
+
config.exclude_labels = %w[duplicate question invalid wontfix wont-fix skip-changelog modulesync github_actions]
|
18
|
+
config.user = 'voxpupuli'
|
19
|
+
config.project = 'beaker-hcloud'
|
20
|
+
config.future_release = Gem::Specification.load("#{config.project}.gemspec").version
|
21
|
+
end
|
22
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
23
|
+
end
|
24
|
+
|
25
|
+
RSpec::Core::RakeTask.new(:spec)
|
26
|
+
task default: %i[spec]
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
4
|
+
require 'beaker-hcloud/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'beaker-hcloud'
|
8
|
+
s.version = BeakerHcloud::VERSION
|
9
|
+
s.summary = 'Hetzner Library for beaker acceptance testing framework'
|
10
|
+
s.description = 'Another gem that extends beaker'
|
11
|
+
s.authors = ['Tim Meusel', 'Vox Pupuli']
|
12
|
+
s.email = 'voxpupuli@groups.io'
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.homepage = 'https://github.com/voxpupuli/beaker-hcloud'
|
15
|
+
s.license = 'AGPL-3.0'
|
16
|
+
|
17
|
+
s.required_ruby_version = '>= 2.7'
|
18
|
+
|
19
|
+
# Testing dependencies
|
20
|
+
s.add_development_dependency 'rake', '~> 13.0', '>= 13.0.6'
|
21
|
+
s.add_development_dependency 'rspec', '~> 3.12'
|
22
|
+
s.add_development_dependency 'voxpupuli-rubocop', '~> 2.0.0'
|
23
|
+
|
24
|
+
s.add_runtime_dependency 'bcrypt_pbkdf', '~> 1.0'
|
25
|
+
s.add_runtime_dependency 'beaker', '~> 5.4'
|
26
|
+
s.add_runtime_dependency 'ed25519', '~> 1.2'
|
27
|
+
s.add_runtime_dependency 'hcloud', '>= 1.0.3', '< 2.0.0'
|
28
|
+
s.add_runtime_dependency 'ssh_data', '~> 1.3'
|
29
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hcloud'
|
4
|
+
require 'ed25519'
|
5
|
+
require 'bcrypt_pbkdf'
|
6
|
+
|
7
|
+
require_relative '../../beaker-hcloud/ssh_data_patches'
|
8
|
+
|
9
|
+
module Beaker
|
10
|
+
# beaker extension to manage cloud instances from https://www.hetzner.com/cloud
|
11
|
+
class Hcloud < Beaker::Hypervisor
|
12
|
+
# @param [Host, Array<Host>, String, Symbol] hosts One or more hosts to act upon, or a role (String or Symbol) that identifies one or more hosts.
|
13
|
+
# @param [Hash{Symbol=>String}] options Options to pass on to the hypervisor
|
14
|
+
def initialize(hosts, options) # rubocop:disable Lint/MissingSuper
|
15
|
+
@options = options
|
16
|
+
@logger = options[:logger] || Beaker::Logger.new
|
17
|
+
@hosts = hosts
|
18
|
+
|
19
|
+
raise 'You need to pass a token as BEAKER_HCLOUD_TOKEN environment variable' unless ENV['BEAKER_HCLOUD_TOKEN']
|
20
|
+
|
21
|
+
@client = ::Hcloud::Client.new(token: ENV.fetch('BEAKER_HCLOUD_TOKEN'))
|
22
|
+
end
|
23
|
+
|
24
|
+
def provision
|
25
|
+
@logger.notify 'Provisioning hcloud'
|
26
|
+
create_ssh_key
|
27
|
+
@hosts.each do |host|
|
28
|
+
create_server(host)
|
29
|
+
end
|
30
|
+
@logger.notify 'Done provisioning hcloud'
|
31
|
+
end
|
32
|
+
|
33
|
+
def cleanup
|
34
|
+
@logger.notify 'Cleaning up hcloud'
|
35
|
+
@hosts.each do |host|
|
36
|
+
@logger.debug("Deleting hcloud server #{host.name}")
|
37
|
+
@client.servers.find(host[:hcloud_id]).destroy
|
38
|
+
end
|
39
|
+
@logger.notify 'Deleting hcloud SSH key'
|
40
|
+
@client.ssh_keys.find(@options[:ssh][:hcloud_id]).destroy
|
41
|
+
File.unlink(@key_file.path)
|
42
|
+
@logger.notify 'Done cleaning up hcloud'
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def ssh_key_name
|
48
|
+
safe_hostname = Socket.gethostname.tr('.', '-')
|
49
|
+
[
|
50
|
+
'Beaker',
|
51
|
+
ENV.fetch('USER', nil),
|
52
|
+
safe_hostname,
|
53
|
+
@options[:aws_keyname_modifier],
|
54
|
+
@options[:timestamp].strftime('%F_%H_%M_%S_%N'),
|
55
|
+
].join('-')
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_ssh_key
|
59
|
+
@logger.notify 'Generating SSH keypair'
|
60
|
+
ssh_key = SSHData::PrivateKey::ED25519.generate
|
61
|
+
@key_file = Tempfile.create(ssh_key_name)
|
62
|
+
File.write(@key_file.path, ssh_key.openssh(comment: ssh_key_name))
|
63
|
+
@logger.notify 'Creating hcloud SSH key'
|
64
|
+
hcloud_ssh_key = @client.ssh_keys.create(
|
65
|
+
name: ssh_key_name,
|
66
|
+
public_key: ssh_key.public_key.openssh(comment: ssh_key_name),
|
67
|
+
)
|
68
|
+
@options[:ssh][:hcloud_id] = hcloud_ssh_key.id
|
69
|
+
hcloud_ssh_key
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_server(host)
|
73
|
+
@logger.notify "provisioning #{host.name}"
|
74
|
+
location = host[:location] || 'nbg1'
|
75
|
+
server_type = host[:server_type] || 'cx11'
|
76
|
+
action, server = @client.servers.create(
|
77
|
+
name: host.hostname,
|
78
|
+
location: location,
|
79
|
+
server_type: server_type,
|
80
|
+
image: host[:image],
|
81
|
+
ssh_keys: [ssh_key_name],
|
82
|
+
)
|
83
|
+
while action.status == 'running'
|
84
|
+
sleep 5
|
85
|
+
action = @client.actions.find(action.id)
|
86
|
+
server = @client.servers.find(server.id)
|
87
|
+
end
|
88
|
+
host[:ip] = server.public_net['ipv4']['ip']
|
89
|
+
host[:vmhostname] = server.public_net['ipv4']['dns_ptr']
|
90
|
+
host[:hcloud_id] = server.id
|
91
|
+
host.options[:ssh][:keys] = [@key_file.path]
|
92
|
+
server
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ed25519'
|
4
|
+
require 'ssh_data'
|
5
|
+
|
6
|
+
# Patches for the 'ssh_data' gem to allow serialization of
|
7
|
+
# ed25519 private keys in OpenSSH format.
|
8
|
+
module BeakerHcloud
|
9
|
+
module SSHDataPatches
|
10
|
+
# Add encoding methods for OpenSSH's PEM-like format to
|
11
|
+
# store private keys.
|
12
|
+
module EncodingPatch
|
13
|
+
def encode_pem(data, type)
|
14
|
+
encoded_data = Base64.strict_encode64(data)
|
15
|
+
.scan(/.{1,70}/m)
|
16
|
+
.join("\n")
|
17
|
+
.chomp
|
18
|
+
<<~PEM
|
19
|
+
-----BEGIN #{type}-----
|
20
|
+
#{encoded_data}
|
21
|
+
-----END #{type}-----
|
22
|
+
PEM
|
23
|
+
end
|
24
|
+
|
25
|
+
def encode_openssh_private_key(private_key, comment = '')
|
26
|
+
public_key = private_key.public_key
|
27
|
+
private_key_data = [
|
28
|
+
(SecureRandom.random_bytes(4) * 2),
|
29
|
+
public_key.rfc4253,
|
30
|
+
encode_string(private_key.ed25519_key.seed + public_key.ed25519_key.to_str),
|
31
|
+
encode_string(comment),
|
32
|
+
].join
|
33
|
+
unpadded = private_key_data.bytesize % 8
|
34
|
+
private_key_data << Array(1..(8 - unpadded)).pack('c*') unless unpadded.zero?
|
35
|
+
[
|
36
|
+
::SSHData::Encoding::OPENSSH_PRIVATE_KEY_MAGIC,
|
37
|
+
encode_string('none'),
|
38
|
+
encode_string('none'),
|
39
|
+
encode_string(''),
|
40
|
+
encode_uint32(1),
|
41
|
+
encode_string(public_key.rfc4253),
|
42
|
+
encode_string(private_key_data),
|
43
|
+
].join
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add method to emit OpenSSH-encoded string
|
48
|
+
module Ed25519PrivateKeyPatch
|
49
|
+
def openssh(comment: '')
|
50
|
+
encoded_key = ::SSHData::Encoding.encode_openssh_private_key(
|
51
|
+
self,
|
52
|
+
comment,
|
53
|
+
)
|
54
|
+
::SSHData::Encoding.encode_pem(
|
55
|
+
encoded_key,
|
56
|
+
'OPENSSH PRIVATE KEY',
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if defined?(SSHData)
|
64
|
+
SSHData::Encoding.extend BeakerHcloud::SSHDataPatches::EncodingPatch
|
65
|
+
SSHData::PrivateKey::ED25519.prepend BeakerHcloud::SSHDataPatches::Ed25519PrivateKeyPatch
|
66
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
# rubocop:disable RSpec/MultipleMemoizedHelpers, RSpec/VerifiedDoubles, RSpec/FilePath
|
6
|
+
describe Beaker::Hcloud do
|
7
|
+
let(:logger_double) do
|
8
|
+
double(:logger).as_null_object
|
9
|
+
end
|
10
|
+
let(:options) do
|
11
|
+
opts = Beaker::Options::Presets.new
|
12
|
+
opts.presets
|
13
|
+
.merge(opts.env_vars)
|
14
|
+
.merge({
|
15
|
+
logger: logger_double,
|
16
|
+
timestamp: Time.now,
|
17
|
+
})
|
18
|
+
end
|
19
|
+
let(:host1_hash) do
|
20
|
+
{
|
21
|
+
hypervisor: 'hcloud',
|
22
|
+
image: 'ubuntu-20.04',
|
23
|
+
}
|
24
|
+
end
|
25
|
+
let(:host2_hash) do
|
26
|
+
{
|
27
|
+
hypervisor: 'hcloud',
|
28
|
+
image: 'custom image',
|
29
|
+
location: 'custom location',
|
30
|
+
server_type: 'custom type',
|
31
|
+
}
|
32
|
+
end
|
33
|
+
let(:hosts) do
|
34
|
+
[[1, host1_hash], [2, host2_hash]].map do |number, host_hash|
|
35
|
+
host_hash = Beaker::Options::OptionsHash.new.merge(host_hash)
|
36
|
+
Beaker::Host.create("Server #{number}", host_hash, options)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
let(:server1) do
|
40
|
+
double(:server1,
|
41
|
+
id: 1,
|
42
|
+
public_net: {
|
43
|
+
'ipv4' => {
|
44
|
+
'ip' => '192.168.0.1',
|
45
|
+
'dns_ptr' => 'server1.example.com',
|
46
|
+
},
|
47
|
+
},
|
48
|
+
destroy: true)
|
49
|
+
end
|
50
|
+
let(:server2) do
|
51
|
+
double(:server2,
|
52
|
+
id: 2,
|
53
|
+
public_net: {
|
54
|
+
'ipv4' => {
|
55
|
+
'ip' => '192.168.0.2',
|
56
|
+
'dns_ptr' => 'server2.example.com',
|
57
|
+
},
|
58
|
+
},
|
59
|
+
destroy: true)
|
60
|
+
end
|
61
|
+
let(:action_double) do
|
62
|
+
double(:action, status: 'success')
|
63
|
+
end
|
64
|
+
let(:actions_double) do
|
65
|
+
double(:actions, find: action_double)
|
66
|
+
end
|
67
|
+
let(:servers_double) do
|
68
|
+
servers_double = double(:servers)
|
69
|
+
allow(servers_double).to receive(:create)
|
70
|
+
.and_return([action_double, server1], [action_double, server2])
|
71
|
+
allow(servers_double).to receive(:find)
|
72
|
+
.and_return(server1, server2)
|
73
|
+
servers_double
|
74
|
+
end
|
75
|
+
let(:key_double) do
|
76
|
+
double(:key, id: 23, destroy: true)
|
77
|
+
end
|
78
|
+
let(:ssh_keys_double) do
|
79
|
+
double(:ssh_keys, create: key_double, find: key_double)
|
80
|
+
end
|
81
|
+
let(:hcloud_client) do
|
82
|
+
double(:hcloud_client,
|
83
|
+
actions: actions_double,
|
84
|
+
servers: servers_double,
|
85
|
+
ssh_keys: ssh_keys_double)
|
86
|
+
end
|
87
|
+
let(:hcloud) do
|
88
|
+
described_class.new(hosts, options)
|
89
|
+
end
|
90
|
+
|
91
|
+
before do
|
92
|
+
ENV['BEAKER_HCLOUD_TOKEN'] = 'abc'
|
93
|
+
allow(Hcloud::Client).to receive(:new).and_return(hcloud_client)
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#provision', :aggregate_failures do
|
97
|
+
subject(:provision) { hcloud.provision }
|
98
|
+
|
99
|
+
before { provision }
|
100
|
+
|
101
|
+
after { hcloud.cleanup }
|
102
|
+
|
103
|
+
it 'uploads an ssh key using the hcloud client' do
|
104
|
+
expect(ssh_keys_double).to have_received(:create)
|
105
|
+
end
|
106
|
+
|
107
|
+
# rubocop:disable RSpec/ExampleLength
|
108
|
+
it 'creates one server for each host via the hcloud client' do
|
109
|
+
expect(servers_double).to have_received(:create)
|
110
|
+
.with(hash_including({
|
111
|
+
name: 'Server 1',
|
112
|
+
location: 'nbg1',
|
113
|
+
server_type: 'cx11',
|
114
|
+
image: 'ubuntu-20.04',
|
115
|
+
}))
|
116
|
+
expect(servers_double).to have_received(:create)
|
117
|
+
.with(hash_including({
|
118
|
+
name: 'Server 2',
|
119
|
+
location: 'custom location',
|
120
|
+
server_type: 'custom type',
|
121
|
+
image: 'custom image',
|
122
|
+
}))
|
123
|
+
end
|
124
|
+
# rubocop:enable RSpec/ExampleLength
|
125
|
+
|
126
|
+
it "saves ip and dns name to the host's settings" do
|
127
|
+
host1, host2 = hosts
|
128
|
+
expect(host1[:ip]).to eq '192.168.0.1'
|
129
|
+
expect(host1[:vmhostname]).to eq 'server1.example.com'
|
130
|
+
expect(host2[:ip]).to eq '192.168.0.2'
|
131
|
+
expect(host2[:vmhostname]).to eq 'server2.example.com'
|
132
|
+
end
|
133
|
+
|
134
|
+
it "saves hcloud's server id with the host's settings" do
|
135
|
+
host1, host2 = hosts
|
136
|
+
expect(host1[:hcloud_id]).to eq 1
|
137
|
+
expect(host2[:hcloud_id]).to eq 2
|
138
|
+
end
|
139
|
+
|
140
|
+
it "saves the path to the temporary ssh key with the host's options" do
|
141
|
+
host1, host2 = hosts
|
142
|
+
expect(host1[:ssh][:keys].size).to eq 1
|
143
|
+
expect(host2[:ssh][:keys].size).to eq 1
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe '#cleanup' do
|
148
|
+
subject(:cleanup) { hcloud.cleanup }
|
149
|
+
|
150
|
+
before do
|
151
|
+
hcloud.provision
|
152
|
+
cleanup
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'destroys first server' do
|
156
|
+
expect(server1).to have_received(:destroy)
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'destroys last server' do
|
160
|
+
expect(server2).to have_received(:destroy)
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'destroys the temporary ssh key' do
|
164
|
+
expect(key_double).to have_received(:destroy)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
# rubocop:enable RSpec/MultipleMemoizedHelpers, RSpec/VerifiedDoubles, RSpec/FilePath
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if ENV['COVERAGE'] == 'yes'
|
4
|
+
require 'simplecov'
|
5
|
+
require 'simplecov-console'
|
6
|
+
require 'codecov'
|
7
|
+
|
8
|
+
SimpleCov.start do
|
9
|
+
track_files 'lib/**/*.rb'
|
10
|
+
|
11
|
+
add_filter '/spec'
|
12
|
+
|
13
|
+
enable_coverage :branch
|
14
|
+
|
15
|
+
# do not track vendored files
|
16
|
+
add_filter '/vendor'
|
17
|
+
add_filter '/.vendor'
|
18
|
+
end
|
19
|
+
|
20
|
+
SimpleCov.formatters = [
|
21
|
+
SimpleCov::Formatter::Console,
|
22
|
+
SimpleCov::Formatter::Codecov,
|
23
|
+
]
|
24
|
+
end
|
25
|
+
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
26
|
+
|
27
|
+
require 'beaker'
|
28
|
+
require 'beaker-hcloud/version'
|
29
|
+
require 'beaker/hypervisor/hcloud'
|
metadata
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: beaker-hcloud
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tim Meusel
|
8
|
+
- Vox Pupuli
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2023-09-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '13.0'
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 13.0.6
|
24
|
+
type: :development
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - "~>"
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '13.0'
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 13.0.6
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rspec
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.12'
|
41
|
+
type: :development
|
42
|
+
prerelease: false
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.12'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: voxpupuli-rubocop
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.0.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.0.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: bcrypt_pbkdf
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
type: :runtime
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.0'
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: beaker
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.4'
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '5.4'
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: ed25519
|
92
|
+
requirement: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.2'
|
97
|
+
type: :runtime
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.2'
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: hcloud
|
106
|
+
requirement: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.0.3
|
111
|
+
- - "<"
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: 2.0.0
|
114
|
+
type: :runtime
|
115
|
+
prerelease: false
|
116
|
+
version_requirements: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 1.0.3
|
121
|
+
- - "<"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 2.0.0
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: ssh_data
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '1.3'
|
131
|
+
type: :runtime
|
132
|
+
prerelease: false
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '1.3'
|
138
|
+
description: Another gem that extends beaker
|
139
|
+
email: voxpupuli@groups.io
|
140
|
+
executables: []
|
141
|
+
extensions: []
|
142
|
+
extra_rdoc_files: []
|
143
|
+
files:
|
144
|
+
- ".github/dependabot.yml"
|
145
|
+
- ".github/workflows/ci.yml"
|
146
|
+
- ".github/workflows/codeql-analysis.yml"
|
147
|
+
- ".github/workflows/release.yml"
|
148
|
+
- ".gitignore"
|
149
|
+
- ".rubocop.yml"
|
150
|
+
- ".rubocop_todo.yml"
|
151
|
+
- CHANGELOG.md
|
152
|
+
- Gemfile
|
153
|
+
- LICENSE
|
154
|
+
- README.md
|
155
|
+
- Rakefile
|
156
|
+
- beaker-hcloud.gemspec
|
157
|
+
- lib/beaker-hcloud/ssh_data_patches.rb
|
158
|
+
- lib/beaker-hcloud/version.rb
|
159
|
+
- lib/beaker/hypervisor/hcloud.rb
|
160
|
+
- spec/beaker/hypervisor/hcloud_spec.rb
|
161
|
+
- spec/spec_helper.rb
|
162
|
+
homepage: https://github.com/voxpupuli/beaker-hcloud
|
163
|
+
licenses:
|
164
|
+
- AGPL-3.0
|
165
|
+
metadata: {}
|
166
|
+
post_install_message:
|
167
|
+
rdoc_options: []
|
168
|
+
require_paths:
|
169
|
+
- lib
|
170
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '2.7'
|
175
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ">="
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
requirements: []
|
181
|
+
rubygems_version: 3.2.33
|
182
|
+
signing_key:
|
183
|
+
specification_version: 4
|
184
|
+
summary: Hetzner Library for beaker acceptance testing framework
|
185
|
+
test_files: []
|