Django admin in 1.4+ support the query parameter __in for filtering on multiple values of the same field. Adding this to the admin took some work but is possible, I am not sure if this is the best way to do it but it does work.
Here is a snippet of my admin.py file
https://gist.github.com/justhamade/5447780
Rambling about Django, Python, Ansible and sometimes PHP and Wordpress. I enjoy talking about all technologies, and offer help when I can.
Tuesday, April 23, 2013
Sunday, April 07, 2013
Securing LAMP for Ubuntu 12.04 LTS
This is a summary of this post http://www.thefanclub.co.za/how-to/how-secure-ubuntu-1204-lts-server-part-1-basics
Setup non root user
Setup non root user
ssh root@YOURSERVERIPInstall LAMP, Security and other useful stuff
adduser YOUNONROOTUSER
useradd -G sudo YOUNONROOTUSER
logout
ssh YOURNONROOTUSER@YOURSERVERIP
sudo -i
sudo apt-get install lamp-server^ ufw denyhosts fail2ban psad rkhunter chkrootkit nmap logwatch libdate-manip-perl apparmor apparmor-profiles tiger htop libxml2 libxml2-dev libxml2-utils libaprutil1 libaprutil1-dev libapache-mod-security -ySetup UFW
sudo ufw enableSecure shared mem (requires reboot)
ufw status verbose
sudo ufw allow ssh
sudo ufw allow http
echo 'tmpfs /dev/shm tmpfs defaults,noexec,nosuid 0 0' >> /etc/fstabDisallow root ssh logins (can also change SSH PORT)
sed -i 's/PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_configLimit su command to users that have sudo
sed -i 's/Port 22/Port 2222/g' /etc/ssh/sshd_config
sudo /etc/init.d/ssh restart
sudo dpkg-statoverride --update --add root sudo 4750 /bin/suHarden network with sysctl settings. This is what my /etc/sysctl.conf file ends up looking like with no comments
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.all.rp_filter=1
net.ipv4.tcp_syncookies=1
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
net.ipv4.icmp_echo_ignore_all = 1
sudo sysctl -pPrevent IP Spoofing
# The "order" line is only used by old versions of the C library.Secure PHP (assumes that exec, system, shell_exec, passthru are not already there)
order bing,hosts
nospoof on
multi on
Secure Apache
sed -i 's/expose_php = On/expose_php = Off/g' /etc/php5/apache2/php.ini
sed '/^disable_functions/ s/$/,exec,system,shell_exec,passthru/' /etc/php5/apache2/php.ini > /etc/php5/apache2/php.ini
sed -i 's/ServerTokens OS/ServerTokens Prod/g' /etc/apache2/conf.d/security
sed -i 's/ServerSignature On/ServerSignature Off/g' /etc/apache2/conf.d/security
echo 'Header unset ETag' >> /etc/apache2/conf.d/security
echo 'FileETag None' >> /etc/apache2/conf.d/security
a2enmod headersUpdate fail2ban
/etc/init.d/apache2 restart
sed -s 'action = %(action_)s/action = %(action_mwl)s/g' s//etc/fail2ban/jail.conf
Monday, February 25, 2013
Vagrant on Cygwin
Not fully tested taken from memory and history so if anything is missing please comment.
Taken mostly from a good post here http://www.enrise.com/2012/12/git-and-vagrant-in-a-windows-environment/ Assumes you have latest cygwin and virtualbox installed.
Cygwin need svn and bash Install other deps
Get Vagrant 1.1.0 dev from git (once this is stable then this step is not needed).
Update pull request for cygwin fix from here https://github.com/mitchellh/vagrant/pull/1366
Install gem so deps are install then rake install to update to dev version with patches applied
Add VBOX_USER_HOME
Add symlink to VBoxManage
Use vagrant
Taken mostly from a good post here http://www.enrise.com/2012/12/git-and-vagrant-in-a-windows-environment/ Assumes you have latest cygwin and virtualbox installed.
Cygwin need svn and bash Install other deps
svn --force export http://apt-cyg.googlecode.com/svn/trunk/ /bin/ chmod +x /bin/apt-cyg apt-cyg install make ruby curl git bsdtar ssh
Get Vagrant 1.1.0 dev from git (once this is stable then this step is not needed).
git clone https://github.com/mitchellh/vagrant.git cd vagrant
Update pull request for cygwin fix from here https://github.com/mitchellh/vagrant/pull/1366
curl https://github.com/mitchellh/vagrant/pull/1366.patch | git am
Install gem so deps are install then rake install to update to dev version with patches applied
gem install vagrant rake install
Add VBOX_USER_HOME
export VBOX_USER_HOME=`pwd`/.VirtualBox/
Add symlink to VBoxManage
ln '/cygdrive/c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe' /usr/local/bin/VBoxManage
Use vagrant
vagrant box add lucid32 http://files.vagrantup.com/lucid32.box vagrant init lucid32 vagrant upYou May get an error when starting up. This is because the Virtual box guest additions need to be installed so the directory can be mounted
vagrant ssh sudo apt-get install virtualbox-guest-addition
Tuesday, November 06, 2012
Stackato
wget http://downloads.activestate.com/stackato/vm/v2.4.3/stackato-vm-vbox-v2.4.3.zip unzip stackato-vm-vbox-v2.4.3.zip cd Stackato-VM VBoxManage import Stackato-v2.4.3.ovf VBoxManage modifyvm Stackato-v2.4.3 --nic1 bridged --bridgeadapter1 eth0 VBoxManage startvm Stackato-v2.4.3 --type headlessTo figure out the ip
# scan port 22 nmap -p 22 --open -sV 192.168.X.0/24 VBoxManage showvminfo Stackato-v2.4.3 | grep MAC # OUTPUT IS: NIC 1: MAC: 080027656420, Attachment: Bridged Interface 'eth0', Cable connected: on, Trace: off (file: none), Type: 82540EM, Reported speed: 0 Mbps, Boot priority: 0, Promisc Policy: deny arp -an | grep -i 08:00:27:65:64:20Install stackato client
wget http://downloads.activestate.com/stackato/client/v1.5/stackato-1.5-linux-glibc2.3-x86_64.zip unzip stackato-1.5-linux-glibc2.3-x86_64.zip cd stackato-1.5-linux-glibc2.3-x86_64/ sudo mv stackato /usr/local/bin/. stackato
Saturday, March 31, 2012
ISPConfig 3.0.4.3 with Django 1.4, Virtualenv and WSGI on Debian Squeeze
I recently go a killer deal on a VPS at http://chicagovps.net/ so I am moving all my stuff from my Webfaction and Linode to my own VPS. I want something to easily manage my apache configs, dns and mail still and have used ISPConfig in the past and found it pretty good for a free open source program. I actually like it better than cPanel or DirectAdmin which I find too restrictive.
Moving my Django projects from Webfaction will take a bit of work. ISPConfig has some nice options in the GUI for PHP but the Python option uses mod_python :(.
This will not be a complete guide but as usual some documentation for myself. It assumes that ISPConfig is already setup and working, there is an decent setup guide in docs/INSTALL_DEBIAN_6.0_courier_mydns.txt and some older but still useable docs here http://www.howtoforge.com/perfect-server-debian-lenny-ispconfig3.
First you need to install some additional packages
Then you need to setup your site in ISPConfig and copy your Django project to it or start a new one. For simplicity we will just create a new one here
Then in your ISPConfig Site go to Sites > Website > mysite.com > Options and in the Apache Directive add the following. Make sure to change the path to the correct absolute path.
Moving my Django projects from Webfaction will take a bit of work. ISPConfig has some nice options in the GUI for PHP but the Python option uses mod_python :(.
This will not be a complete guide but as usual some documentation for myself. It assumes that ISPConfig is already setup and working, there is an decent setup guide in docs/INSTALL_DEBIAN_6.0_courier_mydns.txt and some older but still useable docs here http://www.howtoforge.com/perfect-server-debian-lenny-ispconfig3.
First you need to install some additional packages
apt-get install python-setuptools libapache2-mod-wsgi python-dev -y easy_install pip pip install virtualenv
Then you need to setup your site in ISPConfig and copy your Django project to it or start a new one. For simplicity we will just create a new one here
cd /var/www/mysite.com/ virtualenv myproject-env . /myproject-env/bin/activate pip install mysql-python pip install PIL pip install django django startproject myprojectThis will create a wsgi.py file in myproject/myproject/wsgi.py
Then in your ISPConfig Site go to Sites > Website > mysite.com > Options and in the Apache Directive add the following. Make sure to change the path to the correct absolute path.
Alias /media/ /var/www/clients/client0/web1/myproject/myproject/media/ Alias /static/ /var/www/clients/client0/web1/myproject/myproject/static/ Alias /robots.txt /var/www/clients/client0/web1/myproject/myproject/static/robots.txt Alias /favicon.ico /var/www/clients/client0/web1/myproject/myproject/static/images/favicon.ico WSGIDaemonProcess mysite.com user=web1 group=client0 python-path=/var/www/clients/client0/web1:/var/www/clients/client0/web1/myproject-env/lib/python2.6/site-packages WSGIProcessGroup mysite.com WSGIScriptAlias / /var/www/clients/client0/web1/myproject/myproject/wsgi.py <Directory /var/www/clients/client0/web1/myproject> Order deny,allow Allow from all </Directory> <Directory /var/www/clients/client0/web1/myproject> Order deny,allow Allow from all </Directory> <Directory /var/www/clients/client0/web1/myproject> <Files wsgi.py> Order deny,allow Allow from all </Files> </Directory>This assumes that STATIC_URL STATIC_ROOT MEDIA_URL and MEDIA_ROOT are set to /static/ and /media/ in myproject/myproject
# Django settings for myproject project. import os # Add this near the top PROJECT_DIR = os.path.abspath(os.path. dirname(__file__)) # Absolute filesystem path to the directory that will hold user-uploaded files. # Example: "/home/media/media.lawrence.com/media/" MEDIA_ROOT = PROJECT_DIR + '/media' # URL that handles the media served from MEDIA_ROOT. Make sure to use a # trailing slash. # Examples: "http://media.lawrence.com/media/", "http://example.com/media/" MEDIA_URL = '/media/' # Absolute path to the directory static files should be collected to. # Don't put anything in this directory yourself; store your static files # in apps' "static/" subdirectories and in STATICFILES_DIRS. # Example: "/home/media/media.lawrence.com/static/" STATIC_ROOT = PROJECT_DIR + '/static' # URL prefix for static files. # Example: "http://media.lawrence.com/static/" STATIC_URL = '/static/' That should be it. Make sure that user web1 and group client0 are the owners of the correct directories and files and have exec permission.
Monday, July 04, 2011
Quicksynergy autostart Ubuntu
Starting quicksynergy in Ubuntu is actually really easy. If you do a "ps aux" after you have quicksynergy configured and running you will see something like
All you need to do is add this to your "Startup Applications"
System Settings -> Startup Applications -> Add
Name: Synergy
Command: /usr/bin/synergys -f --config .quicksynergy/synergy.conf
Add->Close->Log out and log back in.
Done!
/usr/bin/synergys -f --config .quicksynergy/synergy.conf
All you need to do is add this to your "Startup Applications"
System Settings -> Startup Applications -> Add
Name: Synergy
Command: /usr/bin/synergys -f --config .quicksynergy/synergy.conf
Add->Close->Log out and log back in.
Done!
Wednesday, March 16, 2011
Screen VT100/ANSI Terminal Emulator Cheat Sheet - good coders code, great reuse
I love using screen I just wish I knew more of the shortcuts. This cheat sheet has everything.
Screen VT100/ANSI Terminal Emulator Cheat Sheet - good coders code, great reuse
Saturday, January 29, 2011
Python Uniquify a List
Using sets it is actually pretty trivial to do
import sets my_list = [1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7] unique_set = sets.Set(my_list)
Sunday, December 12, 2010
What is DevOps and why is it important
With the recent purchase of Heroku by salesforce made me think about the future of the "SysAdmin".
As I was writing this I saw a recent talk given by Jacob Kaplan-Moss at Django Boston Meetup titled DevOps.
The job of a SysAdmin is changing, frameworks like Django and Ruby on Rails along with services providers like Google Apps, Heroku, VMForce, and Djangy give developers everything they need. The role of a SysAdmin is going to become very specialized, unless your talking about Windows systems ;)
As I was writing this I saw a recent talk given by Jacob Kaplan-Moss at Django Boston Meetup titled DevOps.
The job of a SysAdmin is changing, frameworks like Django and Ruby on Rails along with services providers like Google Apps, Heroku, VMForce, and Djangy give developers everything they need. The role of a SysAdmin is going to become very specialized, unless your talking about Windows systems ;)
Thursday, November 25, 2010
Gitorious install on Debian Squeeze with stompserver
I have modified this install tutorial from Christian Johansen found here http://cjohansen.no/en/ruby/setting_up_gitorious_on_your_own_server
Some info from here as well http://www.bluequartz.net/projects/ElectronicImaging/SCMService/html/index.html
There is also source for a debian package by Marius MÃ¥rnes Mathiesen here http://gitorious.org/gitorious-for-debian/gitorious the most recent commits are forked here http://gitorious.org/~brodock/gitorious-for-debian/brodocks-gitorious
Some info from here as well http://www.bluequartz.net/projects/ElectronicImaging/SCMService/html/index.html
There is also source for a debian package by Marius MÃ¥rnes Mathiesen here http://gitorious.org/gitorious-for-debian/gitorious the most recent commits are forked here http://gitorious.org/~brodock/gitorious-for-debian/brodocks-gitorious
Squeeze is needed for the new magickwand stuff
Had issues with activemq so using stompserver instead
apt-get install -y sudo git-core git-svn apg build-essential libpcre3 libpcre3-dev sendmail \
make zlib1g zlib1g-dev ssh memcached apache2 \
libonig-dev libyaml-dev geoip-bin libgeoip-dev libgeoip1 \
uuid uuid-dev openjdk-6-jre apache2-prefork-dev curl openssl libcurl4-gnutls-dev
apt-get install -y imagemagick libmagickwand-dev && \
gem install --no-ri --no-rdoc rmagick
apt-get install -y mysql-client mysql-server libmysqlclient15-dev && \
gem install --no-ri --no-rdoc mysql
wget http://rubyforge.org/frs/download.php/71099/ruby-enterprise_1.8.7-2010.02_i386_ubuntu8.04.deb
sudo dpkg -i ruby-enterprise*
echo 'export PATH=/opt/ruby-enterprise/bin:$PATH
export LD_LIBRARY_PATH="/usr/local/lib"
export LDFLAGS="-L/usr/local/lib -Wl,-rpath,/usr/local/lib"' >> /etc/profile
echo '/usr/local/lib
include ld.so.conf.d/*.conf' >> /etc/ld.so.conf
ldconfig
cd /usr/src
wget http://rubyforge.org/frs/download.php/70696/rubygems-1.3.7.tgz
tar xvzf rubygems*
cd rubygems*
ruby setup.rb
cd /usr/src
wget http://www.sphinxsearch.com/downloads/sphinx-0.9.9.tar.gz
tar xvfz sphinx-*
cd sphinx-*
./configure
make && sudo make install
gem install --no-ri --no-rdoc ultrasphinx
gem install stompserver
echo '#!/bin/sh
# Start/stop the stompserver
# WATCH THE LINE WRAPPING BELOW
### BEGIN INIT INFO
# Provides: stomp
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 1
# Short-Description: Stomp
# Description: Stomp
### END INIT INFO
$DAEMON=/usr/local/bin/stompserver
test -f $DAEMON || exit 0
. /lib/lsb/init-functions
case $1 in
start) log_daemon_msg Starting stompserver stompserver
start-stop-daemon --start --name stompserver --startas $DAEMON \
--background --user git
log_end_msg $?
;;
stop) log_daemon_msg Stopping stompserver stompserver
start-stop-daemon --stop --name stompserver
log_end_msg $?
;;
restart) log_daemon_msg Restarting stompserver stompserver
start-stop-daemon --stop --retry 5 --name stompserver
start-stop-daemon --start --name stompserver --startas $DAEMON \
--background --user git
log_end_msg $?
;;
status)
status_of_proc $DAEMON stompserver && exit 0 || exit $?
;;
*) log_action_msg Usage: /etc/init.d/stomp {start|stop|restart|status}
exit 2
;;
esac
exit 0' > /etc/init.d/stompserver
chmod +x /etc/init.d/stompserver
update-rc.d stompserver defaults
echo '#!/bin/sh
# Start/stop the git poller
#
### BEGIN INIT INFO
# Provides: git-poller
# Required-Start: stomp
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 1
# Short-Description: Gitorious poller
# Description: Gitorious poller
### END INIT INFO
GITORIOUS_ROOT=/var/www/gitorious
echo `date` " Starting git-poller" >> "$GITORIOUS_ROOT/log/git-poller.log"
/bin/su -- git -c " cd $GITORIOUS_ROOT; RAILS_ENV=production script/poller $@"' > /etc/init.d/poller
chmod +x /etc/init.d/poller
update-rc.d poller defaults
git clone git://gitorious.org/gitorious/mainline.git gitorious
chmod -R g+sw /var/www/gitorious
ln -s /var/www/gitorious/script/gitorious /usr/local/bin/gitorious
cd gitorious/
rm public/.htaccess
mkdir -p tmp/pids
chmod ug+x script/*
chmod -R g+w config/ log/ public/ tmp/
which ruby
vi doc/templates/ubuntu/git-daemon
Gitorious ships with ready to use git-ultrasphinx and git-daemon scripts. Be aware that the git-daemon script has hardcoded paths to both Ruby Enterprise Edition and Gitorious. Pop open git-daemon and set correct paths to the Ruby you want to use (stick with REE if you installed it earlier) and your Gitorious installation. These are the lines you need to see (lines 16 and 18 at the time of writing):GIT_DAEMON="/opt/ruby-enterprise/bin/ruby \
/var/www/gitorious/script/git-daemon -d"
ln -s /var/www/gitorious/doc/templates/ubuntu/git-ultrasphinx /etc/init.d/.
ln -s /var/www/gitorious/doc/templates/ubuntu/git-daemon /etc/init.d/.
chmod +x /etc/init.d/git-ultrasphinx
chmod +x /etc/init.d/git-daemon
update-rc.d -f git-daemon start 99 2 3 4 5 .
update-rc.d -f git-ultrasphinx start 99 2 3 4 5 .
gem install --no-ri --no-rdoc rails mongrel mime-types textpow chronic \
ruby-hmac daemons mime-types oniguruma textpow chronic BlueCloth \
ruby-yadis ruby-openid geoip rspec rspec-rails RedCloth echoe
gem install --no-ri --no-rdoc --version="1.0.1" rack
adduser git
usermod -a -G gitorious git
mkdir /var/git
mkdir /var/git/repositories
mkdir /var/git/tarballs
mkdir /var/git/tarball-work
chown -R git:git /var/git
su git
mkdir ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys
vi ~/.bashrc
Append the following to /home/git/.bashrc # User specific aliases and functions export RUBY_HOME=/opt/ruby-enterprise export GEM_HOME=$RUBY_HOME/lib/ruby/gems/1.8/gems export PATH=$RUBY_HOME/bin:$PATH
exit cd /var/www/gitorious cp config/database.sample.yml config/database.yml cp config/gitorious.sample.yml config/gitorious.yml cp config/broker.yml.example config/broker.yml apg -m 64 config/gitorious.ymlSee original doc for details on this config file
rake db:migrate RAILS_ENV=production
mysql -uroot -p
create database gitorious;
create database gitorious_test;
create database gitorious_dev;
grant all privileges on gitorious.* to YOURUSER@localhost \
identified by 'YOURPASSWORD';
grant all privileges on gitorious_test.* to YOURUSER@localhost;
grant all privileges on gitorious_dev.* to YOURUSER@localhost;
sudo rake gems:install
vi config/database.yml
Make your config match your mysql db setuprake db:migrate RAILS_ENV=production
cd /var/www/gitorious
env RAILS_ENV=production ruby script/create_admin
script/console
> user = User.first
> user.login = "yourname" # Change to your desired username
> user.activate
> user.accept_terms
> user.save
rake ultrasphinx:bootstrap RAILS_ENV=production
chown -R git:gitorious config/environment.rb script/poller log tmp
chmod -R g+w config/environment.rb script/poller log tmp
chmod ug+x script/poller
/etc/init.d/activemq start
env RAILS_ENV=production /etc/init.d/git-daemon start
su git -c \
"cd /var/www/gitorious && \
env RAILS_ENV=production script/poller run"
su git -c \
"cd /var/www/gitorious && script/server -e production"
echo '* */1 * * * root cd /var/www/gitorious && rake ultrasphinx:index RAILS_ENV=production' >> /etc/crontab
cp doc/templates/ubuntu/gitorious-logrotate /etc/logrotate.d/gitorious
sudo chmod +x /etc/logrotate.d/gitorious
gem install passenger
passenger-install-apache2-module
a2enmod rewrite
a2enmod deflate
a2enmod passenger
a2enmod expires
a2enmod rewrite
vi conf/vhost.conf
Update configln -s /var/www/gitorious/conf/vhost.conf /etc/apache2/sites-available/gitorious a2ensite gitorious
Wednesday, August 11, 2010
Nagios3 on Debian external commands
Enabling external commands in nagios on a Debian deb install of nagios is a bit of a pain.
First in /etc/nagios3/nagios.cfg change
Then you will get errors about
If you
That error should go away and www-data should have read access to that file. You may need to
First in /etc/nagios3/nagios.cfg change
check_external_commands=1
Then you will get errors about
Error: Could not stat() command file '/var/lib/nagios3/rw/nagios.cmd'!
If you
rm /var/lib/nagios3/rw/nagios.cmd chmod a+x /var/lib/nagios3 chmod g+s /var/lib/nagios3/rw /etc/init.d/nagios restart
That error should go away and www-data should have read access to that file. You may need to
chgrp www-data /var/lib/nagios3/rwBut that was already there for me.
Wednesday, July 21, 2010
Django by Example: Django Tutorials - Django by Example
Django by Example: Django Tutorials - Django by Example
A great list of Django tutorials. I have also started reading Foundation of Agile Python Development by Jeff Younker and will have a book review as soon as I am done.
Sunday, July 18, 2010
Aastra disappoints again
I have been doing VoIP work with Asterisk since pre 1.0 days, which is about 6-7 years. The very first phones we choose were the Aastra/Sayason 480i which were very feature rich and pretty good hardware. The software quality is what seemed to be lacking, it was a while ago so I can't remember specific examples. We decided, back at that time, to switch to Polycom 501s. The 501s were not much more in price, had the same features, maybe even more at that time, and just felt like a much better product.
After a few years Aastra came out with the 57i. The popular Nerd Vittles Blog run by Ward Mundy called this phone the best asterisk phone back in 2008 http://nerdvittles.com/?p=207. I was still hesitant to use it due to my poor experience that I had with Aastra phones previously.
We decided to try them again about 6 months ago, and with the new XML scripts that Aastra has made for Trixbox/Elastix/PIF these phones work great with Asterisk and I have not had one issue with the phones firmware.
Now due to my renewed faith in Aastra we decided to try the Aastralink Pro 160 bundle, which comes with a few phones. Our customer also needed wireless as well so we thought we would try the MBU400 which the ALP 160 fully supports. This is where the fun started.
First the Aastralink Pro 160. It has decent hardware, 2 FXS ports and 6 FXO ports, and it a pretty reasonable price compared to building your own system with Sangoma or Digium PCI cards. For the software that is a different story. As an Asterisk hacker I have been spoiled by flexibility. Even with Elastix (my choice of FreePBX distro) I can always throw something in extensions_custom.conf and change the dial plan to suite any customer's needs. Now I knew the ALP 160 didn't give me root access so I figured the basic stuff would be supported by the web based GUI, I guessed wrong.
So what other options are there for a small PBX? Xorcom makes one that is decent, this is what we switched our customer to. Building your own out of a Atom based barebones kit is a good option too. Or Ward calls his choice the Orgasmatron http://nerdvittles.com/?tag=orgasmatron but they don't have any FXS or FXO.
Second the MBU 400. Now this is a nice looking unit. It actually is identical hardware to the SNOM m3. It integrates pretty easy with the Aastralink Pro 160 (except it can't be a mirrored extension it has to be its own extension). But for some reason the unit we had would not connect back to the access point after being out of range, unless there was some sort of manual intervention. So I spent hours going back and forth with Aastra tech support. Now you figure people calling reseller tech support would be fairly technical, so the support people should be just as technical or even more. This is not the case for Aastra. The most common response I get from them for a few different issues that I had called about was "I don't know." If it is a tough problem that is fine, but at least offer a next step or some sort of escalation.
So what did we do? We switched to Polycom, again. This time to the Polycom Kirk 5040 handsets with the 600 access point, and a couple repeaters. These were a bit tough to dig through the manual and figure out how to get it setup, I did need help from our distributor on setting up the repeaters, but other than that these things have been rock solid for our customer.
The point of me writing this, other than to bash on Aastra, is to plead for them to stop trying to be a software company. I have heard of and experienced many show stopping issues in their firmware. Every time I upgrade an Aastra device I am not sure what I am going to get. It has been like this since the 480i days 7 years ago. I don't know what their development and testing process is, but I doubt that it is good. On the flip side, the hardware they make seems to be great, the problem is it takes them years to release firmware for it that is as good as the hardware is.
After a few years Aastra came out with the 57i. The popular Nerd Vittles Blog run by Ward Mundy called this phone the best asterisk phone back in 2008 http://nerdvittles.com/?p=207. I was still hesitant to use it due to my poor experience that I had with Aastra phones previously.
We decided to try them again about 6 months ago, and with the new XML scripts that Aastra has made for Trixbox/Elastix/PIF these phones work great with Asterisk and I have not had one issue with the phones firmware.
Now due to my renewed faith in Aastra we decided to try the Aastralink Pro 160 bundle, which comes with a few phones. Our customer also needed wireless as well so we thought we would try the MBU400 which the ALP 160 fully supports. This is where the fun started.
First the Aastralink Pro 160. It has decent hardware, 2 FXS ports and 6 FXO ports, and it a pretty reasonable price compared to building your own system with Sangoma or Digium PCI cards. For the software that is a different story. As an Asterisk hacker I have been spoiled by flexibility. Even with Elastix (my choice of FreePBX distro) I can always throw something in extensions_custom.conf and change the dial plan to suite any customer's needs. Now I knew the ALP 160 didn't give me root access so I figured the basic stuff would be supported by the web based GUI, I guessed wrong.
- You are forced to dial 9 (PSTN) or 8 (SIP) to dial out, you can't change this and my customers hate dialing prefixes
- Not only do you have to dial a 8 prefix for SIP but if you have multiple SIP trunks you have to dial another prefix for the trunk number, ie 80 or 81 or 82
- Inbound SIP calls all go to the same place, you cannot control calls based on SIP trunk or DID, you can control where the calls from the FXO ports go.
- Each extension must have a Aastra hardware phone and must be online. You can have any SIP device as a mirrored extension but if the phone that it's mirrored to goes offline so does it.
- I am guessing that timing is not sync'd between the FXO and FXS because I could not get faxing to work for the life of me.
So what other options are there for a small PBX? Xorcom makes one that is decent, this is what we switched our customer to. Building your own out of a Atom based barebones kit is a good option too. Or Ward calls his choice the Orgasmatron http://nerdvittles.com/?tag=orgasmatron but they don't have any FXS or FXO.
Second the MBU 400. Now this is a nice looking unit. It actually is identical hardware to the SNOM m3. It integrates pretty easy with the Aastralink Pro 160 (except it can't be a mirrored extension it has to be its own extension). But for some reason the unit we had would not connect back to the access point after being out of range, unless there was some sort of manual intervention. So I spent hours going back and forth with Aastra tech support. Now you figure people calling reseller tech support would be fairly technical, so the support people should be just as technical or even more. This is not the case for Aastra. The most common response I get from them for a few different issues that I had called about was "I don't know." If it is a tough problem that is fine, but at least offer a next step or some sort of escalation.
So what did we do? We switched to Polycom, again. This time to the Polycom Kirk 5040 handsets with the 600 access point, and a couple repeaters. These were a bit tough to dig through the manual and figure out how to get it setup, I did need help from our distributor on setting up the repeaters, but other than that these things have been rock solid for our customer.
The point of me writing this, other than to bash on Aastra, is to plead for them to stop trying to be a software company. I have heard of and experienced many show stopping issues in their firmware. Every time I upgrade an Aastra device I am not sure what I am going to get. It has been like this since the 480i days 7 years ago. I don't know what their development and testing process is, but I doubt that it is good. On the flip side, the hardware they make seems to be great, the problem is it takes them years to release firmware for it that is as good as the hardware is.
Thursday, July 15, 2010
Rails on Debian
Ran into a strange issue while debugging a Rails app that I am working on. I finally found the exact problem and issue here http://wiki.github.com/radiant/radiant/undefined-method-for-enumerable
Turns out that
Putting this in your environment.rb fixes the issue
Turns out that
the error comes from an incompatibility between Ruby 1.8.7 and Rails 2.0.2. Ruby 1.8.7 has String#chars and returns an Enumerator object, but Rails 2.0.2 expects an ActiveSupport::Multibyte::Chars object.Which is pointed out here http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg528878.html
Putting this in your environment.rb fixes the issue
unless '1.9'.respond_to?(:force_encoding)
String.class_eval do
begin
remove_method :chars
rescue NameError
# OK
end
end
end
Wednesday, July 14, 2010
Fixing Python indentations in VIM
Had this problem today where I created a file with eclipse then edited it with vim and that made the tabs inconsistent. Found this post on stackoverflow that had a couple of suggestions
http://stackoverflow.com/questions/1024435/howto-fix-python-indentation
1. Use reindent.py - this requires apt-get install python-examples on debian/ubuntu
2. :%s/\t/ /g - this is what I used and it worked great
Other vim tricks I have used lately:
- Remove empty lines :%s/^[\ \t]*\n//g
- Re-indent entire file gg=G
- Remove lines with comments g/^#/d
http://stackoverflow.com/questions/1024435/howto-fix-python-indentation
1. Use reindent.py - this requires apt-get install python-examples on debian/ubuntu
2. :%s/\t/ /g - this is what I used and it worked great
Other vim tricks I have used lately:
- Remove empty lines :%s/^[\ \t]*\n//g
- Re-indent entire file gg=G
- Remove lines with comments g/^#/d
Tuesday, June 01, 2010
Modular Django Admin Part 3
Django Auth has a lot of stuff built in http://docs.djangoproject.com/en/dev/topics/auth/
A list of all the default templates and urls you need for login password reset and password change. Most of these templates are in django/contrib/admin/templates/registration
template/registration/login.html (django/contrib/admin/templates/admin/login.html)
template/registration/logged_out.html
template/registration/password_change_form.html
template/registration/password_change_done.html
template/registration/password_reset_email.html
template/registration/password_reset_done.html
template/registration/password_reset_confirm.html
template/registration/password_reset_complete.html
So now we can login see generic view lists of our models, not we need to edit them.
A list of all the default templates and urls you need for login password reset and password change. Most of these templates are in django/contrib/admin/templates/registration
url(r'^accounts/login/$', 'django.contrib.auth.views.login',name='login'),
url(r'^accounts/$', 'django.contrib.auth.views.login',name='login'),
url(r'^accounts/logout/$', 'django.contrib.auth.views.logout',{'next_page': '/'},name='logout'),
url(r'^accounts/password_change/$', 'django.contrib.auth.views.password_change',name='password_change'),
url(r'^accounts/password_change_done/$', 'django.contrib.auth.views.password_change_done',name='password_change_done'),
url(r'^accounts/password_reset/$', 'django.contrib.auth.views.password_reset',name='password_reset'),
url(r'^accounts/accounts/password_reset/done/$', 'django.contrib.auth.views.password_reset_done',name='password_reset_done'),
url(r'^accounts/reset/(?P[0-9A-Za-z]+)-(?P.+)/$', 'django.contrib.auth.views.password_reset_confirm',name='password_reset_confirm'),
url(r'^accounts/reset/done/$', 'django.contrib.auth.views.password_reset_complete',name='password_reset_complete'),
template/registration/login.html (django/contrib/admin/templates/admin/login.html)
template/registration/logged_out.html
template/registration/password_change_form.html
template/registration/password_change_done.html
template/registration/password_reset_email.html
template/registration/password_reset_done.html
template/registration/password_reset_confirm.html
template/registration/password_reset_complete.html
So now we can login see generic view lists of our models, not we need to edit them.
Sunday, May 16, 2010
Django Modular Admin Part 2
I just realized that alot of the functionality that the admin login has is not part of django.contrib.auth but is only in the admin.
A couple of things I have figure out as a result with form validation errors in the template.
{{ form.non_field_errors }} is for a ValidationError that is for the whole form.
A snippet of my login.html template
More to come on django auth
A couple of things I have figure out as a result with form validation errors in the template.
{{ form.non_field_errors }} is for a ValidationError that is for the whole form.
A snippet of my login.html template
<div id="welcome_login" title="Welcome To My Site">
<p><b>Admin Login</b></p>
<form action="." method="post" enctype="multipart/form-data" class="forms" name="form" >{% csrf_token %}
{% if form.non_field_errors %}
<div class="response-msg error ui-corner-all">
<span>Error message</span>
{{ form.non_field_errors }}
</div>
{% endif %}
<ul>
<li>
<label for="id_username" class="desc">{% trans 'Username:' %}</label>
<div>
{% if form.username.errors %}
<div class="response-msg error ui-corner-all">
<span>Error message</span>
{{ form.username.errors }}
</div>
{% endif %}
<input type="text" tabindex="1" maxlength="255" value="" class="field text full" name="username" id="email" />
</div>
</li>
<li>
<label for="id_password" class="desc">{% trans 'Password:' %}</label>
<div>
{% if form.password.errors %}
<div class="response-msg error ui-corner-all">
<span>Error message</span>
{{ form.password.errors }}
</div>
{% endif %}
<input type="password" tabindex="1" maxlength="255" value="" class="field text full" name="password" id="password" />
<input type="hidden" name="this_is_the_login_form" value="1" />
</div>
</li>
</ul>
</form>
</div>
More to come on django auth
Thursday, May 13, 2010
Modular Django Admin Part 1
The django admin is awesome, we all know that, but there is always the debate to role your own or to customize the admin. Make the admin more modular would be ideal and that is what we will be trying to do.
In part one we will just start with the basics and setup a tabular list using the object_list generic view with gives you pagination for free.
One trick to get the key/value pairs into the template of the model is using a function to return self.__dict__.iteritems()
The Model (myapp/models.py)
The View (myapp/views.py)
The Template (templates/myapp/myobject_list.html)
Next up will be where the templates and urls go for login and the built in authentication tools.
In part one we will just start with the basics and setup a tabular list using the object_list generic view with gives you pagination for free.
One trick to get the key/value pairs into the template of the model is using a function to return self.__dict__.iteritems()
The Model (myapp/models.py)
class MyObject(models.Model):
name = models.CharField(max_length=75)
slug = models.SlugField(unique=True)
def __unicode__(self):
return self.name
def attrs(self):
for attr, value in self.__dict__.iteritems():
yield attr, value
The View (myapp/views.py)
from django.views.generic.list_detail import object_list
def applicant_list_jobs(request):
return object_list(request, queryset=Job.objects.all(), paginate_by=5)
The Template (templates/myapp/myobject_list.html)
{% extends "admin/change_list.html" %}
{% block content %}
<table>
{% for object in object_list %}
<tr class="{% cycle 'row1' 'row2' %}">
{% for key,value in object.attrs %}
<td>{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<p class="paginator">
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}"><</a>
{% endif %}
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">></a>
{% endif %}
</p>
{% endblock content %}
Next up will be where the templates and urls go for login and the built in authentication tools.
Wednesday, March 31, 2010
Subscribe to:
Posts (Atom)