train 1.4.4 → 1.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bd7445d39832ea8fdd1ccba4a089153a6352229246b6c7ed8251eb44afd099f
4
- data.tar.gz: e813525dbb9a25e7cf7138d30c704503acd06d96e895c238b0d4453b6fc6323f
3
+ metadata.gz: cecb9bec9682f0acc90154bcdc16a17fbe7c146b30b3be37bbadd774176d7065
4
+ data.tar.gz: fa01c4fde81ed2a58584576a07cb68ad52b3e73926521e6329486352c4dfa14c
5
5
  SHA512:
6
- metadata.gz: d38b05424dbd5431aa31f5a921d724f1e07247d5601a85a61b503a0c73a2194f3694aaddffe39fac89e375825a8f44ed839bd76c0a3e7353f90a593026c97398
7
- data.tar.gz: 814a6345a5f4d3eecc7e9d26d4050831598be0205f2c1a82dbec11678f9776a517bbf7657b3e1182cd72c4bf0192661390afaec1a356831edb1287a256f86f50
6
+ metadata.gz: 49af5ddd1e984052b4b4e3ba9d1f121ece725a29ecbcd672589a21187c19fb5f3d51859806560cfe2835f4f6499574fc5ed21fb5ae4356131297c05663bf0c63
7
+ data.tar.gz: f8e5cf2d0459c8e1b75ee95d91cba4084313f556a8900a0c7b6dbd9536f9602c0fb613f591787cdf02a63a8b8187cf4d8953cbc735a6defde018a01eb8d79e92
@@ -1,22 +1,33 @@
1
- <!-- latest_release 1.4.4 -->
2
- ## [v1.4.4](https://github.com/chef/train/tree/v1.4.4) (2018-05-02)
1
+ <!-- latest_release 1.4.9 -->
2
+ ## [v1.4.9](https://github.com/chef/train/tree/v1.4.9) (2018-05-16)
3
3
 
4
4
  #### Merged Pull Requests
