foreman_google 3.0.8 → 3.0.9

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_google/locale/cs_CZ/foreman_google.js +7 -1
  3. data/app/assets/javascripts/foreman_google/locale/de/foreman_google.js +7 -1
  4. data/app/assets/javascripts/foreman_google/locale/el/foreman_google.js +7 -1
  5. data/app/assets/javascripts/foreman_google/locale/en/foreman_google.js +7 -1
  6. data/app/assets/javascripts/foreman_google/locale/en_GB/foreman_google.js +7 -1
  7. data/app/assets/javascripts/foreman_google/locale/es/foreman_google.js +7 -1
  8. data/app/assets/javascripts/foreman_google/locale/fr/foreman_google.js +8 -2
  9. data/app/assets/javascripts/foreman_google/locale/it/foreman_google.js +7 -1
  10. data/app/assets/javascripts/foreman_google/locale/ja/foreman_google.js +8 -2
  11. data/app/assets/javascripts/foreman_google/locale/ka/foreman_google.js +7 -1
  12. data/app/assets/javascripts/foreman_google/locale/ko/foreman_google.js +8 -2
  13. data/app/assets/javascripts/foreman_google/locale/pl/foreman_google.js +7 -1
  14. data/app/assets/javascripts/foreman_google/locale/pt_BR/foreman_google.js +7 -1
  15. data/app/assets/javascripts/foreman_google/locale/ru/foreman_google.js +7 -1
  16. data/app/assets/javascripts/foreman_google/locale/sv_SE/foreman_google.js +7 -1
  17. data/app/assets/javascripts/foreman_google/locale/zh_CN/foreman_google.js +8 -2
  18. data/app/assets/javascripts/foreman_google/locale/zh_TW/foreman_google.js +7 -1
  19. data/app/lib/google_cloud_compute/compute_attributes.rb +3 -1
  20. data/app/models/foreman_google/google_compute.rb +2 -2
  21. data/lib/foreman_google/version.rb +1 -1
  22. data/locale/cs_CZ/LC_MESSAGES/foreman_google.mo +0 -0
  23. data/locale/cs_CZ/foreman_google.po +7 -1
  24. data/locale/de/LC_MESSAGES/foreman_google.mo +0 -0
  25. data/locale/de/foreman_google.po +7 -1
  26. data/locale/el/LC_MESSAGES/foreman_google.mo +0 -0
  27. data/locale/el/foreman_google.po +7 -1
  28. data/locale/en/LC_MESSAGES/foreman_google.mo +0 -0
  29. data/locale/en/foreman_google.po +7 -1
  30. data/locale/en_GB/LC_MESSAGES/foreman_google.mo +0 -0
  31. data/locale/en_GB/foreman_google.po +7 -1
  32. data/locale/es/LC_MESSAGES/foreman_google.mo +0 -0
  33. data/locale/es/foreman_google.po +7 -1
  34. data/locale/foreman_google.pot +12 -4
  35. data/locale/fr/LC_MESSAGES/foreman_google.mo +0 -0
  36. data/locale/fr/foreman_google.po +9 -3
  37. data/locale/it/LC_MESSAGES/foreman_google.mo +0 -0
  38. data/locale/it/foreman_google.po +7 -1
  39. data/locale/ja/LC_MESSAGES/foreman_google.mo +0 -0
  40. data/locale/ja/foreman_google.po +9 -3
  41. data/locale/ka/LC_MESSAGES/foreman_google.mo +0 -0
  42. data/locale/ka/foreman_google.po +7 -1
  43. data/locale/ko/LC_MESSAGES/foreman_google.mo +0 -0
  44. data/locale/ko/foreman_google.po +9 -3
  45. data/locale/pl/LC_MESSAGES/foreman_google.mo +0 -0
  46. data/locale/pl/foreman_google.po +7 -1
  47. data/locale/pt_BR/LC_MESSAGES/foreman_google.mo +0 -0
  48. data/locale/pt_BR/foreman_google.po +7 -1
  49. data/locale/ru/LC_MESSAGES/foreman_google.mo +0 -0
  50. data/locale/ru/foreman_google.po +7 -1
  51. data/locale/sv_SE/LC_MESSAGES/foreman_google.mo +0 -0
  52. data/locale/sv_SE/foreman_google.po +7 -1
  53. data/locale/zh_CN/LC_MESSAGES/foreman_google.mo +0 -0
  54. data/locale/zh_CN/foreman_google.po +9 -3
  55. data/locale/zh_TW/LC_MESSAGES/foreman_google.mo +0 -0
  56. data/locale/zh_TW/foreman_google.po +7 -1
  57. data/test/controllers/foreman_google/api/v2/compute_resources_extensions_test.rb +51 -0
  58. data/test/models/concerns/foreman_google/host_managed_extensions_test.rb +46 -0
  59. data/test/models/foreman_google/gce_test.rb +275 -3
  60. data/test/models/foreman_google/google_compute_test.rb +193 -4
  61. data/test/unit/foreman_google/google_compute_adapter_test.rb +59 -7
  62. data/test/unit/google_cloud_compute/compute_attributes_test.rb +235 -0
  63. data/test/unit/google_cloud_compute/compute_collection_test.rb +78 -0
  64. data/test/unit/google_extensions/attached_disk_test.rb +35 -0
  65. metadata +10 -2
