chef-provisioning 2.0.1 → 2.0.2
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/CHANGELOG.md +906 -899
- data/Gemfile +17 -17
- data/LICENSE +201 -201
- data/README.md +312 -312
- data/Rakefile +55 -55
- data/chef-provisioning.gemspec +38 -38
- data/lib/chef/provider/load_balancer.rb +75 -75
- data/lib/chef/provider/machine.rb +219 -219
- data/lib/chef/provider/machine_batch.rb +224 -224
- data/lib/chef/provider/machine_execute.rb +36 -36
- data/lib/chef/provider/machine_file.rb +55 -55
- data/lib/chef/provider/machine_image.rb +105 -105
- data/lib/chef/provisioning.rb +110 -110
- data/lib/chef/provisioning/action_handler.rb +68 -68
- data/lib/chef/provisioning/add_prefix_action_handler.rb +35 -35
- data/lib/chef/provisioning/chef_managed_entry_store.rb +128 -128
- data/lib/chef/provisioning/chef_provider_action_handler.rb +74 -74
- data/lib/chef/provisioning/chef_run_data.rb +132 -132
- data/lib/chef/provisioning/convergence_strategy.rb +28 -28
- data/lib/chef/provisioning/convergence_strategy/ignore_convergence_failure.rb +54 -54
- data/lib/chef/provisioning/convergence_strategy/install_cached.rb +188 -188
- data/lib/chef/provisioning/convergence_strategy/install_msi.rb +71 -71
- data/lib/chef/provisioning/convergence_strategy/install_sh.rb +71 -71
- data/lib/chef/provisioning/convergence_strategy/no_converge.rb +35 -35
- data/lib/chef/provisioning/convergence_strategy/precreate_chef_objects.rb +255 -255
- data/lib/chef/provisioning/driver.rb +323 -323
- data/lib/chef/provisioning/load_balancer_spec.rb +14 -14
- data/lib/chef/provisioning/machine.rb +112 -112
- data/lib/chef/provisioning/machine/basic_machine.rb +84 -84
- data/lib/chef/provisioning/machine/unix_machine.rb +288 -288
- data/lib/chef/provisioning/machine/windows_machine.rb +108 -108
- data/lib/chef/provisioning/machine_image_spec.rb +34 -34
- data/lib/chef/provisioning/machine_spec.rb +58 -58
- data/lib/chef/provisioning/managed_entry.rb +121 -121
- data/lib/chef/provisioning/managed_entry_store.rb +136 -136
- data/lib/chef/provisioning/recipe_dsl.rb +99 -99
- data/lib/chef/provisioning/rspec.rb +27 -27
- data/lib/chef/provisioning/transport.rb +100 -100
- data/lib/chef/provisioning/transport/ssh.rb +403 -403
- data/lib/chef/provisioning/transport/winrm.rb +144 -144
- data/lib/chef/provisioning/version.rb +5 -5
- data/lib/chef/resource/chef_data_bag_resource.rb +146 -146
- data/lib/chef/resource/load_balancer.rb +57 -57
- data/lib/chef/resource/machine.rb +128 -128
- data/lib/chef/resource/machine_batch.rb +78 -78
- data/lib/chef/resource/machine_execute.rb +30 -30
- data/lib/chef/resource/machine_file.rb +34 -34
- data/lib/chef/resource/machine_image.rb +35 -35
- data/lib/chef_metal.rb +1 -1
- data/spec/chef/provisioning/convergence_strategy/ignore_convergence_failure_spec.rb +86 -86
- data/spec/spec_helper.rb +27 -27
- metadata +10 -4
@@ -1,144 +1,144 @@
|
|
1
|
-
require 'chef/provisioning/transport'
|
2
|
-
require 'base64'
|
3
|
-
require 'timeout'
|
4
|
-
|
5
|
-
class Chef
|
6
|
-
module Provisioning
|
7
|
-
class Transport
|
8
|
-
# Transport to handle the WinRM connection protocol.
|
9
|
-
class WinRM < Chef::Provisioning::Transport
|
10
|
-
#
|
11
|
-
# Create a new WinRM transport.
|
12
|
-
#
|
13
|
-
# == Arguments
|
14
|
-
# - endpoint: the WinRM endpoint, e.g. http://145.14.51.45:5985/wsman.
|
15
|
-
# - type: the connection type, e.g. :plaintext.
|
16
|
-
# - options: options hash, including both WinRM options and transport options.
|
17
|
-
# For transport options, see the Transport.options definition. WinRM
|
18
|
-
# options include :user, :pass, :disable_sspi => true, among others.
|
19
|
-
# - global_config: an options hash that looks suspiciously similar to
|
20
|
-
# Chef::Config, containing at least the key :log_level.
|
21
|
-
#
|
22
|
-
# The actual connection is made as ::WinRM::WinRMWebService.new(endpoint, type, options)
|
23
|
-
#
|
24
|
-
def initialize(endpoint, type, options, global_config)
|
25
|
-
@options = options
|
26
|
-
@options[:endpoint] = endpoint
|
27
|
-
@options[:transport] = type
|
28
|
-
|
29
|
-
# WinRM v2 switched from :pass to :password
|
30
|
-
# we accept either to avoid having to update every driver
|
31
|
-
@options[:password] = @options[:password] || @options[:pass]
|
32
|
-
|
33
|
-
@config = global_config
|
34
|
-
end
|
35
|
-
|
36
|
-
attr_reader :options
|
37
|
-
attr_reader :config
|
38
|
-
|
39
|
-
def execute(command, execute_options = {})
|
40
|
-
output = with_execute_timeout(execute_options) do
|
41
|
-
block = Proc.new { |stdout, stderr| stream_chunk(execute_options, stdout, stderr) }
|
42
|
-
session.run(command, &block)
|
43
|
-
end
|
44
|
-
WinRMResult.new(command, execute_options, config, output)
|
45
|
-
end
|
46
|
-
|
47
|
-
def read_file(path)
|
48
|
-
result = execute("[Convert]::ToBase64String((Get-Content #{escape(path)} -Encoding byte -ReadCount 0))")
|
49
|
-
if result.exitstatus == 0
|
50
|
-
Base64.decode64(result.stdout)
|
51
|
-
else
|
52
|
-
nil
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def write_file(path, content)
|
57
|
-
file = Tempfile.new('provisioning-upload')
|
58
|
-
begin
|
59
|
-
file.write(content)
|
60
|
-
file.close
|
61
|
-
file_transporter.upload(file.path, path)
|
62
|
-
ensure
|
63
|
-
file.unlink
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def disconnect
|
68
|
-
#
|
69
|
-
end
|
70
|
-
|
71
|
-
def escape(string)
|
72
|
-
"\"#{string.gsub("\"", "`\"")}\""
|
73
|
-
end
|
74
|
-
|
75
|
-
def available?
|
76
|
-
# If you can't pwd within 10 seconds, you can't pwd
|
77
|
-
execute('pwd', :timeout => 10)
|
78
|
-
true
|
79
|
-
rescue ::WinRM::WinRMAuthorizationError
|
80
|
-
Chef::Log.debug("unavailable: winrm authentication error: #{$!.inspect} ")
|
81
|
-
disconnect
|
82
|
-
false
|
83
|
-
rescue Timeout::Error, Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET, ::WinRM::WinRMError
|
84
|
-
Chef::Log.debug("unavailable: network connection failed or broke: #{$!.inspect}")
|
85
|
-
disconnect
|
86
|
-
false
|
87
|
-
end
|
88
|
-
|
89
|
-
def make_url_available_to_remote(local_url)
|
90
|
-
uri = URI(local_url)
|
91
|
-
uri.scheme = 'http' if uri.scheme == 'chefzero' && uri.host == 'localhost'
|
92
|
-
host = Socket.getaddrinfo(uri.host, uri.scheme, nil, :STREAM)[0][3]
|
93
|
-
if host == '127.0.0.1' || host == '::1'
|
94
|
-
raise 'Unable to converge locally via winrm. Local converge is currently only supported with SSH. You may only converge with winrm against a chef-server.'
|
95
|
-
end
|
96
|
-
local_url
|
97
|
-
end
|
98
|
-
|
99
|
-
protected
|
100
|
-
|
101
|
-
def session
|
102
|
-
@session ||= begin
|
103
|
-
require 'winrm'
|
104
|
-
::WinRM::Connection.new(options).shell(:powershell)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def file_transporter
|
109
|
-
@file_transporter ||= begin
|
110
|
-
require 'winrm-fs'
|
111
|
-
::WinRM::FS::Core::FileTransporter.new(session)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
class WinRMResult
|
116
|
-
def initialize(command, options, config, output)
|
117
|
-
@command = command
|
118
|
-
@options = options
|
119
|
-
@config = config
|
120
|
-
@exitstatus = output.exitcode
|
121
|
-
@stdout = output.stdout
|
122
|
-
@stderr = output.stderr
|
123
|
-
end
|
124
|
-
|
125
|
-
attr_reader :stdout
|
126
|
-
attr_reader :stderr
|
127
|
-
attr_reader :exitstatus
|
128
|
-
attr_reader :command
|
129
|
-
attr_reader :options
|
130
|
-
attr_reader :config
|
131
|
-
|
132
|
-
def error!
|
133
|
-
if exitstatus != 0
|
134
|
-
msg = "Error: command '#{command}' exited with code #{exitstatus}.\n"
|
135
|
-
msg << "STDOUT: #{stdout}" if !options[:stream] && !options[:stream_stdout] && config[:log_level] != :debug
|
136
|
-
msg << "STDERR: #{stderr}" if !options[:stream] && !options[:stream_stderr] && config[:log_level] != :debug
|
137
|
-
raise msg
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
1
|
+
require 'chef/provisioning/transport'
|
2
|
+
require 'base64'
|
3
|
+
require 'timeout'
|
4
|
+
|
5
|
+
class Chef
|
6
|
+
module Provisioning
|
7
|
+
class Transport
|
8
|
+
# Transport to handle the WinRM connection protocol.
|
9
|
+
class WinRM < Chef::Provisioning::Transport
|
10
|
+
#
|
11
|
+
# Create a new WinRM transport.
|
12
|
+
#
|
13
|
+
# == Arguments
|
14
|
+
# - endpoint: the WinRM endpoint, e.g. http://145.14.51.45:5985/wsman.
|
15
|
+
# - type: the connection type, e.g. :plaintext.
|
16
|
+
# - options: options hash, including both WinRM options and transport options.
|
17
|
+
# For transport options, see the Transport.options definition. WinRM
|
18
|
+
# options include :user, :pass, :disable_sspi => true, among others.
|
19
|
+
# - global_config: an options hash that looks suspiciously similar to
|
20
|
+
# Chef::Config, containing at least the key :log_level.
|
21
|
+
#
|
22
|
+
# The actual connection is made as ::WinRM::WinRMWebService.new(endpoint, type, options)
|
23
|
+
#
|
24
|
+
def initialize(endpoint, type, options, global_config)
|
25
|
+
@options = options
|
26
|
+
@options[:endpoint] = endpoint
|
27
|
+
@options[:transport] = type
|
28
|
+
|
29
|
+
# WinRM v2 switched from :pass to :password
|
30
|
+
# we accept either to avoid having to update every driver
|
31
|
+
@options[:password] = @options[:password] || @options[:pass]
|
32
|
+
|
33
|
+
@config = global_config
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :options
|
37
|
+
attr_reader :config
|
38
|
+
|
39
|
+
def execute(command, execute_options = {})
|
40
|
+
output = with_execute_timeout(execute_options) do
|
41
|
+
block = Proc.new { |stdout, stderr| stream_chunk(execute_options, stdout, stderr) }
|
42
|
+
session.run(command, &block)
|
43
|
+
end
|
44
|
+
WinRMResult.new(command, execute_options, config, output)
|
45
|
+
end
|
46
|
+
|
47
|
+
def read_file(path)
|
48
|
+
result = execute("[Convert]::ToBase64String((Get-Content #{escape(path)} -Encoding byte -ReadCount 0))")
|
49
|
+
if result.exitstatus == 0
|
50
|
+
Base64.decode64(result.stdout)
|
51
|
+
else
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def write_file(path, content)
|
57
|
+
file = Tempfile.new('provisioning-upload')
|
58
|
+
begin
|
59
|
+
file.write(content)
|
60
|
+
file.close
|
61
|
+
file_transporter.upload(file.path, path)
|
62
|
+
ensure
|
63
|
+
file.unlink
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def disconnect
|
68
|
+
#
|
69
|
+
end
|
70
|
+
|
71
|
+
def escape(string)
|
72
|
+
"\"#{string.gsub("\"", "`\"")}\""
|
73
|
+
end
|
74
|
+
|
75
|
+
def available?
|
76
|
+
# If you can't pwd within 10 seconds, you can't pwd
|
77
|
+
execute('pwd', :timeout => 10)
|
78
|
+
true
|
79
|
+
rescue ::WinRM::WinRMAuthorizationError
|
80
|
+
Chef::Log.debug("unavailable: winrm authentication error: #{$!.inspect} ")
|
81
|
+
disconnect
|
82
|
+
false
|
83
|
+
rescue Timeout::Error, Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET, ::WinRM::WinRMError
|
84
|
+
Chef::Log.debug("unavailable: network connection failed or broke: #{$!.inspect}")
|
85
|
+
disconnect
|
86
|
+
false
|
87
|
+
end
|
88
|
+
|
89
|
+
def make_url_available_to_remote(local_url)
|
90
|
+
uri = URI(local_url)
|
91
|
+
uri.scheme = 'http' if uri.scheme == 'chefzero' && uri.host == 'localhost'
|
92
|
+
host = Socket.getaddrinfo(uri.host, uri.scheme, nil, :STREAM)[0][3]
|
93
|
+
if host == '127.0.0.1' || host == '::1'
|
94
|
+
raise 'Unable to converge locally via winrm. Local converge is currently only supported with SSH. You may only converge with winrm against a chef-server.'
|
95
|
+
end
|
96
|
+
local_url
|
97
|
+
end
|
98
|
+
|
99
|
+
protected
|
100
|
+
|
101
|
+
def session
|
102
|
+
@session ||= begin
|
103
|
+
require 'winrm'
|
104
|
+
::WinRM::Connection.new(options).shell(:powershell)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def file_transporter
|
109
|
+
@file_transporter ||= begin
|
110
|
+
require 'winrm-fs'
|
111
|
+
::WinRM::FS::Core::FileTransporter.new(session)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class WinRMResult
|
116
|
+
def initialize(command, options, config, output)
|
117
|
+
@command = command
|
118
|
+
@options = options
|
119
|
+
@config = config
|
120
|
+
@exitstatus = output.exitcode
|
121
|
+
@stdout = output.stdout
|
122
|
+
@stderr = output.stderr
|
123
|
+
end
|
124
|
+
|
125
|
+
attr_reader :stdout
|
126
|
+
attr_reader :stderr
|
127
|
+
attr_reader :exitstatus
|
128
|
+
attr_reader :command
|
129
|
+
attr_reader :options
|
130
|
+
attr_reader :config
|
131
|
+
|
132
|
+
def error!
|
133
|
+
if exitstatus != 0
|
134
|
+
msg = "Error: command '#{command}' exited with code #{exitstatus}.\n"
|
135
|
+
msg << "STDOUT: #{stdout}" if !options[:stream] && !options[:stream_stdout] && config[:log_level] != :debug
|
136
|
+
msg << "STDERR: #{stderr}" if !options[:stream] && !options[:stream_stderr] && config[:log_level] != :debug
|
137
|
+
raise msg
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
class Chef
|
2
|
-
module Provisioning
|
3
|
-
VERSION = '2.0.
|
4
|
-
end
|
5
|
-
end
|
1
|
+
class Chef
|
2
|
+
module Provisioning
|
3
|
+
VERSION = '2.0.2'
|
4
|
+
end
|
5
|
+
end
|
@@ -1,146 +1,146 @@
|
|
1
|
-
require 'chef/resource/lwrp_base'
|
2
|
-
require 'cheffish'
|
3
|
-
|
4
|
-
# A resource that is backed by a data bag in a Chef server somewhere
|
5
|
-
class Chef::Resource::ChefDataBagResource < Chef::Resource::LWRPBase
|
6
|
-
|
7
|
-
# The key to store this thing under (/data/bag/<<name>>).
|
8
|
-
attr_reader :name
|
9
|
-
|
10
|
-
class << self
|
11
|
-
# The name of the databag to store the item in.
|
12
|
-
attr_reader :databag_name
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize(name, run_context=nil)
|
16
|
-
super
|
17
|
-
Chef::Log.debug("Re-hydrating #{name} from #{self.class.databag_name}...")
|
18
|
-
self.hydrate
|
19
|
-
end
|
20
|
-
|
21
|
-
# A list of attributes to be persisted into the databag.
|
22
|
-
# @return [Array] List of attributes that are stored in the databag
|
23
|
-
def self.stored_attributes
|
24
|
-
@stored_attributes || []
|
25
|
-
end
|
26
|
-
|
27
|
-
# Set databag name
|
28
|
-
# @return [Void]
|
29
|
-
def self.databag_name= name
|
30
|
-
Chef::Log.debug("Setting databag name to #{name}")
|
31
|
-
@databag_name = name
|
32
|
-
end
|
33
|
-
|
34
|
-
# Mark an attribute as stored by adding it to the internal tracking list {stored_attributes}
|
35
|
-
# and then delegating to {Chef::Resource::LWRPBase#attribute}
|
36
|
-
# @param attr_name [Symbol] Name of the attribute as a symbol
|
37
|
-
# @return [Void]
|
38
|
-
def self.stored_attribute(attr_name, *args)
|
39
|
-
@stored_attributes ||= []
|
40
|
-
@stored_attributes << attr_name
|
41
|
-
self.attribute attr_name, *args
|
42
|
-
end
|
43
|
-
|
44
|
-
# Load persisted data from the server's databag. If the databag does not exist on the
|
45
|
-
# server, returns nil.
|
46
|
-
#
|
47
|
-
# @param chef_server [Hash] A hash representing which Chef server to talk to
|
48
|
-
# @option chef_server [String] :chef_server_url URL to the Chef server
|
49
|
-
# @option chef_server [Hash] :options Options for when talking to the Chef server
|
50
|
-
# @option options [String] :client_name The node name making the call
|
51
|
-
# @option options [String] :signing_key_filename Path to the signing key
|
52
|
-
# @return [Object] an instance of this class re-hydrated from the data hash stored in the
|
53
|
-
# databag.
|
54
|
-
def hydrate(chef_server = Cheffish.default_chef_server)
|
55
|
-
chef_api = Cheffish.chef_server_api(chef_server)
|
56
|
-
begin
|
57
|
-
data = chef_api.get("/data/#{self.class.databag_name}/#{name}")
|
58
|
-
load_from_hash(data)
|
59
|
-
Chef::Log.debug("Rehydrating resource from #{self.class.databag_name}/#{name}: #{data}")
|
60
|
-
rescue Net::HTTPServerException => e
|
61
|
-
if e.response.code == '404'
|
62
|
-
nil
|
63
|
-
else
|
64
|
-
raise
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Load instance variable data from a hash. For each key,value pair, set @<key> to value
|
70
|
-
# @param hash [Hash] Hash containing the instance variable data
|
71
|
-
# @return [Object] self after having been populated with data.
|
72
|
-
def load_from_hash hash
|
73
|
-
hash.each do |k,v|
|
74
|
-
self.instance_variable_set("@#{k}", v)
|
75
|
-
end
|
76
|
-
self
|
77
|
-
end
|
78
|
-
|
79
|
-
# Convert the values in {stored_attributes} to a hash for storing in a databag
|
80
|
-
# @return [Hash] a hash of (k,v) pairs where k is each record in {stored_attributes}
|
81
|
-
def storage_hash
|
82
|
-
ignored = []
|
83
|
-
|
84
|
-
hash = {}
|
85
|
-
(self.class.stored_attributes - ignored).each do |attr_name|
|
86
|
-
varname = "@#{attr_name.to_s.gsub('@', '')}"
|
87
|
-
key = varname.gsub('@', '')
|
88
|
-
hash[key] = self.instance_variable_get varname
|
89
|
-
end
|
90
|
-
|
91
|
-
hash
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
# Save this entity to the server. If you have significant information that
|
96
|
-
# could be lost, you should do this as quickly as possible.
|
97
|
-
# @return [Void]
|
98
|
-
def save
|
99
|
-
|
100
|
-
create_databag_if_needed self.class.databag_name
|
101
|
-
|
102
|
-
# Clone for inline_resource
|
103
|
-
_databag_name = self.class.databag_name
|
104
|
-
_hash = self.storage_hash
|
105
|
-
_name = self.name
|
106
|
-
|
107
|
-
Cheffish.inline_resource(self, @action) do
|
108
|
-
chef_data_bag_item _name do
|
109
|
-
data_bag _databag_name
|
110
|
-
raw_data _hash
|
111
|
-
action :create
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Delete this entity from the server
|
117
|
-
# @return [Void]
|
118
|
-
def delete
|
119
|
-
# Clone for inline_resource
|
120
|
-
_name = self.name
|
121
|
-
_databag_name = self.class.databag_name
|
122
|
-
|
123
|
-
Cheffish.inline_resource(self, @action) do
|
124
|
-
chef_data_bag_item _name do
|
125
|
-
data_bag _databag_name
|
126
|
-
action :delete
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def new_resource
|
132
|
-
self
|
133
|
-
end
|
134
|
-
|
135
|
-
private
|
136
|
-
# Create the databag with Cheffish if required
|
137
|
-
# @return [Void]
|
138
|
-
def create_databag_if_needed databag_name
|
139
|
-
_databag_name = databag_name
|
140
|
-
Cheffish.inline_resource(self, @action) do
|
141
|
-
chef_data_bag _databag_name do
|
142
|
-
action :create
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
1
|
+
require 'chef/resource/lwrp_base'
|
2
|
+
require 'cheffish'
|
3
|
+
|
4
|
+
# A resource that is backed by a data bag in a Chef server somewhere
|
5
|
+
class Chef::Resource::ChefDataBagResource < Chef::Resource::LWRPBase
|
6
|
+
|
7
|
+
# The key to store this thing under (/data/bag/<<name>>).
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# The name of the databag to store the item in.
|
12
|
+
attr_reader :databag_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(name, run_context=nil)
|
16
|
+
super
|
17
|
+
Chef::Log.debug("Re-hydrating #{name} from #{self.class.databag_name}...")
|
18
|
+
self.hydrate
|
19
|
+
end
|
20
|
+
|
21
|
+
# A list of attributes to be persisted into the databag.
|
22
|
+
# @return [Array] List of attributes that are stored in the databag
|
23
|
+
def self.stored_attributes
|
24
|
+
@stored_attributes || []
|
25
|
+
end
|
26
|
+
|
27
|
+
# Set databag name
|
28
|
+
# @return [Void]
|
29
|
+
def self.databag_name= name
|
30
|
+
Chef::Log.debug("Setting databag name to #{name}")
|
31
|
+
@databag_name = name
|
32
|
+
end
|
33
|
+
|
34
|
+
# Mark an attribute as stored by adding it to the internal tracking list {stored_attributes}
|
35
|
+
# and then delegating to {Chef::Resource::LWRPBase#attribute}
|
36
|
+
# @param attr_name [Symbol] Name of the attribute as a symbol
|
37
|
+
# @return [Void]
|
38
|
+
def self.stored_attribute(attr_name, *args)
|
39
|
+
@stored_attributes ||= []
|
40
|
+
@stored_attributes << attr_name
|
41
|
+
self.attribute attr_name, *args
|
42
|
+
end
|
43
|
+
|
44
|
+
# Load persisted data from the server's databag. If the databag does not exist on the
|
45
|
+
# server, returns nil.
|
46
|
+
#
|
47
|
+
# @param chef_server [Hash] A hash representing which Chef server to talk to
|
48
|
+
# @option chef_server [String] :chef_server_url URL to the Chef server
|
49
|
+
# @option chef_server [Hash] :options Options for when talking to the Chef server
|
50
|
+
# @option options [String] :client_name The node name making the call
|
51
|
+
# @option options [String] :signing_key_filename Path to the signing key
|
52
|
+
# @return [Object] an instance of this class re-hydrated from the data hash stored in the
|
53
|
+
# databag.
|
54
|
+
def hydrate(chef_server = Cheffish.default_chef_server)
|
55
|
+
chef_api = Cheffish.chef_server_api(chef_server)
|
56
|
+
begin
|
57
|
+
data = chef_api.get("/data/#{self.class.databag_name}/#{name}")
|
58
|
+
load_from_hash(data)
|
59
|
+
Chef::Log.debug("Rehydrating resource from #{self.class.databag_name}/#{name}: #{data}")
|
60
|
+
rescue Net::HTTPServerException => e
|
61
|
+
if e.response.code == '404'
|
62
|
+
nil
|
63
|
+
else
|
64
|
+
raise
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Load instance variable data from a hash. For each key,value pair, set @<key> to value
|
70
|
+
# @param hash [Hash] Hash containing the instance variable data
|
71
|
+
# @return [Object] self after having been populated with data.
|
72
|
+
def load_from_hash hash
|
73
|
+
hash.each do |k,v|
|
74
|
+
self.instance_variable_set("@#{k}", v)
|
75
|
+
end
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
# Convert the values in {stored_attributes} to a hash for storing in a databag
|
80
|
+
# @return [Hash] a hash of (k,v) pairs where k is each record in {stored_attributes}
|
81
|
+
def storage_hash
|
82
|
+
ignored = []
|
83
|
+
|
84
|
+
hash = {}
|
85
|
+
(self.class.stored_attributes - ignored).each do |attr_name|
|
86
|
+
varname = "@#{attr_name.to_s.gsub('@', '')}"
|
87
|
+
key = varname.gsub('@', '')
|
88
|
+
hash[key] = self.instance_variable_get varname
|
89
|
+
end
|
90
|
+
|
91
|
+
hash
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# Save this entity to the server. If you have significant information that
|
96
|
+
# could be lost, you should do this as quickly as possible.
|
97
|
+
# @return [Void]
|
98
|
+
def save
|
99
|
+
|
100
|
+
create_databag_if_needed self.class.databag_name
|
101
|
+
|
102
|
+
# Clone for inline_resource
|
103
|
+
_databag_name = self.class.databag_name
|
104
|
+
_hash = self.storage_hash
|
105
|
+
_name = self.name
|
106
|
+
|
107
|
+
Cheffish.inline_resource(self, @action) do
|
108
|
+
chef_data_bag_item _name do
|
109
|
+
data_bag _databag_name
|
110
|
+
raw_data _hash
|
111
|
+
action :create
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Delete this entity from the server
|
117
|
+
# @return [Void]
|
118
|
+
def delete
|
119
|
+
# Clone for inline_resource
|
120
|
+
_name = self.name
|
121
|
+
_databag_name = self.class.databag_name
|
122
|
+
|
123
|
+
Cheffish.inline_resource(self, @action) do
|
124
|
+
chef_data_bag_item _name do
|
125
|
+
data_bag _databag_name
|
126
|
+
action :delete
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def new_resource
|
132
|
+
self
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
# Create the databag with Cheffish if required
|
137
|
+
# @return [Void]
|
138
|
+
def create_databag_if_needed databag_name
|
139
|
+
_databag_name = databag_name
|
140
|
+
Cheffish.inline_resource(self, @action) do
|
141
|
+
chef_data_bag _databag_name do
|
142
|
+
action :create
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|