Class: OpenNebula::Role

Inherits:
Object
  • Object
show all
Defined in:
lib/models/role.rb

Overview

Service Role Class (Generic Role type)

Direct Known Subclasses

VMRole, VRRole

Constant Summary collapse

LOG_COMP =
'ROL'
STATE =
{
    'PENDING'            => 0,
    'DEPLOYING'          => 1,
    'RUNNING'            => 2,
    'UNDEPLOYING'        => 3,
    'WARNING'            => 4,
    'DONE'               => 5,
    'FAILED_UNDEPLOYING' => 6,
    'FAILED_DEPLOYING'   => 7,
    'SCALING'            => 8,
    'FAILED_SCALING'     => 9,
    'COOLDOWN'           => 10,
    'HOLD'               => 11
}
STATE_STR =
[
    'PENDING',
    'DEPLOYING',
    'RUNNING',
    'UNDEPLOYING',
    'WARNING',
    'DONE',
    'FAILED_UNDEPLOYING',
    'FAILED_DEPLOYING',
    'SCALING',
    'FAILED_SCALING',
    'COOLDOWN',
    'HOLD'
]
FAILURE_STATES =
[
    'BOOT_FAILURE',
    'BOOT_MIGRATE_FAILURE',
    'PROLOG_MIGRATE_FAILURE',
    'PROLOG_FAILURE',
    'EPILOG_FAILURE',
    'EPILOG_STOP_FAILURE',
    'EPILOG_UNDEPLOY_FAILURE',
    'PROLOG_MIGRATE_POWEROFF_FAILURE',
    'PROLOG_MIGRATE_SUSPEND_FAILURE',
    'PROLOG_MIGRATE_UNKNOWN_FAILURE',
    'BOOT_UNDEPLOY_FAILURE',
    'BOOT_STOPPED_FAILURE',
    'PROLOG_RESUME_FAILURE',
    'PROLOG_UNDEPLOY_FAILURE'
]
RECOVER_DEPLOY_STATES =
[
    'FAILED_DEPLOYING',
    'DEPLOYING',
    'PENDING'
]
RECOVER_UNDEPLOY_STATES =
[
    'FAILED_UNDEPLOYING',
    'UNDEPLOYING'
]
RECOVER_SCALE_STATES =
[
    'FAILED_SCALING',
    'SCALING'
]
SCALE_WAYS =
{
    'UP'   => 0,
    'DOWN' => 1
}
SCHEDULE_ACTIONS =

Actions that can be performed on the VMs of a given Role

[
    'terminate',
    'terminate-hard',
    'undeploy',
    'undeploy-hard',
    'hold',
    'release',
    'stop',
    'suspend',
    'resume',
    'reboot',
    'reboot-hard',
    'poweroff',
    'poweroff-hard',
    'snapshot-create',
    'snapshot-revert',
    'snapshot-delete',
    'disk-snapshot-create',
    'disk-snapshot-revert',
    'disk-snapshot-delete'
]
VM_INFO =

Information to save in document

['ID', 'UID', 'GID', 'UNAME', 'GNAME', 'NAME']
IMMUTABLE_ATTRS =

List of attributes that can’t be changed in update operation last_vmname: this is internal information managed by OneFlow server nodes: this is internal information managed by OneFlow server parents: this has only sense in deploy operation state: this is internal information managed by OneFlow server template_id: this will affect scale operation cardinality: this is internal information managed by OneFlow server

[
    'cardinality',
    'last_vmname',
    'nodes',
    'parents',
    'state',
    'template_id'
]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(body, service) ⇒ Role

Returns a new instance of Role.



203
204
205
206
207
208
209
# File 'lib/models/role.rb', line 203

def initialize(body, service)
    @body    = body
    @service = service

    @body['nodes']  ||= []
    @body['on_hold']  = false if @body['on_hold'].nil?
end

Instance Attribute Details

#serviceObject (readonly)

Returns the value of attribute service.



33
34
35
# File 'lib/models/role.rb', line 33

def service
  @service
end

Class Method Details

.for(body, service) ⇒ Role