@@ -10,7 +10,7 @@
10
10
  #
11
11
  msgid ""
12
12
  msgstr ""
13
- "Project-Id-Version: foreman_google 3.0.6\n"
13
+ "Project-Id-Version: foreman_google 3.1.0\n"
14
14
  "Report-Msgid-Bugs-To: \n"
15
15
  "PO-Revision-Date: 2022-08-01 12:51+0000\n"
16
16
  "Last-Translator: 0868a4d1af5275b3f70b0a6dac4c99a4, 2022\n"
@@ -99,3 +99,9 @@ msgstr ""
99
99
 
100
100
  msgid "console is not available at this time because the instance is powered off"
101
101
  msgstr ""
102
+
103
+ msgid "unable to start machine that is not persisted"
104
+ msgstr ""
105
+
106
+ msgid "unable to stop machine that is not persisted"
107
+ msgstr ""
@@ -8,14 +8,14 @@
8
8
  # Bryan Kearney <bryan.kearney@gmail.com>, 2022
9
9
  # Amit Upadhye <aupadhye@redhat.com>, 2022
10
10
  # Ewoud Kohl van Wijngaarden <ewoud+transifex@kohlvanwijngaarden.nl>, 2024
11
+ # Ondřej Gajdušek, 2026
11
12
  #
12
13
  msgid ""
13
14
  msgstr ""
14
- "Project-Id-Version: foreman_google 3.0.6\n"
15
+ "Project-Id-Version: foreman_google 3.1.0\n"
15
16
  "Report-Msgid-Bugs-To: \n"
16
17
  "PO-Revision-Date: 2022-08-01 12:51+0000\n"
17
- "Last-Translator: Ewoud Kohl van Wijngaarden <ewoud+transifex@kohlvanwijngaarde"
18
- "n.nl>, 2024\n"
18
+ "Last-Translator: Ondřej Gajdušek, 2026\n"
19
19
  "Language-Team: Japanese (https://app.transifex.com/foreman/teams/114/ja/)\n"
20
20
  "MIME-Version: 1.0\n"
21
21
  "Content-Type: text/plain; charset=UTF-8\n"
@@ -100,3 +100,9 @@ msgstr "ゾーン、GCE 専用"
100
100
 
101
101
  msgid "console is not available at this time because the instance is powered off"
102
102
  msgstr "インスタンスの電源がオフであるため、現時点ではコンソールは使用できません"
103
+
104
+ msgid "unable to start machine that is not persisted"
105
+ msgstr "永続化されていないマシンを起動できません"
106
+
107
+ msgid "unable to stop machine that is not persisted"
108
+ msgstr "永続化されていないマシンを停止できません"
@@ -8,7 +8,7 @@
8
8
  #
9
9
  msgid ""
10
10
  msgstr ""
11
- "Project-Id-Version: foreman_google 3.0.6\n"
11
+ "Project-Id-Version: foreman_google 3.1.0\n"
12
12
  "Report-Msgid-Bugs-To: \n"
