1

I have a Django application that I wrote 5 years ago, which has been running successfully on Google App Engine - until last month when Google upgraded to Second Generation Cloud SQL.

Currently, I have a settings.py file, which includes a database definition which looks like this:

DATABASES = {
    'default': {
        'ENGINE': 'google.appengine.ext.django.backends.rdbms',
        'INSTANCE': 'my-project-name:my-db-instance',
        'NAME': 'my-db-name',
    },

Google's upgrade guide, tells me that the connection name needs to change from 'my-project-name:my-db-instance' to 'my-project-name:my-region:my-db-instance'. That's simple enough. Changing this leads me to get the error

InternalError at /login/

(0, u'Not authorized to access instance: my-project-name:my-region:my-db-instance')

According to this question, I need to add the prefix '/cloudsql/' to my instance name. So, I changed this (and the ENGINE specification) to give:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'INSTANCE': '/cloudsql/my-project-name:my-region:my-db-instance',
        'NAME': 'my-db-name',
        'USER' : 'root',
        'PASSWORD': '******************',
    },

I uploaded the modified file to Google (using gcloud app deploy). This time I get a completely different error screen, showing:

Error: Server Error

The server encountered an error and could not complete your request.

Please try again in 30 seconds.

When I look in the Logs, I see:

ImproperlyConfigured: Error loading MySQLdb module: No module named MySQLdb

It was pointed out by Daniel Ocando in this question, "The rdbms library will not work with an upgraded Second Generation Cloud SQL instance". Connections to the database now need to be made by means of a Unix domain socket.

Google provide documentation and examples of how to do this. However, I dont find Google's instructions very helpful. For connecting a Python application, they give this example code:

main.py:
db = sqlalchemy.create_engine(
    sqlalchemy.engine.url.URL(
        drivername="mysql+pymysql",
        username=db_user,
        password=db_pass,
        database=db_name,
        query={"unix_socket": "/cloudsql/{}".format(cloud_sql_connection_name)},
    ),
)

My application doesnt have a main.py file, so I'm really not sure where to put this code. I have looked at the full example code for this in GitHub, but I am none the wiser about what changes I need to make in my settings.py file, or elsewhere in my application.

My question is: Do I really have to go down this route (shifting to use SQLalchemy library), or can I upgrade my Django app to work with a second generation Google cloud SQL instance simply by making some changes in my settings.py file? And, if so, what changes?

My application uses Django 1.4, Python 2.7, and I'm not using the Flask framework which Google suggest.

I learned to use Django purely for the purposes of writing this application 5 years ago, but I have not used it since - so I have forgotten pretty much everything I knew about Django and Python.

Dustin Ingram
  • 20,502
  • 7
  • 59
  • 82
David-o
  • 41
  • 4

2 Answers2

1

A few notes here before I start: Django 1.4 and Python 2.7 are no longer supported, so this configuration may or may not work.

You were on the right track up until the part where you introduced the SQLAlchemy instructions. These aren't Django configurations. You should be able to keep your current DATABASES syntax, provided you complete the following steps:

  • Ensure you add the settings to your app.yaml to allow your new database.
  • Ensure you have set the Cloud SQL Client (preferred) permissions to the App Engine service account.
  • Make sure you have mysqlclient as a Python dependency.

The Django on App Engine Flex guide uses PostgreSQL, but does include some MySQL specific suggestions that should be useful. There's also sample DATABASE configurations there.

Hope this helps!

glasnt
  • 2,865
  • 5
  • 35
  • 55
0

Many thanks to glasnt for the helpful suggestions. These put me on the right track, and together with some information I found elsewhere, I got my site back up and running again - much to the delight of my client!

Here are the details of what I had to change:

I updated my app.yaml file and added:

beta_settings: 
  cloud_sql_instance: "my-project-name:my-region:my-db-instance"

and also:

libraries:
- name: MySQLdb
  version: "latest"

I updated settings.py, and added:

import MySQLdb

and I updated the DATABASES definition to:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '/cloudsql/my-project-name:my-region:my-db-instance',
        'NAME': 'my-db-name',
        'USER' : 'root',
        'PASSWORD': 'my-db-password',
    },

I found that I did not need to set up any permissions for the App Engine Service account. Google's upgrade guide, states:

When you upgrade an instance with an authorized App Engine project from First Generation to Second Generation, Cloud SQL creates a special service account that provides the same access as the authorized App Engine project did before the upgrade. Because this service account authorizes access only to a specific instance, rather than the entire project, this service account is not visible in the IAM service account page, and you cannot update or delete it.

So, for a migrated first-gen application, no permissions need to be configured.

David-o
  • 41
  • 4