Top Level Namespace

Defined Under Namespace

Modules: Deferable, IONeLoggerKit, ONeHelper, OpenNebula Classes: AR, AnsiblePlaybook, AnsiblePlaybookProcess, Array, Biller, Billing, CapacityBiller, DiskBiller, DiskRecord, EmptyQuery, Hash, IONe, IPAddr, NilClass, Record, RecordsSource, SnapshotRecord, SnapshotsBiller, String, Timeline, TrafficBiller, TrafficRecord, VLAN, VLANLease

Constant Summary collapse

STARTUP_TIME =

Server start-up time

Time.now().to_i
INIT_IONE =

IONe server start time

true
ALPINE =
ENV["ALPINE"] == 'true'
ONE_LOCATION =

OpenNebula Ruby files location

ENV["ONE_LOCATION"]
LOG_LOCATION =

OpenNebula(and IONe) Logs location

"/var/log/one"
VAR_LOCATION =

OpenNebula home

"/var/lib/one"
ETC_LOCATION =

OpenNebula configs location

"/etc/one"
ROOT_DIR =

IONe source location

File.dirname(__FILE__)
ROOT =

IONe root path

ENV['IONEROOT']
LOG_ROOT =

IONe logs path

LOG_LOCATION
MAIN_IONE =

Shows if current IONe Sunstone process was started by systemd(first time so). True or False

Process.ppid == 1
CONF =

for sure

$ione_conf
VERSION =

IONe version

File.read("#{ROOT}/meta/version.txt")
CREDENTIALS =

OpenNebula credentials

ALPINE ? ENV["ONE_CREDENTIALS"] : File.read(VAR_LOCATION + "/.one/one_auth").chomp
ENDPOINT =

XML_RPC endpoint where OpenNebula is listening

ALPINE ? ENV["ONE_ENDPOINT"] : "http://localhost:#{$oned_conf.get('PORT')}/RPC2"
RPC_LOGGER =

Logger instance for rpc calls

Logger.new(rpc_log_file)
ANSIBLE_HOST =

Hostname or IP-address of host where ansible installed

$ione_conf['AnsibleServer']['host']
ANSIBLE_HOST_PORT =

Ansible-host SSH-port

$ione_conf['AnsibleServer']['port']
ANSIBLE_HOST_USER =

SSH user to user

$ione_conf['AnsibleServer']['user']

Constants included from ONeHelper

ONeHelper::ON_INSTANCES, ONeHelper::ON_INSTANCE_POOLS, ONeHelper::VIM

Constants included from IONeLoggerKit

IONeLoggerKit::DESTINATIONS

Instance Method Summary collapse

Methods included from ONeHelper

#ChooseDS, #ClusterType, #get_ds_vdata, #get_vcenter_dc, #onblock, #putc, #recursive_find_ds, #recursive_find_vm

Methods included from IONeLoggerKit

#LOG, #LOG_AUTO, #LOG_COLOR, #LOG_DEBUG, #id_gen

Instance Method Details

#class_from_string(str) ⇒ Object

Generates class from string class-name



4
5
6
7
8
# File 'lib/ione-scheduler/main.rb', line 4

def class_from_string(str)
  str.split('::').inject(Object) do |mod, class_name|
    mod.const_get(class_name)
  end
end

#DELETE '/ansible/:id'Object

Deletes given playbook



37
38
39
40
41
42
43
44
45
46
47
48
# File 'routes/ansible.rb', line 37

delete '/ansible/:id' do |id|
  begin
    data = { 'action' => { 'perform' => 'delete', 'params' => nil } }
    pb = AnsiblePlaybookModel.new(id: id, data: data, user: @one_user)

    r response: pb.call
  rescue JSON::ParserError # If JSON.parse fails
    r error: "Broken data received, unable to parse."
  rescue => e
    r error: e.message, backtrace: e.backtrace
  end
end

#DELETE '/ansible_process/:id'Object

