wakame-vdc-agents 10.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +202 -0
- data/NOTICE +1 -0
- data/Rakefile +142 -0
- data/bin/hva +972 -0
- data/bin/nsa +147 -0
- data/bin/sta +182 -0
- data/config/hva.conf.example +10 -0
- data/config/initializers/isono.rb +43 -0
- data/config/initializers/passenger.rb +6 -0
- data/config/initializers/sequel.rb +21 -0
- data/config/nsa.conf.example +9 -0
- data/config/path_resolver.rb +12 -0
- data/lib/dcmgr.rb +115 -0
- data/lib/dcmgr/endpoints/core_api.rb +1004 -0
- data/lib/dcmgr/endpoints/core_api_mock.rb +816 -0
- data/lib/dcmgr/endpoints/errors.rb +55 -0
- data/lib/dcmgr/endpoints/metadata.rb +129 -0
- data/lib/dcmgr/logger.rb +44 -0
- data/lib/dcmgr/models/account.rb +104 -0
- data/lib/dcmgr/models/account_resource.rb +16 -0
- data/lib/dcmgr/models/base.rb +69 -0
- data/lib/dcmgr/models/base_new.rb +371 -0
- data/lib/dcmgr/models/frontend_system.rb +38 -0
- data/lib/dcmgr/models/host_pool.rb +102 -0
- data/lib/dcmgr/models/image.rb +46 -0
- data/lib/dcmgr/models/instance.rb +255 -0
- data/lib/dcmgr/models/instance_netfilter_group.rb +16 -0
- data/lib/dcmgr/models/instance_nic.rb +68 -0
- data/lib/dcmgr/models/instance_spec.rb +21 -0
- data/lib/dcmgr/models/ip_lease.rb +42 -0
- data/lib/dcmgr/models/netfilter_group.rb +88 -0
- data/lib/dcmgr/models/netfilter_rule.rb +21 -0
- data/lib/dcmgr/models/network.rb +32 -0
- data/lib/dcmgr/models/physical_host.rb +67 -0
- data/lib/dcmgr/models/request_log.rb +25 -0
- data/lib/dcmgr/models/ssh_key_pair.rb +55 -0
- data/lib/dcmgr/models/storage_pool.rb +134 -0
- data/lib/dcmgr/models/tag.rb +126 -0
- data/lib/dcmgr/models/tag_mapping.rb +28 -0
- data/lib/dcmgr/models/volume.rb +130 -0
- data/lib/dcmgr/models/volume_snapshot.rb +47 -0
- data/lib/dcmgr/node_modules/hva_collector.rb +134 -0
- data/lib/dcmgr/node_modules/sta_collector.rb +72 -0
- data/lib/dcmgr/scheduler.rb +12 -0
- data/lib/dcmgr/scheduler/find_last.rb +16 -0
- data/lib/dcmgr/scheduler/find_random.rb +16 -0
- data/lib/dcmgr/stm/instance.rb +25 -0
- data/lib/dcmgr/stm/snapshot_context.rb +33 -0
- data/lib/dcmgr/stm/volume_context.rb +65 -0
- data/lib/dcmgr/web/base.rb +21 -0
- data/lib/sinatra/accept_media_types.rb +128 -0
- data/lib/sinatra/lazy_auth.rb +56 -0
- data/lib/sinatra/rabbit.rb +278 -0
- data/lib/sinatra/respond_to.rb +272 -0
- data/lib/sinatra/sequel_transaction.rb +27 -0
- data/lib/sinatra/static_assets.rb +83 -0
- data/lib/sinatra/url_for.rb +44 -0
- metadata +270 -0
@@ -0,0 +1,126 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Dcmgr::Models
|
4
|
+
class Tag < BaseNew
|
5
|
+
taggable('tag')
|
6
|
+
with_timestamps
|
7
|
+
plugin :single_table_inheritance, :type_id, :model_map=>{}
|
8
|
+
plugin :subclasses
|
9
|
+
|
10
|
+
inheritable_schema do
|
11
|
+
Fixnum :account_id, :null=>false
|
12
|
+
index :account_id
|
13
|
+
Fixnum :owner_id
|
14
|
+
String :name, :fixed=>true, :size=>200, :null=>false
|
15
|
+
Fixnum :type_id, :null=>false
|
16
|
+
String :attributes
|
17
|
+
end
|
18
|
+
|
19
|
+
TYPE_NORMAL = 0
|
20
|
+
TYPE_AUTH = 1
|
21
|
+
|
22
|
+
many_to_one :account
|
23
|
+
|
24
|
+
#one_to_many :tag_mappings, :dataset=>proc{ TagMapping.dataset.filter(:tag_id=>self.id) } do
|
25
|
+
one_to_many :mapped_uuids, :class=>TagMapping do |ds|
|
26
|
+
ds.instance_eval {
|
27
|
+
def exists?(canonical_uuid)
|
28
|
+
!self.filter(:uuid=>canonical_uuid).empty?
|
29
|
+
end
|
30
|
+
}
|
31
|
+
ds
|
32
|
+
end
|
33
|
+
|
34
|
+
class UnacceptableTagType < StandardError
|
35
|
+
def initialize(msg, tag, taggable)
|
36
|
+
super(msg)
|
37
|
+
|
38
|
+
raise ArgumentError, "Expected #{Tag.class}: #{tag.class}" unless tag.is_a?(Tag)
|
39
|
+
raise ArgumentError, "Expected #{Taggable.class}: #{tag.class}" unless taggable.is_a?(Taggable)
|
40
|
+
@tag = tag
|
41
|
+
@taggable = taggable
|
42
|
+
end
|
43
|
+
#TODO: show @tag and @taggable info to the error message.
|
44
|
+
end
|
45
|
+
class TagAlreadyLabeled < StandardError; end
|
46
|
+
class TagAlreadyUnlabeled < StandardError; end
|
47
|
+
|
48
|
+
def labeled?(canonical_uuid)
|
49
|
+
# TODO: check if the uuid exists
|
50
|
+
|
51
|
+
!TagMapping.filter(:uuid=>canonical_uuid, :tag_id=>self.pk).empty?
|
52
|
+
end
|
53
|
+
|
54
|
+
def label(canonical_uuid)
|
55
|
+
tgt = Taggable.find(canonical_uuid)
|
56
|
+
|
57
|
+
raise(UnacceptableTagType, self, tgt) if accept_mapping?(tgt)
|
58
|
+
raise(TagAlreadyLabeled) if labeled?(canonical_uuid)
|
59
|
+
TagMapping.create(:uuid=>canonical_uuid, :tag_id=>self.pk)
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
def unlabel(canonical_uuid)
|
64
|
+
t = TagMapping.find(:uuid=>canonical_uuid, :tag_id=>self.pk) || raise(TagAlreadyUnlabeled)
|
65
|
+
t.delete
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
#many_to_many :tags, :join_table=>:tag_mappings, :left_key=>:target_id, :conditions=>{:target_type=>TagMapping::TYPE_TAG}
|
70
|
+
|
71
|
+
#many_to_one :owner, :class=>:User
|
72
|
+
|
73
|
+
#one_to_many :tag_attributes, :one_to_one=>true
|
74
|
+
|
75
|
+
def self.find_tag_class(name)
|
76
|
+
self.subclasses.find { |m|
|
77
|
+
m.to_s.sub(/^#{self.class}::/, '') == name
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
# STI class variable setter, getter methods.
|
82
|
+
class << self
|
83
|
+
|
84
|
+
# Declare the integer number for the tag.
|
85
|
+
#
|
86
|
+
# Also set the value to sti map in class Tag.
|
87
|
+
# class Tag1 < Tag
|
88
|
+
# type_id 123456
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# puts Tag1.type_id # == 123456
|
92
|
+
def type_id(type_id=nil)
|
93
|
+
if type_id.is_a?(Fixnum)
|
94
|
+
@type_id = type_id
|
95
|
+
Tag.sti_model_map[type_id] = self
|
96
|
+
Tag.sti_key_map[self.to_s] = type_id
|
97
|
+
end
|
98
|
+
@type_id || raise("#{self}.type_id is unset. Please set the unique number for the tag instance.")
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
# Set or read description of the Tag class.
|
103
|
+
def description(desc=nil)
|
104
|
+
if desc
|
105
|
+
@description = desc
|
106
|
+
end
|
107
|
+
@description
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
# Check the object class type before associating to the Tag.
|
113
|
+
# Child class must implement this method.
|
114
|
+
# @param taggable_obj any object kind_of?(Model::Taggable)
|
115
|
+
def accept_mapping?(taggable_obj)
|
116
|
+
raise NotImplementedError
|
117
|
+
end
|
118
|
+
|
119
|
+
def after_initialize
|
120
|
+
super
|
121
|
+
self[:type_id] = self.class.type_id
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Dcmgr::Models
|
4
|
+
class TagMapping < BaseNew
|
5
|
+
TYPE_ACCOUNT = 0
|
6
|
+
TYPE_TAG = 1
|
7
|
+
TYPE_USER = 2
|
8
|
+
TYPE_INSTANCE = 3
|
9
|
+
TYPE_INSTANCE_IMAGE = 4
|
10
|
+
TYPE_HV_CONTROLLER = 5
|
11
|
+
TYPE_HV_AGENT = 6
|
12
|
+
TYPE_PHYSICAL_HOST = 7
|
13
|
+
TYPE_PHYSICAL_HOST_LOCATION = 8
|
14
|
+
TYPE_IMAGE_STORAGE_HOST = 9
|
15
|
+
TYPE_IMAGE_STORAGE = 10
|
16
|
+
|
17
|
+
inheritable_schema do
|
18
|
+
Fixnum :tag_id, :null=>false
|
19
|
+
index :tag_id
|
20
|
+
String :uuid, :null=>false, :fixed=>true, :size=>20
|
21
|
+
index :uuid
|
22
|
+
end
|
23
|
+
|
24
|
+
many_to_one :tag
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'statemachine'
|
3
|
+
|
4
|
+
module Dcmgr::Models
|
5
|
+
class Volume < AccountResource
|
6
|
+
taggable 'vol'
|
7
|
+
|
8
|
+
STATUS_TYPE_REGISTERING = "registering"
|
9
|
+
STATUS_TYPE_ONLINE = "online"
|
10
|
+
STATUS_TYPE_OFFLINE = "offline"
|
11
|
+
STATUS_TYPE_FAILED = "failed"
|
12
|
+
|
13
|
+
STATE_TYPE_REGISTERING = "registering"
|
14
|
+
STATE_TYPE_CREATING = "creating"
|
15
|
+
STATE_TYPE_AVAILABLE = "available"
|
16
|
+
STATE_TYPE_ATTATING = "attating"
|
17
|
+
STATE_TYPE_ATTACHED = "attached"
|
18
|
+
STATE_TYPE_DETACHING = "detaching"
|
19
|
+
STATE_TYPE_FAILED = "failed"
|
20
|
+
STATE_TYPE_DEREGISTERING = "deregistering"
|
21
|
+
STATE_TYPE_DELETING = "deleting"
|
22
|
+
STATE_TYPE_DELETED = "deleted"
|
23
|
+
|
24
|
+
inheritable_schema do
|
25
|
+
Fixnum :storage_pool_id, :null=>false
|
26
|
+
String :status, :null=>false, :default=>STATUS_TYPE_REGISTERING
|
27
|
+
String :state, :null=>false, :default=>STATE_TYPE_REGISTERING
|
28
|
+
Fixnum :size, :null=>false
|
29
|
+
Fixnum :instance_id
|
30
|
+
String :snapshot_id
|
31
|
+
String :host_device_name
|
32
|
+
String :guest_device_name
|
33
|
+
String :export_path, :null=>false
|
34
|
+
Text :transport_information
|
35
|
+
Time :deleted_at
|
36
|
+
Time :attached_at
|
37
|
+
Time :detached_at
|
38
|
+
index :storage_pool_id
|
39
|
+
index :instance_id
|
40
|
+
index :snapshot_id
|
41
|
+
end
|
42
|
+
with_timestamps
|
43
|
+
|
44
|
+
# serialization plugin must be defined at the bottom of all class
|
45
|
+
# method calls.
|
46
|
+
# Possible column data:
|
47
|
+
# iscsi:
|
48
|
+
# {:iqn=>'iqn.1986-03.com.sun:02:a1024afa-775b-65cf-b5b0-aa17f3476bfc', :lun=>0}
|
49
|
+
plugin :serialization, :yaml, :transport_information
|
50
|
+
|
51
|
+
many_to_one :storage_pool
|
52
|
+
many_to_one :instance
|
53
|
+
|
54
|
+
class DiskError < RuntimeError; end
|
55
|
+
class RequestError < RuntimeError; end
|
56
|
+
|
57
|
+
def before_create
|
58
|
+
# check the volume size
|
59
|
+
sp = self.storage_pool
|
60
|
+
volume_size = Volume.dataset.where(:storage_pool_id=> self.storage_pool_id).get{sum(:size)}
|
61
|
+
total_size = sp.offerring_disk_space - volume_size.to_i
|
62
|
+
if self.size > total_size
|
63
|
+
raise DiskError, "out of disk space"
|
64
|
+
end
|
65
|
+
|
66
|
+
super
|
67
|
+
end
|
68
|
+
|
69
|
+
def before_save
|
70
|
+
self.updated_at = Time.now
|
71
|
+
super
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.get_list(account_id, *args)
|
75
|
+
data = args.first
|
76
|
+
vl = self.dataset.where(:account_id=>account_id)
|
77
|
+
vl = vl.limit(data[:limit], data[:start]) if data[:start] && data[:limit]
|
78
|
+
if data[:target] && data[:sort]
|
79
|
+
vl = case data[:sort]
|
80
|
+
when 'desc'
|
81
|
+
vl.order(data[:target].to_sym.desc)
|
82
|
+
when 'asc'
|
83
|
+
vl.order(data[:target].to_sym.asc)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
if data[:target] && data[:filter]
|
87
|
+
filter = case data[:target]
|
88
|
+
when 'uuid'
|
89
|
+
data[:filter].split('vol-').last
|
90
|
+
else
|
91
|
+
data[:filter]
|
92
|
+
end
|
93
|
+
vl = vl.grep(data[:target].to_sym, "%#{filter}%")
|
94
|
+
end
|
95
|
+
vl.all.map{|row|
|
96
|
+
row.to_hash_document
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.delete_volume(account_id, uuid)
|
101
|
+
v = self.dataset.where(:account_id=>account_id).where(:uuid=>uuid.split('-').last).first
|
102
|
+
if v.state.to_sym != :available
|
103
|
+
raise RequestError, "invalid delete request"
|
104
|
+
end
|
105
|
+
v.state = :deregistering
|
106
|
+
v.save_changes
|
107
|
+
v
|
108
|
+
end
|
109
|
+
|
110
|
+
def merge_pool_data
|
111
|
+
v = self.to_hash_document
|
112
|
+
v.merge(:storage_pool=>storage_pool.to_hash_document)
|
113
|
+
end
|
114
|
+
|
115
|
+
def to_hash_document
|
116
|
+
h = self.values.dup
|
117
|
+
h[:id] = h[:uuid] = h[:export_path] = self.canonical_uuid
|
118
|
+
# yaml -> hash translation
|
119
|
+
h[:transport_information]=self.transport_information
|
120
|
+
h
|
121
|
+
end
|
122
|
+
|
123
|
+
def create_snapshot(account_id)
|
124
|
+
vs = VolumeSnapshot.create(:account_id=>account_id,
|
125
|
+
:storage_pool_id=>self.storage_pool_id,
|
126
|
+
:origin_volume_id=>self.canonical_uuid,
|
127
|
+
:size=>self.size)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Dcmgr::Models
|
4
|
+
class VolumeSnapshot < AccountResource
|
5
|
+
taggable 'snap'
|
6
|
+
|
7
|
+
STATE_TYPE_REGISTERING = "registering"
|
8
|
+
STATE_TYPE_CREATING = "creating"
|
9
|
+
STATE_TYPE_AVAILABLE = "available"
|
10
|
+
STATE_TYPE_FAILED = "failed"
|
11
|
+
STATE_TYPE_DELETING = "deleting"
|
12
|
+
STATE_TYPE_DELETED = "deleted"
|
13
|
+
|
14
|
+
inheritable_schema do
|
15
|
+
Fixnum :storage_pool_id, :null=>false
|
16
|
+
String :origin_volume_id, :null=>false
|
17
|
+
Fixnum :size, :null=>false
|
18
|
+
Fixnum :status, :null=>false, :default=>0
|
19
|
+
String :state, :null=>false, :default=>STATE_TYPE_REGISTERING
|
20
|
+
index :storage_pool_id
|
21
|
+
end
|
22
|
+
with_timestamps
|
23
|
+
|
24
|
+
many_to_one :storage_pool
|
25
|
+
|
26
|
+
def to_hash_document
|
27
|
+
h = self.values.dup
|
28
|
+
h[:id] = h[:uuid] = self.canonical_uuid
|
29
|
+
h
|
30
|
+
end
|
31
|
+
|
32
|
+
# create volume inherite from this snapshot for the account.
|
33
|
+
# limitation: inherit volume is created on same storage_pool.
|
34
|
+
def create_volume(account_id)
|
35
|
+
storage_pool.create_volume(account_id, self.size, self.canonical_uuid)
|
36
|
+
end
|
37
|
+
|
38
|
+
def origin_volume
|
39
|
+
Volume[origin_volume_id]
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete_snapshot
|
43
|
+
self.state = STATE_TYPE_DELETING
|
44
|
+
self.save_changes
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'isono'
|
3
|
+
require 'ipaddress'
|
4
|
+
|
5
|
+
module Dcmgr
|
6
|
+
module NodeModules
|
7
|
+
class HvaCollector < Isono::NodeModules::Base
|
8
|
+
include Isono::NodeModules
|
9
|
+
|
10
|
+
initialize_hook do
|
11
|
+
rpc = RpcChannel.new(node)
|
12
|
+
app = Isono::Rack::ObjectMethod.new(myinstance)
|
13
|
+
rpc.register_endpoint('hva-collector', Isono::Rack.build do
|
14
|
+
use Isono::Rack::DataStore
|
15
|
+
run proc { |req, res|
|
16
|
+
Thread.current[Models::BaseNew::LOCK_TABLES_KEY] = {}
|
17
|
+
app.call(req, res)
|
18
|
+
}
|
19
|
+
end)
|
20
|
+
end
|
21
|
+
|
22
|
+
terminate_hook do
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_instance(instance_id)
|
26
|
+
Models::Instance.lock!
|
27
|
+
inst = Models::Instance[instance_id]
|
28
|
+
raise "UnknownInstanceID" if inst.nil?
|
29
|
+
|
30
|
+
ret = inst.to_hash
|
31
|
+
ret
|
32
|
+
end
|
33
|
+
|
34
|
+
def update_instance(instance_id, data)
|
35
|
+
Models::Instance.lock!
|
36
|
+
inst = Models::Instance[instance_id]
|
37
|
+
inst.set_fields(data, [:state]).save
|
38
|
+
# do not respond model object.
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_netfilter_groups_of_instance(instance_id)
|
43
|
+
Models::Instance.lock!
|
44
|
+
inst = Models::Instance[instance_id]
|
45
|
+
raise "UnknownInstanceID" if inst.nil?
|
46
|
+
|
47
|
+
inst.netfilter_groups.map { |g| g.to_hash }
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_group_instance_ipv4s(instance_id)
|
51
|
+
Models::Instance.lock!
|
52
|
+
inst = Models::Instance[instance_id]
|
53
|
+
raise "UnknownInstanceID" if inst.nil?
|
54
|
+
|
55
|
+
insts = inst.netfilter_group_instances
|
56
|
+
ips = insts.map { |instance|
|
57
|
+
next if instance.nil?
|
58
|
+
instance.ips.map { |ip| ip.ipv4 unless ip.nil? }
|
59
|
+
}
|
60
|
+
|
61
|
+
ips.flatten! if ips.size > 0
|
62
|
+
ips.compact
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_network(network_id)
|
66
|
+
Models::Network.lock!
|
67
|
+
network = Models::Network[network_id]
|
68
|
+
raise "UnknownNetworkID" if network.nil?
|
69
|
+
network.to_hash
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_networks
|
73
|
+
Models::Network.lock!
|
74
|
+
networks = Models::Network.all
|
75
|
+
networks.map { |network|
|
76
|
+
network.to_hash
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
def get_dhcp_conf(network_name)
|
81
|
+
Models::Network.lock!
|
82
|
+
network = Models::Network.find(:name=>network_name)
|
83
|
+
raise "Unknown network name: #{network_name}" if network.nil?
|
84
|
+
prefix = IPAddress::Prefix32.new(network.prefix)
|
85
|
+
h = {
|
86
|
+
:ipv4_gw=>network.ipv4_gw,
|
87
|
+
:netmask => prefix.to_ip,
|
88
|
+
:prefix => network.prefix,
|
89
|
+
:dns_server=> network.dns_server,
|
90
|
+
:domain_name => network.domain_name,
|
91
|
+
:mac2addr => [],
|
92
|
+
:addr2host=> [],
|
93
|
+
}
|
94
|
+
|
95
|
+
network.ip_lease.each { |ip|
|
96
|
+
# ignore IPs unbound to vnic.
|
97
|
+
next if ip.instance_nic.nil? || ip.instance_nic.instance.nil?
|
98
|
+
|
99
|
+
h[:mac2addr] << {
|
100
|
+
:mac_addr => ip.instance_nic.pretty_mac_addr,
|
101
|
+
:ipaddr => ip.ipv4
|
102
|
+
}
|
103
|
+
h[:addr2host] << {
|
104
|
+
:hostname => ip.instance_nic.instance.fqdn_hostname,
|
105
|
+
:ipaddr => ip.ipv4
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
h
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_instances_of_netfilter_group(netfilter_group_id)
|
113
|
+
Models::NetfilterGroup.lock!
|
114
|
+
g = Models::NetfilterGroup[netfilter_group_id]
|
115
|
+
raise "UnknownNetfilterGroupID" if g.nil?
|
116
|
+
inst_maps = g.instances.map { |instance| instance.to_hash unless instance.nil? }
|
117
|
+
inst_maps.compact
|
118
|
+
end
|
119
|
+
|
120
|
+
def get_alive_instances(node_id)
|
121
|
+
Models::HostPool.lock!
|
122
|
+
hp = Models::HostPool.find(:node_id => node_id)
|
123
|
+
raise "UnknownNodeID", node_id if hp.nil?
|
124
|
+
|
125
|
+
inst_on_hp = hp.instances_dataset.lives.all.map { |inst|
|
126
|
+
inst.to_hash
|
127
|
+
}
|
128
|
+
inst_on_hp.uniq! if inst_on_hp.size > 0
|
129
|
+
inst_on_hp
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|