wakame 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. data/History.txt +4 -0
  2. data/LICENSE +202 -0
  3. data/Rakefile +11 -12
  4. data/VERSION +1 -1
  5. data/app_generators/wakame/templates/bin/wakame-agent +1 -1
  6. data/app_generators/wakame/templates/bin/wakame-master +1 -1
  7. data/app_generators/wakame/templates/config/cluster.rb +32 -24
  8. data/app_generators/wakame/templates/config/init.d/centos/wakame-agent +40 -0
  9. data/app_generators/wakame/templates/config/init.d/centos/wakame-master +40 -0
  10. data/app_generators/wakame/templates/config/init.d/wakame-master +1 -1
  11. data/lib/ext/eventmachine.rb +5 -5
  12. data/lib/wakame.rb +12 -0
  13. data/lib/wakame/action.rb +10 -11
  14. data/lib/wakame/actions/deploy_application.rb +61 -0
  15. data/lib/wakame/actions/deploy_config.rb +1 -3
  16. data/lib/wakame/actions/freeze_cluster.rb +15 -0
  17. data/lib/wakame/actions/launch_cluster.rb +1 -3
  18. data/lib/wakame/actions/launch_vm.rb +1 -1
  19. data/lib/wakame/actions/migrate_service.rb +4 -3
  20. data/lib/wakame/actions/notify_child_changed.rb +3 -6
  21. data/lib/wakame/actions/notify_parent_changed.rb +4 -7
  22. data/lib/wakame/actions/propagate_resource.rb +1 -3
  23. data/lib/wakame/actions/propagate_service.rb +1 -3
  24. data/lib/wakame/actions/register_agent.rb +43 -0
  25. data/lib/wakame/actions/reload_service.rb +2 -2
  26. data/lib/wakame/actions/shutdown_cluster.rb +4 -6
  27. data/lib/wakame/actions/shutdown_vm.rb +27 -6
  28. data/lib/wakame/actions/start_service.rb +40 -32
  29. data/lib/wakame/actions/stop_service.rb +8 -10
  30. data/lib/wakame/actions/unfreeze_cluster.rb +15 -0
  31. data/lib/wakame/actor.rb +2 -5
  32. data/lib/wakame/actor/deploy.rb +110 -0
  33. data/lib/wakame/actor/monitor.rb +14 -0
  34. data/lib/wakame/actor/s3fs.rb +45 -0
  35. data/lib/wakame/actor/service_monitor.rb +0 -17
  36. data/lib/wakame/actor/system.rb +5 -1
  37. data/lib/wakame/agent.rb +29 -179
  38. data/lib/wakame/agent_manager.rb +11 -0
  39. data/lib/wakame/agent_managers/actor_manager.rb +101 -0
  40. data/lib/wakame/agent_managers/monitor_manager.rb +48 -0
  41. data/lib/wakame/command.rb +4 -7
  42. data/lib/wakame/command/actor.rb +9 -12
  43. data/lib/wakame/command/agent_status.rb +2 -2
  44. data/lib/wakame/command/control_service.rb +66 -0
  45. data/lib/wakame/command/deploy_application.rb +18 -0
  46. data/lib/wakame/command/deploy_config.rb +16 -0
  47. data/lib/wakame/command/launch_cluster.rb +1 -1
  48. data/lib/wakame/command/launch_vm.rb +1 -1
  49. data/lib/wakame/command/propagate_resource.rb +1 -1
  50. data/lib/wakame/command/propagate_service.rb +5 -3
  51. data/lib/wakame/command/reload_service.rb +1 -1
  52. data/lib/wakame/command/shutdown_cluster.rb +1 -1
  53. data/lib/wakame/command/shutdown_vm.rb +37 -11
  54. data/lib/wakame/command/start_service.rb +1 -1
  55. data/lib/wakame/command/status.rb +6 -4
  56. data/lib/wakame/command/stop_service.rb +1 -1
  57. data/lib/wakame/configuration.rb +5 -0
  58. data/lib/wakame/event.rb +85 -33
  59. data/lib/wakame/event_dispatcher.rb +2 -2
  60. data/lib/wakame/initializer.rb +97 -31
  61. data/lib/wakame/master.rb +23 -346
  62. data/lib/wakame/master_manager.rb +11 -0
  63. data/lib/wakame/master_managers/action_manager.rb +321 -0
  64. data/lib/wakame/master_managers/agent_monitor.rb +166 -0
  65. data/lib/wakame/master_managers/cluster_manager.rb +176 -0
  66. data/lib/wakame/master_managers/command_queue.rb +133 -0
  67. data/lib/wakame/models/agent_pool.rb +113 -0
  68. data/lib/wakame/models/application_repository.rb +34 -0
  69. data/lib/wakame/models/object_store.rb +32 -0
  70. data/lib/wakame/models/service_cluster_pool.rb +36 -0
  71. data/lib/wakame/monitor.rb +3 -6
  72. data/lib/wakame/monitor/agent.rb +9 -6
  73. data/lib/wakame/monitor/service.rb +56 -29
  74. data/lib/wakame/runner/administrator_command.rb +210 -24
  75. data/lib/wakame/runner/agent.rb +2 -0
  76. data/lib/wakame/runner/master.rb +2 -1
  77. data/lib/wakame/service.rb +140 -130
  78. data/lib/wakame/status_db.rb +101 -121
  79. data/lib/wakame/util.rb +26 -15
  80. data/tests/setup_master.rb +1 -0
  81. data/tests/test_master.rb +0 -2
  82. data/tests/test_model_agent_pool.rb +21 -0
  83. data/tests/test_service.rb +14 -8
  84. data/tests/test_status_db.rb +2 -0
  85. data/tests/test_util.rb +12 -1
  86. data/wakame_generators/resource/templates/apache_app/apache_app.rb +20 -11
  87. data/wakame_generators/resource/templates/apache_app/conf/vh/aaa.test.conf +1 -1
  88. data/wakame_generators/resource/templates/apache_lb/apache_lb.rb +7 -7
  89. data/wakame_generators/resource/templates/apache_lb/conf/system-lb.conf +6 -4
  90. data/wakame_generators/resource/templates/apache_www/apache_www.rb +15 -13
  91. data/wakame_generators/resource/templates/ec2_elastic_ip/ec2_elastic_ip.rb +17 -17
  92. data/wakame_generators/resource/templates/ec2_elb/ec2_elb.rb +22 -15
  93. data/wakame_generators/resource/templates/mongodb/conf/mongodb.conf +95 -0
  94. data/wakame_generators/resource/templates/mongodb/init.d/mongodb +244 -0
  95. data/wakame_generators/resource/templates/mongodb/mongodb.rb +64 -0
  96. data/wakame_generators/resource/templates/mysql_master/mysql_master.rb +17 -21
  97. data/wakame_generators/resource/templates/nginx/conf/nginx.conf +4 -0
  98. data/wakame_generators/resource/templates/nginx/conf/vh/ec2_elb_common.conf +19 -0
  99. data/wakame_generators/resource/templates/nginx/init.d/nginx +6 -0
  100. data/wakame_generators/resource/templates/nginx/init.d/spawn-fcgi +46 -0
  101. data/wakame_generators/resource/templates/nginx/nginx.rb +15 -10
  102. data/wakame_generators/resource/templates/nginx_passenger/conf/nginx-passenger.conf +39 -0
  103. data/wakame_generators/resource/templates/nginx_passenger/conf/vh/ec2_elb_common.conf +10 -0
  104. data/wakame_generators/resource/templates/nginx_passenger/init.d/nginx-passenger +70 -0
  105. data/wakame_generators/resource/templates/nginx_passenger/nginx_passenger.rb +71 -0
  106. data/wakame_generators/resource/templates/s3fs/s3fs.rb +24 -0
  107. metadata +195 -74
  108. data/lib/wakame/action_manager.rb +0 -303
  109. data/lib/wakame/command/clone_service.rb +0 -12
  110. data/lib/wakame/command_queue.rb +0 -135
  111. data/lib/wakame/vm_manipulator.rb +0 -187
