Saturday, December 8, 2012

Working with Amazon's Elastic Beanstalk

I decided to start using Amazon cloud services.

There is a pretty instresting solution Amazon Beastalk, which you should consider.

There is a lot of documentation, but as normal, there are always pseudo dark steps not thoroughly documented.

For intance, when you arrive to "Develop, Test, and Deploy" section of the "AWS Elastic Beanstalk" documentation, there is a step, name #1 quite obscure:


1.- From your Git repository directory, type the following command.
git aws.config

Nowhere it is told that you must previously 'set up your gir repository' as described here.

I also encountered what I think is a bug regarding timezones on Amazon's service, which was easily fixed. Following the README of the "AWS Command line tools". I got this error:


 $ elastic-beanstalk-describe-applications
Service returned an error.
Type: Sender
Code: RequestExpired
Message: Request has expired. Timestamp date: 2012-06-02T14:44:13-04:30

Strangely, this happened because I had my ubuntu virtual box configured to show time as in my timezone (-04:30), while the EC2 instance (at least that's we're I checked) showed in UTC format.

So I decided to change my locale to UTC

doing
 $ sudo dpkg-reconfigure tzdata

I had to select "ETC", and then "UTC"...

Done that, the command "elastic-beanstalk-describe-applications" ran without problems. showing my applications.

Then I continued following the beanstalk documentation and did
git aws.config
git aws.push

The only problem I encountered after doing this is that I realized that Amazon Beanstalk doesn't support Git Submodules !! So I had to make a new directory, copy all my application there, do a new complete repository with all the code and push it to amazon. At first I was kind of reluctant to do this, but then I started to think that it was not that bad ... (I also didn't have other options : )