Deletes given playbook process



47
48
49
50
51
52
53
54
55
56
57
58
# File 'routes/ansible_process.rb', line 47

delete '/ansible_process/:id' do |id|
  begin
    data = { 'action' => { 'perform' => 'delete', 'params' => nil } }
    pb = AnsiblePlaybookProcessModel.new(id: id, data: data, user: @one_user)

    r response: pb.call
  rescue JSON::ParserError # If JSON.parse fails
    r error: "Broken data received, unable to parse."
  rescue => e
    r error: e.message, backtrace: e.backtrace
  end
end

#DELETE '/settings/:key'Object



50
51
52
53
54
55
56
57
58
# File 'routes/settings.rb', line 50

delete '/settings/:key' do | key |
  begin
    raise StandardError.new("NoAccess") unless env[:one_user].admin?

    json response: SETTINGS_TABLE.where(name: key).delete
  rescue => e
    json error: e.message
  end
end

#DELETE '/vlan/:id/delete'Object

Note:

All Leases gotta be deleted

Deletes VLAN pool



62
63
64
65
66
67
68
69
70
71
# File 'routes/vlan_manager.rb', line 62

delete '/vlan/:id/delete' do | pool_id |
  begin
    raise StandardError.new("NoAccess") unless @one_user.admin?

    VLAN.where(id: pool_id).delete
    json response: true
  rescue => e
    json error: e.message
  end
end

#DELETE '/vlan/:id/lease/:lid'Object

Delete VLANLease

See Also:



101
102
103
104
105
106
107
108
109
# File 'routes/vlan_manager.rb', line 101

delete '/vlan/:id/lease/:lid' do | id, vlan_id |
  begin
    raise StandardError.new("NoAccess") unless @one_user.admin?

    json response: VLANLease.where(pool_id: id, id: vlan_id).release
  rescue => e
    json error: e.message
  end
end

#fmt_time(sec) ⇒ String

Formats time from seconds from the start of Time to dd:hh:mm:ss format

Parameters:

  • sec (Integer)

Returns:



4
5
6
7
8
9
10
11
12
# File 'service/time.rb', line 4

def fmt_time(sec)
  sec = sec.to_i
  days = (sec / 86400).to_i
  sec -= days * 86400
  hours = (sec / 3600.0).to_i
  sec -= hours * 3600
  minutes = (sec / 60.0).to_i
  "#{days}d:#{hours}h:#{minutes}m:#{sec % 60}s"
end

#GET '/ansible'Object

Returns full Ansible Playbooks pool



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'routes/ansible.rb', line 4

get '/ansible' do
  begin
    pool = IONe.new($client, $db).ListAnsiblePlaybooks # Array of playbooks
    pool.delete_if { |pb| !ansible_check_permissions(pb, @one_user, 0) } # Deletes playbooks, which aren't under user access
    pool.map! do | pb | # Adds user and group name to every object
      user, group = OpenNebula::User.new_with_id(pb['uid'], @client),
                OpenNebula::Group.new_with_id(pb['gid'], @client)
      user.info!; group.info!
      pb['vars'] = IONe.new($client, $db).GetAnsiblePlaybookVariables(pb['id'])
      pb.merge(
        'uname' => user.name, 'gname' => group.name,
        'vars' => pb['vars'].nil? ? {} : pb['vars']
      )
    end
    r response: pool
  rescue => e
    r error: e.message, backtrace: e.backtrace
  end
end

#GET '/ansible/:id'Object

Returns playbook



51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'routes/ansible.rb', line 51

get '/ansible/:id' do | id |
  begin
    pb = AnsiblePlaybookModel.new(id: id, user: @one_user) # Getting playbook
    # Saving user and group to objects
    user, group = OpenNebula::User.new_with_id(pb.body['uid'], @client),
              OpenNebula::Group.new_with_id(pb.body['gid'], @client)
    user.info!; group.info! # Retrieving information about this objects from ONe
    pb.body.merge!('uname' => user.name, 'gname' => group.name, 'vars' => pb.vars.nil? ? {} : pb.vars) # Adding user and group names to playbook body

    r response: pb.body
  rescue => e
    r error: e.message, backtrace: e.backtrace
  end
