corl 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. data/.document +5 -0
  2. data/.gitmodules +4 -0
  3. data/Gemfile +24 -0
  4. data/Gemfile.lock +123 -0
  5. data/LICENSE.txt +674 -0
  6. data/README.rdoc +27 -0
  7. data/Rakefile +78 -0
  8. data/VERSION +1 -0
  9. data/bin/corl +55 -0
  10. data/corl.gemspec +228 -0
  11. data/lib/corl/action/add.rb +69 -0
  12. data/lib/corl/action/bootstrap.rb +83 -0
  13. data/lib/corl/action/clone.rb +40 -0
  14. data/lib/corl/action/create.rb +55 -0
  15. data/lib/corl/action/exec.rb +41 -0
  16. data/lib/corl/action/extract.rb +49 -0
  17. data/lib/corl/action/image.rb +30 -0
  18. data/lib/corl/action/images.rb +55 -0
  19. data/lib/corl/action/lookup.rb +35 -0
  20. data/lib/corl/action/machines.rb +51 -0
  21. data/lib/corl/action/provision.rb +37 -0
  22. data/lib/corl/action/remove.rb +51 -0
  23. data/lib/corl/action/save.rb +53 -0
  24. data/lib/corl/action/seed.rb +115 -0
  25. data/lib/corl/action/spawn.rb +75 -0
  26. data/lib/corl/action/start.rb +37 -0
  27. data/lib/corl/action/stop.rb +30 -0
  28. data/lib/corl/action/update.rb +37 -0
  29. data/lib/corl/command/shell.rb +164 -0
  30. data/lib/corl/configuration/file.rb +386 -0
  31. data/lib/corl/event/puppet.rb +90 -0
  32. data/lib/corl/event/regex.rb +52 -0
  33. data/lib/corl/extension/puppetloader.rb +24 -0
  34. data/lib/corl/machine/fog.rb +310 -0
  35. data/lib/corl/machine/physical.rb +161 -0
  36. data/lib/corl/network/default.rb +26 -0
  37. data/lib/corl/node/aws.rb +90 -0
  38. data/lib/corl/node/fog.rb +198 -0
  39. data/lib/corl/node/google.rb +115 -0
  40. data/lib/corl/node/local.rb +26 -0
  41. data/lib/corl/node/rackspace.rb +89 -0
  42. data/lib/corl/project/git.rb +465 -0
  43. data/lib/corl/project/github.rb +108 -0
  44. data/lib/corl/provisioner/puppetnode/resource.rb +245 -0
  45. data/lib/corl/provisioner/puppetnode/resource_group.rb +205 -0
  46. data/lib/corl/provisioner/puppetnode.rb +407 -0
  47. data/lib/corl/template/environment.rb +73 -0
  48. data/lib/corl/template/json.rb +16 -0
  49. data/lib/corl/template/wrapper.rb +16 -0
  50. data/lib/corl/template/yaml.rb +16 -0
  51. data/lib/corl/translator/json.rb +27 -0
  52. data/lib/corl/translator/yaml.rb +27 -0
  53. data/lib/corl.rb +173 -0
  54. data/lib/corl_core/codes.rb +107 -0
  55. data/lib/corl_core/config/collection.rb +57 -0
  56. data/lib/corl_core/config/options.rb +70 -0
  57. data/lib/corl_core/config.rb +337 -0
  58. data/lib/corl_core/core.rb +59 -0
  59. data/lib/corl_core/corl.rb +254 -0
  60. data/lib/corl_core/errors.rb +84 -0
  61. data/lib/corl_core/facade.rb +126 -0
  62. data/lib/corl_core/gems.rb +72 -0
  63. data/lib/corl_core/manager.rb +425 -0
  64. data/lib/corl_core/mixin/action/commit.rb +58 -0
  65. data/lib/corl_core/mixin/action/keypair.rb +105 -0
  66. data/lib/corl_core/mixin/action/node.rb +129 -0
  67. data/lib/corl_core/mixin/action/project.rb +53 -0
  68. data/lib/corl_core/mixin/action/push.rb +52 -0
  69. data/lib/corl_core/mixin/config/collection.rb +53 -0
  70. data/lib/corl_core/mixin/config/ops.rb +53 -0
  71. data/lib/corl_core/mixin/config/options.rb +39 -0
  72. data/lib/corl_core/mixin/lookup.rb +196 -0
  73. data/lib/corl_core/mixin/macro/object_interface.rb +361 -0
  74. data/lib/corl_core/mixin/macro/plugin_interface.rb +380 -0
  75. data/lib/corl_core/mixin/settings.rb +46 -0
  76. data/lib/corl_core/mixin/sub_config.rb +148 -0
  77. data/lib/corl_core/mod/hash.rb +29 -0
  78. data/lib/corl_core/mod/hiera_backend.rb +63 -0
  79. data/lib/corl_core/plugin/action.rb +381 -0
  80. data/lib/corl_core/plugin/base.rb +374 -0
  81. data/lib/corl_core/plugin/command.rb +98 -0
  82. data/lib/corl_core/plugin/configuration.rb +177 -0
  83. data/lib/corl_core/plugin/event.rb +53 -0
  84. data/lib/corl_core/plugin/extension.rb +12 -0
  85. data/lib/corl_core/plugin/machine.rb +266 -0
  86. data/lib/corl_core/plugin/network.rb +359 -0
  87. data/lib/corl_core/plugin/node.rb +904 -0
  88. data/lib/corl_core/plugin/project.rb +927 -0
  89. data/lib/corl_core/plugin/provisioner.rb +51 -0
  90. data/lib/corl_core/plugin/template.rb +80 -0
  91. data/lib/corl_core/plugin/translator.rb +38 -0
  92. data/lib/corl_core/util/cli.rb +352 -0
  93. data/lib/corl_core/util/data.rb +404 -0
  94. data/lib/corl_core/util/disk.rb +114 -0
  95. data/lib/corl_core/util/git.rb +47 -0
  96. data/lib/corl_core/util/interface.rb +319 -0
  97. data/lib/corl_core/util/liquid.rb +17 -0
  98. data/lib/corl_core/util/package.rb +93 -0
  99. data/lib/corl_core/util/shell.rb +239 -0
  100. data/lib/corl_core/util/ssh.rb +286 -0
  101. data/lib/facter/corl_config_ready.rb +13 -0
  102. data/lib/facter/corl_exists.rb +15 -0
  103. data/lib/facter/corl_network.rb +17 -0
  104. data/lib/hiera/corl_logger.rb +18 -0
  105. data/lib/puppet/indirector/corl.rb +27 -0
  106. data/lib/puppet/indirector/data_binding/corl.rb +6 -0
  107. data/lib/puppet/parser/functions/config_initialized.rb +26 -0
  108. data/lib/puppet/parser/functions/corl_include.rb +44 -0
  109. data/lib/puppet/parser/functions/corl_resources.rb +58 -0
  110. data/lib/puppet/parser/functions/deep_merge.rb +21 -0
  111. data/lib/puppet/parser/functions/ensure.rb +29 -0
  112. data/lib/puppet/parser/functions/file_exists.rb +19 -0
  113. data/lib/puppet/parser/functions/global_array.rb +35 -0
  114. data/lib/puppet/parser/functions/global_hash.rb +35 -0
  115. data/lib/puppet/parser/functions/global_options.rb +23 -0
  116. data/lib/puppet/parser/functions/global_param.rb +43 -0
  117. data/lib/puppet/parser/functions/interpolate.rb +26 -0
  118. data/lib/puppet/parser/functions/is_false.rb +21 -0
  119. data/lib/puppet/parser/functions/is_true.rb +21 -0
  120. data/lib/puppet/parser/functions/module_array.rb +38 -0
  121. data/lib/puppet/parser/functions/module_hash.rb +38 -0
  122. data/lib/puppet/parser/functions/module_options.rb +23 -0
  123. data/lib/puppet/parser/functions/module_param.rb +48 -0
  124. data/lib/puppet/parser/functions/name.rb +21 -0
  125. data/lib/puppet/parser/functions/render.rb +33 -0
  126. data/lib/puppet/parser/functions/value.rb +21 -0
  127. data/locales/en.yml +232 -0
  128. data/spec/corl_core/interface_spec.rb +489 -0
  129. data/spec/corl_mock_input.rb +29 -0
  130. data/spec/corl_test_kernel.rb +22 -0
  131. data/spec/spec_helper.rb +15 -0
  132. metadata +406 -0
