Commits

Mikhail Korobov committed 507ac0e

Remove obsolete port management code; fix the apache config templates; decouple nginx from apache. Tests are now passing.

Comments (0)

Files changed (10)

   webserver.nginx, mysql become db.mysql);
 - task prefixes are removed in favor of namespaces (so e.g. ``apache_restart``
   becomes ``apache.restart``);
+- new port management facilities based on `port-for <http://pypi.python.org/pypi/port-for/>`_.
 
 Other changes:
 
 So custom tasks should be updated: wrap them with ``fabric.api.task``
 decorator + update import paths and task names for tasks from django-fab-deploy.
 
-The server-side organization is not changed. After switching to new API
-tasks should continue to work with existing servers.
+Server itself should also be upgraded. Django-fab-deploy 0.8 introduced
+much more powerful port management based on `port-for <http://pypi.python.org/pypi/port-for/>`_.
 
+In order to upgrade from 0.7.x to 0.8.x new port management:
+
+1) Run 'fab_deploy.system.install_software' task for each of your hosts: add
+
+   ::
+
+        from fab_deploy import system
+
+   line to your fabfile.py (or fabfile/__init__.py) and execute
+
+   ::
+
+        $ fab <host_function_name> system.install_software
+
+   for each host.
+
+2) Replace ``{{ APACHE_PORT }}`` with ``{{ PORTS['apache'] }}`` in
+   apache and nginx configs (``apache.conf`` and ``nginx.conf``);
+
+3) Add ``Listen 127.0.0.1:{{ {{ PORTS['apache'] }} }}`` directive to the
+   top of your ``apache.conf``.
+
+4) Run ``apache.install``, ``apache.update_config`` and ``nginx.update_config``
+   tasks for each of your hosts.
 
 0.7.5 (2012-03-02)
 ------------------
 
     Default is 'all.txt'.
 
-.. attribute:: env.conf.APACHE_PORT
-
-    The port used by apache backend. It is managed automatically
-    and shouldn't be set manually.
-
 You can put any other variables into the :attr:`env.conf`.
 They will be accessible in config templates as template context variables.
 

fab_deploy/config_templates/apache.config

+Listen 127.0.0.1:{{ PORTS['apache'] }}
 NameVirtualHost 127.0.0.1:{{ PORTS['apache'] }}
 <VirtualHost 127.0.0.1:{{ PORTS['apache'] }}
     ServerName {{ SERVER_NAME }}

fab_deploy/system.py

 
     sudo('easy_install -U pip')
     sudo('pip install -U virtualenv')
-    sudo('pip install port-for==0.2')
+    sudo('pip install port-for==0.3')
 
 @task
 @utils.run_as_sudo

fab_deploy/webserver/apache.py

 APACHE_PORTS_FILE = '/etc/apache2/ports.conf'
 APACHE_FIRST_PORT = 50000 # see http://www.iana.org/assignments/port-numbers
 APACHE_LAST_PORT = 60000
+TAKEOVER_STRING = '# This file is managed by django-fab-deploy 0.8.x. "Listen" directives are in /etc/apache2/sites-available/*'
 
 @task
 def touch(wsgi_file=None):
     sudo('rm -f /etc/apache2/sites-enabled/default')
     sudo('rm -f /etc/apache2/sites-enabled/000-default')
     setup_locale()
+    _disable_ports_conf()
 
 @task
 @utils.run_as_sudo
 def make_config():
     """ Updates apache config. """