end

#GET '/ansible/:id/vars'Object

I think it's not needed here, rly



67
68
69
70
71
72
73
74
# File 'routes/ansible.rb', line 67

get '/ansible/:id/vars' do | id |
  begin
    pb = AnsiblePlaybookModel.new(id: id, data: { 'action' => { 'perform' => 'vars' } }, user: @one_user)
    r vars: pb.call
  rescue => e
    r error: e.message, backtrace: e.backtrace
  end
end

#GET '/ansible_process'Object

Returns full Ansible Playbooks Processes pool



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'routes/ansible_process.rb', line 4

get '/ansible_process' do
  begin
    pool = IONe.new(@client, $db).ListAnsiblePlaybookProcesses
    pool.delete_if { |apc| !@one_user.groups.include?(0) && apc['uid'] != @one_user.id }
    pool.map! do | apc | # Adds user name to every object
      user =  OpenNebula::User.new_with_id(apc['uid'], @client)
      user.info!
      apc.merge('id' => apc['proc_id'], 'uname' => user.name)
    end

    r response: pool
  rescue => e
    r error: e.message, backtrace: e.backtrace
  end
end

#GET '/ansible_process/:id'Object

Returns playbook process data



33
34
35
36
37
38
39
40
41
42
43
44
# File 'routes/ansible_process.rb', line 33

get '/ansible_process/:id' do |id|
  begin
    apc = AnsiblePlaybookProcessModel.new(id: id, user: @one_user) # Getting playbook
    # Saving user and group to objects
    user = OpenNebula::User.new_with_id(apc.body['uid'], @client)
    user.info!
    apc.body.merge!('id' => apc.body['proc_id'], 'uname' => user.name) # Retrieving information about this objects from ONe
    r response: apc.body
  rescue => e
    r error: e.message, backtrace: e.backtrace
  end
end

#GET '/settings'Object



1
2
3
4
5
6
7
8
9
10
11
12
# File 'routes/settings.rb', line 1

get '/settings' do
  begin
    begin
      access_level = env[:one_user].admin? ? 1 : 0
    rescue
      access_level = 0
    end
    json response: SETTINGS_TABLE.where(Sequel.lit('access_level <= ?', access_level)).to_a
  rescue => e
    json error: e.message
  end
end

#GET '/settings/:key'Object



14
15
16
17
18
19
20
21
22
23
24
25
# File 'routes/settings.rb', line 14

get '/settings/:key' do | key |
  begin
    begin
      access_level = env[:one_user].admin? ? 1 : 0
    rescue
      access_level = 0
    end
    json response: SETTINGS_TABLE.where(Sequel.lit('access_level <= ?', access_level)).where(name: key).to_a.last
  rescue => e
    json error: e.message
  end
end

#GET '/vlan'Object

Endpoint returns all VLAN pools

See Also:



19
20
21
22
23
24
25
26
27
# File 'routes/vlan_manager.rb', line 19

get '/vlan' do
  begin
    raise StandardError.new("NoAccess") unless @one_user.admin?

    json response: VLAN.all_with_meta
  rescue => e
    json error: e.message
  end
end

#GET '/vlan/:id'Object

Get particular VLAN pool object



50
51
52
53
54
55
56
57
58
# File 'routes/vlan_manager.rb', line 50

get '/vlan/:id' do | pool_id |
  begin
    raise StandardError.new("NoAccess") unless @one_user.admin?

    json response: VLAN.where(id: pool_id).first.hash_with_meta_and_leases
  rescue => e
    json error: e.message
  end
end

#Invoke(action) ⇒ Object

Invokes scheduled action