Return a role object based on type attribute of the role template

Parameters:

  • Role (Hash)

    template in Hash format

Returns:

  • (Role)

    Role object type



150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/models/role.rb', line 150

def for(body, service)
    role_type = body.fetch('type', 'vm')

    case role_type.downcase
    when 'vm'
        VMRole.new(body, service)
    when 'vr'
        VRRole.new(body, service)
    else
        raise "Unsupported role type: #{role_type}"
    end
end

.init_default_cooldown(default_cooldown) ⇒ Object

rubocop:disable Style/ClassVars



180
181
182
# File 'lib/models/role.rb', line 180

def init_default_cooldown(default_cooldown)
    @@default_cooldown = default_cooldown
end

.init_default_shutdown(shutdown_action) ⇒ Object



184
185
186
# File 'lib/models/role.rb', line 184

def init_default_shutdown(shutdown_action)
    @@default_shutdown = shutdown_action
end

.init_default_vm_name_template(vm_name_template) ⇒ Object



192
193
194
# File 'lib/models/role.rb', line 192

def init_default_vm_name_template(vm_name_template)
    @@vm_name_template = vm_name_template
end

.init_default_vr_name_template(vr_name_template) ⇒ Object



196
197
198
# File 'lib/models/role.rb', line 196

def init_default_vr_name_template(vr_name_template)
    @@vr_name_template = vr_name_template
end

.init_force_deletion(force_deletion) ⇒ Object



188
189
190
# File 'lib/models/role.rb', line 188

def init_force_deletion(force_deletion)
    @@force_deletion = force_deletion
end

.vm_failure?(vm_state, lcm_state) ⇒ true, false

Returns true if the VM state is failure

Parameters:

  • vm_state (Integer)

    VM state

  • lcm_state (Integer)

    VM LCM state

Returns:

  • (true, false)

    True if the lcm state is one of *_FAILURE



167
168
169
170
171
172
173
174
175
176
177
# File 'lib/models/role.rb', line 167

def vm_failure?(vm_state, lcm_state)
    vm_state_str  = VirtualMachine::VM_STATE[vm_state.to_i]
    lcm_state_str = VirtualMachine::LCM_STATE[lcm_state.to_i]

    if vm_state_str == 'ACTIVE' &&
    FAILURE_STATES.include?(lcm_state_str)
        return true
    end

    false
end

Instance Method Details

#any_parent_on_hold?Boolean

Checks if any parent role is currently on hold.

Returns:

  • (Boolean)

    Returns ‘true` if any parent role is in an `on_hold` state, `false` otherwise.



330
331
332
333
334
335
336
337
# File 'lib/models/role.rb', line 330

def any_parent_on_hold?
    parents.each do |parent|
        next unless @service.roles[parent]

        return true if @service.roles[parent].on_hold?
    end
    false
end

#batch_action(action, period, vms_per_period, args) ⇒ Object

Raises:

  • (NotImplementedError)


428
429
430
# File 'lib/models/role.rb', line 428

def batch_action(action, period, vms_per_period, args)
    raise NotImplementedError
end

#can_recover_deploy?Boolean

Determines whether the current deployment can be recovered based on its state and the states of its parent roles.

Returns:

  • (Boolean)

    Returns ‘true` if the deployment can be recovered, `false` otherwise.



519
520
521
522
523
524
525
526
527
528
529
530
531
# File 'lib/models/role.rb', line 519

def can_recover_deploy?
    if state != STATE['PENDING']
        return RECOVER_DEPLOY_STATES.include? STATE_STR[state]
    end

    parents.each do |parent|
        next unless @service.roles[parent]

        return false if @service.roles[parent].state != STATE['RUNNING']
    end

    true
end

#can_recover_scale?Boolean

Returns:

  • (Boolean)


553
554
555
556
557
# File 'lib/models/role.rb', line 553

def can_recover_scale?
    return false unless RECOVER_SCALE_STATES.include? STATE_STR[state]

    true
end

#can_recover_undeploy?Boolean

Determines if the current deployment can be recovered and undeployed based on its state and the states of its child roles.