13
13
  "PO-Revision-Date: 2022-08-01 12:51+0000\n"
14
14
  "Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>, 2023\n"
@@ -96,3 +96,9 @@ msgstr "ზონა, მხოლოდ GCE-სთვის"
96
96
 
97
97
  msgid "console is not available at this time because the instance is powered off"
98
98
  msgstr "კონსოლი ამჟამად მიუწვდომელია. გაშვებული ასლი გამორთულია"
99
+
100
+ msgid "unable to start machine that is not persisted"
101
+ msgstr ""
102
+
103
+ msgid "unable to stop machine that is not persisted"
104
+ msgstr ""
@@ -7,14 +7,14 @@
7
7
  # Bryan Kearney <bryan.kearney@gmail.com>, 2022
8
8
  # 0868a4d1af5275b3f70b0a6dac4c99a4, 2022
9
9
  # Ewoud Kohl van Wijngaarden <ewoud+transifex@kohlvanwijngaarden.nl>, 2024
10
+ # Ondřej Gajdušek, 2026
10
11
  #
11
12
  msgid ""
12
13
  msgstr ""
13
- "Project-Id-Version: foreman_google 3.0.6\n"
14
+ "Project-Id-Version: foreman_google 3.1.0\n"
14
15
  "Report-Msgid-Bugs-To: \n"
15
16
  "PO-Revision-Date: 2022-08-01 12:51+0000\n"
16
- "Last-Translator: Ewoud Kohl van Wijngaarden <ewoud+transifex@kohlvanwijngaarde"
17
- "n.nl>, 2024\n"
17
+ "Last-Translator: Ondřej Gajdušek, 2026\n"
18
18
  "Language-Team: Korean (https://app.transifex.com/foreman/teams/114/ko/)\n"
19
19
  "MIME-Version: 1.0\n"
20
20
  "Content-Type: text/plain; charset=UTF-8\n"
@@ -99,3 +99,9 @@ msgstr "Zone, GCE 전용"
99
99
 
100
100
  msgid "console is not available at this time because the instance is powered off"
101
101
  msgstr "인스턴스 전원이 꺼져 있으므로 현재 콘솔을 사용할 수 없습니다."
102
+
103
+ msgid "unable to start machine that is not persisted"
104
+ msgstr "영구 저장되지 않은 머신은 시작할 수 없습니다."
105
+
106
+ msgid "unable to stop machine that is not persisted"
107
+ msgstr "영구 저장되지 않은 머신은 중지할 수 없습니다."
@@ -9,7 +9,7 @@
9
9
  #
10
10
  msgid ""
11
11
  msgstr ""
12
- "Project-Id-Version: foreman_google 3.0.6\n"
12
+ "Project-Id-Version: foreman_google 3.1.0\n"
13
13
  "Report-Msgid-Bugs-To: \n"
14
14
  "PO-Revision-Date: 2022-08-01 12:51+0000\n"
15
15
  "Last-Translator: Michał Foryt <michal.foryt@gmail.com>, 2022\n"
@@ -99,3 +99,9 @@ msgstr ""
99
99
 
100
100
  msgid "console is not available at this time because the instance is powered off"
101
101
  msgstr ""
102
+
103
+ msgid "unable to start machine that is not persisted"
104
+ msgstr ""
105
+
106
+ msgid "unable to stop machine that is not persisted"
107
+ msgstr ""
@@ -12,7 +12,7 @@
12
12
  #
13
13
  msgid ""
14
14
  msgstr ""
15
- "Project-Id-Version: foreman_google 3.0.6\n"
15
+ "Project-Id-Version: foreman_google 3.1.0\n"
16
16
  "Report-Msgid-Bugs-To: \n"
17
17
  "PO-Revision-Date: 2022-08-01 12:51+0000\n"
18
18
  "Last-Translator: Luiz Henrique Vasconcelos <luizvasconceloss@yahoo.com.br>, 20"
@@ -103,3 +103,9 @@ msgstr ""
103
103
 
104
104
  msgid "console is not available at this time because the instance is powered off"
105
105
  msgstr "console não está disponível neste momento porque a instância está desligada"
