chef-provisioning 2.0.1 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|