34
35
36
37
# File 'lib/ione-scheduler/main.rb', line 34

def Invoke(action)
  Unschedule(action['id'])
  IONe.new($client, $db).send(action['method'], *(JSON.parse(action['params'])))
end

#POST '/ansible'Object

Allocates new playbook



25
26
27
28
29
30
31
32
33
34
# File 'routes/ansible.rb', line 25

post '/ansible' do
  begin
    r response: AnsiblePlaybookModel.new(id: nil, data: @request_hash, user: @one_user).id
  rescue JSON::ParserError # If JSON.parse fails
    r error: "Broken data received, unable to parse."
  rescue => e
    @one_user.info!
    r error: e.message, backtrace: e.backtrace, data: data
  end
end

#POST '/ansible/:action'Object

Performs actions, which are defined as def self.method for AnsiblePlaybookModel model



90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'routes/ansible.rb', line 90

post '/ansible/:action' do | action |
  begin
    if action == 'check_syntax' then
      r response: IONe.new($client, $db).CheckAnsiblePlaybookSyntax(@request_hash['body'])
    else
      r response: "Action is not defined"
    end
  rescue JSON::ParserError # If JSON.parse fails
    r error: "Broken data received, unable to parse."
  rescue => e
    r error: e.message, backtrace: e.backtrace
  end
end

#POST '/ansible/:id/action'Object

Performs action on AnsiblePlaybook



77
78
79
80
81
82
83
84
85
86
87
# File 'routes/ansible.rb', line 77

post '/ansible/:id/action' do | id |
  begin
    pb = AnsiblePlaybookModel.new(id: id, data: @request_hash, user: @one_user)

    r response: pb.call
  rescue JSON::ParserError # If JSON.parse fails
    r error: "Broken data received, unable to parse."
  rescue => e
    r error: e.message, backtrace: e.backtrace
  end
end

#POST '/ansible_process'Object

Allocates new process



21
22
23
24
25
26
27
28
29
30
# File 'routes/ansible_process.rb', line 21

post '/ansible_process' do
  begin
    r response: AnsiblePlaybookProcessModel.new(id: nil, data: @request_hash, user: @one_user).id
  rescue JSON::ParserError # If JSON.parse fails
    r error: "Broken data received, unable to parse."
  rescue => e
    @one_user.info!
    r error: e.message, backtrace: e.backtrace, data: data
  end
end

#POST '/ansible_process/:id/action'Object

Performs action on AnsiblePlaybookProcess



61
62
63
64
65
66
67
68
69
70
71
# File 'routes/ansible_process.rb', line 61

post '/ansible_process/:id/action' do | id |
  begin
    pb = AnsiblePlaybookProcessModel.new(id: id, data: @request_hash, user: @one_user)

    r response: pb.call
  rescue JSON::ParserError # If JSON.parse fails
    r error: "Broken data received, unable to parse."
  rescue => e
    r error: e.message, backtrace: e.backtrace
  end
end

#POST '/hooks/:hook'Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'routes/hooks.rb', line 4

post '/hooks/:hook' do | hook |
  addr = IPAddr.new(request.env['REMOTE_ADDR'])
  unless addr.private? || addr.loopback? then
    halt 403
  end
  hook = "#{ROOT_DIR}/hooks/#{hook}"
  unless File.exist? hook then
    halt 400, { 'Content-Type' => 'application/json' }, { error: "Script doesn't exist" }.to_json
  end

  cmd = "#{RbConfig.ruby} #{hook} #{@request_hash['params'].join(' ')}"
  stdout, stderr, status = Open3.capture3(cmd)
  json hook: hook, stdout: stdout, stderr: stderr, status: status.exitstatus
end

#POST '/ione/:method'Object

Endpoint to invoke IONe methods

Examples:

Request:

POST /ione/Test
    Headers:
        Authorization: Basic base64_encoded_credentials
    Body:
    {
        "params": [ "PING" ]
    }
Response:
    200 - { "response": "PONG" }