Returns:

  • (Boolean)

    Returns ‘true` if the deployment can be recovered and undeployed, `false` otherwise.



537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
# File 'lib/models/role.rb', line 537

def can_recover_undeploy?
    if !RECOVER_UNDEPLOY_STATES.include? STATE_STR[state]
        # TODO, check childs if !empty? check if can be undeployed
        @service.roles.each do |role_name, role|
            next if role_name == name

            if role.parents.include?(name) &&
               role.state != STATE['DONE']
                return false
            end
        end
    end

    true
end

#can_release?Boolean

Checks if the current role is in a state where it can be released.

Returns:

  • (Boolean)

    Returns ‘true` if the current state is `HOLD`, `false` otherwise.



384
385
386
# File 'lib/models/role.rb', line 384

def can_release?
    state == STATE['HOLD']
end

#cardinalityInteger

Returns the role cardinality

Returns:

  • (Integer)

    the role cardinality



288
289
290
# File 'lib/models/role.rb', line 288

def cardinality
    @body['cardinality'].to_i
end

#cardinality=(target_cardinality) ⇒ Object

Sets a new cardinality for this role

Parameters:

  • the (Integer)

    new cardinality



294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/models/role.rb', line 294

def cardinality=(target_cardinality)
    if target_cardinality > cardinality
        dir = 'up'
    else
        dir = 'down'
    end

    msg = "Role #{name} scaling #{dir} from #{cardinality} to " \
          "#{target_cardinality} nodes"

    Log.info(LOG_COMP, msg, @service.id)
    @service.log_info(msg)

    @body['cardinality'] = target_cardinality.to_i
end

#check_new_template(template) ⇒ Boolean, String

Check that changes values are correct

Parameters:

  • template_json (String)

    New template

Returns:

  • (Boolean, String)

    True, nil if everything is correct False, attr if attr was changed



406
407
408
409
410
411
412
413
414
# File 'lib/models/role.rb', line 406

def check_new_template(template)
    IMMUTABLE_ATTRS.each do |attr|
        next if template[attr] == @body[attr]

        return [false, "role/#{attr}"]
    end

    [true, nil]
end

#chown(uid, gid) ⇒ Object

Raises:

  • (NotImplementedError)


388
389
390
# File 'lib/models/role.rb', line 388

def chown(uid, gid)
    raise NotImplementedError
end

#clean_scale_wayObject



476
477
478
# File 'lib/models/role.rb', line 476

def clean_scale_way
    return NotImplementedError
end

#cooldownObject

Raises:

  • (NotImplementedError)


464
465
466
# File 'lib/models/role.rb', line 464

def cooldown
    raise NotImplementedError
end

#deployObject

Deployment

Raises:

  • (NotImplementedError)


484
485
486
# File 'lib/models/role.rb', line 484

def deploy
    raise NotImplementedError
end

#elasticity_policiesObject

Raises:

  • (NotImplementedError)


456
457
458
# File 'lib/models/role.rb', line 456

def elasticity_policies
    raise NotImplementedError
end

#info_nodes(vm_pool) ⇒ Object



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/models/role.rb', line 249

def info_nodes(vm_pool)
    ret = []

    monitoring = vm_pool[:monitoring]
    vm_pool    = vm_pool[:vm_pool]

    @body['nodes'].each do |node|
        id = node['deploy_id']
        vm = vm_pool.retrieve_xmlelements("/VM_POOL/VM[ID=#{id}]")[0]

        if vm.nil?
            Log.error LOG_COMP,
                      "Error getting VM #{id}",
                      @service.id
        else
            obj = {}
            obj['deploy_id'] = node['deploy_id']

            hash     = vm.to_hash
            vm_monit = monitoring.select {|v| v['ID'].to_i == id }[0]

            hash['VM']['MONITORING'] = vm_monit if vm_monit
            obj['vm_info']           = hash

            ret << obj
        end
    end

    ret
end

#max_cardinalityInteger?

Returns the role max cardinality

Returns:

  • (Integer, nil)

    the role cardinality or nil if it isn’t defined