@@ -0,0 +1,465 @@
1
+
2
+ module CORL
3
+ module Project
4
+ class Git < Plugin::Project
5
+
6
+ #-----------------------------------------------------------------------------
7
+ # Project plugin interface
8
+
9
+ def normalize
10
+ super
11
+ end
12
+
13
+ #-----------------------------------------------------------------------------
14
+ # Git interface (local)
15
+
16
+ def ensure_git(reset = false)
17
+ if reset || @git_lib.nil?
18
+ @git_lib = nil
19
+
20
+ if directory.empty?
21
+ logger.warn("Can not manage Git project at #{directory} as it does not exist")
22
+ else
23
+ logger.debug("Ensuring Git instance to manage #{directory}")
24
+ @git_lib = Util::Git.new(directory)
25
+
26
+ if ! @git_lib.nil? && get(:create, false)
27
+ unless File.directory?(directory) && @git_lib.git.exist?
28
+ FileUtils.mkdir_p(directory) unless File.directory?(directory)
29
+ @git_lib.git.init({ :bare => false })
30
+ end
31
+ end
32
+ end
33
+ end
34
+ return myself
35
+ end
36
+ protected :ensure_git
37
+
38
+ #-----------------------------------------------------------------------------
39
+ # Checks
40
+
41
+ def can_persist?
42
+ ensure_git
43
+ return true unless @git_lib.nil?
44
+ return false
45
+ end
46
+
47
+ #---
48
+
49
+ def top?(path)
50
+ git_dir = File.join(path, '.git')
51
+ if File.exist?(git_dir)
52
+ return true if File.directory?(git_dir)
53
+ elsif File.exist?(path) && (path =~ /\.git$/ && File.exist?(File.join(path, 'HEAD')))
54
+ return true
55
+ end
56
+ return false
57
+ end
58
+
59
+ #---
60
+
61
+ def subproject?(path)
62
+ git_dir = File.join(path, '.git')
63
+ if File.exist?(git_dir)
64
+ unless File.directory?(git_dir)
65
+ git_dir = Util::Disk.read(git_dir)
66
+ unless git_dir.nil?
67
+ git_dir = git_dir.gsub(/^gitdir\:\s*/, '').strip
68
+ return true if File.directory?(git_dir)
69
+ end
70
+ end
71
+ end
72
+ return false
73
+ end
74
+
75
+ #---
76
+
77
+ def project_directory?(path, require_top_level = false)
78
+ path = File.expand_path(path)
79
+ git_dir = File.join(path, '.git')
80
+
81
+ if File.exist?(git_dir)
82
+ if File.directory?(git_dir)
83
+ return true
84
+ elsif ! require_top_level
85
+ git_dir = Util::Disk.read(git_dir)
86
+ unless git_dir.nil?
87
+ git_dir = git_dir.gsub(/^gitdir\:\s*/, '').strip
88
+ return true if File.directory?(git_dir)
89
+ end
90
+ end
91
+ elsif File.exist?(path) && (path =~ /\.git$/ && File.exist?(File.join(path, 'HEAD')))
92
+ return true
93
+ end
94
+ return false
95
+ end
96
+
97
+ #---
98
+
99
+ def new?(reset = false)
100
+ if get(:new, nil).nil? || reset
101
+ set(:new, git.native(:rev_parse, { :all => true }).empty?)
102
+ end
103
+ get(:new, false)
104
+ end
105
+
106
+ #-----------------------------------------------------------------------------
107
+ # Property accessors / modifiers
108
+
109
+ def lib
110
+ return @git_lib
111
+ end
112
+
113
+ #---
114
+
115
+ def git
116
+ return lib.git if can_persist?
117
+ return nil
118
+ end
119
+ protected :git
120
+
121
+ #---
122
+
123
+ def set_location(directory)
124
+ super do
125
+ ensure_git(true)
126
+ end
127
+ return myself
128
+ end
129
+
130
+ #---
131
+
132
+ def config(name, options = {})
133
+ return super do |config|
134
+ git.config(config.export, name)
135
+ end
136
+ end
137
+
138
+ #---
139
+
140
+ def set_config(name, value, options = {})
141
+ return super do |config, processed_value|
142
+ git.config(config.export, name, processed_value)
143
+ end
144
+ end
145
+
146
+ #---
147
+
148
+ def delete_config(name, options = {})
149
+ return super do |config|
150
+ git.config(config.import({ :remove_section => true }).export, name)
151
+ end
152
+ end
153
+
154
+ #---
155
+
156
+ def subproject_config(options = {})
157
+ return super do |config|
158
+ result = {}
159
+
160
+ if new?
161
+ logger.debug("Project has no sub project configuration yet (has not been committed to)")
162
+ else
163
+ commit = lib.commit(revision)
164
+ blob = commit.tree/'.gitmodules' unless commit.nil?
165
+
166
+ if blob
167
+ logger.debug("Houston, we have a Git blob!")
168
+
169
+ lines = blob.data.gsub(/\r\n?/, "\n" ).split("\n")
170
+ current = nil
171
+
172
+ lines.each do |line|
173
+ if line =~ /^\[submodule "(.+)"\]$/
174
+ current = $1
175
+ result[current] = {}
176
+ result[current]['id'] = (commit.tree/current).id
177
+
178
+ logger.debug("Reading: #{current}")
179
+
180
+ elsif line =~ /^\t(\w+) = (.+)$/
181
+ result[current][$1] = $2
182
+ result[current]['id'] = (commit.tree/$2).id if $1 == 'path'
183
+ end
184
+ end
185
+ end
186
+ end
187
+ result
188
+ end
189
+ end
190
+
191
+ #-----------------------------------------------------------------------------
192
+ # Basic Git operations
193
+
194
+ def load_revision
195
+ return super do
196
+ if new?
197
+ logger.debug("Project has no current revision yet (has not been committed to)")
198
+ nil
199
+
200
+ else
201
+ current_revision = git.native(:rev_parse, { :abbrev_ref => true }, 'HEAD').strip
202
+
203
+ logger.debug("Current revision: #{current_revision}")
204
+ current_revision
205
+ end
206
+ end
207
+ end
208
+
209
+ #---
210
+
211
+ def checkout(revision)
212
+ return super do |success|
213
+ if new?
214
+ logger.debug("Project can not be checked out (has not been committed to)")
215
+ else
216
+ unless lib.bare
217
+ success = safe_exec(false) do
218
+ git.checkout({ :raise => true }, revision)
219
+ end
220
+ end
221
+ end
222
+ success
223
+ end
224
+ end
225
+
226
+ #---
227
+
228
+ def commit(files = '.', options = {})
229
+ return super do |config, time, user, message|
230
+ safe_exec(false) do
231
+ git.reset({}, 'HEAD') # Clear the index so we get a clean commit
232
+
233
+ files = array(files)
234
+
235
+ logger.debug("Adding files to Git index")
236
+
237
+ git.add({ :raise => true }, files) # Get all added and updated files
238
+ git.add({ :update => true, :raise => true }, files) # Get all deleted files
239
+
240
+ commit_options = {
241
+ :raise => true,
242
+ :m => "#{time} by <#{user}> - #{message}",
243
+ :allow_empty => config.get(:allow_empty, false)
244
+ }
245
+ commit_options[:author] = config[:author] if config.get(:author, false)
246
+
247
+ logger.debug("Composing commit options: #{commit_options.inspect}")
248
+ git.commit(commit_options)
249
+
250
+ new?(true)
251
+ end
252
+ end
253
+ end
254
+
255
+ #-----------------------------------------------------------------------------
256
+ # Subproject operations
257
+
258
+ def load_subprojects(options = {})
259
+ return super do |project_path, data|
260
+ File.exist?(File.join(project_path, '.git'))
261
+ end
262
+ end
263
+
264
+ #---
265
+
266
+ def add_subproject(path, url, revision, options = {})
267
+ return super do |config|
268
+ safe_exec(false) do
269
+ branch_options = ''
270
+ branch_options = [ '-b', config[:revision] ] if config.get(:revision, false)
271
+
272
+ path = config[:path]
273
+ url = config[:url]
274
+
275
+ git.submodule({ :raise => true }, 'add', *branch_options, url, path)
276
+
277
+ config.set(:files, [ '.gitmodules', path ])
278
+ end
279
+ end
280
+ end
281
+
282
+ #---
283
+
284
+ def delete_subproject(path)
285
+ return super do |config|
286
+ safe_exec(false) do
287
+ path = config[:path]
288
+ submodule_key = "submodule.#{path}"
289
+
290
+ logger.debug("Deleting Git configurations for #{submodule_key}")
291
+ delete_config(submodule_key)
292
+ delete_config(submodule_key, { :file => '.gitmodules' })
293
+
294
+ logger.debug("Cleaning Git index cache for #{path}")
295
+ git.rm({ :cached => true }, path)
296
+
297
+ logger.debug("Removing Git submodule directories")
298
+ FileUtils.rm_rf(File.join(directory, path))
299
+ FileUtils.rm_rf(File.join(git.git_dir, 'modules', path))
300
+
301
+ config.set(:files, [ '.gitmodules', path ])
302
+ end
303
+ end
304
+ end
305
+
306
+ #---
307
+
308
+ def update_subprojects
309
+ return super do
310
+ safe_exec(false) do
311
+ git.submodule({ :raise => true, :timeout => false }, 'update', '--init', '--recursive')
312
+ end
313
+ end
314
+ end
315
+
316
+ #-----------------------------------------------------------------------------
317
+ # Remote operations
318
+
319
+ def init_remotes
320
+ return super do
321
+ origin_url = config('remote.origin.url').strip
322
+
323
+ logger.debug("Original origin remote url: #{origin_url}")
324
+ origin_url
325
+ end
326
+ end
327
+
328
+ #---
329
+
330
+ def remote(name)
331
+ return super do
332
+ url = config("remote.#{name}.url").strip
333
+ url.empty? ? nil : url
334
+ end
335
+ end
336
+
337
+ #---
338
+
339
+ def set_remote(name, url)
340
+ return super do |processed_url|
341
+ safe_exec(false) do
342
+ git.remote({ :raise => true }, 'add', name.to_s, processed_url)
343
+ end
344
+ end
345
+ end
346
+
347
+ #---
348
+
349
+ def add_remote_url(name, url, options = {})
350
+ return super do |config, processed_url|
351
+ safe_exec(false) do
352
+ git.remote({
353
+ :raise => true,
354
+ :add => true,
355
+ :delete => config.get(:delete, false),
356
+ :push => config.get(:push, false)
357
+ }, 'set-url', name.to_s, processed_url)
358
+ end
359
+ end
360
+ end
361
+
362
+ #---
363
+
364
+ def delete_remote(name)
365
+ return super do
366
+ if config("remote.#{name}.url").empty?
367
+ logger.debug("Project can not delete remote #{name} because it does not exist yet")
368
+ true
369
+ else
370
+ safe_exec(false) do
371
+ git.remote({ :raise => true }, 'rm', name.to_s)
372
+ end
373
+ end
374
+ end
375
+ end
376
+
377
+ #---
378
+
379
+ def syncronize(cloud, options = {})
380
+ return super do |config|
381
+ config.init(:remote_path, '/var/git')
382
+ config.set(:add, true)
383
+ end
384
+ end
385
+
386
+ #-----------------------------------------------------------------------------
387
+ # SSH operations
388
+
389
+ def pull(remote = :origin, options = {})
390
+ return super do |config, processed_remote|
391
+ flags = []
392
+ flags << :tags if config.get(:tags, true)
393
+
394
+ result = CORL.command({
395
+ :command => :git,
396
+ :data => { 'git-dir=' => git.git_dir },
397
+ :subcommand => {
398
+ :command => :pull,
399
+ :flags => flags,
400
+ :args => [ processed_remote, config.get(:revision, get(:revision, :master)) ]
401
+ }
402
+ }, config.get(:provider, :shell)).exec(config) do |op, command, data|
403
+ block_given? ? yield(op, command, data) : true
404
+ end
405
+
406
+ if result.status == CORL.code.success
407
+ new?(true)
408
+ true
409
+ else
410
+ false
411
+ end
412
+ end
413
+ end
414
+
415
+ #---
416
+
417
+ def push(remote = :edit, options = {})
418
+ return super do |config, processed_remote|
419
+ push_branch = config.get(:revision, '')
420
+
421
+ flags = []
422
+ flags << :all if push_branch.empty?
423
+ flags << :tags if ! push_branch.empty? && config.get(:tags, true)
424
+
425
+ result = CORL.command({
426
+ :command => :git,
427
+ :data => { 'git-dir=' => git.git_dir },
428
+ :subcommand => {
429
+ :command => :push,
430
+ :flags => flags,
431
+ :args => [ processed_remote, push_branch ]
432
+ }
433
+ }, config.get(:provider, :shell)).exec(config) do |op, command, data|
434
+ block_given? ? yield(op, command, data) : true
435
+ end
436
+
437
+ result.status == CORL.code.success
438
+ end
439
+ end
440
+
441
+ #-----------------------------------------------------------------------------
442
+ # Utilities
443
+
444
+ def translate_url(host, path, options = {})
445
+ return super do |config|
446
+ user = config.get(:user, 'git')
447
+ auth = config.get(:auth, true)
448
+
449
+ user + (auth ? '@' : '://') + host + (auth ? ':' : '/') + path
450
+ end
451
+ end
452
+
453
+ #---
454
+
455
+ def translate_edit_url(url, options = {})
456
+ return super do |config|
457
+ if matches = url.strip.match(/^(https?|git)\:\/\/([^\/]+)\/(.+)/)
458
+ protocol, host, path = matches.captures
459
+ translate_url(host, path, config.import({ :auth => true }))
460
+ end
461
+ end
462
+ end
463
+ end
464
+ end
465
+ end
@@ -0,0 +1,108 @@
1
+
2
+ corl_require(File.dirname(__FILE__), :git)
3
+
4
+ #---
5
+
6
+ module CORL
7
+ module Project
8
+ class Github < Git
9
+
10
+ #-----------------------------------------------------------------------------
11
+ # Project plugin interface
12
+
13
+ def normalize
14
+ if reference = delete(:reference, nil)
15
+ myself.name = reference
16
+ else
17
+ if url = get(:url, nil)
18
+ myself.name = url
19
+ set(:url, myself.class.expand_url(url, get(:ssh, false)))
20
+ end
21
+ end
22
+ super
23
+ end
24
+
25
+ #---
26
+
27
+ def set_connection
28
+ require 'octokit'
29
+
30
+ @client = Octokit::Client.new :netrc => true
31
+ @client.login
32
+ end
33
+
34
+ #-----------------------------------------------------------------------------
35
+ # Property accessor / modifiers
36
+
37
+ def client
38
+ set_connection unless @client
39
+ @client
40
+ end
41
+
42
+ #-----------------------------------------------------------------------------
43
+ # Project operations
44
+
45
+ def init_auth
46
+ super do
47
+ key_id = ENV['USER'] + '@' + lookup(:ipaddress)
48
+ ssh_key = public_key_str
49
+
50
+ if private_key && ssh_key
51
+ begin
52
+ deploy_keys = client.deploy_keys(self.name)
53
+ github_id = nil
54
+ keys_match = true
55
+
56
+ deploy_keys.each do |key_resource|
57
+ if key_resource.title == key_id
58
+ github_id = key_resource.id
59
+ keys_match = false if key_resource.key != ssh_key
60
+ break
61
+ end
62
+ end
63
+
64
+ if github_id
65
+ unless keys_match
66
+ client.edit_deploy_key(self.name, github_id, { :key => ssh_key })
67
+ verify_key
68
+ end
69
+ else
70
+ client.add_deploy_key(self.name, key_id, ssh_key)
71
+ verify_key
72
+ end
73
+
74
+ rescue Exception => error
75
+ logger.error(error.inspect)
76
+ logger.error(error.message)
77
+ logger.error(Util::Data.to_yaml(error.backtrace))
78
+
79
+ ui.error(error.message, { :prefix => false }) if error.message
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ #-----------------------------------------------------------------------------
86
+ # Utilities
87
+
88
+ def self.expand_url(path, editable = false)
89
+ if editable
90
+ protocol = 'git@'
91
+ separator = ':'
92
+ else
93
+ protocol = 'https://'
94
+ separator = '/'
95
+ end
96
+ return "#{protocol}github.com#{separator}" + path + '.git'
97
+ end
98
+
99
+ #---
100
+
101
+ def verify_key
102
+ Util::SSH.init_session('github.com', 'git', 22, private_key)
103
+ Util::SSH.close('github.com', 'git')
104
+ end
105
+ protected :verify_key
106
+ end
107
+ end
108
+ end