I realized that my app was configured to always redirect to https protocol (secure http) (this gave me a lot of headaches, because if Beanstalk is not configured to work with SSL then the Health Check URL didn't work at all because of the difference http/https... ). So I decided to buy a $13 SSL certificate from godaddy (they cost this if you click on their ad after a google search, not if you enter directy to godaddy).

I wanted to configure mydomain.com instead of www.mydomain.com, and also to use Amazon Route 53. This was not a problem with the current documentation at Amazon.









Friday, December 7, 2012

rsync over ssh with a private key

RSYNC is my favorite tool to sync two directories, either local or remotely.

Now I learned how to do it over ssh using a private key:

Thanks to Troy and this link: http://troy.jdmz.net/rsync/index.html

This is the command:

rsync -e "ssh -i /path/to/my/key.pem -l myuser" myremotehost:/remote/path/ localpath -iva

Easy peasy

Thursday, December 6, 2012

joomla white page in template after server migration/update // comparing packages

I changed servers mounted all the stuff and some of the Joomla sites I had opened correctly, others just showed a white page.

I didn't know why.

After many many failed attemps to fix it, god's hand enlightened me and I decided to compare the installed php packages between servers.

This can be done using
dpkg --get-selections | grep php

Comparing these packages between servers, it showed evidently I had missed installation of the package
php5-mcrypt

An apt-get install put my joomla sites running again.

Tuesday, December 4, 2012

install LAMP - postgres - change data dir - ssh without password... all donde minuted in AWS Amazon Web Services

I just wanted to comment on how good Amazon Web Services are.

I had my server hosted with another provider, whose name I'm not going to say...

I was with them a lot of time, maybe 10 years. Upgraded my server a couple of times and all. One day my server went nuts and they wanted to charge me $99 dollars AN HOUR just to take a look and help me, no warranties.

So I decided it was time to migrate to a better service: Amazon AWS.

I was getting used to it while setting up the a webapp on Elastic Beanstalk, which is also an excellent service you should try if you have a big webapp you want to deploy. It has and all integration with git, so its all really easy. Using it was that I started understading the relationship between the different services:
EC2: the app servers
RDS: database servers
Route52: domain record management
CloudFront: asset delivery
etc...

Well, as I was saying I was urged to migrate from my old server.

I could set up a running new server in minutes. Maybe the most complicated stuff would be opening a new account and passing through the telephone validation.

So I wrote all this because I wanted to documents the command I did to install the LAMP+Postgres environment I needed. Also to change the datadir of mysql:

I decided to use an instance running Ubuntu.

commands (with sudo or as root):
apt-get update
apt-get install apache2 libapache2-mod-php5 mysql-server libapache2-mod-auth-mysql php5-mysql postgresql-client php5-pgsql

that get all I needed installed.

I had a snapshot of a volume I wanted to mount in the new server. So in Amazon's interface I select attach volume to xxxx instance. After that I had to modify mount the drive that appeared in /dev/xvdf with the command

mount /dev/xvdf /mnt

To make the change permanent I edited the file

/etc/fstab

and added the line

/dev/xvdf /mnt ext4 defaults 0 0

where /mnt is the mount point... the other options are googlable.

I also needed to change MySql's data directory. This was kind of tricky the first time I had to do it.

One needs to change /etc/mysql/my.cnf file find datadir options and change it to what one needs.

The restart mysql with

service mysql restart

But that't not all, it is necessaty to update ubuntu's apparmor file with

vim /etc/apparmor.d/usr.sbin.mysqld

There you must find the old datadir path and change for the new one. Afterwards, reconfigure mysql with

dpkg-reconfigure mysql-server-5.5

And then restart again mysql (I did this, I don't know if its absolutely necessary).

I also needed to log in to the server using classic user/password combination, so its necessary to edit sshd_config with

vim /etc/ssh/sshd_config

There it is necessary to change the directive to

PasswordAuthentication yes

Finally I installed exim4 as an MTA

apt-get install exim4

and configured it with

dpkg-reconfigure exim4-config

I then chose a user to forward me root and postmaster mails. It is necessary to create a file in the user home

~/.forward

and the contents are the email address to which you wish to forward the emails.

that's it !

Monday, May 28, 2012

Database migration from PostgreSQL to MySql

Since I need to use Amazon RDS for my new application, I needed to migrate from my current PostgreSQL database to MySql.

Luckily I didn't realy in anything specific of postgresql, so migration  of schema and data was a breeze. I used a free downloadable online console tool pg2mysql

Well, in the schema generated my pg2mysql the TIMESTAMP fields in Postgres were converted to TIMESTAMP datatype in MySql (which has a DEFAULT CURRENT_TIMESTAMP by default), which is not what I wanted. So I manually edited my schema dump replacing "timestamp" to "datetime".

I also changed the default MyISAM to InnoDB...

In particular, in my code I had to be careful because certain syntax changes:

  • DISTINCT ON  (field1, field2)  field2 as f1, field2 as f2, field3 -> DISTINCT(CONCAT(field1, field2)), field3



Wednesday, May 16, 2012

error running shared postrotate script for mysql

I was receiving this emails on a daily basis:
/etc/cron.daily/logrotate:
error: error running shared postrotate script for /var/log/mysql.log /var/log/mysql/mysql.log /var/log/mysql/mysql-slow.log
run-parts: /etc/cron.daily/logrotate exited with return code 1
I decided to do something about it. After checking this link I determined it was because of a password error in the user debian-sys-maint.


I had deleted this user without noticing it's importance.

So in this link I found how to recover the user, and also I read Ubuntu: Reset debian-sys-maint’s mysql password ...

I hope I don't receive the email tomorrow.

Just for documentation sake, I copy the relevant contents of the previous link I mentioned.

1)
Recently I upgraded Linux on my home server and every day I would get this email:
Subject: Anacron job 'cron.daily' on server.local
/etc/cron.daily/logrotate:
error: error running shared postrotate script for '/var/log/mysql.log /var/log/mysql/mysql.log /var/log/mysql/mysql-slow.log '
run-parts: /etc/cron.daily/logrotate exited with return code 1
I first examined the /etc/cron.daily/logrotate script.
There was only one executable line: /usr/sbin/logrotate /etc/logrotate.conf
I next examined /etc/logrotate.conf and found this: include /etc/logrotate.d
logrotate.d is a directory of scripts to run.
SInce my error message was for MySQL, I examined the /etc/logrorate.d/mysql-server script.
One line in this script is
MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
I examined /etc/mysql/debian.cnf and found the cause of the error message:
user = debian-sys-maint
password = oMhAfEiEiO
It was the PASSWORD! There was a mismatch between the password in debian.cnf and the password for thedebian-sys-maint user in MySQL.
Finally, I changed the password for debian-sys-maint in MySQL to the password listed in debian.cnf and the daily error message email stopped.

2)
Log into MySQL as the root user and run the following SQL query, substituting PASSWORD-HERE for the actual plain text password which is the same as the password in the /etc/mysql/debian.conf file:

