wakame-vdc-dcmgr 10.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/LICENSE +202 -0
  2. data/NOTICE +1 -0
  3. data/Rakefile +142 -0
  4. data/bin/collector +46 -0
  5. data/config/dcmgr.conf.example +9 -0
  6. data/config/initializers/isono.rb +43 -0
  7. data/config/initializers/passenger.rb +6 -0
  8. data/config/initializers/sequel.rb +21 -0
  9. data/config/path_resolver.rb +12 -0
  10. data/lib/dcmgr.rb +115 -0
  11. data/lib/dcmgr/endpoints/core_api.rb +1004 -0
  12. data/lib/dcmgr/endpoints/core_api_mock.rb +816 -0
  13. data/lib/dcmgr/endpoints/errors.rb +55 -0
  14. data/lib/dcmgr/endpoints/metadata.rb +129 -0
  15. data/lib/dcmgr/logger.rb +44 -0
  16. data/lib/dcmgr/models/account.rb +104 -0
  17. data/lib/dcmgr/models/account_resource.rb +16 -0
  18. data/lib/dcmgr/models/base.rb +69 -0
  19. data/lib/dcmgr/models/base_new.rb +371 -0
  20. data/lib/dcmgr/models/frontend_system.rb +38 -0
  21. data/lib/dcmgr/models/host_pool.rb +102 -0
  22. data/lib/dcmgr/models/image.rb +46 -0
  23. data/lib/dcmgr/models/instance.rb +255 -0
  24. data/lib/dcmgr/models/instance_netfilter_group.rb +16 -0
  25. data/lib/dcmgr/models/instance_nic.rb +68 -0
  26. data/lib/dcmgr/models/instance_spec.rb +21 -0
  27. data/lib/dcmgr/models/ip_lease.rb +42 -0
  28. data/lib/dcmgr/models/netfilter_group.rb +88 -0
  29. data/lib/dcmgr/models/netfilter_rule.rb +21 -0
  30. data/lib/dcmgr/models/network.rb +32 -0
  31. data/lib/dcmgr/models/physical_host.rb +67 -0
  32. data/lib/dcmgr/models/request_log.rb +25 -0
  33. data/lib/dcmgr/models/ssh_key_pair.rb +55 -0
  34. data/lib/dcmgr/models/storage_pool.rb +134 -0
  35. data/lib/dcmgr/models/tag.rb +126 -0
  36. data/lib/dcmgr/models/tag_mapping.rb +28 -0
  37. data/lib/dcmgr/models/volume.rb +130 -0
  38. data/lib/dcmgr/models/volume_snapshot.rb +47 -0
  39. data/lib/dcmgr/node_modules/hva_collector.rb +134 -0
  40. data/lib/dcmgr/node_modules/sta_collector.rb +72 -0
  41. data/lib/dcmgr/scheduler.rb +12 -0
  42. data/lib/dcmgr/scheduler/find_last.rb +16 -0
  43. data/lib/dcmgr/scheduler/find_random.rb +16 -0
  44. data/lib/dcmgr/stm/instance.rb +25 -0
  45. data/lib/dcmgr/stm/snapshot_context.rb +33 -0
  46. data/lib/dcmgr/stm/volume_context.rb +65 -0
  47. data/lib/dcmgr/web/base.rb +21 -0
  48. data/lib/sinatra/accept_media_types.rb +128 -0
  49. data/lib/sinatra/lazy_auth.rb +56 -0
  50. data/lib/sinatra/rabbit.rb +278 -0
  51. data/lib/sinatra/respond_to.rb +272 -0
  52. data/lib/sinatra/sequel_transaction.rb +27 -0
  53. data/lib/sinatra/static_assets.rb +83 -0
  54. data/lib/sinatra/url_for.rb +44 -0
  55. data/web/api/config.ru +20 -0
  56. data/web/api/public/index.html +0 -0
  57. data/web/metadata/config.ru +20 -0
  58. data/web/metadata/public/index.html +0 -0
  59. metadata +326 -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