See Also:



314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'ione_server.rb', line 314

post '/ione/:method' do | method |
  begin
    RPC_LOGGER.info "IONeAPI calls proxy method #{method}(#{@request_hash['params'].collect { |p| p.inspect }.join(", ")})"
    r = IONe.new(@client, $db).send(method, *@request_hash['params'])
  rescue => e
    r = e.message
    backtrace = e.backtrace
  ensure
    r = { error: r.message } if OpenNebula.is_error? r
  end
  err = defined?(backtrace) && !backtrace.nil?
  RPC_LOGGER.info "IONeAPI sends response #{r.inspect}"
  RPC_LOGGER.info "Backtrace #{backtrace.inspect}" if err
  json response: r
end

#POST '/ione_showback'Object



1
2
3
4
5
6
7
8
9
# File 'routes/showback.rb', line 1

post '/ione_showback' do
  headers['Cache-Control'] = "no-transform" # Disables Rack::Deflater

  data = JSON.parse(@request_body)
  uid, stime, etime, group_by_day = data['uid'], data['stime'], data['etime'], data['group_by_day'] || false
  stream do | out |
    out << '{"response":' << "{" << IONe.new($client, $db).CalculateShowback(uid, stime, etime, group_by_day, out) << "}}"
  end
end

#POST '/ione_showback/v2'Object



11
12
13
14
15
16
17
18
19
# File 'routes/showback.rb', line 11

post '/ione_showback/v2' do
  headers['Cache-Control'] = "no-transform" # Disables Rack::Deflater

  data = JSON.parse(@request_body)
  uid, stime, etime, group_by_day = data['uid'], data['stime'], data['etime'], data['group_by_day'] || false
  stream do | out |
    out << '{"response":' << "{" << IONe.new($client, $db).calculate_showback(uid, stime, etime, group_by_day, out) << "}}"
  end
end

#POST '/settings'Object



27
28
29
30
31
32
33
34
35
36
# File 'routes/settings.rb', line 27

post '/settings' do
  begin
    raise StandardError.new("NoAccess") unless env[:one_user].admin?

    data = JSON.parse(@request_body)
    json response: SETTINGS_TABLE.insert(**data.to_sym!)
  rescue => e
    json error: e.message
  end
end

#POST '/settings/:key'Object



38
39
40
41
42
43
44
45
46
47
48
# File 'routes/settings.rb', line 38

post '/settings/:key' do | key |
  begin
    raise StandardError.new("NoAccess") unless env[:one_user].admin?

    data = JSON.parse(@request_body)
    data = data.to_sym!
    json response: SETTINGS_TABLE.where(name: key).update(name: key, **data)
  rescue => e
    json error: e.message
  end
end

#POST '/vlan'Object

Endpoint for VLAN pool creation

Required body with following scheme:
{
  "start": Integer
  "size" : Integer
  "type" : String
}


36
37
38
39
40
41
42
43
44
45
46
# File 'routes/vlan_manager.rb', line 36

post '/vlan' do
  begin
    raise StandardError.new("NoAccess") unless @one_user.admin?

    data = JSON.parse(@request_body)
    id = VLAN.insert(**data.to_sym!)
    json response: id
  rescue => e
    json error: e.message
  end
end

#POST '/vlan/:id/lease'Object

Create Lease and VNet with VLAN ID from given VLAN pool

See Also:



75
76
77
78
79
80
81
82
83
84
# File 'routes/vlan_manager.rb', line 75

post '/vlan/:id/lease' do | pool_id |
  begin
    raise StandardError.new("NoAccess") unless @one_user.admin?

    data = JSON.parse(@request_body)
    json response: VLAN.where(id: pool_id).first.lease(*data['params'])
  rescue => e
    json error: e.message
  end
end

#POST '/vlan/:id/reserve'Object

Create Lease without VNet or bind to existing VNet

See Also:

  • VLAN@reserve


