Class: AnsiblePlaybookProcess

Inherits:
Object
  • Object
show all
Defined in:
modules/ansible/db.rb

Overview

Ansible Playbook run process implementation

Constant Summary collapse

TABLE =

DB Table name

'ansible_playbook_process'
FIELDS =

DB Table columns names

%w(
    uid playbook_id install_id
    create_time start_time end_time
    status log hosts 
    vars playbook_name runnable
    comment codes run_after
)
STATUS =

Process states dictionary

{
    '0' => 'PENDING',
    '1' => 'RUNNING',
    'ok' => 'SUCCESS',
    'changed' => 'CHANGED',
    'unreachable' => 'UNREACHABLE',
    'failed' => 'FAILED',
    '6' => 'LOST',
    'done' => 'DONE'
}
DB =

Getting table object from DB object

$db[:ansible_playbook_process]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(proc_id: nil, playbook_id: nil, uid: nil, hosts: {}, vars: {}, comment: '', auth: 'default', run_after: {}) ⇒ AnsiblePlaybookProcess

hosts: { 'vmid' => [ip:port, credentials]}

"method" => "Reboot",
"params" => 777 # vmid

# So VM will be rebooted after

Examples:

Hosts example:

Run After example:

Parameters:

  • proc_id (Fixnum)
    • Process will be loaded from DB if given

  • playbook_id (Fixnum)
    • Playbook object ID to use

  • uid (Fixnum)
    • User ID who initiates the process

  • hosts (Hash)
    • see example

  • vars (Hash)
    • Variables that should be inserted in PB

  • comment (String)
    • Anything you want to tell another users or admins about this Process

  • auth (String)
    • auth driver to use, now is only one supported - default, which uses login and password pair

  • run_after (Hash)

Options Hash (run_after:):

  • method (String)
    • IONe method name to call after Ansible will end its work

  • params (Array)
    • Params for this method, see example



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
# File 'modules/ansible/db.rb', line 274

def initialize proc_id:nil, playbook_id:nil, uid:nil, hosts:{}, vars:{}, comment:'', auth:'default', run_after:{}
    if proc_id.nil? then
        @uid, @playbook_id = uid, playbook_id
        @install_id = SecureRandom.uuid + '-' + Date.today.strftime
        @create_time, @start_time, @end_time = Time.now.to_i, -1, -1
        @status = '0'
        @log = ''
        @comment = comment.to_s
        @hosts = hosts
        @vars = vars
        @playbook = AnsiblePlaybook.new(id: @playbook_id)
        @playbook_name, @runnable = @playbook.runnable(@vars).to_a[0]
        @codes = ''
        @run_after = run_after
    else
        @id = proc_id
        sync
    end
rescue
    @playbook = @playbook_name = @runnable = ''
    @status = 'done'
ensure
    allocate if @id.nil?
end

Instance Attribute Details

#end_timeObject (readonly)

Returns the value of attribute end_time



255
256
257
# File 'modules/ansible/db.rb', line 255

def end_time
  @end_time
end

#hostsObject (readonly)

Returns the value of attribute hosts



255
256
257
# File 'modules/ansible/db.rb', line 255

def hosts
  @hosts
end

#idObject (readonly)

Returns the value of attribute id



255
256
257
# File 'modules/ansible/db.rb', line 255

def id
  @id
end

#install_idObject (readonly)

Returns the value of attribute install_id



255
256
257
# File 'modules/ansible/db.rb', line 255

def install_id
  @install_id
end

#start_timeObject (readonly)

Returns the value of attribute start_time



255
256
257
# File 'modules/ansible/db.rb', line 255

def start_time
  @start_time
end

Class Method Details

.listObject

Lists all Processes from DB



440
441
442
443
444
445
446
447
# File 'modules/ansible/db.rb', line 440

def self.list
    result = DB.all
    result.map{ |pb| pb.to_s! }
    result.each do |app|
        app['status'] = STATUS[app['status']]
    end
    result
end

Instance Method Details

#deleteObject

Sets Process state to Done



407
408
409
410
411
# File 'modules/ansible/db.rb', line 407

def delete
    @status = 'done'
ensure
    update
end

#humanObject

Returns object with State to humanreadable replaced in Hash form



421
422
423
424
425
# File 'modules/ansible/db.rb', line 421

def human
    r = to_hash
    r['status'] = STATUS[r['status']]
    r
end

#run(thread = true) ⇒ Object

Start Process

Parameters:

  • thread (Boolean) (defaults to: true)
    • Runs in another Thread and returns its object if true



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'modules/ansible/db.rb', line 301