106
+
107
+ msgid "unable to start machine that is not persisted"
108
+ msgstr ""
109
+
110
+ msgid "unable to stop machine that is not persisted"
111
+ msgstr ""
@@ -12,7 +12,7 @@
12
12
  #
13
13
  msgid ""
14
14
  msgstr ""
15
- "Project-Id-Version: foreman_google 3.0.6\n"
15
+ "Project-Id-Version: foreman_google 3.1.0\n"
16
16
  "Report-Msgid-Bugs-To: \n"
17
17
  "PO-Revision-Date: 2022-08-01 12:51+0000\n"
18
18
  "Last-Translator: 0868a4d1af5275b3f70b0a6dac4c99a4, 2022\n"
@@ -102,3 +102,9 @@ msgstr ""
102
102
 
103
103
  msgid "console is not available at this time because the instance is powered off"
104
104
  msgstr ""
105
+
106
+ msgid "unable to start machine that is not persisted"
107
+ msgstr ""
108
+
109
+ msgid "unable to stop machine that is not persisted"
110
+ msgstr ""
@@ -10,7 +10,7 @@
10
10
  #
11
11
  msgid ""
12
12
  msgstr ""
13
- "Project-Id-Version: foreman_google 3.0.6\n"
13
+ "Project-Id-Version: foreman_google 3.1.0\n"
14
14
  "Report-Msgid-Bugs-To: \n"
15
15
  "PO-Revision-Date: 2022-08-01 12:51+0000\n"
16
16
  "Last-Translator: johnny.westerlund <johnny.westerlund@gmail.com>, 2022\n"
@@ -99,3 +99,9 @@ msgstr ""
99
99
 
100
100
  msgid "console is not available at this time because the instance is powered off"
101
101
  msgstr ""
102
+
103
+ msgid "unable to start machine that is not persisted"
104
+ msgstr ""
105
+
106
+ msgid "unable to stop machine that is not persisted"
107
+ msgstr ""
@@ -9,14 +9,14 @@
9
9
  # tim123, 2022
10
10
  # Amit Upadhye <aupadhye@redhat.com>, 2022
11
11
  # Ewoud Kohl van Wijngaarden <ewoud+transifex@kohlvanwijngaarden.nl>, 2024
12
+ # Ondřej Gajdušek, 2026
12
13
  #
13
14
  msgid ""
14
15
  msgstr ""
15
- "Project-Id-Version: foreman_google 3.0.6\n"
16
+ "Project-Id-Version: foreman_google 3.1.0\n"
16
17
  "Report-Msgid-Bugs-To: \n"
17
18
  "PO-Revision-Date: 2022-08-01 12:51+0000\n"
18
- "Last-Translator: Ewoud Kohl van Wijngaarden <ewoud+transifex@kohlvanwijngaarde"
19
- "n.nl>, 2024\n"
19
+ "Last-Translator: Ondřej Gajdušek, 2026\n"
20
20
  "Language-Team: Chinese (China) (https://app.transifex.com/foreman/teams/114/zh"
21
21
  "_CN/)\n"
22
22
  "MIME-Version: 1.0\n"
@@ -102,3 +102,9 @@ msgstr "Zone,仅限 GCE"
102
102
 
103
103
  msgid "console is not available at this time because the instance is powered off"
104
104
  msgstr "控制台目前不可用,因为实例已关闭"
105
+
106
+ msgid "unable to start machine that is not persisted"
107
+ msgstr "无法启动没有持久化的机器"
108
+
109
+ msgid "unable to stop machine that is not persisted"
110
+ msgstr "无法停止没有持久化的机器"
@@ -10,7 +10,7 @@
10
10
  #
11
11
  msgid ""
12
12
  msgstr ""
13
- "Project-Id-Version: foreman_google 3.0.6\n"
13
+ "Project-Id-Version: foreman_google 3.1.0\n"
14
14
  "Report-Msgid-Bugs-To: \n"
15
15
  "PO-Revision-Date: 2022-08-01 12:51+0000\n"
16
16
  "Last-Translator: 0868a4d1af5275b3f70b0a6dac4c99a4, 2022\n"
@@ -99,3 +99,9 @@ msgstr ""
99
99
 
100
100
  msgid "console is not available at this time because the instance is powered off"
101
101
  msgstr ""