-    _setup_port()
     name = env.conf['INSTANCE_NAME']
     utils.upload_config_template('apache.config',
                                  '/etc/apache2/sites-available/%s' % name,
 
 # === automatic apache ports management ===
 
+@task
+@utils.run_as_sudo
+def _disable_ports_conf():
+    lines = _ports_lines()
+    if lines[0] == TAKEOVER_STRING:
+        return
+    sudo("echo '%s\n' > %s" % (TAKEOVER_STRING, APACHE_PORTS_FILE))
+
 #@task
 @utils.run_as_sudo
 def _ports_lines():
     with settings(hide('stdout')):
         ports_data = sudo('cat ' + APACHE_PORTS_FILE)
     return ports_data.splitlines()
-
-def _used_ports(lines):
-    ports_mapping = dict()
-
-    listen_re = re.compile('^Listen (?P<host>.+):\s*(?P<port>\d+)')
-    instance_re = re.compile('^# used by (?P<instance>.+)')
-
-    for index, line in enumerate(lines):
-        match = re.match(listen_re, line)
-        if match:
-            instance = None
-            if index:
-                instance_match = re.match(instance_re, lines[index - 1])
-                if instance_match:
-                    instance = instance_match.group('instance')
-            ports_mapping[match.group('port')] = instance
-    return ports_mapping
-
-#@task
-@utils.run_as_sudo
-def _setup_port():
-    """
-    Makes sure some port is correctly listened in
-    :file:`ports.conf` and sets :attr:`env.conf.APACHE_PORT`
-    to this port.
-    """
-    lines = _ports_lines()
-
-    # take over ports.conf
-    TAKEOVER_STRING = '# This file is managed by django-fab-deploy. Please do not edit it manually.'
-    if lines[0] != TAKEOVER_STRING:
-        lines = [TAKEOVER_STRING]
-
-    used_ports = _used_ports(lines)
-
-    for port in used_ports:
-        if used_ports[port] == env.conf.INSTANCE_NAME:
-            # instance is binded to port
-            env.conf.APACHE_PORT = port
-            puts('Instance is binded to port ' + str(port))
-            return
-
-    # instance is not binded to any port yet;
-    # find an empty port and listen to it.
-    for port in range(APACHE_FIRST_PORT, APACHE_LAST_PORT):
-        if str(port) not in used_ports: # port is found!
-            lines.extend([
-                '',
-                '# used by ' + env.conf.INSTANCE_NAME,
-                'Listen 127.0.0.1:' + str(port)
-            ])
-            env.conf.APACHE_PORT = port
-            puts('Instance is not binded to any port. Binding it to port ' + str(port))
-            sudo("echo '%s\n' > %s" % ('\n'.join(lines), APACHE_PORTS_FILE))
-            return
-    warn('All apache ports are used!')

fab_deploy/webserver/nginx.py

 
 from fab_deploy import utils
 from fab_deploy import system
-from fab_deploy.webserver import apache
 
 __all__ = ['install', 'setup']
 
 @utils.run_as_sudo
 def setup():
     """ Updates nginx config and restarts nginx. """
-    apache._setup_port()
     name = env.conf['INSTANCE_NAME']
     utils.upload_config_template('nginx.config',
                                  '/etc/nginx/sites-available/%s' % name,

fab_deploy_tests/test_project/config_templates/apache.config

+Listen 127.0.0.1:{{ PORTS['apache'] }}
 NameVirtualHost 127.0.0.1:{{ PORTS['apache'] }}
 <VirtualHost 127.0.0.1:{{ PORTS['apache'] }}>
     ServerName {{ SERVER_NAME }}

fab_deploy_tests/test_project2/hosting/apache.config

+Listen 127.0.0.1:{{ PORTS['apache'] }}
 NameVirtualHost 127.0.0.1:{{ PORTS['apache'] }}
 <VirtualHost 127.0.0.1:{{ PORTS['apache'] }}>
     ServerName {{ SERVER_NAME }}

fab_deploy_tests/test_project3/test_project3/config_templates/apache.config

+Listen 127.0.0.1:{{ PORTS['apache'] }}
 NameVirtualHost 127.0.0.1:{{ PORTS['apache'] }}
 <VirtualHost 127.0.0.1:{{ PORTS['apache'] }}>
     ServerName {{ SERVER_NAME }}

fab_deploy_tests/tests/deploy.py

         return run('netstat -A inet -lnp')
     return fab(ports)
 
-def is_local_port_binded(port):
+def is_local_port_bound(port):
     port_string = '127.0.0.1:%s' % port
     ports = get_ports()
     return port_string in ports
 
 class ApacheSetupTest(FabDeployProjectTest):
 
-    def assertPortBinded(self, port):
-        self.assertTrue(is_local_port_binded(port))
+    def assertPortBound(self, port):
+        self.assertTrue(is_local_port_bound(port))
 
-    def assertPortNotBinded(self, port):
-        self.assertFalse(is_local_port_binded(port))
+    def assertPortNotBound(self, port):
+        self.assertFalse(is_local_port_bound(port))
 
     def test_apache_config(self):
         fab(apache.install)
         fab(foo_site)
         fab(apache.make_config)
 
-        foo_port = env.conf.APACHE_PORT
-        self.assertPortNotBinded(foo_port)
+        foo_port = env.conf.PORTS['apache']
+        self.assertPortNotBound(foo_port)
         self.assertFileExists('/etc/apache2/sites-enabled/foo')
 
         fab(apache.restart)
-        self.assertPortBinded(foo_port)
+        self.assertPortBound(foo_port)
 
         # second site
         fab(bar_site)
         fab(apache.make_config)
 
-        bar_port = env.conf.APACHE_PORT
+        bar_port = env.conf.PORTS['apache']
         self.assertNotEqual(foo_port, bar_port)
-        self.assertPortNotBinded(bar_port)
+        self.assertPortNotBound(bar_port)
 
         fab(apache.restart)
-        self.assertPortBinded(bar_port)
+        self.assertPortBound(bar_port)
 
         # re-configuring doesn't lead to errors
         fab(apache.make_config)
         fab(apache.restart)
-        self.assertPortBinded(bar_port)
+        self.assertPortBound(bar_port)
 
     def test_apache_make_wsgi(self):
         self.assertNoFile(env.conf.ENV_DIR+'/var/wsgi/foo.py')
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.