def run thread = true
    nil if STATUS.keys.index(@status) > 0
    @start_time, @status = Time.now.to_i, '1'
    
    update

    process = Proc.new do
        begin
            Net::SSH.start( ANSIBLE_HOST, ANSIBLE_HOST_USER, :port => ANSIBLE_HOST_PORT ) do | ssh |
                # Create local Playbook version
                File.open("/tmp/#{@install_id}.yml", 'w') do |file|
                    file.write( @runnable.gsub('<%group%>', @install_id) )
                end
                # Upload Playbook to Ansible host
                ssh.sftp.upload!("/tmp/#{@install_id}.yml", "/tmp/#{@install_id}.yml")
                # Create local Hosts File
                File.open("/tmp/#{@install_id}.ini", 'w') do |file|
                    file.write("[#{@install_id}]\n")
                    @hosts.values.each do |host|
                        unless host[1].nil? then
                            cred = host[1].split ':'
                            cred = "ansible_user=#{cred[0]} ansible_password=#{cred[1]}"
                        else
                            cred = ''
                        end
                        file.write("#{host[0]} #{cred}\n")
                    end
                end
                # Upload Hosts file
                ssh.sftp.upload!("/tmp/#{@install_id}.ini", "/tmp/#{@install_id}.ini")
                # Creating run log
                ssh.exec!("echo 'START' > /tmp/#{@install_id}.runlog")
                # Run Playbook
                ssh.exec!(
                    "ansible-playbook /tmp/#{@install_id}.yml -i /tmp/#{@install_id}.ini >> /tmp/#{@install_id}.runlog; echo 'DONE' >> /tmp/#{@install_id}.runlog" )
            
                @end_time = Time.now.to_i
            end
            clean
            scan
        rescue => e
            @status = 'failed'
            @log = "Internal Error:\n" + e.message + "\n---\n---\nBacktrace:\n" + e.backtrace.join("\n")
        ensure
            update
        end
    end
    if thread then
        Thread.new do
            process.call
        end
    else
        process.call
    end
ensure
    update
end

#run_afterObject

Runs method from run_after field



427
428
429
430
431
432
433
434
435
436
437
# File 'modules/ansible/db.rb', line 427

def run_after
    return if @run_after['method'].nil?

    if @run_after['params'].nil? then
        IONe.new($client, $db).send(@run_after['method'])         
    elsif @run_after['params'].class == Array then
        IONe.new($client, $db).send(@run_after['method'], *@run_after['params'])
    else
        IONe.new($client, $db).send(@run_after['method'], @run_after['params'])
    end
end

#scanObject

Note:

Normally it runs automatically, you shouldn't do it by yourself

Scans Ansible log file after its work end



360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'modules/ansible/db.rb', line 360

def scan
    return nil if STATUS.keys.index(@status) > 1
    Net::SSH.start( ANSIBLE_HOST, ANSIBLE_HOST_USER, :port => ANSIBLE_HOST_PORT ) do | ssh |
        ssh.sftp.download!("/tmp/#{@install_id}.runlog", "/tmp/#{@install_id}.runlog")
        @log = File.read("/tmp/#{@install_id}.runlog")
        if @log.split(/\n/)[-1] == 'DONE' then
            ssh.sftp.remove("/tmp/#{@install_id}.runlog")
            @log.slice!("START\n")
            @log.slice!("\nDONE\n")
        else
            @log = ""
            return
        end
    end if @log == ""

    codes = {}
    
    @log.split('PLAY RECAP').last.split(/\n/).map do | host |
        host = host.split("\n").last.split(" ")
        next if host.size == 1
        codes.store host[0], {}
        host[-4..-1].map do |code|
            code = code.split("=")
            codes[host[0]].store(code.first, code.last.to_i)
        end
    end
    
    if codes.values.inject(0){|sum, vals| sum +=  vals['failed']} != 0 then
        @status = 'failed'
    elsif codes.values.inject(0){|sum, vals| sum +=  vals['unreachable']} != 0 then
        @status = 'unreachable'
    else
        @status = codes.values.last.keys.map do | key |
            { key => codes.values.inject(0){|sum, vals| sum +=  vals[key]} }
        end.sort_by{|attribute| attribute.values.last }.last.keys.last
    end
    
    @codes = codes

    run_after
rescue => e
    puts e.message, e.backtrace
    @status = '6'
ensure
    update
end

#statusObject

Returns humanreadable Process state



413
414
415
# File 'modules/ansible/db.rb', line 413

def status
    STATUS[@status]
end

#to_hashObject

Returns object as is in Hash form



417
418
419
# File 'modules/ansible/db.rb', line 417

def to_hash
    get_me
end