redis_server.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #
3 # License: BSD
4 # https://raw.github.com/robotics-in-concert/rocon_multimaster/license/LICENSE
5 #
6 ##############################################################################
7 # Imports
8 ##############################################################################
9 
10 import os
11 import sys
12 import re
13 import shutil
14 import subprocess
15 import signal
16 
17 # Delete this once we upgrade (hopefully anything after precise)
18 # Refer to https://github.com/robotics-in-concert/rocon_multimaster/issues/248
19 import threading
20 
21 import rospy
22 import rospkg
23 try:
24  import rocon_python_redis as redis
25 except ImportError:
26  # actually unused right now while we use redis as a ros package
27  sys.exit("\n[ERROR] No python-redis found - 'rosdep install rocon_hub'\n")
28 import rocon_semantic_version as semantic_version
29 
30 from . import utils
31 
32 ##############################################################################
33 # Redis Server
34 ##############################################################################
35 
36 
38  def __init__(self, parameters):
39  self._parameters = parameters
40  self._process = None
41  self._home_dir = os.path.join(rospkg.get_ros_home(), 'redis', self._parameters['name'].lower().replace(" ", "_"))
42  # clean out old redis information
43  if os.path.isdir(self._home_dir):
44  shutil.rmtree(self._home_dir)
45  self._files = {}
47  self._files['redis_conf'] = os.path.join(self._home_dir, 'redis-%s.conf' % self._version_extension)
48  self._files['redis_conf_local'] = os.path.join(self._home_dir, 'redis-%s.conf.local' % self._version_extension)
49  self._files['redis_server_log'] = os.path.join(self._home_dir, 'redis-server.log')
50  self._server = None
51  self._setup()
52 
54  '''
55  Sniff the version in major.minor format for decision making elsewhere (patch we disregard since our
56  decisions don't depend on it).
57 
58  @return version extension in 'major.minor' format.
59  @rtype str
60  '''
61  process = subprocess.Popen(["redis-server", "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
62  output, unused_error = process.communicate()
63  try:
64  version_string = re.search('v=([0-9.]+)', output).group(1) # 2.6+ pattern
65  except AttributeError:
66  version_string = re.search('version ([0-9.]+)', output).group(1) # 2.2 pattern
67  version = semantic_version.Version(version_string)
68  rospy.loginfo("Hub : version %s" % (version_string))
69  return str(version.major) + "." + str(version.minor)
70 
71  def _setup(self):
72  '''
73  Clear and configure redis conf, log files in the ros home
74  directories under a subdirectory styled by the name of this hub.
75 
76  Also check that we have support for the redis server - i.e. check if we
77  have a .conf file for that version and exit this script if not found.
78  '''
79  if os.path.isdir(self._home_dir):
80  shutil.rmtree(self._home_dir)
81  os.makedirs(self._home_dir)
82  rospack = rospkg.RosPack()
83  package_redis_conf_file = os.path.join(rospack.get_path('rocon_hub'), 'redis', 'redis-%s.conf' % self._version_extension)
84  package_redis_conf_local_file = os.path.join(rospack.get_path('rocon_hub'), 'redis', 'redis-%s.conf.local' % self._version_extension)
85 
86  # Checks
87  if not os.path.isfile(package_redis_conf_file):
88  utils.logfatal("Hub : the version of the redis server you have installed is not supported by rocon.")
89  sys.exit(utils.logfatal("Hub : please submit a ticket at https://github.com/robotics-in-concert/rocon_multimaster"))
90 
91  redis_conf_template = utils.read_template(package_redis_conf_file)
92  redis_conf_template = instantiate_redis_conf_template(redis_conf_template, self._files['redis_conf_local']) # drop the local file path to use into the settings
93  redis_local_template = utils.read_template(package_redis_conf_local_file)
94  redis_local_template = instantiate_local_conf_template(redis_local_template,
95  self._parameters['port'],
96  self._parameters['max_memory'],
97  self._files['redis_server_log'],
98  self._home_dir)
99  try:
100  f = open(self._files['redis_conf'], 'w')
101  f.write(redis_conf_template.encode('utf-8'))
102  finally:
103  f.close()
104  try:
105  f = open(self._files['redis_conf_local'], 'w')
106  f.write(redis_local_template.encode('utf-8'))
107  finally:
108  f.close()
109 
110  def start(self):
111  '''
112  Start the server. Also connect, delete all rocon:xxx
113  variables and reinitialise with specified values.
114 
115  Aborts the program if the connection fails.
116  '''
117  # Launch as a separate process group so we can control when it gets shut down.
118  self._process = subprocess.Popen(["redis-server", self._files['redis_conf']], preexec_fn=os.setpgrp)
119  pool = redis.ConnectionPool(host='localhost', port=int(self._parameters['port']), db=0)
120  no_attempts = 5
121  count = 0
122  while count < no_attempts:
123  try:
124  self._server = redis.Redis(connection_pool=pool)
125  rocon_keys = self._server.keys("rocon:*")
126  pattern = re.compile("rocon:*")
127  keys_to_delete = []
128  for key in rocon_keys:
129  if pattern.match(key):
130  keys_to_delete.append(key)
131  pipe = self._server.pipeline()
132  if len(keys_to_delete) != 0:
133  pipe.delete(*keys_to_delete) # * unpacks the list args - http://stackoverflow.com/questions/2921847/python-once-and-for-all-what-does-the-star-operator-mean-in-python
134  pipe.set("rocon:hub:name", self._parameters['name'])
135  pipe.execute()
136  rospy.loginfo("Hub : reset hub variables on the redis server.")
137  break
138  except redis.ConnectionError:
139  count += 1
140  if count == no_attempts:
141  self.shutdown()
142  sys.exit(utils.logfatal("Hub : could not connect to the redis server - is it running?"))
143  else:
144  rospy.rostime.wallsleep(0.1)
145 
146  def shutdown(self):
147  '''
148  Clears rocon: keys on the server.
149  '''
150  try:
151  rocon_keys = self._server.keys("rocon:*")
152  pattern = re.compile("rocon:*")
153  keys_to_delete = []
154  for key in rocon_keys:
155  if pattern.match(key):
156  keys_to_delete.append(key)
157  pipe = self._server.pipeline()
158  if len(keys_to_delete) != 0:
159  pipe.delete(*keys_to_delete) # * unpacks the list args - http://stackoverflow.com/questions/2921847/python-once-and-for-all-what-does-the-star-operator-mean-in-python
160  pipe.execute()
161  #rospy.loginfo("Hub : clearing hub variables on the redis server.")
162  except redis.ConnectionError:
163  pass
164  try:
165  # because we start the redis sserver as a separate process group, we need to handle its shutdown
166  # as roslaunch knows nothing of it.
167  self._process.send_signal(signal.SIGINT)
168  self._process.wait()
169  except OSError:
170  pass # process already shut down
171 
172 
173 ##############################################################################
174 # Functions
175 ##############################################################################
176 
177 
178 def instantiate_redis_conf_template(template, local_conf_filename):
179  '''
180  Variable substitution in a template file.
181 
182  @param local_conf_filename : where to find the local redis configuration file
183  @type string
184  '''
185  return template % locals()
186 
187 
188 def instantiate_local_conf_template(template, port, max_memory, logfile, working_dir):
189  '''
190  Variable substitution in a template file.
191 
192  @param port : port on which the server will run
193  @type int
194  @param pid_file : pathname to where the pid file will be stored
195  @type string
196  @param max_memory: how much memory to allocate to the redis server in bytes
197  @type string (e.g. 10mb)
198  @param logfile
199  @type string
200  @param working_dir : filesystem which redis uses to dump (can we turn this off in 2.6?)
201  @type string
202  '''
203  return template % locals()
204 
205 if __name__ == "__main__":
206  pool = redis.ConnectionPool(host='localhost', port='6380', db=0)
207  try:
208  print "dude"
209  except redis.exceptions.ConnectionError:
210  print "err"
def instantiate_redis_conf_template(template, local_conf_filename)
def instantiate_local_conf_template(template, port, max_memory, logfile, working_dir)
def __init__(self, parameters)
Definition: redis_server.py:38


rocon_hub
Author(s): Daniel Stonier , Jihoon Lee , Piyush Khandelwal
autogenerated on Mon Jun 10 2019 14:40:13