right_agent 0.5.1

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.
Files changed (147) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +78 -0
  3. data/Rakefile +86 -0
  4. data/lib/right_agent.rb +66 -0
  5. data/lib/right_agent/actor.rb +163 -0
  6. data/lib/right_agent/actor_registry.rb +76 -0
  7. data/lib/right_agent/actors/agent_manager.rb +189 -0
  8. data/lib/right_agent/agent.rb +735 -0
  9. data/lib/right_agent/agent_config.rb +403 -0
  10. data/lib/right_agent/agent_identity.rb +209 -0
  11. data/lib/right_agent/agent_tags_manager.rb +213 -0
  12. data/lib/right_agent/audit_formatter.rb +107 -0
  13. data/lib/right_agent/broker_client.rb +683 -0
  14. data/lib/right_agent/command.rb +30 -0
  15. data/lib/right_agent/command/agent_manager_commands.rb +134 -0
  16. data/lib/right_agent/command/command_client.rb +136 -0
  17. data/lib/right_agent/command/command_constants.rb +42 -0
  18. data/lib/right_agent/command/command_io.rb +128 -0
  19. data/lib/right_agent/command/command_parser.rb +87 -0
  20. data/lib/right_agent/command/command_runner.rb +105 -0
  21. data/lib/right_agent/command/command_serializer.rb +63 -0
  22. data/lib/right_agent/console.rb +65 -0
  23. data/lib/right_agent/core_payload_types.rb +42 -0
  24. data/lib/right_agent/core_payload_types/cookbook.rb +61 -0
  25. data/lib/right_agent/core_payload_types/cookbook_position.rb +46 -0
  26. data/lib/right_agent/core_payload_types/cookbook_repository.rb +116 -0
  27. data/lib/right_agent/core_payload_types/cookbook_sequence.rb +70 -0
  28. data/lib/right_agent/core_payload_types/dev_repositories.rb +90 -0
  29. data/lib/right_agent/core_payload_types/event_categories.rb +38 -0
  30. data/lib/right_agent/core_payload_types/executable_bundle.rb +138 -0
  31. data/lib/right_agent/core_payload_types/login_policy.rb +72 -0
  32. data/lib/right_agent/core_payload_types/login_user.rb +62 -0
  33. data/lib/right_agent/core_payload_types/planned_volume.rb +94 -0
  34. data/lib/right_agent/core_payload_types/recipe_instantiation.rb +60 -0
  35. data/lib/right_agent/core_payload_types/repositories_bundle.rb +50 -0
  36. data/lib/right_agent/core_payload_types/right_script_attachment.rb +95 -0
  37. data/lib/right_agent/core_payload_types/right_script_instantiation.rb +73 -0
  38. data/lib/right_agent/core_payload_types/secure_document.rb +66 -0
  39. data/lib/right_agent/core_payload_types/secure_document_location.rb +63 -0
  40. data/lib/right_agent/core_payload_types/software_repository_instantiation.rb +61 -0
  41. data/lib/right_agent/daemonize.rb +35 -0
  42. data/lib/right_agent/dispatcher.rb +348 -0
  43. data/lib/right_agent/enrollment_result.rb +217 -0
  44. data/lib/right_agent/exceptions.rb +30 -0
  45. data/lib/right_agent/ha_broker_client.rb +1278 -0
  46. data/lib/right_agent/idempotent_request.rb +140 -0
  47. data/lib/right_agent/log.rb +418 -0
  48. data/lib/right_agent/monkey_patches.rb +29 -0
  49. data/lib/right_agent/monkey_patches/amqp_patch.rb +274 -0
  50. data/lib/right_agent/monkey_patches/ruby_patch.rb +49 -0
  51. data/lib/right_agent/monkey_patches/ruby_patch/array_patch.rb +29 -0
  52. data/lib/right_agent/monkey_patches/ruby_patch/darwin_patch.rb +24 -0
  53. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch.rb +24 -0
  54. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +30 -0
  55. data/lib/right_agent/monkey_patches/ruby_patch/object_patch.rb +49 -0
  56. data/lib/right_agent/monkey_patches/ruby_patch/singleton_patch.rb +46 -0
  57. data/lib/right_agent/monkey_patches/ruby_patch/string_patch.rb +107 -0
  58. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch.rb +32 -0
  59. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +90 -0
  60. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/process_patch.rb +63 -0
  61. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/stdio_patch.rb +27 -0
  62. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/time_patch.rb +55 -0
  63. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/win32ole_patch.rb +34 -0
  64. data/lib/right_agent/multiplexer.rb +91 -0
  65. data/lib/right_agent/operation_result.rb +270 -0
  66. data/lib/right_agent/packets.rb +637 -0
  67. data/lib/right_agent/payload_formatter.rb +104 -0
  68. data/lib/right_agent/pid_file.rb +159 -0
  69. data/lib/right_agent/platform.rb +319 -0
  70. data/lib/right_agent/platform/darwin.rb +227 -0
  71. data/lib/right_agent/platform/linux.rb +268 -0
  72. data/lib/right_agent/platform/windows.rb +1204 -0
  73. data/lib/right_agent/scripts/agent_controller.rb +522 -0
  74. data/lib/right_agent/scripts/agent_deployer.rb +379 -0
  75. data/lib/right_agent/scripts/common_parser.rb +153 -0
  76. data/lib/right_agent/scripts/log_level_manager.rb +193 -0
  77. data/lib/right_agent/scripts/stats_manager.rb +256 -0
  78. data/lib/right_agent/scripts/usage.rb +58 -0
  79. data/lib/right_agent/secure_identity.rb +92 -0
  80. data/lib/right_agent/security.rb +32 -0
  81. data/lib/right_agent/security/cached_certificate_store_proxy.rb +63 -0
  82. data/lib/right_agent/security/certificate.rb +102 -0
  83. data/lib/right_agent/security/certificate_cache.rb +89 -0
  84. data/lib/right_agent/security/distinguished_name.rb +56 -0
  85. data/lib/right_agent/security/encrypted_document.rb +84 -0
  86. data/lib/right_agent/security/rsa_key_pair.rb +76 -0
  87. data/lib/right_agent/security/signature.rb +86 -0
  88. data/lib/right_agent/security/static_certificate_store.rb +69 -0
  89. data/lib/right_agent/sender.rb +937 -0
  90. data/lib/right_agent/serialize.rb +29 -0
  91. data/lib/right_agent/serialize/message_pack.rb +102 -0
  92. data/lib/right_agent/serialize/secure_serializer.rb +131 -0
  93. data/lib/right_agent/serialize/secure_serializer_initializer.rb +47 -0
  94. data/lib/right_agent/serialize/serializable.rb +135 -0
  95. data/lib/right_agent/serialize/serializer.rb +149 -0
  96. data/lib/right_agent/stats_helper.rb +731 -0
  97. data/lib/right_agent/subprocess.rb +38 -0
  98. data/lib/right_agent/tracer.rb +124 -0
  99. data/right_agent.gemspec +60 -0
  100. data/spec/actor_registry_spec.rb +81 -0
  101. data/spec/actor_spec.rb +99 -0
  102. data/spec/agent_config_spec.rb +226 -0
  103. data/spec/agent_identity_spec.rb +75 -0
  104. data/spec/agent_spec.rb +571 -0
  105. data/spec/broker_client_spec.rb +961 -0
  106. data/spec/command/agent_manager_commands_spec.rb +51 -0
  107. data/spec/command/command_io_spec.rb +93 -0
  108. data/spec/command/command_parser_spec.rb +79 -0
  109. data/spec/command/command_runner_spec.rb +72 -0
  110. data/spec/command/command_serializer_spec.rb +51 -0
  111. data/spec/core_payload_types/dev_repositories_spec.rb +64 -0
  112. data/spec/core_payload_types/executable_bundle_spec.rb +59 -0
  113. data/spec/core_payload_types/login_user_spec.rb +98 -0
  114. data/spec/core_payload_types/right_script_attachment_spec.rb +65 -0
  115. data/spec/core_payload_types/spec_helper.rb +23 -0
  116. data/spec/dispatcher_spec.rb +372 -0
  117. data/spec/enrollment_result_spec.rb +53 -0
  118. data/spec/ha_broker_client_spec.rb +1673 -0
  119. data/spec/idempotent_request_spec.rb +136 -0
  120. data/spec/log_spec.rb +177 -0
  121. data/spec/monkey_patches/amqp_patch_spec.rb +100 -0
  122. data/spec/monkey_patches/eventmachine_spec.rb +62 -0
  123. data/spec/monkey_patches/string_patch_spec.rb +99 -0
  124. data/spec/multiplexer_spec.rb +48 -0
  125. data/spec/operation_result_spec.rb +171 -0
  126. data/spec/packets_spec.rb +418 -0
  127. data/spec/platform/platform_spec.rb +60 -0
  128. data/spec/results_mock.rb +45 -0
  129. data/spec/secure_identity_spec.rb +50 -0
  130. data/spec/security/cached_certificate_store_proxy_spec.rb +56 -0
  131. data/spec/security/certificate_cache_spec.rb +71 -0
  132. data/spec/security/certificate_spec.rb +49 -0
  133. data/spec/security/distinguished_name_spec.rb +46 -0
  134. data/spec/security/encrypted_document_spec.rb +55 -0
  135. data/spec/security/rsa_key_pair_spec.rb +55 -0
  136. data/spec/security/signature_spec.rb +66 -0
  137. data/spec/security/static_certificate_store_spec.rb +52 -0
  138. data/spec/sender_spec.rb +887 -0
  139. data/spec/serialize/message_pack_spec.rb +131 -0
  140. data/spec/serialize/secure_serializer_spec.rb +102 -0
  141. data/spec/serialize/serializable_spec.rb +90 -0
  142. data/spec/serialize/serializer_spec.rb +174 -0
  143. data/spec/spec.opts +2 -0
  144. data/spec/spec_helper.rb +77 -0
  145. data/spec/stats_helper_spec.rb +681 -0
  146. data/spec/tracer_spec.rb +114 -0
  147. metadata +320 -0