INSERT INTO `user` (
 `Host`,
 `User`,
 `Password`,
 `Select_priv`,
 `Insert_priv`,
 `Update_priv`,
 `Delete_priv`,
 `Create_priv`,
 `Drop_priv`,
 `Reload_priv`,
 `Shutdown_priv`,
 `Process_priv`,
 `File_priv`,
 `Grant_priv`,
 `References_priv`,
 `Index_priv`,
 `Alter_priv`,
 `Show_db_priv`,
 `Super_priv`,
 `Create_tmp_table_priv`,
 `Lock_tables_priv`,
 `Execute_priv`,
 `Repl_slave_priv`,
 `Repl_client_priv`,
 `Create_view_priv`,
 `Show_view_priv`,
 `Create_routine_priv`,
 `Alter_routine_priv`,
 `Create_user_priv`,
 `ssl_type`,
 `ssl_cipher`,
 `x509_issuer`,
 `x509_subject`,
 `max_questions`,
 `max_updates`,
 `max_connections`,
 `max_user_connections`
)
VALUES (
 'localhost',
 'debian-sys-maint',
 password('PASSWORD-HERE'),
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'Y',
 'N',
 'N',
 'N',
 'N',
 'N',
 '',
 '',
 '',
 '',
 0,
 0,
 0,
 0
);
FLUSH PRIVILEGES;

3)
On Ubuntu systems there is a (system) mysql user debian-sys-maint that is used by the system’s init scripts to control the mysql database, e.g. to start or stop the mysql server. The password of this user is stored (in clear text) in /etc/mysql/debian.cnf. If this password does not match the the actual password in the mysql server the mysql init scripts will fail:
# /etc/init.d/mysql restart
 * Stopping MySQL database server mysqld     [fail]
 * Starting MySQL database server mysqld     [ OK ]
# /etc/init.d/mysql status
/usr/bin/mysqladmin: connect to server at 'localhost' failed
error: 'Access denied for user 'debian-sys-maint'@'localhost' (using password: YES)'
Moreover trying to update the mysql server will fail with an error like:
Fehler traten auf beim Bearbeiten von:
 /var/cache/apt/archives/mysql-server-5.1_5.1.37-1ubuntu5.1_i386.deb