5
- - Split train into a core gem. [#293](https://github.com/chef/train/pull/293) ([miah](https://github.com/miah))
6
- - Enable expeditor release tasks [#294](https://github.com/chef/train/pull/294) ([jquick](https://github.com/jquick))
5
+ - Unpin google-protobuf now that we are building it as a gem [#300](https://github.com/chef/train/pull/300) ([scotthain](https://github.com/scotthain))
7
6
  <!-- latest_release -->
8
7
 
9
- <!-- release_rollup since=1.4.2 -->
10
- ### Changes since 1.4.2 release
8
+ <!-- release_rollup since=1.4.4 -->
9
+ ### Changes since 1.4.4 release
10
+
11
+ #### Bug Fixes
12
+ - Allow nil password and www_form_encoded_password to work together. [#297](https://github.com/chef/train/pull/297) ([marcparadise](https://github.com/marcparadise)) <!-- 1.4.6 -->
11
13
 
12
14
  #### Merged Pull Requests
13
- - Split train into a core gem. [#293](https://github.com/chef/train/pull/293) ([miah](https://github.com/miah)) <!-- 1.4.4 -->
14
- - Enable expeditor release tasks [#294](https://github.com/chef/train/pull/294) ([jquick](https://github.com/jquick)) <!-- 1.4.3 -->
15
+ - Unpin google-protobuf now that we are building it as a gem [#300](https://github.com/chef/train/pull/300) ([scotthain](https://github.com/scotthain)) <!-- 1.4.9 -->
16
+ - Change Cisco IOS transport log level to INFO [#298](https://github.com/chef/train/pull/298) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) <!-- 1.4.8 -->
17
+ - Initial import of transport for GCP. [#283](https://github.com/chef/train/pull/283) ([skpaterson](https://github.com/skpaterson)) <!-- 1.4.7 -->
18
+ - Support encoded passwords in target url [#296](https://github.com/chef/train/pull/296) ([marcparadise](https://github.com/marcparadise)) <!-- 1.4.5 -->
15
19
  <!-- release_rollup -->
16
20
 
17
21
  <!-- latest_stable_release -->
22
+ ## [v1.4.4](https://github.com/chef/train/tree/v1.4.4) (2018-05-02)
23
+
24
+ #### Merged Pull Requests
25
+ - Enable expeditor release tasks [#294](https://github.com/chef/train/pull/294) ([jquick](https://github.com/jquick))
26
+ - Split train into a core gem. [#293](https://github.com/chef/train/pull/293) ([miah](https://github.com/miah))
18
27
  <!-- latest_stable_release -->
19
28
 
29
+
30
+
20
31
  # Change Log
21
32
 
22
33
  ## [1.4.2](https://github.com/chef/train/tree/1.4.2) (2018-04-26)
data/Gemfile CHANGED
@@ -23,7 +23,7 @@ group :test do
23
23
  end
24
24
 
25
25
  group :integration do
26
- gem 'berkshelf', '~> 4.3'
26
+ gem 'berkshelf', '~> 5.2'
27
27
  gem 'test-kitchen', '~> 1.11'
28
28
  gem 'kitchen-vagrant'
29
29
  end
@@ -66,8 +66,13 @@ module Train
66
66
  conf[:host] ||= uri.hostname
67
67
  conf[:port] ||= uri.port
68
68
  conf[:user] ||= uri.user
69
- conf[:password] ||= uri.password
70
69
  conf[:path] ||= uri.path
70
+ conf[:password] ||=
71
+ if conf[:www_form_encoded_password] && !uri.password.nil?
72
+ URI.decode_www_form_component(uri.password)
73
+ else
74
+ uri.password
75
+ end
71
76
  end
72
77
 
73
78
  # ensure path is nil, if its empty; e.g. required to reset defaults for winrm
@@ -10,6 +10,7 @@ module Train::Platforms::Detect::Specifications
10
10
  plat.family('cloud').in_family('api')
11
11
  plat.name('aws').in_family('cloud')
12
12
  plat.name('azure').in_family('cloud')
13
+ plat.name('gcp').in_family('cloud')
13
14
  end
14
15
  end
15
16
  end
@@ -7,6 +7,8 @@ class Train::Transports::SSH
7
7
  def initialize(options)
8
8
  super(options)
9
9
 
10
+ logger.level = Logger::INFO
11
+
10
12
  # Extract options to avoid passing them in to `Net::SSH.start` later
11
13
  @host = options.delete(:host)
12
14
  @user = options.delete(:user)
@@ -0,0 +1,92 @@
1
+ # encoding: utf-8
2
+
3
+ require 'train/plugins'
4
+ require 'google/apis'
5
+ require 'google/apis/cloudresourcemanager_v1'
6
+ require 'google/apis/compute_v1'
7
+ require 'google/apis/storage_v1'
8
+ require 'google/apis/iam_v1'
9
+ require 'googleauth'
10
+
11
+ module Train::Transports
12
+ class Gcp < Train.plugin(1)
13
+ name 'gcp'
14
+
15
+ # GCP will look automatically for the below env var for service accounts etc. :
16
+ option :google_application_credentials, required: false, default: ENV['GOOGLE_APPLICATION_CREDENTIALS']
17
+ # see https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application
18
+ # In the absence of this, the client is expected to have already set up local credentials via:
19
+ # $ gcloud auth application-default login
20
+ # $ gcloud config set project <project-name>
21
+ # GCP projects can have default regions / zones set, see:
22
+ # https://cloud.google.com/compute/docs/regions-zones/changing-default-zone-region
23
+ # can also specify project via env var:
24
+ option :google_cloud_project, required: false, default: ENV['GOOGLE_CLOUD_PROJECT']
25
+
26
+ def connection(_ = nil)
27
+ @connection ||= Connection.new(@options)
28
+ end
29
+
30
+ class Connection < BaseConnection
31
+ def initialize(options)
32
+ super(options)
33
+
34
+ # additional GCP platform metadata
35
+ release = Gem.loaded_specs['google_cloud']
36
+ @platform_details = { release: "google-cloud-v#{release}" }
37
+
38
+ # Initialize the client object cache
39
+ @cache_enabled[:api_call] = true
40
+ @cache[:api_call] = {}
41
+
42
+ connect
43
+ end
44
+
45
+ def platform
46
+ direct_platform('gcp', @platform_details)
47
+ end
48
+
49
+ # Instantiate some named classes for ease of use
50
+ def gcp_compute_client
51
+ gcp_client(Google::Apis::ComputeV1::ComputeService)
52
+ end
53
+
54
+ def gcp_iam_client
55
+ gcp_client(Google::Apis::IamV1::IamService)
56
+ end
57
+
58
+ def gcp_project_client
59
+ gcp_client(Google::Apis::CloudresourcemanagerV1::CloudResourceManagerService)
60
+ end
61
+
62
+ def gcp_storage_client
63
+ gcp_client(Google::Apis::StorageV1::StorageService)
64
+ end
65
+
66
+ # Let's allow for other clients too
67
+ def gcp_client(klass)
68
+ return klass.new unless cache_enabled?(:api_call)
69
+ @cache[:api_call][klass.to_s.to_sym] ||= klass.new
70
+ end
71
+
72
+ def connect
73
+ ENV['GOOGLE_APPLICATION_CREDENTIALS'] = @options[:google_application_credentials] if @options[:google_application_credentials]
74
+ ENV['GOOGLE_CLOUD_PROJECT'] = @options[:google_cloud_project] if @options[:google_cloud_project]
75
+ # GCP initialization
76
+ scopes = ['https://www.googleapis.com/auth/cloud-platform',
77
+ 'https://www.googleapis.com/auth/compute']
78
+ authorization = Google::Auth.get_application_default(scopes)
79
+ Google::Apis::RequestOptions.default.authorization = authorization
80
+ end
81
+
82
+ def uri
83
+ "gcp://#{unique_identifier}"
84
+ end
85
+
86
+ def unique_identifier
87
+ # use auth client_id - same to retrieve for any of the clients but use IAM
88
+ gcp_iam_client.request_options.authorization.client_id
89
+ end
90
+ end
91
+ end
92
+ end
@@ -3,5 +3,5 @@
3
3
  # Author:: Dominik Richter (<dominik.richter@gmail.com>)
4
4
 
5
5
  module Train
6
- VERSION = '1.4.4'.freeze
6
+ VERSION = '1.4.9'.freeze
7
7
  end
@@ -177,6 +177,32 @@ describe Train do
177
177
  res[:target].must_equal org[:target]
178
178
  end
179
179
 
180
+ it 'supports www-form encoded passwords when the option is set' do
181
+ raw_password = '+!@#$%^&*()_-\';:"\\|/?.>,<][}{=`~'
182
+ encoded_password = URI.encode_www_form_component(raw_password)
183
+ org = { target: "mock://username:#{encoded_password}@1.2.3.4:100",
184
+ www_form_encoded_password: true}
185
+ res = Train.target_config(org)
186
+ res[:backend].must_equal 'mock'
187
+ res[:host].must_equal '1.2.3.4'
188
+ res[:user].must_equal 'username'
189
+ res[:password].must_equal raw_password
190
+ res[:port].must_equal 100
191
+ res[:target].must_equal org[:target]
192
+ end
193
+
194
+ it 'ignores www-form-encoded password value when there is no password' do
195
+ org = { target: "mock://username@1.2.3.4:100",
196
+ www_form_encoded_password: true}
197
+ res = Train.target_config(org)
198
+ res[:backend].must_equal 'mock'
199
+ res[:host].must_equal '1.2.3.4'
200
+ res[:user].must_equal 'username'
201
+ res[:password].must_be_nil
202
+ res[:port].must_equal 100
203
+ res[:target].must_equal org[:target]
204
+ end
205
+
180
206
  it 'it raises UserError on invalid URIs' do
181
207
  org = { target: 'mock world' }
182
208
  proc { Train.target_config(org) }.must_raise Train::UserError
@@ -0,0 +1,191 @@
1
+ # encoding: utf-8
2
+
3
+ require 'helper'
4
+
5
+ describe 'gcp transport' do
6
+
7
+ let(:credentials_file) do
8
+ require 'tempfile'
9
+ file = Tempfile.new('application_default_credentials.json')
10
+ info = <<-INFO
11
+ {
12
+ "client_id": "asdfasf-asdfasdf.apps.googleusercontent.com",
13
+ "client_secret": "d-asdfasdf",
14
+ "refresh_token": "1/adsfasdf-lCkju3-yQmjr20xVZonrfkE48L",
15
+ "type": "authorized_user"
16
+ }
17
+ INFO
18
+ file.write(info)
19
+ file.close
20
+ file
21
+ end
22
+
23
+ let(:credentials_file_override) do
24
+ require 'tempfile'
25
+ file = Tempfile.new('application_default_credentials.json')
26
+ info = <<-INFO
27
+ {
28
+ "client_id": "asdfasf-asdfasdf.apps.googleusercontent.com",
29
+ "client_secret": "d-asdfasdf",
30
+ "refresh_token": "1/adsfasdf-lCkju3-yQmjr20xVZonrfkE48L",
31
+ "type": "authorized_user"
32
+ }
33
+ INFO
34
+ file.write(info)
35
+ file.close
36
+ file
37
+ end
38
+
39
+ def transport(options = nil)
40
+ ENV['GOOGLE_APPLICATION_CREDENTIALS'] = credentials_file.path
41
+ ENV['GOOGLE_CLOUD_PROJECT'] = 'test_project'
42
+ # need to require this at here as it captures the envs on load
43
+ require 'train/transports/gcp'
44
+ Train::Transports::Gcp.new(options)
45
+ end
46
+
47
+ let(:connection) { transport.connection }
48
+ let(:options) { connection.instance_variable_get(:@options) }
49
+ let(:cache) { connection.instance_variable_get(:@cache) }
50
+
51
+ describe 'options' do
52
+ it 'defaults to env options' do
53
+ options[:google_application_credentials] = credentials_file.path
54
+ options[:google_cloud_project].must_equal 'test_project'
55
+ end
56
+ end
57
+
58
+ it 'allows for options override' do
59
+ transport = transport(google_application_credentials: credentials_file_override.path, google_cloud_project: "override_project")
60
+ options = transport.connection.instance_variable_get(:@options)
61
+ options[:google_application_credentials].must_equal credentials_file_override.path
62
+ options[:google_cloud_project].must_equal "override_project"
63
+ end
64
+
65
+ describe 'platform' do
66
+ it 'returns platform' do
67
+ platform = connection.platform
68
+ platform.name.must_equal 'gcp'
69
+ platform.family_hierarchy.must_equal ['cloud', 'api']
70
+ end
71
+ end
72
+
73
+ describe 'gcp_client' do
74
+ it 'test gcp_client with caching' do
75
+ client = connection.gcp_client(Object)
76
+ client.is_a?(Object).must_equal true
77
+ cache[:api_call].count.must_equal 1
78
+ end
79
+
80
+ it 'test gcp_client without caching' do
81
+ connection.disable_cache(:api_call)
82
+ client = connection.gcp_client(Object)
83
+ client.is_a?(Object).must_equal true
84
+ cache[:api_call].count.must_equal 0
85
+ end
86
+ end
87
+
88
+
89
+ describe 'gcp_compute_client' do
90
+ it 'test gcp_compute_client with caching' do
91
+ client = connection.gcp_compute_client
92
+ client.is_a?(Google::Apis::ComputeV1::ComputeService).must_equal true
93
+ cache[:api_call].count.must_equal 1
94
+ end
95
+
96
+ it 'test gcp_client without caching' do
97
+ connection.disable_cache(:api_call)
98
+ client = connection.gcp_compute_client
99
+ client.is_a?(Google::Apis::ComputeV1::ComputeService).must_equal true
100
+ cache[:api_call].count.must_equal 0
101
+ end
102
+ end
103
+
104
+ describe 'gcp_iam_client' do
105
+ it 'test gcp_iam_client with caching' do
106
+ client = connection.gcp_iam_client
107
+ client.is_a?(Google::Apis::IamV1::IamService).must_equal true
108
+ cache[:api_call].count.must_equal 1
109
+ end
110
+
111
+ it 'test gcp_iam_client without caching' do
112
+ connection.disable_cache(:api_call)
113
+ client = connection.gcp_iam_client
114
+ client.is_a?(Google::Apis::IamV1::IamService).must_equal true
115
+ cache[:api_call].count.must_equal 0
116
+ end
117
+ end
118
+
119
+ describe 'gcp_project_client' do
120
+ it 'test gcp_project_client with caching' do
121
+ client = connection.gcp_project_client
122
+ client.is_a?(Google::Apis::CloudresourcemanagerV1::CloudResourceManagerService).must_equal true
123
+ cache[:api_call].count.must_equal 1
124
+ end
125
+
126
+ it 'test gcp_project_client without caching' do
127
+ connection.disable_cache(:api_call)
128
+ client = connection.gcp_project_client
129
+ client.is_a?(Google::Apis::CloudresourcemanagerV1::CloudResourceManagerService).must_equal true
130
+ cache[:api_call].count.must_equal 0
131
+ end
132
+ end
133
+
134
+ describe 'gcp_storage_client' do
135
+ it 'test gcp_storage_client with caching' do
136
+ client = connection.gcp_storage_client
137
+ client.is_a?(Google::Apis::StorageV1::StorageService).must_equal true
138
+ cache[:api_call].count.must_equal 1
139
+ end
140
+
141
+ it 'test gcp_storage_client without caching' do
142
+ connection.disable_cache(:api_call)
143
+ client = connection.gcp_storage_client
144
+ client.is_a?(Google::Apis::StorageV1::StorageService).must_equal true
145
+ cache[:api_call].count.must_equal 0
146
+ end
147
+ end
148
+
149
+ # test options override of env vars in connect
150
+ describe 'connect' do
151
+ let(:creds) do
152
+ require 'tempfile'
153
+ file = Tempfile.new('creds')
154
+ info = <<-INFO
155
+ {
156
+ "client_id": "asdfasf-asdfasdf.apps.googleusercontent.com",
157
+ "client_secret": "d-asdfasdf",
158
+ "refresh_token": "1/adsfasdf-lCkju3-yQmjr20xVZonrfkE48L",
159
+ "type": "authorized_user"
160
+ }
161
+ INFO
162
+ file.write(info)
163
+ file.close
164
+ file
165
+ end
166
+ it 'validate gcp connection with credentials' do
167
+ options[:google_application_credentials] = creds.path
168
+ connection.connect
169
+ ENV['GOOGLE_APPLICATION_CREDENTIALS'].must_equal creds.path
170
+ end
171
+ it 'validate gcp connection with project' do
172
+ options[:google_cloud_project] = 'project'
173
+ connection.connect
174
+ ENV['GOOGLE_CLOUD_PROJECT'].must_equal 'project'
175
+ end
176
+ end
177
+
178
+ describe 'unique_identifier' do
179
+ it 'test connection unique identifier' do
180
+ client = connection
181
+ client.unique_identifier.must_equal 'asdfasf-asdfasdf.apps.googleusercontent.com'
182
+ end
183
+ end
184
+
185
+ describe 'uri' do
186
+ it 'test uri' do
187
+ client = connection
188
+ client.uri.must_equal 'gcp://asdfasf-asdfasdf.apps.googleusercontent.com'
189
+ end
190
+ end
191
+ end
@@ -35,6 +35,9 @@ Gem::Specification.new do |spec|
35
35
  spec.add_dependency 'docker-api', '~> 1.26'
36
36
  spec.add_dependency 'aws-sdk', '~> 2'
37
37
  spec.add_dependency 'azure_mgmt_resources', '~> 0.15'
38
+ spec.add_dependency 'google-api-client', '~> 0.19.8'
39
+ spec.add_dependency 'googleauth', '~> 0.6.2'
40
+ spec.add_dependency 'google-cloud', '~> 0.51.1'
38
41
  spec.add_dependency 'inifile'
39
42
 
40
43
  spec.add_development_dependency 'mocha', '~> 1.1'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: train
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.4
4
+ version: 1.4.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-02 00:00:00.000000000 Z
11
+ date: 2018-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -148,6 +148,48 @@ dependencies:
148
148
  - - "~>"
149
149
  - !ruby/object:Gem::Version
150
150
  version: '0.15'
151
+ - !ruby/object:Gem::Dependency
152
+ name: google-api-client
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: 0.19.8
158
+ type: :runtime
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - "~>"
163
+ - !ruby/object:Gem::Version
164
+ version: 0.19.8
165
+ - !ruby/object:Gem::Dependency
166
+ name: googleauth
167
+ requirement: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - "~>"
170
+ - !ruby/object:Gem::Version
171
+ version: 0.6.2
172
+ type: :runtime
173
+ prerelease: false
174
+ version_requirements: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - "~>"
177
+ - !ruby/object:Gem::Version
178
+ version: 0.6.2
179
+ - !ruby/object:Gem::Dependency
180
+ name: google-cloud
181
+ requirement: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - "~>"
184
+ - !ruby/object:Gem::Version
185
+ version: 0.51.1
186
+ type: :runtime
187
+ prerelease: false
188
+ version_requirements: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - "~>"
191
+ - !ruby/object:Gem::Version
192
+ version: 0.51.1
151
193
  - !ruby/object:Gem::Dependency
152
194
  name: inifile
153
195
  requirement: !ruby/object:Gem::Requirement
@@ -224,6 +266,7 @@ files:
224
266
  - lib/train/transports/azure.rb
225
267
  - lib/train/transports/cisco_ios_connection.rb
226
268
  - lib/train/transports/docker.rb
269
+ - lib/train/transports/gcp.rb
227
270
  - lib/train/transports/local.rb
228
271
  - lib/train/transports/mock.rb
229
272
  - lib/train/transports/ssh.rb
@@ -290,6 +333,7 @@ files:
290
333
  - test/unit/transports/aws_test.rb
291
334
  - test/unit/transports/azure_test.rb
292
335
  - test/unit/transports/cisco_ios_connection.rb
336
+ - test/unit/transports/gcp_test.rb
293
337
  - test/unit/transports/local_test.rb
294
338
  - test/unit/transports/mock_test.rb
295
339
  - test/unit/transports/ssh_test.rb
@@ -381,6 +425,7 @@ test_files:
381
425
  - test/unit/transports/aws_test.rb
382
426
  - test/unit/transports/azure_test.rb
383
427
  - test/unit/transports/cisco_ios_connection.rb
428
+ - test/unit/transports/gcp_test.rb
384
429
  - test/unit/transports/local_test.rb
385
430
  - test/unit/transports/mock_test.rb
386
431
  - test/unit/transports/ssh_test.rb