Raises:

  • (NotImplementedError)


438
439
440
# File 'lib/models/role.rb', line 438

def max_cardinality
    raise NotImplementedError
end

#min_cardinalityInteger?

Returns the role min cardinality

Returns:

  • (Integer, nil)

    the role cardinality or nil if it isn’t defined

Raises:

  • (NotImplementedError)


444
445
446
# File 'lib/models/role.rb', line 444

def min_cardinality
    raise NotImplementedError
end

#nameObject



211
212
213
# File 'lib/models/role.rb', line 211

def name
    @body['name']
end

#nodesArray

Returns the nodes of the role

Returns:

  • (Array)

    the nodes



241
242
243
# File 'lib/models/role.rb', line 241

def nodes
    @body['nodes']
end

#nodes_idsObject



245
246
247
# File 'lib/models/role.rb', line 245

def nodes_ids
    @body['nodes'].map {|node| node['deploy_id'] }
end

#on_hold=(on_hold) ⇒ Object

Change the ‘on_hold` option value



311
312
313
# File 'lib/models/role.rb', line 311

def on_hold=(on_hold)
    @body['on_hold'] = on_hold
end

#on_hold?true, false

Returns the ‘on_hold` role option

Returns:

  • (true, false)

    ‘true` if the `on_hold` option is enabled



317
318
319
# File 'lib/models/role.rb', line 317

def on_hold?
    @body['on_hold']
end

#parentsArray

Returns the role parents

Returns:

  • (Array)

    the role parents



282
283
284
# File 'lib/models/role.rb', line 282

def parents
    @body['parents'] || []
end

#recover_deploy(report) ⇒ Object



559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
# File 'lib/models/role.rb', line 559

def recover_deploy(report)
    nodes = @body['nodes']
    deployed_nodes = []

    nodes.each do |node|
        vm_id = node['deploy_id']

        vm = OpenNebula::VirtualMachine.new_with_id(vm_id,
                                                    @service.client)

        rc = vm.info

        if OpenNebula.is_error?(rc)
            msg = "Role #{name} : Retry failed for VM "\
                  "#{vm_id}; #{rc.message}"
            Log.error LOG_COMP, msg, @service.id

            next true
        end

        vm_state = vm.state
        lcm_state = vm.lcm_state

        # ACTIVE/RUNNING
        next false if vm_state == 3 && lcm_state == 3 && !report

        next true if vm_state == '6' # Delete DONE nodes

        if Role.vm_failure?(vm_state, lcm_state)
            rc = vm.recover(2)

            if OpenNebula.is_error?(rc)
                msg = "Role #{name} : Retry failed for VM "\
                      "#{vm_id}; #{rc.message}"

                Log.error LOG_COMP, msg, @service.id
                @service.log_error(msg)
            else
                deployed_nodes << vm_id
            end
        else
            vm.resume

            deployed_nodes << vm_id
        end
    end

    rc = deploy

    unless rc[0]
        return [false, "Error deploying nodes for role `#{name}`"]
    end

    deployed_nodes.concat(rc[0])

    deployed_nodes
end

#recover_scaleObject

Raises:

  • (NotImplementedError)


627
628
629
# File 'lib/models/role.rb', line 627

def recover_scale
    raise NotImplementedError
end

#recover_undeployObject



617
618
619
620
621
622
623
624
625
# File 'lib/models/role.rb', line 617

def recover_undeploy
    undeployed_nodes = []

    rc = shutdown(true)

    undeployed_nodes.concat(rc[0]) if rc[1].nil?

    undeployed_nodes
end

#releaseArray, Bool

Release all the nodes in this role

Returns:

  • (Array, Bool)

    true if all the VMs were released, false otherwise and Array with VMs released



346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/models/role.rb', line 346

