class StateBasedChainer(MultiTargetChainer): """<class maturity="stable" abstract="yes"> <summary> Class encapsulating connection establishment with multiple target addresses and keeping down state between connects. </summary> <description> <para> This class encapsulates a real TCP/IP connection establishment, and is used when a top-level proxy wants to perform chaining. In addition to ConnectChainer, this class adds the capability to perform stateful, load balance server connections among a set of IP addresses. </para> <note> <para>Both the <link linkend="python.Chainer.FailoverChainer">FailoverChainer</link> and <link linkend="python.Chainer.RoundRobinChainer">RoundRobinChainer</link> classes are derived from StateBasedChainer.</para> </note> </description> <metainfo> <attributes> <attribute internal="yes"> <name>state</name> <type></type> <description>Down state of target hosts. </description> </attribute> </attributes> </metainfo> </class> """ def __init__(self, protocol=ZD_PROTO_AUTO, timeout_connect=None, timeout_state=None): """<method maturity="stable"> <summary> Constructor to initialize a StateBasedChainer instance. </summary> <description> <para> This constructor initializes a StateBasedChainer class by filling arguments with appropriate values and calling the inherited constructor. </para> </description> <metainfo> <arguments> <argument maturity="stable"> <name>protocol</name> <type> <link id="zorp.proto.id"/> </type> <default>ZD_PROTO_AUTO</default> <description> Optional, specifies connection protocol (<parameter> ZD_PROTO_TCP</parameter> or <parameter>ZD_PROTO_UDP </parameter>), when not specified it defaults to the same protocol used on the client side. </description> </argument> <argument> <name>timeout_connect</name> <type> <integer/> </type> <default>30000</default> <description> Specifies connection timeout to be used when connecting to the target server. </description> </argument> <argument> <name>timeout_state</name> <type> <integer/> </type> <default>60000</default> <description> The down state of remote hosts is kept for this interval in miliseconds. </description> </argument> </arguments> </metainfo> </method> """ MultiTargetChainer.__init__(self, protocol, timeout_connect) if not timeout_state: timeout_state = 60000 self.state = TimedCache('chainer-state', int((timeout_state + 999) / 1000), update_stamp=FALSE) def getNextTarget(self, session): """<method internal="yes"> </method> """ while 1: (target_local, target_remote) = MultiTargetChainer.getNextTarget(self, session) if not target_remote: # we enumerated all targets try: session.chainer_targets_enumerated = session.chainer_targets_enumerated + 1 except AttributeError: session.chainer_targets_enumerated = 1 if not self.state or session.chainer_targets_enumerated == 2: # we enumerated all our targets twice, once # with state held, and then all state # cleared, we were not successful, terminate # target iteration log( None, CORE_MESSAGE, 4, "All destinations are down for two full iterations, giving up;" ) return (None, None) ## LOG ## # This message reports that the remote end is down and Zorp stores the # down state of the remote end, so Zorp wont try to connect to it within the # timeout latter. ## log( None, CORE_MESSAGE, 4, "All destinations are down, clearing cache and trying again;" ) # we enumerated all targets, and all of them were # down, clear our state and try once more self.state.clear() self.restart(session) continue is_host_down = self.state.lookup(target_remote.ip_s) if not is_host_down: return (target_local, target_remote) else: ## LOG ## # This message reports that the remote end is down, but Zorp does not store the # down state of the remote end, so Zorp will try to connect to it next time. ## log(session.session_id, CORE_MESSAGE, 4, "Destination is down, skipping; remote='%s'", (target_remote, )) def disableTarget(self, session, target_local, target_remote): """<method internal="yes"> </method> """ ## LOG ## # This message reports that the remote end is down and Zorp stores the # down state of the remote end, so Zorp wont try to connect to it within the # timeout latter. ## log(session.session_id, CORE_MESSAGE, 4, "Destination is down, keeping state; remote='%s'", (target_remote, )) self.state.store(target_remote.ip_s, 1)
class StateBasedChainer(MultiTargetChainer): """<class maturity="stable" abstract="yes"> <summary> Class encapsulating connection establishment with multiple target addresses and keeping down state between connects. </summary> <description> <para> This class encapsulates a real TCP/IP connection establishment, and is used when a top-level proxy wants to perform chaining. In addition to ConnectChainer, this class adds the capability to perform stateful, load balance server connections among a set of IP addresses. </para> <note> <para>Both the <link linkend="python.Chainer.FailoverChainer">FailoverChainer</link> and <link linkend="python.Chainer.RoundRobinChainer">RoundRobinChainer</link> classes are derived from StateBasedChainer.</para> </note> </description> <metainfo> <attributes> <attribute internal="yes"> <name>state</name> <type></type> <description>Down state of target hosts. </description> </attribute> </attributes> </metainfo> </class> """ def __init__(self, protocol=ZD_PROTO_AUTO, timeout_connect=None, timeout_state=None): """<method maturity="stable"> <summary> Constructor to initialize a StateBasedChainer instance. </summary> <description> <para> This constructor initializes a StateBasedChainer class by filling arguments with appropriate values and calling the inherited constructor. </para> </description> <metainfo> <arguments> <argument maturity="stable"> <name>protocol</name> <type> <link id="zorp.proto.id"/> </type> <default>ZD_PROTO_AUTO</default> <description> Optional, specifies connection protocol (<parameter> ZD_PROTO_TCP</parameter> or <parameter>ZD_PROTO_UDP </parameter>), when not specified it defaults to the same protocol used on the client side. </description> </argument> <argument> <name>timeout_connect</name> <type> <integer/> </type> <default>30000</default> <description> Specifies connection timeout to be used when connecting to the target server. </description> </argument> <argument> <name>timeout_state</name> <type> <integer/> </type> <default>60000</default> <description> The down state of remote hosts is kept for this interval in miliseconds. </description> </argument> </arguments> </metainfo> </method> """ MultiTargetChainer.__init__(self, protocol, timeout_connect) if not timeout_state: timeout_state = 60000 self.state = TimedCache('chainer-state', int((timeout_state + 999) / 1000), update_stamp=FALSE) def getNextTarget(self, session): """<method internal="yes"> </method> """ while 1: (target_local, target_remote) = MultiTargetChainer.getNextTarget(self, session) if not target_remote: # we enumerated all targets try: session.chainer_targets_enumerated = session.chainer_targets_enumerated + 1 except AttributeError: session.chainer_targets_enumerated = 1 if not self.state or session.chainer_targets_enumerated == 2: # we enumerated all our targets twice, once # with state held, and then all state # cleared, we were not successful, terminate # target iteration log(None, CORE_MESSAGE, 4, "All destinations are down for two full iterations, giving up;") return (None, None) ## LOG ## # This message reports that the remote end is down and Zorp stores the # down state of the remote end, so Zorp wont try to connect to it within the # timeout latter. ## log(None, CORE_MESSAGE, 4, "All destinations are down, clearing cache and trying again;") # we enumerated all targets, and all of them were # down, clear our state and try once more self.state.clear() self.restart(session) continue is_host_down = self.state.lookup(target_remote.ip_s) if not is_host_down: return (target_local, target_remote) else: ## LOG ## # This message reports that the remote end is down, but Zorp does not store the # down state of the remote end, so Zorp will try to connect to it next time. ## log(session.session_id, CORE_MESSAGE, 4, "Destination is down, skipping; remote='%s'", (target_remote,)) def disableTarget(self, session, target_local, target_remote): """<method internal="yes"> </method> """ ## LOG ## # This message reports that the remote end is down and Zorp stores the # down state of the remote end, so Zorp wont try to connect to it within the # timeout latter. ## log(session.session_id, CORE_MESSAGE, 4, "Destination is down, keeping state; remote='%s'", (target_remote,)) self.state.store(target_remote.ip_s, 1)