Class: StackBuilder::Chef::NodeManager

Inherits:
Stack::NodeManager show all
Includes:
ERB::Util
Defined in:
lib/stackbuilder/chef/stack_node_manager.rb

Constant Summary collapse

SSH_CREDENTIAL_KEYS =
Set.new(['ssh_user', 'ssh_password', 'identity_file'])

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Stack::NodeManager

#set_scale

Constructor Details

#initialize(id, node_config, repo_path, environment) ⇒ NodeManager

Returns a new instance of NodeManager.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 19

def initialize(id, node_config, repo_path, environment)

    @logger = StackBuilder::Common::Config.logger

    @id = id
    @name = node_config['node']
    @node_id = @name + '-' + @id

    @environment = environment

    @run_list = node_config.has_key?('run_list') ? node_config['run_list'].join(',') : nil
    @run_on_event = node_config['run_on_event']

    @knife_config = node_config['knife']

    @env_key_file = "#{repo_path}/secrets/#{environment}"
    @env_key_file = nil unless File.exist?(@env_key_file)
end

Instance Attribute Details

#nameObject

Returns the value of attribute name.



11
12
13
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 11

def name
  @name
end

#node_idObject

Returns the value of attribute node_id.



12
13
14
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 12

def node_id
  @node_id
end

#run_listObject

Returns the value of attribute run_list.



14
15
16
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 14

def run_list
  @run_list
end

#run_on_eventObject

Returns the value of attribute run_on_event.



15
16
17
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 15

def run_on_event
  @run_on_event
end

Instance Method Details

#config_knife(name, knife_cmd, options) ⇒ Object



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 198