102
+
103
+ msgid "unable to start machine that is not persisted"
104
+ msgstr ""
105
+
106
+ msgid "unable to stop machine that is not persisted"
107
+ msgstr ""
@@ -0,0 +1,51 @@
1
+ require 'test_google_helper'
2
+
3
+ module ForemanGoogle
4
+ module Api
5
+ module V2
6
+ class ComputeResourcesExtensionsTest < GoogleTestCase
7
+ let(:controller_class) do
8
+ Class.new do
9
+ def self.before_action(*)
10
+ end
11
+
12
+ include ForemanGoogle::Api::V2::ComputeResourcesExtensions
13
+
14
+ attr_accessor :params
15
+
16
+ def compute_resource_params
17
+ params[:compute_resource]
18
+ end
19
+ end
20
+ end
21
+
22
+ describe '#read_key' do
23
+ it 'reads key file content into password for GCE provider' do
24
+ key_content = '{"type": "service_account", "project_id": "test"}'
25
+
26
+ Tempfile.open('gce_key') do |f|
27
+ f.write(key_content)
28
+ f.flush
29
+
30
+ ctrl = controller_class.new
31
+ ctrl.params = { 'compute_resource' => { 'provider' => 'GCE', 'key_path' => f.path } }.with_indifferent_access
32
+ ctrl.send(:read_key)
33
+
34
+ assert_equal key_content, ctrl.params[:compute_resource][:password]
35
+ assert_not ctrl.params[:compute_resource].key?('key_path')
36
+ end
37
+ end
38
+
39
+ it 'skips when provider is not GCE' do
40
+ ctrl = controller_class.new
41
+ ctrl.params = { 'compute_resource' => { 'provider' => 'EC2', 'key_path' => '/nonexistent' } }.with_indifferent_access
42
+ ctrl.send(:read_key)
43
+
44
+ assert_nil ctrl.params[:compute_resource][:password]
45
+ assert_equal '/nonexistent', ctrl.params[:compute_resource]['key_path']
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_google_helper'
2
+
3
+ module ForemanGoogle
4
+ class HostManagedExtensionsTest < GoogleTestCase
5
+ let(:host_class) do
6
+ Class.new do
7
+ include ForemanGoogle::HostManagedExtensions
8
+ attr_accessor :vm
9
+ end
10
+ end
11
+
12
+ describe '#ip_addresses' do
13
+ it 'returns vm ip_addresses when vm exists' do
14
+ vm = mock('GoogleCompute')
15
+ vm.expects(:ip_addresses).returns(['1.2.3.4', '10.0.0.1'])
16
+
17
+ host = host_class.new
18
+ host.vm = vm
19
+ assert_equal ['1.2.3.4', '10.0.0.1'], host.ip_addresses
20
+ end
21
+
22
+ it 'returns empty array when vm is nil' do
23
+ host = host_class.new
24
+ host.vm = nil
25
+ assert_empty host.ip_addresses
26
+ end
27
+ end
28
+
29
+ describe '#vm_ip_address' do
30
+ it 'returns vm public IP when vm exists' do
31
+ vm = mock('GoogleCompute')
32
+ vm.expects(:vm_ip_address).returns('1.2.3.4')
33
+
34
+ host = host_class.new
35
+ host.vm = vm
36
+ assert_equal '1.2.3.4', host.vm_ip_address
37
+ end
38
+
39
+ it 'returns nil when vm is nil' do
40
+ host = host_class.new
41
+ host.vm = nil
42
+ assert_nil host.vm_ip_address
43
+ end
44
+ end
45
+ end
46
+ end
@@ -2,7 +2,7 @@ require 'test_google_helper'
2
2
 
3
3
  module ForemanGoogle
4
4
  class GCETest < GoogleTestCase
5
- subject { ForemanGoogle::GCE.new(zone: 'zone', password: gauth_json) }
5
+ subject { ForemanGoogle::GCE.new(zone: 'us-east1-b', password: gauth_json) }
6
6
  let(:service) { mock('GoogleAdapter') }
7
7
 
8
8
  let(:instance_args) do
@@ -18,6 +18,142 @@ module ForemanGoogle
18
18
  service.stubs(:project_id).returns('project_id')