@@ -0,0 +1,30 @@
1
+ #
2
+ # Copyright (c) 2009-2011 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ COMMAND_BASE_DIR = File.join(File.dirname(__FILE__), 'command')
24
+
25
+ require File.normalize_path(File.join(COMMAND_BASE_DIR, 'command_constants'))
26
+ require File.normalize_path(File.join(COMMAND_BASE_DIR, 'command_parser'))
27
+ require File.normalize_path(File.join(COMMAND_BASE_DIR, 'command_serializer'))
28
+ require File.normalize_path(File.join(COMMAND_BASE_DIR, 'command_io'))
29
+ require File.normalize_path(File.join(COMMAND_BASE_DIR, 'command_runner'))
30
+ require File.normalize_path(File.join(COMMAND_BASE_DIR, 'command_client'))
@@ -0,0 +1,134 @@
1
+ #
2
+ # Copyright (c) 2009-2011 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ module RightScale
24
+
25
+ # Commands exposed by agent that has an AgentManager actor
26
+ class AgentManagerCommands
27
+
28
+ # List of command names associated with description
29
+ # The commands should be implemented in methods in this class named '<name>_command'
30
+ # where <name> is the name of the command.
31
+ COMMANDS = {
32
+ :list => 'List all available commands with their description',
33
+ :set_log_level => 'Set log level to options[:level]',
34
+ :get_log_level => 'Get log level',
35
+ :ping => 'Ping agent',
36
+ :stats => 'Get statistics about agent operation',
37
+ :terminate => 'Terminate agent'
38
+ }
39
+
40
+ # Build hash of commands associating command names with block
41
+ #
42
+ # === Parameter
43
+ # agent_manager(AgentManager):: Agent manager used by ping and stats commands
44
+ #
45
+ # === Return
46
+ # cmds(Hash):: Hash of command blocks keyed by command names
47
+ def self.get(agent_manager)
48
+ cmds = {}
49
+ target = new(agent_manager)
50
+ COMMANDS.each { |k, v| cmds[k] = lambda { |opts, conn| opts[:conn] = conn; target.send("#{k.to_s}_command", opts) } }
51
+ cmds
52
+ end
53
+
54
+ # Initialize command server
55
+ #
56
+ # === Parameter
57
+ # agent_manager(AgentManager):: Agent manager used by ping and stats commands
58
+ def initialize(agent_manager)
59
+ @agent_manager = agent_manager
60
+ @serializer = Serializer.new
61
+ end
62
+
63
+ protected
64
+
65
+ # List command implementation
66
+ #
67
+ # === Parameters
68
+ # opts(Hash):: Should contain the connection for sending data
69
+ #
70
+ # === Return
71
+ # true:: Always return true
72
+ def list_command(opts)
73
+ usage = "Agent exposes the following commands:\n"
74
+ COMMANDS.reject { |k, _| k == :list || k.to_s =~ /test/ }.each do |c|
75
+ c.each { |k, v| usage += " - #{k.to_s}: #{v}\n" }
76
+ end
77
+ CommandIO.instance.reply(opts[:conn], usage)
78
+ end
79
+
80
+ # Set log level command
81
+ #
82
+ # === Return
83
+ # true:: Always return true
84
+ def set_log_level_command(opts)
85
+ Log.level = opts[:level] if [ :debug, :info, :warn, :error, :fatal ].include?(opts[:level])
86
+ CommandIO.instance.reply(opts[:conn], Log.level)
87
+ end
88
+
89
+ # Get log level command
90
+ #
91
+ # === Return
92
+ # true:: Always return true
93
+ def get_log_level_command(opts)
94
+ CommandIO.instance.reply(opts[:conn], Log.level)
95
+ end
96
+
97
+ # Ping command
98
+ #
99
+ # === Parameters
100
+ # opts[:conn](EM::Connection):: Connection used to send reply
101
+ #
102
+ # === Return
103
+ # true
104
+ def ping_command(opts)
105
+ CommandIO.instance.reply(opts[:conn], @serializer.dump(@agent_manager.ping))
106
+ end
107
+
108
+ # Stats command
109
+ #
110
+ # === Parameters
111
+ # opts[:conn](EM::Connection):: Connection used to send reply
112
+ # opts[:reset](Boolean):: Whether to reset stats
113
+ #
114
+ # === Return
115
+ # true
116
+ def stats_command(opts)
117
+ CommandIO.instance.reply(opts[:conn], @serializer.dump(@agent_manager.stats({:reset => opts[:reset]})))
118
+ end
119
+
120
+ # Terminate command
121
+ #
122
+ # === Parameters
123
+ # opts[:conn](EM::Connection):: Connection used to send reply
124
+ #
125
+ # === Return
126
+ # true:: Always return true
127
+ def terminate_command(opts)
128
+ CommandIO.instance.reply(opts[:conn], 'Terminating')
129
+ @agent_manager.terminate
130
+ end
131
+
132
+ end # AgentManagerCommands
133
+
134
+ end # RightScale
@@ -0,0 +1,136 @@
1
+ #
2
+ # Copyright (c) 2009-2011 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ module RightScale
24
+
25
+ class CommandClient
26
+
27
+ # Agent response if any
28
+ attr_accessor :response
29
+
30
+ # Create client
31
+ #
32
+ # === Parameters
33
+ # socket_port(Integer):: Socket port on which to connect to agent
34
+ # cookie(String):: Cookie associated with command server
35
+ def initialize(socket_port, cookie)
36
+ @socket_port = socket_port
37
+ @cookie = cookie
38
+ @pending = 0
39
+ end
40
+
41
+ # Stop command client
42
+ #
43
+ # === Block
44
+ # Given block gets called back once last response has been received or timeout
45
+ def stop(&close_handler)
46
+ if @pending > 0
47
+ @close_timeout = EM::Timer.new(@last_timeout) { close_handler.call(timeout=true) }
48
+ @close_handler = lambda { @close_timeout.cancel; close_handler.call(timeout=false) }
49
+ else
50
+ close_handler.call(timeout=false)
51
+ end
52
+ end
53
+
54
+ # Send command to running agent
55
+ #
56
+ # === Parameters
57
+ # options(Hash):: Hash of options and command name
58
+ # options[:name]:: Command name
59
+ # options[:...]:: Other command specific options, passed through to agent
60
+ # verbose(Boolean):: Whether client should display debug info
61
+ # timeout(Integer):: Number of seconds we should wait for a reply from the agent
62
+ #
63
+ # === Block
64
+ # handler: Command results handler
65
+ #
66
+ # === Return
67
+ # true:: Always return true
68
+ #
69
+ # === Raise
70
+ # RuntimeError:: Timed out waiting for result, raised in EM thread
71
+ def send_command(options, verbose=false, timeout=20, &handler)
72
+ return if @closing
73
+ @last_timeout = timeout
74
+ manage_em = !EM.reactor_running?
75
+ response_handler = lambda do
76
+ EM.stop if manage_em
77
+ handler.call(@response) if handler && @response
78
+ @pending -= 1
79
+ @close_handler.call if @close_handler && @pending == 0
80
+ end
81
+ send_handler = lambda do
82
+ @pending += 1
83
+ command = options.dup
84
+ command[:verbose] = verbose
85
+ command[:cookie] = @cookie
86
+ EM.next_tick { EM.connect('127.0.0.1', @socket_port, ConnectionHandler, command, self, response_handler) }
87
+ EM.add_timer(timeout) { EM.stop; raise 'Timed out waiting for agent reply' } if manage_em
88
+ end
89
+ if manage_em
90
+ EM.run { send_handler.call }
91
+ else
92
+ send_handler.call
93
+ end
94
+ true
95
+ end
96
+
97
+ protected
98
+
99
+ # EventMachine connection handler which sends command to agent
100
+ # and waits for response
101
+ module ConnectionHandler
102
+
103
+ # Initialize command
104
+ #
105
+ # === Parameters
106
+ # command(Hash):: Command to be sent
107
+ # client(RightScale::CommandClient):: Client whose response field should be initialized
108
+ # callback(Proc):: Called back after response has been set
109
+ def initialize(command, client, callback)
110
+ @command = command
111
+ @parser = CommandParser.new do |data|
112
+ close_connection
113
+ client.response = data
114
+ callback.call
115
+ end
116
+ end
117
+
118
+ # Send command to agent
119
+ # Called by EventMachine after connection with agent has been established
120
+ #
121
+ # === Return
122
+ # true:: Always return true
123
+ def post_init
124
+ puts "Sending command #{@command.inspect}" if @command[:verbose]
125
+ send_data(CommandSerializer.dump(@command))
126
+ true
127
+ end
128
+
129
+ # Handle agent response
130
+ def receive_data(data)
131
+ @parser.parse_chunk(data)
132
+ end
133
+ end
134
+
135
+ end
136
+ end
@@ -0,0 +1,42 @@
1
+ #
2
+ # Copyright (c) 2009-2011 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ module RightScale
25
+
26
+ class CommandConstants
27
+
28
+ # Ports used for command protocol
29
+ BASE_INSTANCE_AGENT_SOCKET_PORT = 60000
30
+ BASE_INSTANCE_AGENT_CHECKER_SOCKET_PORT = 61000
31
+
32
+ BASE_CORE_AGENT_SOCKET_PORT = 70000
33
+ BASE_LABORER_AGENT_SOCKET_PORT = 71000
34
+ BASE_REPLICANT_AGENT_SOCKET_PORT = 72000
35
+ BASE_PROXY_AGENT_SOCKET_PORT = 73000
36
+ BASE_LIBRARY_AGENT_SOCKET_PORT = 74000
37
+ BASE_WASABI_AGENT_SOCKET_PORT = 75000
38
+
39
+ BASE_MAPPER_SOCKET_PORT = 79000
40
+
41
+ end
42
+ end
@@ -0,0 +1,128 @@
1
+ # Copyright (c) 2009-2011 RightScale, Inc, All Rights Reserved Worldwide.
2
+ #
3
+ # THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
4
+ # AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
5
+ # reproduction, modification, or disclosure of this program is
6
+ # strictly prohibited. Any use of this program by an authorized
7
+ # licensee is strictly subject to the terms and conditions,
8
+ # including confidentiality obligations, set forth in the applicable
9
+ # License Agreement between RightScale.com, Inc. and
10
+ # the licensee.
11
+
12
+ require 'singleton'
13
+
14
+ module RightScale
15
+
16
+ # Class which allows listening for data and sending data on sockets
17
+ # This allows other processes running on the same machine to send commands to
18
+ # the agent without having to go through RabbitMQ.
19
+ class CommandIO
20
+
21
+ include Singleton
22
+
23
+ # ensure uniqueness of handler to avoid confusion.
24
+ raise "#{ServerInputHandler.name} is already defined" if defined?(ServerInputHandler)
25
+
26
+ # EventMachine connection
27
+ # Define event loop callbacks handler
28
+ module ServerInputHandler
29
+
30
+ # Keep block used to handle incoming data
31
+ #
32
+ # === Parameters
33
+ # handler(Proc):: Incoming data handler should take two arguments:
34
+ # * First argument contains command
35
+ # * Second argument contains connection used to reply
36
+ def initialize(handler)
37
+ @handler = handler
38
+ @parser = CommandParser.new { |cmd| handler.call(cmd, self) }
39
+ end
40
+
41
+ # EventMachine loop callback called whenever there is data coming from the socket
42
+ #
43
+ # === Parameter
44
+ # data(String):: Incoming data
45
+ #
46
+ # === Return
47
+ # true:: Always return true
48
+ def receive_data(data)
49
+ @parser.parse_chunk(data)
50
+ true
51
+ end
52
+
53
+ end
54
+
55
+ # Is listener currently waiting for input?
56
+ #
57
+ # === Return
58
+ # true:: If 'listen' was last called
59
+ # false:: Otherwise
60
+ def listening
61
+ !@conn.nil?
62
+ end
63
+
64
+ # Open command socket and wait for input on it
65
+ # This can only be called again after 'stop_listening' was called
66
+ #
67
+ # === Parameters
68
+ # socket_port(Integer):: Socket port on which to listen
69
+ #
70
+ # === Block
71
+ # The given block should take two arguments:
72
+ # * First argument will be given the commands sent through the socket
73
+ # Commands should be serialized using RightScale::CommandSerializer.
74
+ # * Second argument contains the connection that should be given back to
75
+ # +reply+ to send reply
76
+ #
77
+ # === Return
78
+ # true:: Always return true
79
+ #
80
+ # === Raise
81
+ # (RightScale::Exceptions::Argument):: If block is missing
82
+ # (RightScale::Exceptions::Application):: If +listen+ has already been called and +stop+ hasn't since
83
+ # (RightScale::Exceptions::Application):: If port is already bound
84
+ def listen(socket_port, &block)
85
+ raise Exceptions::Argument, 'Missing listener block' unless block_given?
86
+ raise Exceptions::Application, 'Already listening' if listening
87
+ begin
88
+ @conn = EM.start_server('127.0.0.1', socket_port, ServerInputHandler, block)
89
+ rescue Exception => e
90
+ raise Exceptions::IO, 'Listen port unavailable' if e.message =~ /no acceptor/
91
+ end
92
+ true
93
+ end
94
+
95
+ # Stop listening for commands
96
+ # Do nothing if already stopped
97
+ #
98
+ # === Return
99
+ # true:: If command listener was listening
100
+ # false:: Otherwise
101
+ def stop_listening
102
+ res = !@conn.nil?
103
+ if res
104
+ EM.stop_server(@conn)
105
+ @conn = nil
106
+ end
107
+ res
108
+ end
109
+
110
+ # Write given data to socket, must be listening
111
+ #
112
+ # === Parameters
113
+ # conn(EM::Connection):: Connection used to send data
114
+ # data(String):: Data that should be written
115
+ # close_after_writing(TrueClass|FalseClass):: Whether TCP connection with client should be
116
+ # closed after reply is sent
117
+ #
118
+ # === Return
119
+ # true:: Always return true
120
+ def reply(conn, data, close_after_writing=true)
121
+ conn.send_data(CommandSerializer.dump(data))
122
+ conn.close_connection_after_writing if close_after_writing
123
+ true
124
+ end
125
+
126
+ end
127
+
128
+ end