88
89
90
91
92
93
94
95
96
97
# File 'routes/vlan_manager.rb', line 88

post '/vlan/:id/reserve' do | pool_id |
  begin
    raise StandardError.new("NoAccess") unless @one_user.admin?

    data = JSON.parse(@request_body)
    json response: VLAN.where(id: pool_id).first.reserve(*data['params'])
  rescue => e
    json error: e.message
  end
end

#POST %r{/one\.(\w+)\.(\w+)(\!|\=)?}Object

Endpoint to invoke ONe Instances methods

Examples:

Request:

POST /one.vm.name
    Headers:
        Authorization: Basic base64_encoded_credentials
    Body:
    {
        "oid": 777,
        "params": [ ]
    }
Response:
    200 - { "response": "one-vm-777-name" }

See Also:

  • ONeHelper#onblock-instance_method


344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'ione_server.rb', line 344

post %r{/one\.(\w+)\.(\w+)(\!|\=)?} do | object, method, excl |
  begin
    RPC_LOGGER.info "ONeAPI calls proxy object method one.#{object}.#{method}(#{@request_hash['params'].collect { |p| p.inspect }.join(", ")})"
    r = onblock(object.to_sym, @request_hash['oid'], @client).send(method.to_s << excl.to_s, *@request_hash['params'])
  rescue => e
    r = e.message
    backtrace = e.backtrace
  ensure
    r = { error: r.message } if OpenNebula.is_error? r
  end
  err = defined?(backtrace) && !backtrace.nil?
  RPC_LOGGER.info "ONeAPI sends response #{r.inspect}"
  RPC_LOGGER.info "Backtrace #{backtrace.inspect}" if err
  json response: r
end

#POST %r{/one\.(\w+)\.pool\.(\w+)(\!|\=)?}Object

Endpoint to invoke ONe Pool methods

Examples:

Request:

POST /one.vm.pool.monitoring
    Headers:
        Authorization: Basic base64_encoded_credentials
    Body:
    {
        "uid": "0"  // optional
        "params": [ ]
    }
Response:
    200 - { "response": [...] }

See Also:

  • ONeHelper#onblock-instance_method


374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'ione_server.rb', line 374

post %r{/one\.(\w+)\.pool\.(\w+)(\!|\=)?} do | object, method, excl |
  begin
    RPC_LOGGER.info "ONeAPI calls proxy pool method one.#{object}.pool.#{method}(#{@request_hash['params'].collect { |p| p.inspect }.join(", ")})"
    r =
      (
        @request_hash['uid'].nil? ?
          ON_INSTANCE_POOLS[object.to_sym].new(@client) :
          ON_INSTANCE_POOLS[object.to_sym].new(@client, @request_hash['uid'])
      ).send(method.to_s << excl.to_s, *@request_hash['params'])
  rescue => e
    r = e.message
    backtrace = e.backtrace
  ensure
    r = { error: r.message } if OpenNebula.is_error? r
  end
  err = defined?(backtrace) && !backtrace.nil?
  RPC_LOGGER.info "ONeAPI sends response #{r.inspect}"
  RPC_LOGGER.info "Backtrace #{backtrace.inspect}" if err
  json response: r
end

#Schedule(time, action, *params) ⇒ Object

Schedules action



16
17
18
19
20
21
22
23
24
# File 'lib/ione-scheduler/main.rb', line 16

def Schedule(time, action, *params)
  # action = action.split('.')

  @db_client.query(
    "INSERT INTO action (method, params, time)
         VALUES ('#{action}', '#{JSON.generate(params)}', '#{time}')"
  )
  @db_client.query('SELECT * FROM action').to_a.last['id']
end

#Unschedule(id) ⇒ Object

Unschedules action



27
28
29
30
31
# File 'lib/ione-scheduler/main.rb', line 27

def Unschedule(id)
  @db_client.query(
    "DELETE FROM action WHERE id=#{id}"
  )
end