19
19
  end
20
20
 
21
+ describe '#to_label' do
22
+ it 'includes name, zone, and provider' do
23
+ subject.name = 'my-gce'
24
+ expected = 'my-gce (us-east1-b-Google)'
25
+ assert_equal expected, subject.to_label
26
+ end
27
+ end
28
+
29
+ describe '#capabilities' do
30
+ it 'returns image and new_volume' do
31
+ assert_equal %i[image new_volume], subject.capabilities
32
+ end
33
+ end
34
+
35
+ describe '#provided_attributes' do
36
+ it 'includes ip mapped to vm_ip_address' do
37
+ attrs = subject.provided_attributes
38
+ assert_equal :vm_ip_address, attrs[:ip]
39
+ end
40
+ end
41
+
42
+ describe '#user_data_supported?' do
43
+ it 'returns true' do
44
+ assert subject.user_data_supported?
45
+ end
46
+ end
47
+
48
+ describe '#zone' do
49
+ it 'reads from url attribute' do
50
+ subject.url = 'us-central1-a'
51
+ assert_equal 'us-central1-a', subject.zone
52
+ end
53
+ end
54
+
55
+ describe '#zone=' do
56
+ it 'writes to url attribute' do
57
+ subject.zone = 'europe-west1-b'
58
+ assert_equal 'europe-west1-b', subject.url
59
+ end
60
+ end
61
+
62
+ describe 'validations' do
63
+ it 'is valid with name, zone, and password' do
64
+ subject.name = 'test-gce'
65
+ assert subject.valid?, "Expected subject to be valid, got errors: #{subject.errors.full_messages}"
66
+ end
67
+
68
+ it 'requires password' do
69
+ cr = ForemanGoogle::GCE.new(zone: 'us-east1-b', password: nil)
70
+ assert_not cr.valid?
71
+ assert_includes cr.errors.attribute_names, :password
72
+ end
73
+
74
+ it 'requires zone' do
75
+ cr = ForemanGoogle::GCE.new(zone: nil, password: gauth_json)
76
+ assert_not cr.valid?
77
+ assert_includes cr.errors.attribute_names, :zone
78
+ end
79
+
80
+ it 'requires name' do
81
+ cr = ForemanGoogle::GCE.new(name: nil, zone: 'us-east1-b', password: gauth_json)
82
+ assert_not cr.valid?
83
+ assert_includes cr.errors.attribute_names, :name
84
+ end
85
+ end
86
+
87
+ describe '#zones' do
88
+ it 'returns zone names from client' do
89
+ zones = [OpenStruct.new(name: 'us-east1-b'), OpenStruct.new(name: 'us-west1-a')]
90
+ service.expects(:zones).returns(zones)
91
+ assert_equal %w[us-east1-b us-west1-a], subject.zones
92
+ end
93
+
94
+ it 'is aliased as available_zones' do
95
+ zones = [OpenStruct.new(name: 'us-east1-b')]
96
+ service.expects(:zones).returns(zones)
97
+ assert_equal %w[us-east1-b], subject.available_zones
98
+ end
99
+ end
100
+
101
+ describe '#networks' do
102
+ it 'returns network names from client' do
103
+ networks = [OpenStruct.new(name: 'default'), OpenStruct.new(name: 'custom')]
104
+ service.expects(:networks).returns(networks)
105
+ assert_equal %w[default custom], subject.networks
106
+ end
107
+ end
108
+
109
+ describe '#available_networks' do
110
+ it 'returns full network objects from client' do
111
+ network_objects = [OpenStruct.new(name: 'default')]
112
+ service.expects(:networks).returns(network_objects)
113
+ assert_equal network_objects, subject.available_networks
114
+ end
115
+ end
116
+
117
+ describe '#machine_types' do
118
+ it 'returns machine types for the zone from client' do
119
+ types = [OpenStruct.new(name: 'e2-micro')]
120
+ service.expects(:machine_types).with('us-east1-b').returns(types)
121
+ assert_equal types, subject.machine_types
122
+ end
123
+
124
+ it 'is aliased as available_flavors' do
125
+ types = [OpenStruct.new(name: 'n1-standard-1')]
126
+ service.expects(:machine_types).with('us-east1-b').returns(types)
127
+ assert_equal types, subject.available_flavors
128
+ end
129
+ end
130
+
131
+ describe '#available_images' do
132
+ it 'delegates to client.images with filter' do
133
+ images = [OpenStruct.new(name: 'centos-7')]
134
+ service.expects(:images).with(filter: nil).returns(images)
135
+ assert_equal images, subject.available_images
136
+ end
137
+
138
+ it 'passes custom filter to client' do
139
+ images = [OpenStruct.new(name: 'centos-7')]
140
+ service.expects(:images).with(filter: 'name = "centos"').returns(images)
141
+ assert_equal images, subject.available_images(filter: 'name = "centos"')
142
+ end
143
+ end
144
+
145
+ describe '#filter_for_images' do
146
+ it 'defaults to nil' do
147
+ assert_nil subject.filter_for_images
148
+ end
149
+ end
150
+
151
+ describe '#google_project_id' do
152
+ it 'delegates to client' do
153
+ assert_equal 'project_id', subject.google_project_id
154
+ end
155
+ end
156
+
21
157
  describe '#find_vm_by_uuid' do
