root / README.develop @ fc2afa67
History | View | Annotate | Download (10.9 kB)
1 |
DEVELOP.txt - Information on how to setup a development environment. |
---|---|
2 |
|
3 |
Dependencies |
4 |
------------ |
5 |
|
6 |
Synnefo is written in Python 2.6 and depends on the following Python modules |
7 |
[package versions confirmed to be compatible are in braces] |
8 |
|
9 |
- django 1.2 [Django==1.2.4] |
10 |
- simplejson [simplejson==2.1.3] |
11 |
- pycurl [pycurl==7.19.0] |
12 |
- python-dateutil [python-dateutil==1.4.1] |
13 |
WARNING: version python-dateutil==2.0 downloaded by pip known *not* to work |
14 |
with Python 2.6 |
15 |
- south [south==0.7.1] |
16 |
WARNING: not working with Debian squeeze's default south-0.7-1 package. |
17 |
- amqplib [amqplib==0.6.1] |
18 |
|
19 |
also, depending on the database engine of choice, on one of the following: |
20 |
- MySQL-python [MySQL-python==1.2.3] |
21 |
- psycopg2 [psycopg2==2.4] |
22 |
|
23 |
if the invitations application is deployed, the following |
24 |
dependencies should be installed |
25 |
|
26 |
- pycrypto==2.1.0 |
27 |
|
28 |
if you want to test the ganeti (FIXME) |
29 |
|
30 |
to run the user interface tests, selenium must be installed |
31 |
- selenium [?] |
32 |
|
33 |
Preparing the development environment |
34 |
------------------------------------- |
35 |
|
36 |
1. Prepare the system: The easiest method is to setup a working environment |
37 |
through virtualenv. Alternatively, you can use your system's package manager |
38 |
to install the dependencies (e.g. Macports has them all). |
39 |
|
40 |
* On Snow Leopard and linux (64-bit), you have to set the following environment |
41 |
variable for pip to compile the dependencies correctly. |
42 |
|
43 |
$ export ARCHFLAGS="-arch x86_64" |
44 |
|
45 |
* On Ubuntu, a few more packages must be installed before installing the |
46 |
prerequisite Python libraries |
47 |
|
48 |
$ sudo aptitude install libcurl3-gnutls libcurl3-gnutls-dev uuid-dev |
49 |
|
50 |
2. Checkout the code and install the Python prerequisites. This assumes |
51 |
that python is already installed on the host. |
52 |
|
53 |
$ sudo easy_install virtualenv |
54 |
$ git clone https://user@code.grnet.gr/git/synnefo synnefo |
55 |
$ virtualenv --python=python2.6 synnefo --no-site-packages |
56 |
... |
57 |
$ cd synnefo |
58 |
$ ./bin/pip install <list_of_prerequisites> |
59 |
|
60 |
3. At this point you should have all required dependencies installed. Now you |
61 |
have to select a database engine. The choices are: postgres, mysql and sqlite. |
62 |
|
63 |
- SQLite |
64 |
The python sqlite driver is available by default with Python so no additional |
65 |
configuration is required. Also, most self-respecting systems have the sqlite |
66 |
library installed by default. |
67 |
|
68 |
- MySQL |
69 |
MySQL must be installed first |
70 |
|
71 |
* Ubuntu - Debian |
72 |
$ sudo apt-get install libmysqlclient-dev |
73 |
|
74 |
* MacPorts |
75 |
$sudo port install mysql5 |
76 |
|
77 |
Install the MySQL python library |
78 |
|
79 |
$ bin/pip install MySQL-python |
80 |
|
81 |
Note: On MacOSX with Mysql install from MacPorts the above command will fail |
82 |
complaining that it cannot find the mysql_config command. Do the following and |
83 |
restart the installation |
84 |
|
85 |
$ echo "mysql_config = /opt/local/bin/mysql_config5" >> ./build/MySQL-python/site.cfg |
86 |
|
87 |
Configure a MySQL db/account for synnefo |
88 |
|
89 |
$ mysql -u root -p |
90 |
|
91 |
mysql> create database synnefo; |
92 |
mysql> show databases; |
93 |
mysql> GRANT ALL on synnefo.* TO username IDENTIFIED BY 'password'; |
94 |
|
95 |
- Postgres |
96 |
|
97 |
# Ubuntu - Debian |
98 |
$ sudo apt-get install postgresql-8.4 libpq-dev |
99 |
|
100 |
# MacPorts |
101 |
$ sudo port install postgresql84 |
102 |
|
103 |
Install the postgres Python library |
104 |
|
105 |
$ bin/pip install psycopg2 |
106 |
|
107 |
Configure a postgres db/account for synnefo |
108 |
Become the postgres user, connect to PostgreSQL: |
109 |
$ sudo su - postgres |
110 |
$ psql |
111 |
|
112 |
Run the following commands: |
113 |
DROP DATABASE synnefo; |
114 |
DROP USER username; |
115 |
CREATE USER username WITH PASSWORD 'password'; |
116 |
CREATE DATABASE synnefo; |
117 |
GRANT ALL PRIVILEGES ON DATABASE synnefo TO username; |
118 |
ALTER DATABASE synnefo OWNER TO username; |
119 |
ALTER USER username CREATEDB; |
120 |
|
121 |
The last line enables the newly created user to create own databases. This is |
122 |
needed for Django to create and drop the test_synnefo database for unit |
123 |
testing. |
124 |
|
125 |
4. At this point you should have a working DB. Now configure Django to access it: |
126 |
Copy the default configuration file |
127 |
|
128 |
$ cp settings.py.dist settings.py |
129 |
|
130 |
and then copy/edit according to the database used: |
131 |
|
132 |
- SQLite |
133 |
|
134 |
PROJECT_PATH = os.path.dirname(os.path.abspath(__file__)) + '/' |
135 |
|
136 |
DATABASES = { |
137 |
'default': { |
138 |
'ENGINE': 'django.db.backends.sqlite3', |
139 |
'NAME': PROJECT_PATH + 'synnefo.db' #WARN: This must be an absolute path |
140 |
} |
141 |
} |
142 |
|
143 |
- MySQL |
144 |
DATABASES = { |
145 |
'default': { |
146 |
'ENGINE': 'django.db.backends.mysql', |
147 |
'NAME': 'synnefo', |
148 |
'USER': 'USERNAME', |
149 |
'PASSWORD': 'PASSWORD', |
150 |
'HOST': 'HOST', |
151 |
'PORT': 'PORT', |
152 |
'OPTIONS': { |
153 |
'init_command': 'SET storage_engine=INNODB', |
154 |
} |
155 |
} |
156 |
} |
157 |
|
158 |
- Postgres |
159 |
|
160 |
DATABASES = { |
161 |
'default': { |
162 |
'ENGINE': 'django.db.backends.postgresql_psycopg2', |
163 |
'NAME': 'DATABASE', |
164 |
'USER': 'USERNAME', |
165 |
'PASSWORD': 'PASSWORD', |
166 |
'HOST': 'HOST', |
167 |
'PORT': 'PORT', |
168 |
} |
169 |
} |
170 |
|
171 |
5. Try it out. The following command will attempt to connect to the DB and |
172 |
print out DDL statements. It should not fail. |
173 |
|
174 |
$ ./bin/python manage.py sql db |
175 |
|
176 |
6. Create the DB and load initial data: |
177 |
|
178 |
$ ./bin/python manage.py syncdb |
179 |
$ ./bin/python manage.py migrate db |
180 |
$ ./bin/python manage.py loaddata db/fixtures/flavors.json |
181 |
$ ./bin/python manage.py loaddata db/fixtures/images.json |
182 |
|
183 |
The following fixtures can be loaded optionally depending on |
184 |
testing requirements: |
185 |
|
186 |
$ ./bin/python manage.py loaddata db/fixtures/vms.json |
187 |
$ ./bin/python manage.py loaddata db/fixtures/disks.json |
188 |
|
189 |
7. Set the BACKEND_PREFIX_ID variable to some unique prefix, e.g. your commit |
190 |
username in settings.py. Several functional conventions within the system |
191 |
require this variable to include a dash at its end (e.g. snf-) |
192 |
|
193 |
8. Fix the AMQP-specific settings based on the selected BACKEND_PREFIX_ID. |
194 |
The fix_amqp_settings() function is called once at the end of |
195 |
settings.py.dist, you must call it again if you change BACKEND_PREFIX_ID |
196 |
at some later point. |
197 |
Also make sure that if /var/log/synnefo/dispatcher.log exists, it has proper |
198 |
permissions. If not, /var/log/synnefo/ should be writable by the dispatcher. |
199 |
|
200 |
9. Start the system |
201 |
$ ./bin/python logic/dispatcher.py # DB synch daemon |
202 |
$ ./bin/python manage.py runserver # Django |
203 |
|
204 |
10. (Hopefully) Done |
205 |
|
206 |
|
207 |
South Database Migrations |
208 |
------------------------ |
209 |
|
210 |
* Initial Migration |
211 |
|
212 |
First, remember to add the south app to settings.py (it is already included in |
213 |
the settings.py.dist). |
214 |
|
215 |
To initialise south migrations in your database the following commands must be |
216 |
executed: |
217 |
|
218 |
$ ./bin/python manage.py syncdb # Create / update the database with the south tables |
219 |
$ ./bin/python manage.py migrate db # Perform migration in the database |
220 |
|
221 |
Note that syncdb will create the latest models that exist in the db app, so |
222 |
some migrations may fail. If you are sure a migration has already taken place |
223 |
you must use the "--fake" option, to apply it. |
224 |
|
225 |
For example: |
226 |
|
227 |
$ ./bin/python manage.py migrate db 0001 --fake |
228 |
|
229 |
To be sure that all migrations are applied type: |
230 |
|
231 |
$ ./bin/python manage.py migrate db --list |
232 |
|
233 |
All starred migrations are applied. |
234 |
|
235 |
Remember, the migration is performed mainly for the data, not for the database |
236 |
schema. If you do not want to migrate the data, a syncdb and fake migrations |
237 |
for all the migration versions will suffice. |
238 |
|
239 |
* Schema migrations: |
240 |
|
241 |
Do not use the syncdb management command. It can only be used |
242 |
the first time and/or if you drop the database and must recreate it from |
243 |
scratch. |
244 |
See "Initial Migration" section. |
245 |
|
246 |
Every time you make changes to the database and data migration is not required |
247 |
(WARNING: always perform this with extreme care): |
248 |
|
249 |
$ ./bin/python manage.py schemamigration db --auto |
250 |
|
251 |
The above will create the migration script. Now this must be applied to the |
252 |
live database. |
253 |
|
254 |
$ ./bin/python migrate db |
255 |
|
256 |
Consider this example (adding a field to the SynnefoUser model): |
257 |
|
258 |
bkarak@nefarian:~/devel/synnefo$ ./bin/python manage.py schemamigration db --auto |
259 |
+ Added field new_south_test_field on db.SynnefoUser |
260 |
Created 0002_auto__add_field_synnefouser_new_south_test_field.py. |
261 |
|
262 |
You can now apply this migration with: ./manage.py migrate db |
263 |
|
264 |
$ ./manage.py migrate db |
265 |
Running migrations for db: |
266 |
- Migrating forwards to 0002_auto__add_field_synnefouser_new_south_test_field. |
267 |
> db:0002_auto__add_field_synnefouser_new_south_test_field |
268 |
- Loading initial data for db. |
269 |
Installing json fixture 'initial_data' from '/home/bkarak/devel/synnefo/../synnefo/db/fixtures'. |
270 |
Installed 1 object(s) from 1 fixture(s) |
271 |
|
272 |
South needs some extra definitions to the model to preserve and migrate the |
273 |
existing data, for example, if we add a field in a model, we should declare its |
274 |
default value. If not, South will propably fail, after indicating the error. |
275 |
|
276 |
$ ./bin/python manage.py schemamigration db --auto |
277 |
? The field 'SynnefoUser.new_south_field_2' does not have a default specified, yet is NOT NULL. |
278 |
? Since you are adding or removing this field, you MUST specify a default |
279 |
? value to use for existing rows. Would you like to: |
280 |
? 1. Quit now, and add a default to the field in models.py |
281 |
? 2. Specify a one-off value to use for existing columns now |
282 |
? Please select a choice: 1 |
283 |
|
284 |
* Data migrations: |
285 |
|
286 |
If we need to do data migration as well, for example rename a field, we use tha |
287 |
'datamigration' management command. |
288 |
|
289 |
In contrast with schemamigration, to perform complex data migration, we must |
290 |
write the script manually. The process is the following: |
291 |
|
292 |
1. Introduce the changes in the code and fixtures (initial data). |
293 |
2. Execute: |
294 |
|
295 |
$ ./bin/python manage.py datamigration <migration_name_here> |
296 |
|
297 |
For example: |
298 |
|
299 |
$ ./bin/python manage.py datamigration db rename_credit_wallet |
300 |
Created 0003_rename_credit_wallet.py. |
301 |
|
302 |
3. We edit the generated script. It contains two methods: forwards and |
303 |
backwards. |
304 |
|
305 |
For database operations (column additions, alter tables etc) we use the |
306 |
South database API (http://south.aeracode.org/docs/databaseapi.html). |
307 |
|
308 |
To access the data, we use the database reference (orm) provided as |
309 |
parameter in forwards, backwards method declarations in the migration |
310 |
script. For example: |
311 |
|
312 |
class Migration(DataMigration): |
313 |
|
314 |
def forwards(self, orm): |
315 |
orm.SynnefoUser.objects.all() |
316 |
|
317 |
4. To migrate the database to the latest version, we execute: |
318 |
|
319 |
./manage.py migrate db |
320 |
|
321 |
To see which migrations are applied: |
322 |
|
323 |
$ ./bin/python manage.py migrate db --list |
324 |
|
325 |
db |
326 |
(*) 0001_initial |
327 |
(*) 0002_auto__add_field_synnefouser_new_south_test_field |
328 |
(*) 0003_rename_credit_wallet |
329 |
|
330 |
More information and more thorough examples can be found in the South web site. |
331 |
|
332 |
http://south.aeracode.org/ |
333 |
|
334 |
|
335 |
UI Testing |
336 |
---------- |
337 |
The functional ui tests require the Selenium server and the synnefo app to |
338 |
be running. |
339 |
|
340 |
$ wget http://selenium.googlecode.com/files/selenium-server-standalone-2.0b2.jar |
341 |
$ java -jar selenium-server-standalone-2.0b2.jar & |
342 |
$ ./bin/python manage.py runserver & |
343 |
$ ./bin/python manage.py test ui |
344 |
|
345 |
|
346 |
Test coverage |
347 |
------------- |
348 |
|
349 |
In order to get code coverage reports you need to install django-test-coverage |
350 |
|
351 |
$ ./bin/pip install django-test-coverage |
352 |
|
353 |
Then edit your settings.py and configure the test runner: |
354 |
|
355 |
TEST_RUNNER = 'django-test-coverage.runner.run_tests' |