@@ -0,0 +1,176 @@
1
+ module Wakame
2
+ module MasterManagers
3
+ class ClusterManager
4
+ include MasterManager
5
+
6
+ class ClusterConfigLoader
7
+
8
+ def load(cluster_rb_path=Wakame.config.cluster_config_path)
9
+ Wakame.log.info("#{self.class}: Loading cluster.rb: #{cluster_rb_path}")
10
+ @loaded_cluster_names = {}
11
+
12
+ eval(File.readlines(cluster_rb_path).join(''), binding)
13
+
14
+ # Clear uninitialized cluster data in the store.
15
+ Service::ServiceCluster.find_all.each { |cluster|
16
+ cluster.delete unless @loaded_cluster_names.has_key?(cluster.name)
17
+ }
18
+
19
+ @loaded_cluster_names
20
+ end
21
+
22
+
23
+ private
24
+ def define_cluster(name, &blk)
25
+ cluster = Service::ServiceCluster.find(Service::ServiceCluster.id(name))
26
+ if cluster.nil?
27
+ cluster = Service::ServiceCluster.new
28
+ cluster.name = name
29
+ end
30
+
31
+ Models::AgentPool.reset
32
+ cluster.reset
33
+
34
+ blk.call(cluster)
35
+
36
+ cluster.save
37
+
38
+ Wakame.log.info("#{self.class}: Loaded Service Cluster: #{cluster.name}")
39
+ @loaded_cluster_names[name]=cluster.id
40
+ end
41
+
42
+ end
43
+
44
+ def init
45
+ # Periodical cluster status updater
46
+ @status_check_timer = EM::PeriodicTimer.new(5) {
47
+ StatusDB.pass {
48
+ clusters.each { |cluster_id|
49
+ Service::ServiceCluster.find(cluster_id).update_cluster_status
50
+ }
51
+ }
52
+ }
53
+
54
+ # Event based cluster status updater
55
+ @check_event_tickets = []
56
+ [Event::ServiceOnline, Event::ServiceOffline, Event::ServiceFailed].each { |evclass|
57
+ @check_event_tickets << EventDispatcher.subscribe(evclass) { |event|
58
+ StatusDB.pass {
59
+ clusters.each { |cluster_id|
60
+ Service::ServiceCluster.find(cluster_id).update_cluster_status
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ @check_event_tickets << EventDispatcher.subscribe(Event::ServiceStatusChanged) { |event|
67
+ svc = Service::ServiceInstance.find(event.instance_id)
68
+ case svc.status
69
+ when Service::STATUS_ENTERING
70
+ EM.defer {
71
+ # Refresh the monitoring conf on the agent
72
+ svc.cloud_host.live_monitors.each { |path, conf|
73
+ Wakame.log.debug("#{self.class}: Refreshing monitoring setting on #{svc.cloud_host.agent_id} (on enter): #{path} => #{conf.inspect}")
74
+ Master.instance.actor_request(svc.cloud_host.agent_id, '/monitor/reload', path, conf).request.wait
75
+ }
76
+ }
77
+ when Service::STATUS_QUITTING
78
+ EM.defer {
79
+ # Refresh the monitoring conf on the agent
80
+ svc.cloud_host.live_monitors.each { |path, conf|
81
+ Wakame.log.debug("#{self.class}: Refreshing monitoring setting on #{svc.cloud_host.agent_id} (on quit): #{path} => #{conf.inspect}")
82
+ Master.instance.actor_request(svc.cloud_host.agent_id, '/monitor/reload', path, conf).request.wait
83
+ }
84
+ }
85
+ end
86
+ }
87
+ end
88
+
89
+ def reload
90
+ end
91
+
92
+ def terminate
93
+ @status_check_timer.cancel
94
+ @check_event_tickets.each { |t|
95
+ EventDispatcher.unsubscribe(t)
96
+ }
97
+ end
98
+
99
+ def clusters
100
+ Models::ServiceClusterPool.all.map{|r| r.service_cluster_id }
101
+ end
102
+
103
+ def register(cluster)
104
+ raise ArgumentError unless cluster.is_a?(Service::ServiceCluster)
105
+ Models::ServiceClusterPool.register_cluster(cluster.name)
106
+ end
107
+
108
+ def unregister(cluster_id)
109
+ @clusters.delete(cluster_id)
110
+ end
111
+
112
+ def load_config_cluster
113
+ ClusterConfigLoader.new.load.each { |name, id|
114
+ Models::ServiceClusterPool.register_cluster(name)
115
+ }
116
+ resolve_template_vm_attr
117
+ end
118
+
119
+
120
+ private
121
+ def resolve_template_vm_attr
122
+ Models::ServiceClusterPool.each_cluster { |cluster|
123
+ cluster_id = cluster.id
124
+
125
+ if cluster.template_vm_attr.nil? || cluster.template_vm_attr.empty?
126
+ update_template_spec = lambda { |agent|
127
+ raise ArgumentError unless agent.is_a?(Service::Agent)
128
+
129
+ require 'right_aws'
130
+ ec2 = RightAws::Ec2.new(Wakame.config.aws_access_key, Wakame.config.aws_secret_key)
131
+
132
+ ref_attr = ec2.describe_instances([agent.vm_attr[:aws_instance_id]])
133
+ ref_attr = ref_attr[0]
134
+
135
+ cluster = Service::ServiceCluster.find(cluster_id)
136
+ spec = cluster.template_vm_spec
137
+ Service::VmSpec::EC2.vm_attr_defs.each { |k, v|
138
+ spec.attrs[k] = ref_attr[v[:right_aws_key]]
139
+ }
140
+ cluster.save
141
+
142
+ Wakame.log.debug("ServiceCluster \"#{cluster.name}\" template_vm_attr based on VM \"#{agent.vm_attr[:aws_instance_id]}\" : #{spec.attrs.inspect}")
143
+ }
144
+
145
+
146
+ agent_id = Models::AgentPool.instance.group_active.first
147
+ if agent_id.nil?
148
+ # Set a single shot event handler to set the template values up from the first connected agent.
149
+ EventDispatcher.subscribe_once(Event::AgentMonitored) { |event|
150
+ StatusDB.pass {
151
+ update_template_spec.call(event.agent)
152
+ }
153
+ }
154
+ else
155
+ StatusDB.pass {
156
+ update_template_spec.call(Service::Agent.find(agent_id))
157
+ }
158
+ end
159
+ end
160
+
161
+ if cluster.advertised_amqp_servers.nil?
162
+ StatusDB.pass {
163
+ cluster = Service::ServiceCluster.find(cluster_id)
164
+ #cluster.advertised_amqp_servers = master.amqp_server_uri.to_s
165
+ attrs = Wakame::Master.ec2_fetch_local_attrs
166
+ cluster.advertised_amqp_servers = "amqp://#{attrs[:local_ipv4]}/"
167
+ cluster.save
168
+ Wakame.log.debug("ServiceCluster \"#{cluster.name}\" advertised_amqp_servers: #{cluster.advertised_amqp_servers}")
169
+ }
170
+ end
171
+
172
+ }
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,133 @@
1
+
2
+ require 'uri'
3
+ require 'thin'
4
+ require 'thread'
5
+ require 'json'
6
+
7
+ module Wakame
8
+ module MasterManagers
9
+ class CommandQueue
10
+ include MasterManager
11
+
12
+ def initialize()
13
+ @queue = Queue.new
14
+ @result_queue = Queue.new
15
+ @statistics = {
16
+ :total_command_count => 0
17
+ }
18
+ end
19
+
20
+ def init
21
+ @command_thread = Thread.new {
22
+ Wakame.log.info("#{self.class}: Started command thread: #{Thread.current}")
23
+ while cmd = @queue.deq
24
+ begin
25
+ unless cmd.kind_of?(Wakame::Command)
26
+ Wakame.log.warn("#{self.class}: Incompatible type of object has been sent to ProcessCommand thread. #{cmd.class}")
27
+ next
28
+ end
29
+
30
+ res = nil
31
+ Wakame.log.debug("#{self.class}: Being processed the command: #{cmd.class}")
32
+ res = cmd.run
33
+ res
34
+ rescue => e
35
+ Wakame.log.error(e)
36
+ res = e
37
+ ensure
38
+ @result_queue.enq(res)
39
+ end
40
+ end
41
+ }
42
+
43
+ cmdsv_uri = URI.parse(Wakame.config.http_command_server_uri)
44
+
45
+ @thin_server = Thin::Server.new(cmdsv_uri.host, cmdsv_uri.port, Adapter.new(self))
46
+ @thin_server.threaded = true
47
+ @thin_server.start
48
+ end
49
+
50
+ def terminate
51
+ @thin_server.stop
52
+ @command_thread.kill
53
+ end
54
+
55
+ def send_cmd(cmd)
56
+ begin
57
+ @queue.enq(cmd)
58
+
59
+ ED.fire_event(Event::CommandReceived.new(cmd))
60
+
61
+ return @result_queue.deq()
62
+ rescue => e
63
+ Wakame.log.error("#{self.class}:")
64
+ Wakame.log.error(e)
65
+ end
66
+ end
67
+
68
+
69
+ class Adapter
70
+
71
+ def initialize(command_queue)
72
+ @command_queue = command_queue
73
+ end
74
+
75
+ def call(env)
76
+ req = Rack::Request.new(env)
77
+ begin
78
+ unless req.get?().to_s == "true"
79
+ raise "No Support Response"
80
+ end
81
+ query = req.query_string()
82
+ params = req.params()
83
+ if Wakame.config.enable_authentication == "true"
84
+ auth = authentication(params, query)
85
+ end
86
+ cname = params["action"].split("_")
87
+ begin
88
+ cmd = eval("Command::#{(cname.collect{|c| c.capitalize}).join}").new
89
+ cmd.options = params
90
+ command = @command_queue.send_cmd(cmd)
91
+
92
+ if command.is_a?(Exception)
93
+ status = 500
94
+ body = json_encode(status, command.message)
95
+ else
96
+ status = 200
97
+ body = json_encode(status, "OK", command)
98
+ end
99
+ rescue => e
100
+ status = 404
101
+ body = json_encode(status, e)
102
+ end
103
+ rescue => e
104
+ status = 403
105
+ body = json_encode(status, e)
106
+ Wakame.log.error(e)
107
+ end
108
+ [ status, {'Content-Type' => 'text/javascript+json'}, body]
109
+ end
110
+
111
+ def authentication(path, query)
112
+ key = Wakame.config.private_key
113
+ req = query.split(/\&signature\=/)
114
+ hash = OpenSSL::HMAC::digest(OpenSSL::Digest::SHA256.new, key, req[0])
115
+ hmac = Base64.encode64(hash).gsub(/\+/, "").gsub(/\n/, "").to_s
116
+ if hmac != path["signature"]
117
+ raise "Authentication failed"
118
+ end
119
+ end
120
+
121
+ def json_encode(status, message, data=nil)
122
+ if status == 200 && data.is_a?(Hash)
123
+ body = [{:status=>status, :message=>message}, {:data=>data}].to_json
124
+ else
125
+ body = [{:status=>status, :message=>message}].to_json
126
+ end
127
+ body
128
+ end
129
+ end
130
+
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,113 @@
1
+
2
+ module Wakame
3
+ module Models
4
+ class AgentPool < Sequel::Model
5
+ plugin :schema
6
+ plugin :hook_class_methods
7
+
8
+ set_schema {
9
+ primary_key :id, :type => Integer
10
+ column :agent_pool_id, :int
11
+ column :agent_id, :varchar, :unique=>true
12
+ column :group_type, :int
13
+ column :created_at, :datetime
14
+ column :updated_at, :datetime
15
+ }
16
+
17
+ before_create(:set_created_at) do
18
+ self.updated_at = self.created_at = Time.now
19
+ end
20
+ before_update(:set_updated_at) do
21
+ self.updated_at = Time.now
22
+ end
23
+
24
+ GROUP_ACTIVE=1
25
+ GROUP_OBSERVED=2
26
+
27
+ DEFAULT_POOL_ID=1
28
+
29
+ def self.instance
30
+ self
31
+ end
32
+
33
+ def self.reset
34
+ filter(:agent_pool_id=>DEFAULT_POOL_ID).all.each { |row|
35
+ agent = Service::Agent.find(row[:agent_id])
36
+ if agent
37
+ agent.cloud_host_id = nil
38
+ agent.save
39
+ else
40
+ row.delete
41
+ end
42
+ }
43
+ end
44
+
45
+ def self.group_active
46
+ filter(:agent_pool_id=>DEFAULT_POOL_ID, :group_type=>GROUP_ACTIVE).all.map {|row| row[:agent_id] }
47
+ end
48
+
49
+ def self.group_observed
50
+ filter(:agent_pool_id=>DEFAULT_POOL_ID, :group_type=>GROUP_OBSERVED).all.map {|row| row[:agent_id] }
51
+ end
52
+
53
+ def self.agent_find_or_create(agent_id)
54
+ agent = Service::Agent.find(agent_id)
55
+ if agent.nil?
56
+ agent = Service::Agent.new
57
+ agent.id = agent_id
58
+ Wakame.log.debug("#{self.class}: Created new agent object with Agent ID: #{agent_id}")
59
+ end
60
+ agent
61
+ end
62
+
63
+ def self.register_as_observed(agent)
64
+ raise ArgumentError unless agent.is_a? Service::Agent
65
+ row = find_or_create(:agent_id=>agent.id, :agent_pool_id=>DEFAULT_POOL_ID)
66
+ if row[:group_type].nil? || row[:group_type] == GROUP_ACTIVE
67
+ # The agent is being registered at first time.
68
+ # Move the reference from active group to observed group.
69
+ row[:group_type]=GROUP_OBSERVED
70
+ row.save
71
+ Wakame.log.debug("#{self.class}: Register agent to observed group: #{agent.id}")
72
+ elsif
73
+ row[:group_type]=GROUP_OBSERVED
74
+ end
75
+ end
76
+
77
+ def self.register(agent)
78
+ raise ArgumentError unless agent.is_a?(Service::Agent)
79
+ row = find_or_create(:agent_id=>agent.id, :agent_pool_id=>DEFAULT_POOL_ID)
80
+ if row[:group_type].nil? || row[:group_type] == GROUP_OBSERVED
81
+ # The agent is being registered at first time.
82
+ # Move the reference from observed group to the active group.
83
+ row[:group_type]=GROUP_ACTIVE
84
+ row.save
85
+
86
+ Wakame.log.debug("#{self}: Register agent to active group: #{agent.id}")
87
+ ED.fire_event(Event::AgentMonitored.new(agent))
88
+ elsif row[:group_type] == GROUP_ACTIVE
89
+ end
90
+ end
91
+
92
+ def self.unregister(agent)
93
+ raise ArgumentError unless agent.is_a?(Service::Agent)
94
+ row = first(:agent_id=>agent.id, :agent_pool_id=>DEFAULT_POOL_ID)
95
+ if row.nil?
96
+ else
97
+ row.delete
98
+ Wakame.log.debug("#{self}: Unregister agent: #{agent.id}")
99
+ ED.fire_event(Event::AgentUnMonitored.new(agent))
100
+ end
101
+ end
102
+
103
+ def self.find_agent(agent_id)
104
+ raise "The agent ID \"#{agent_id}\" is not registered in the pool" unless first(:agent_id=>agent_id, :agent_pool_id=>DEFAULT_POOL_ID)
105
+ Service::Agent.find(agent_id) || raise("The agent ID #{agent_id} is registered. but not in the database.")
106
+ end
107
+
108
+ end
109
+ end
110
+
111
+ Initializer.loaded_classes << Models::AgentPool if const_defined? :Initializer
112
+
113
+ end
@@ -0,0 +1,34 @@
1
+
2
+ require 'sequel/model'
3
+
4
+ module Wakame
5
+ module Models
6
+ class ApplicationRepository < Sequel::Model
7
+ plugin :schema
8
+ plugin :hook_class_methods
9
+
10
+ set_schema {
11
+ primary_key :id, :type => Integer
12
+ column :app_name, :varchar, :unique=>true
13
+ column :repo_type, :varchar
14
+ column :repo_uri, :varchar
15
+ column :revision, :varchar
16
+ column :resource_tag, :varchar
17
+ column :options, :text
18
+ column :comment, :text
19
+ column :created_at, :datetime
20
+ column :updated_at, :datetime
21
+ }
22
+
23
+ before_create(:set_created_at) do
24
+ self.updated_at = self.created_at = Time.now
25
+ end
26
+ before_update(:set_updated_at) do
27
+ self.updated_at = Time.now
28
+ end
29
+
30
+ end
31
+ end
32
+
33
+ Initializer.loaded_classes << Models::ApplicationRepository if const_defined? :Initializer
34
+ end