Source code for iceprod.server.squid

"""
A helper to auto-configure a `Squid Cache <http://www.squid-cache.org/>`_
server and control starts, stops, and reloads.
"""

from __future__ import absolute_import, division, print_function

import os
import time
import subprocess
import crypt
import string
import random
import signal
import glob
from datetime import datetime,timedelta
import logging
from functools import partial

from iceprod.server import salt,KwargConfig

logger = logging.getLogger('squid')


[docs]class Squid(KwargConfig): """ Wrapper around the `Squid` server. `Squid` is used to proxy and cache web requests by IceProd running on worker nodes. """ def __init__(self, *args, **kwargs): # defaults self._cfg = { 'username': None, 'password': None, #'sslcert': None, #'sslkey': None, #'cacert': os.path.expandvars('$I3PROD/etc/cacerts.crt'), 'request_timeout': 10000, 'cache_dir': os.path.expandvars('$I3PROD/var/cache/squid'), 'cache_size': 200, # in MB 'port': 8082, # space separated networks for valid nodes (default: private IPv4) 'localnet': '10.0.0.0/8 172.16.0.0/12 192.168.0.0/16', 'pid_file': os.path.expandvars('$I3PROD/var/run/squid.pid'), 'cfg_file': os.path.expandvars('$I3PROD/etc/squid.conf'), 'cache_log': os.path.expandvars('$I3PROD/var/log/squid/cache.log'), 'access_log': os.path.expandvars('$I3PROD/var/log/squid/access.log'), 'squid_bin': os.path.expandvars('$I3PROD/sbin/squid'), } self._cfg_types = { 'username': 'str', 'password': 'str', #'sslcert': 'file', #'sslkey': 'file', #'cacert': 'file', 'request_timeout': 'int', 'cache_dir': 'dir', 'cache_size': 'int', 'port': 'int', 'localnet': 'str', 'pid_file': 'file', 'cfg_file': 'file', 'cache_log': 'file', 'access_log': 'file', 'squid_bin': 'file', } self.update(**kwargs) self.process = None
[docs] def update(self,**kwargs): # setup cfg variables self.validate(kwargs) if self._cfg['username'] is not None and self._cfg['password'] is not None: logger.info('enabling auth_basic') self.auth_basic = True self.authbasicfile = os.path.join(os.getcwd(),'authbasic_squid.htpasswd') with open(self.authbasicfile,'w') as file: passwd = crypt.crypt(self._cfg['password'],salt()) file.write('{}:{}\n'.format(self._cfg['username'],passwd)) else: logger.info('disabling auth_basic') self.auth_basic = False #if self._cfg['sslcert'] is not None and self._cfg['sslkey'] is not None: # logger.info('enabling SSL for squid') # self.ssl = True #else: # logger.info('disabling SSL for squid') # self.ssl = False # write config file self.cfgfile = os.path.abspath(self._cfg['cfg_file']) with open(self.cfgfile,'w') as file: p = partial(print,sep='',file=file) # core squid options p('http_port {}'.format(self._cfg['port'])) p('pid_filename {}'.format(self._cfg['pid_file'])) # general options p('cache_mgr not_to_be_disturbed') p('client_db off') p('detect_broken_pconn on') p('dns_timeout 5 minutes') p('forwarded_for off') p('half_closed_clients off') p('httpd_suppress_version_string on') p('pipeline_prefetch on') p('retry_on_error on') p('strip_query_terms off') p('uri_whitespace strip') p('visible_hostname localhost') # timeouts p('forward_timeout {} seconds'.format(self._cfg['request_timeout'])) p('connect_timeout {} seconds'.format(self._cfg['request_timeout'])) p('read_timeout {} seconds'.format(self._cfg['request_timeout'])) p('request_timeout {} seconds'.format(self._cfg['request_timeout'])) p('persistent_request_timeout {} seconds'.format(self._cfg['request_timeout'])) p('client_lifetime 20 hours') # acl definitions #p('acl all src 0.0.0.0/0') #p('acl localhost src 127.0.0.1/255.255.255.255') #p('acl to_localhost dst 127.0.0.0/8') p('acl localnet src {}'.format(self._cfg['localnet'])) # access rules p('http_access allow localhost manager') p('http_access deny manager') p('http_access deny to_localhost') p('http_access allow localnet') p('http_access allow localhost') p('http_access deny all') # max connections per ip p('acl maxuserconn src 127.0.0.0/8 {}'.format(self._cfg['localnet'])) p('acl limitusercon maxconn 500') p('http_access deny maxuserconn limitusercon') # caching p('cache allow all') p('cache_dir ufs {} {} 16 256'.format(self._cfg['cache_dir'],self._cfg['cache_size'])) # logs p('logformat squid [%tl] %>A %{Host}>h "%rm %ru HTTP/%rv" %Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh') p('logfile_rotate 4') p('access_log daemon:{} squid'.format(self._cfg['access_log'])) p('cache_log {} squid'.format(self._cfg['cache_log']))
[docs] def start(self): """Start server""" if self.process: raise Exception('Squid already running') logger.warning('starting Squid...') self.process = subprocess.Popen([self._cfg['squid_bin'],'-Nzf',self.cfgfile]) time.sleep(1) logger.warning('Squid running on %d',self._cfg['port'])
[docs] def stop(self): """Stop server""" if self.process: logger.warning('stopping Squid...') self.process.send_signal(signal.SIGTERM) self.process = None time.sleep(0.5) else: raise Exception('Squid not running')
[docs] def kill(self): """Stop server""" if self.process: logger.warning('killing Squid...') self.process.send_signal(signal.SIGINT) self.process = None else: raise Exception('Squid not running')
[docs] def restart(self): """Restart (reconfigure) the server""" if self.process: logger.warning('reconfiguring Squid...') self.process.send_signal(signal.SIGHUP) time.sleep(0.5) else: self.start()
[docs] def logrotate(self): """Rotate log files""" if self.process: logger.warning('rotating Squid log files...') try: self.process.send_signal(signal.SIGUSR1) except Exception as e: logger.error('error rotating Squid log files: %r',e) raise else: raise Exception('Squid not running')