def release
    release_nodes = []
    success       = true

    # Release all vms in the role
    nodes.each do |node|
        vm_id = node['deploy_id']

        Log.debug(LOG_COMP,
                  "Role #{name}: Releasing VM #{vm_id}",
                  @service.id)

        vm = OpenNebula::VirtualMachine.new_with_id(vm_id,
                                                    @service.client)
        rc = vm.release

        if OpenNebula.is_error?(rc)
            msg = "Role #{name}: Release failed for VM #{vm_id}, " \
                  "#{rc.message}"

            Log.error(LOG_COMP, msg, @service.id)
            @service.log_error(msg)
            success = false
        else
            Log.debug(LOG_COMP,
                      "Role #{name}: Release success for VM #{vm_id}",
                      @service.id)

            release_nodes << vm_id
        end
    end

    [release_nodes, success]
end

#scale?(vm_pool) ⇒ Array<Integer>

Returns a positive, 0, or negative number of nodes to adjust,

according to the elasticity and scheduled policies

Returns:

  • (Array<Integer>)

    positive, 0, or negative number of nodes to adjust, plus the cooldown period duration

Raises:

  • (NotImplementedError)


452
453
454
# File 'lib/models/role.rb', line 452

def scale?(vm_pool)
    raise NotImplementedError
end

#scale_way(_) ⇒ Object



472
473
474
# File 'lib/models/role.rb', line 472

def scale_way(_)
    return NotImplementedError
end

#scheduled_policiesObject

Scheduler



420
421
422
# File 'lib/models/role.rb', line 420

def scheduled_policies
    @body['scheduled_policies']
end

#service_on_hold?true, false

Returns the ‘on_hold` service option

Returns:

  • (true, false)

    ‘true` if the `on_hold` option is enabled



323
324
325
# File 'lib/models/role.rb', line 323

def service_on_hold?
    @service.on_hold?
end

#shutdown(recover) ⇒ Array<true, nil>, Array<false, String>

Terminate all the nodes in this role

Parameters:

  • scale_down (true, false)

    true to terminate and dispose the number of VMs needed to get down to cardinality nodes

Returns:

  • (Array<true, nil>, Array<false, String>)

    true if all the VMs were terminated, false and the error reason if there was a problem shutting down the VMs



495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# File 'lib/models/role.rb', line 495

def shutdown(recover)
    if nodes.size != cardinality
        n_nodes = nodes.size - cardinality
    else
        n_nodes = nodes.size
    end

    rc = shutdown_nodes(nodes, n_nodes, recover)

    unless rc[0]
        return [false, "Error undeploying nodes for role `#{name}`"]
    end

    [rc[1], nil]
end

#stateObject



215
216
217
# File 'lib/models/role.rb', line 215

def state
    @body['state']
end

#state=(state) ⇒ Object

Sets a new state

Parameters:

  • the (Integer)

    new state



221
222
223
224
225
226
227
228
229
230
231
# File 'lib/models/role.rb', line 221

def state=(state)
    return if state < 0 || state > STATE_STR.size

    @body['state'] = state.to_i

    Log.info(
        LOG_COMP,
        "Role #{name} new state: #{STATE_STR[state]}",
        @service.id
    )
end

#state_strString

Returns the string representation of the service state

Returns:

  • (String)

    the state string



235
236
237
# File 'lib/models/role.rb', line 235

def state_str
    STATE_STR[state]
end

#update(template) ⇒ nil, OpenNebula::Error

Updates the role

Parameters:

Returns:

Raises:

  • (NotImplementedError)


396
397
398
# File 'lib/models/role.rb', line 396

def update(template)
    raise NotImplementedError
end

#update_cooldown(new_cooldown) ⇒ Object

Raises:

  • (NotImplementedError)


468
469
470
# File 'lib/models/role.rb', line 468

def update_cooldown(new_cooldown)
    raise NotImplementedError
end

#update_elasticity_policies(new_policies) ⇒ Object

Raises:

  • (NotImplementedError)


460
461
462
# File 'lib/models/role.rb', line 460

def update_elasticity_policies(new_policies)
    raise NotImplementedError
end

#update_scheduled_policies(new_policies) ⇒ Object



424
425
426
# File 'lib/models/role.rb', line 424

def update_scheduled_policies(new_policies)
    @body['scheduled_policies'] = new_policies
end