def config_knife(name, knife_cmd, options)

    options.each_pair do |k, v|

        unless SSH_CREDENTIAL_KEYS.include?(k)

            arg = k.gsub(/-/, '_')

            # Fix issue where '~/' is not expanded to home dir
            v.gsub!(/~\//, Dir.home + '/') if arg.end_with?('_dir') && v.start_with?('~/')

            knife_cmd.config[arg.to_sym] = v
        end
    end

    unless @env_key_file.nil?
        env_key = IO.read(@env_key_file)
        knife_cmd.config[:secret] = env_key
    end

    ssh_user, ssh_password, ssh_identity_file = self.get_ssh_credentials(name)
    knife_cmd.config[:ssh_user] = ssh_user
    knife_cmd.config[:ssh_password] = ssh_password unless ssh_password.nil?
    knife_cmd.config[:identity_file] = ssh_identity_file unless ssh_identity_file.nil?
end

#create(index) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 71

def create(index)

    name = "#{@node_id}-#{index}"
    self.create_vm(index, name, @knife_config)

    node = Chef::Node.load(name)
    node.normal['stack_id'] = @id
    node.normal['stack_node'] = @name
    node.save

    begin
        # Wait for node to become available
        node_search("name:#{name}", StackBuilder::Common::Config.timeouts[:QUERY_TIMEOUT])                

    rescue Exception => msg
        raise StackBuilder::Common::StackBuilderError, \
            "Error waiting for node named '#{name} to be indexed in Chef Server: #{msg}"
    end

    unless @env_key_file.nil?
        env_key = IO.read(@env_key_file)
        knife_ssh( name,
            "echo '#{env_key}' > /etc/chef/encrypted_data_bag_secret\n" +
            "chmod 0600 /etc/chef/encrypted_data_bag_secret" )
    end

rescue Exception => msg
    puts("\nError creating node #{name} using knife config: #{msg}\n#{@knife_config.to_yaml}\n")
    @logger.info(msg.backtrace.join("\n\t")) if @logger.debug

    raise msg
end

#create_vm(index, name, knife_config) ⇒ Object



104
105
106
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 104

def create_vm(index, name, knife_config)
    raise StackBuilder::Common::NotImplemented, 'HostNodeManager.create_vm'
end

#delete(index) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 172

def delete(index)

    name = "#{@node_id}-#{index}"
    self.delete_vm(name, @knife_config)

    knife_cmd = Chef::Knife::NodeDelete.new
    knife_cmd.name_args = [ name ]
    knife_cmd.config[:yes] = true
    run_knife(knife_cmd)

    knife_cmd = Chef::Knife::ClientDelete.new
    knife_cmd.name_args = [ name ]
    knife_cmd.config[:yes] = true
    run_knife(knife_cmd)

rescue Exception => msg
    puts("\nError deleting node #{name} using knife config: #{msg}\n#{@knife_config.to_yaml}\n")
    @logger.info(msg.backtrace.join("\n\t")) if @logger.debug

    raise msg
end

#delete_vm(name, knife_config) ⇒ Object



194
195
196
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 194

def delete_vm(name, knife_config)
    raise StackBuilder::Common::NotImplemented, 'HostNodeManager.delete_vm'
end

#get_nameObject



38
39
40
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 38

def get_name
    @name
end

#get_scaleObject



42
43
44
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 42

def get_scale
    get_stack_node_resources
end

#get_ssh_credentials(name) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 46

def get_ssh_credentials(name)

    if @ssh_user.nil?

        raise ArgumentError, 'An ssh user is required to create ssh sessions.' \
            unless @knife_config['options'].has_key?('ssh_user')

        raise ArgumentError, 'An ssh key file or password is required to create ssh sessions.' \
            unless @knife_config['options'].has_key?('identity_file') ||
               @knife_config['options'].has_key?('ssh_password')

        @ssh_user = @knife_config['options']['ssh_user']
        @ssh_password = @knife_config['options']['ssh_password']
        @ssh_identity_file = @knife_config['options']['identity_file']
        @ssh_identity_file.gsub!(/~\//, Dir.home + '/') unless @ssh_identity_file.nil?
    end

    [ @ssh_user, @ssh_password, @ssh_identity_file ]
end

#node_attributesObject



66
67
68
69
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 66

def node_attributes
    get_stack_node_resources
    @nodes.collect { |n| n.attributes }
end

#process(index, events, attributes, target = nil) ⇒ Object



108
109
110
111
112
113
114
115
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 108

def process(index, events, attributes, target = nil)

    if target.nil?
        self.process_vm(index, events, attributes)
    else
        target.process_vm(index, events, attributes, self)
    end
end

#process_vm(index, events, attributes, node_manager = nil) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/stackbuilder/chef/stack_node_manager.rb', line 117

def process_vm(index, events, attributes, node_manager = nil)

    name = "#{@node_id}-#{index}"

    if node_manager.nil?
        run_list = @run_list
        run_on_event = @run_on_event
    else
        run_list = node_manager.run_list
        run_on_event = node_manager.run_on_event
    end

    if (events.include?('configure') || events.include?('update')) && !run_list.nil?

        log_level = (
            @logger.debug? ? 'debug' :
            @logger.info? ? 'info' :
            @logger.warn? ? 'warn' :
            @logger.error? ? 'error' :
            @logger.fatal? ? 'fatal' : 'error' )

        knife_cmd = Chef::Knife::NodeRunListSet.new
        knife_cmd.name_args = [ name, run_list ]
        run_knife(knife_cmd)

        knife_ssh( name,
            "TMPFILE=`mktemp`\n" +
            "echo '#{attributes.to_json}' > $TMPFILE\n" +
            "chef-client -l #{log_level} -j $TMPFILE\n" +
            "result=$?\n" +
            "rm -f $TMPFILE\n" +
            "exit $result" )
    else
        node = Chef::Node.load(name)
        attributes.each { |k,v| node.normal[k] = v }
        node.save
    end

    run_on_event.each_pair { |event, cmd|
        knife_ssh(name, ERB.new(cmd, nil, '-<>').result(binding)) if events.include?(event) } \
        unless run_on_event.nil?

rescue Exception => msg

    puts( "\nError processing node #{name}: #{msg} " +
        "\nEvents => #{events.collect { |e| e } .join(", ")}" +
        "\nknife config =>\n#{@knife_config.to_yaml}" +
        "\nrun list =>\n#{run_list}" +
        "\nevent scripts =>\n#{run_on_event.to_yaml}\n" )

    @logger.info(msg.backtrace.join("\n\t")) if @logger.debug

    raise msg
end