22
158
  it 'does query gce' do
23
159
  instance = OpenStruct.new(**instance_args)
@@ -48,11 +184,29 @@ module ForemanGoogle
48
184
  end
49
185
 
50
186
  it 'iteration over the vms array' do
51
- subject.vms.each_with_index { |instance, i| assert instance.name, instances[i].name }
187
+ subject.vms.each_with_index { |instance, i| assert_equal instances[i].name, instance.name }
52
188
  end
53
189
 
54
190
  it 'all method' do
55
- subject.vms.all.each_with_index { |instance, i| assert instance.name, instances[i].name }
191
+ subject.vms.all.each_with_index { |instance, i| assert_equal instances[i].name, instance.name }
192
+ end
193
+ end
194
+
195
+ describe '#new_vm' do
196
+ it 'assigns provided attributes' do
197
+ vm = subject.new_vm(name: 'test-vm', machine_type: 'e2-micro')
198
+ assert_equal 'test-vm', vm.name
199
+ assert_equal 'e2-micro', vm.machine_type
200
+ end
201
+
202
+ it 'converts volumes_attributes nested hash' do
203
+ attrs = {
204
+ 'name' => 'test-vm',
205
+ 'volumes_attributes' => { '0' => { 'size_gb' => '20' } },
206
+ }
207
+ vm = subject.new_vm(attrs)
208
+ assert_equal 1, vm.volumes.size
209
+ assert_equal 20, vm.volumes.first.size_gb
56
210
  end
57
211
  end
58
212
 
@@ -65,5 +219,123 @@ module ForemanGoogle
65
219
  value { subject.create_vm({ image_id: 0 }) }.must_raise(::Foreman::Exception)
66
220
  end
67
221
  end