E: Sub-process /usr/bin/dpkg returned an error code (1)
To fix the problem you have to update the mysql password for the user debian-sys-maint:
  1. Get the password from /etc/mysql/debian.cnf. The clear text password is stored twice in the file (the lines starting with “password =”:
    # Automatically generated for Debian scripts. DO NOT TOUCH!
    [client]
    host = localhost
    user = debian-sys-maint
    password = your-secret-password
    socket = /var/run/mysqld/mysqld.sock
    [mysql_upgrade]
    host = localhost
    user = debian-sys-maint
    password = your-secret-password
    socket = /var/run/mysqld/mysqld.sock
    basedir = /usr
  2. Update the password in the mysql server (you need mysql root access):
    mysql --user root --password
    mysql> SET PASSWORD FOR 'debian-sys-maint'@'localhost' = PASSWORD('your-secret-password');
  3. If an previous mysql-server system upgrade failed, just restart the upgrade.
The (debian) documentation can be found in /usr/share/doc/mysql-server-5.1/README.Debian:
[...] You may never ever delete the special mysql user “debian-sys-maint”. This user together with the credentials in /etc/mysql/debian.cnf are used by the init scripts to stop the server as they would require knowledge of the mysql root users password else. So in most of the times you can fix the situation by making sure that the debian.cnf file contains the right password, e.g. by setting a new one (remember to do a “flush privileges” then). [...]

Friday, April 13, 2012

configuring MX records

i realized i didn't know how to configure correctly my MX record

i found out here:

http://www.petri.co.il/configure_mx_records_for_incoming_smtp_email_traffic.htm

Record FQDN
Record Type
Record Value
MX Pref
mail.dpetri.net
A
192.90.1.17
dpetri.net
MX
mail.dpetri.net
10

linux swap memory

interesting article from http://www.linux.com/feature/121916

these lines made want to include it on the blog:

The Linux 2.6 kernel added a new kernel parameter called swappiness to let administrators tweak the way Linux swaps. It is a number from 0 to 100. In essence, higher values lead to more pages being swapped, and lower values lead to more applications being kept in memory, even if they are idle. Kernel maintainer Andrew Morton has said that he runs his desktop machines with a swappiness of 100, stating that "My point is that decreasing the tendency of the kernel to swap stuff out is wrong. You really don't want hundreds of megabytes of BloatyApp's untouched memory floating about in the machine. Get it out on the disk, use the memory for something useful."
One downside to Morton's idea is that if memory is swapped out too quickly then application response time drops, because when the application's window is clicked the system has to swap the application back into memory, which will make it feel slow.
The default value for swappiness is 60. You can alter it temporarily (until you next reboot) by typing as root:
echo 50 > /proc/sys/vm/swappiness


CakePHP SELECT ... FOR UPDATE hack

Sometimes one needs to do a SELECT ... FOR UPDATE in order to preserve the integrity of our transactions. Here is a use-at-you-own-discretion 'hack', which saves coding time if you are in a hurry (like me at the moment) or don't mind writing a useful behaviour for all of us.

The problem can be seen easily with the following example:

Suppose we have a user, an `account table` with the `account.available_money` field on it. Suppose the user has initially $100.

The problem arrives if the hacker manages to concurrently run two processes:

One process does:
    BEGIN
    SELECT available_money from account where user_id = '1' ; // $money = $100
    UPDATE account SET available_money = 0 where user_id = '1';
    COMMIT
   
While another *concurrent* process does
    -- php process _also_ finds $100 money and uses it all _again_
    BEGIN
    SELECT available_money from account  where user_id = '1'; // $money = $100
    UPDATE account SET available_money = 0 where user_id = '1'; //the user buy $100 and he depletes his account
    COMMIT
   
If this happens, then the user could use more money than he is entitled to. SELECT FOR UPDATE comes to the rescue. Following the previous example

One process does:
    BEGIN
    SELECT available_money from account  where user_id = '1' FOR UPDATE; // $money = $100
    UPDATE account SET available_money = 0 where user_id = '1';
    COMMIT
   
While another *concurrent* process does
    BEGIN
    SELECT available_money from account where user_id = '1' FOR UPDATE; // now this second process must wait the first process to finish, so $money = $0
    -- the user doest not have money to buy anything
    COMMIT
   

Now, how to achieve this using CakePHP ?

CakePHP's dbo doesn't currently support FOR UPDATE syntax. BUT there is a litlle quick and dirty (maybe too dirty for some) **hack** you can do without doing any modifications to the core ...

Since in the dbo_source, in the `SELECT`statement, the `LIMIT` clause gets parsed at last (see line 1497 from cake/libs/models/dbo_source.php):

    switch (strtolower($type)) {
        case 'select':
            return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order} {$limit}";
        break;
        //...
       
If in a need, **and if using PostgreSQL** (mysql later), you *could* do
        $transac = $this->AccountModel->find('all', array(
            'conditions' => array(
                'user_id' =>$id
            ),
            'fields' => array('available_money'),
            'limit' => 'ALL FOR UPDATE'
        ));`

... and this would generate the `SELECT available_money from account  where user_id = '1' FOR UPDATE` clause we are looking for... The trick is in the `'limit' => 'ALL FOR UPDATE'`. This selects ALL records that match the conditions FOR UPDATE.

For MySql you would have to do something a lot uglier. Since MySql doesn't support LIMIT ALL, you would have to use LIMIT 0,18446744073709551615. This is **pretty horrible**, I know... The other options are to code a behavior for all of us : )

Just remember to put your `find` inside a transaction !

**Watch out**, there is a little (but important) catch... You can't do `find('first)`, since the LIMIT clause would be overwritten by Cake as `LIMIT 1`, instead you can do find('all', ... 'limit' => '1 FOR UPDATE' ...)