222
+
223
+ describe '#create_vm success path' do
224
+ let(:os_image) { OpenStruct.new(username: 'gce_user', name: 'centos-7') }
225
+ let(:gce_image) { OpenStruct.new(id: 42, self_link: 'image-link') }
226
+ let(:key_pair_obj) { OpenStruct.new(public: 'ssh-rsa AAAA') }
227
+ let(:vm) { mock('GoogleCompute') }
228
+
229
+ setup do
230
+ service.stubs(:image).returns(gce_image)
231
+ service.stubs(:instance)
232
+ subject.stubs(:images).returns(stub(find_by: os_image))
233
+ subject.stubs(:key_pair).returns(key_pair_obj)
234
+ subject.stubs(:new_vm).returns(vm)
235
+ vm.stubs(:hostname).returns('test-vm')
236
+
237
+ vm.expects(:create_volumes)
238
+ vm.expects(:create_instance)
239
+ vm.expects(:set_disk_auto_delete)
240
+ end
241
+
242
+ it 'creates volumes, instance, and sets auto-delete' do
243
+ result = subject.create_vm({ image_id: 42 })
244
+ assert_kind_of ForemanGoogle::GoogleCompute, result
245
+ end
246
+ end
247
+
248
+ describe '#create_vm rollback on error' do
249
+ let(:os_image) { OpenStruct.new(username: 'gce_user', name: 'centos-7') }
250
+ let(:gce_image) { OpenStruct.new(id: 42, self_link: 'image-link') }
251
+ let(:key_pair_obj) { OpenStruct.new(public: 'ssh-rsa AAAA') }
252
+ let(:vm) { mock('GoogleCompute') }
253
+
254
+ setup do
255
+ subject.stubs(:images).returns(stub(find_by: os_image))
256
+ service.stubs(:image).returns(gce_image)
257
+ subject.stubs(:key_pair).returns(key_pair_obj)
258
+ subject.stubs(:new_vm).returns(vm)
259
+ vm.stubs(:create_volumes).raises(::Google::Cloud::Error.new('quota exceeded'))
260
+
261
+ vm.expects(:destroy_volumes)
262
+ end
263
+
264
+ it 'destroys volumes and raises WrappedException' do
265
+ assert_raises(Foreman::WrappedException) { subject.create_vm({ image_id: 42 }) }
266
+ end
267
+ end
268
+
269
+ describe '#destroy_vm' do
270
+ it 'calls set_disk_auto_delete and delete_instance' do
271
+ service.expects(:set_disk_auto_delete).with('us-east1-b', 'vm-uuid')
272
+ service.expects(:delete_instance).with('us-east1-b', 'vm-uuid')
273
+ subject.destroy_vm('vm-uuid')
274
+ end
275
+
276
+ it 'returns true when VM not found' do
277
+ service.expects(:set_disk_auto_delete).raises(ActiveRecord::RecordNotFound)
278
+ assert subject.destroy_vm('missing-vm')
279
+ end
280
+ end
281
+
282
+ describe '#new_volume' do
283
+ it 'returns an AttachedDisk with 20 GB default' do
284
+ vol = subject.new_volume
285
+ assert_kind_of Google::Cloud::Compute::V1::AttachedDisk, vol
286
+ assert_equal 20, vol.disk_size_gb
287
+ end
288
+
289
+ it 'merges provided attributes' do
290
+ vol = subject.new_volume(device_name: 'boot-disk')
291
+ assert_equal 'boot-disk', vol.device_name
292
+ assert_equal 20, vol.disk_size_gb
293
+ end
294
+ end
295
+
296
+ describe '#console' do
297
+ let(:vm) { mock('GoogleCompute') }
298
+
299
+ setup do
300
+ subject.stubs(:find_vm_by_uuid).returns(vm)
301
+ end
302
+
303
+ it 'returns serial output when VM is ready' do
304
+ vm.stubs(:ready?).returns(true)
305
+ vm.stubs(:serial_port_output).returns('boot log...')
306
+ vm.stubs(:name).returns('test-vm')
307
+
308
+ result = subject.console('test-vm')
309
+ assert_equal 'boot log...', result['output']
310
+ assert_equal 'log', result[:type]
311
+ assert_equal 'test-vm', result[:name]
312
+ assert result['timestamp'].is_a?(Time)
313
+ end
314
+
315
+ it 'raises when VM is not ready' do
316
+ vm.stubs(:ready?).returns(false)
317
+ assert_raises(::Foreman::Exception) { subject.console('test-vm') }
318
+ end
319
+ end
320
+
321
+ describe '#associated_host' do
322
+ it 'calls associate_by with ip addresses' do
323
+ vm = OpenStruct.new(public_ip_address: '1.2.3.4', private_ip_address: '10.0.0.1')
324
+ subject.expects(:associate_by).with('ip', ['1.2.3.4', '10.0.0.1'])
325
+ subject.associated_host(vm)
326
+ end
327
+ end
328
+
329
+ describe '#vm_ready' do
330
+ it 'polls until vm is ready' do
331
+ vm = mock('GoogleCompute')
332
+ vm.stubs(:reload).returns(vm)
333
+ vm.stubs(:ready?).returns(false, true)
334
+ vm.stubs(:wait_for).yields.returns({ duration: 2 })
335
+
336
+ result = subject.vm_ready(vm)
337
+ assert_equal({ duration: 2 }, result)
338
+ end
339
+ end
68
340
  end
69
341
  end