Brainleak

Blog as external memory

Daemonizing a Script Within Suwappu With Chef

The Suwappu network consists of multiple web apps and other scripts. All those should start when the machine is booted. Webapps use the puma daemon script for now.

With Chef we can create a bootscript on every Suwappu appserver by running ‘suwappu::appserver-bootscript’. The node should contain following information :

{
  "name": "qualitycontrol.suwappu.net",
  "chef_environment": "_default",
  "normal": {
    "tags": [

    ],
    "rvm": {
      "install_pkgs": [
        "sed",
        "grep",
        "tar",
        "gzip",
        "bzip2",
        "bash",
        "curl",
        "git-core"
      ]
    },
    "app": {
      "name": "qualitycontrol"
    },
    "boot": [
      {
        "name": "quality_control",
        "command": "cd /nfs/apps/qualitycontrol_production/current; nohup bundle exec script/quality_control production > log/quality_control.out 2> log/quality_control.err &"
      }
    ]
  },
  "run_list": [
    "recipe[suwappu::backup_install]"
  ]
}

Using Separate Server for Subdir - Nginx

www.gameswap.be/* and www.gameswap.be/blog uses a different server. To facilitate this, add location blog to configuration of the reverse proxy (nginx).

location /blog {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header Host $host;
    proxy_pass http://10.1.0.22:8080;
  }

Creating a Currency Textfield in AngularJS

When working with currencies I have the tendency to store the value in the database as an INT value, to encounter less rounding errors. The value shown is 99.99 while the persisted value is 9999.

AngularJS Directive seems to be a great way to make a custom textfield.

app.directive("currencyField",['$sce',function($sce) {
      return {
        restrict: 'AE',
        require: 'ngModel',
        template: '<input type="text" min="0.0" step="0.01" size="4" />',
        replace: true,
        link: function(scope,elem,attrs,ngModel) {
          if (!ngModel) return;

          function centsToEuro(value) {
            return value / 100.0;
          }

          function euroToCents(value) {
            return parseInt(value * 100);
          }

          ngModel.$parsers.push(euroToCents);
          ngModel.$formatters.push(centsToEuro);
        }
      }
    }]);

To use it, just add currency-field to input field

<input currency-field ng-model="saleitem.price" ng-blur="update(saleitem)" placeholder="price" />

Detect a USB Device on Linux With Udev

I needed a way to start an application when a device is connected to the RPi. In this example the barcodescanner software should start when we connect the scanner. Adding a udev rule should do the trick.

  • First get the ID of the specific device
lsusb

    Bus 001 Device 006: ID 05f9:2214 PSC Scanning, Inc. 
    Bus 001 Device 004: ID 0a5f:0015 Zebra
  • Add the rules file located in /etc/udev/rules.d/, for instance /etc/udev/rules.d/85-custom_usb_device_rules.rules

  • Add the rule to detect scanner and start software, the idVendor and idProduct point to the ID we got from lsusb

ACTION=="add",SUBSYSTEM=="usb",ATTR{idVendor}=="05f9",
    ATTR{idProduct}=="2214",RUN+="/etc/init.d/barcodescanner start"
  • Reload the rules or reboot
udevadm control --reload-rules

List of ID’s

Device ID ID
Barcodescanner 05f9:2214
Zebra Printer 0a5f:0015
Dacal DC-300 04b4:5a9b 04b4:5203

Updating My Capistrano Deployment Process for Rails 4

Now that I’m getting at the point that I can update the different rails apps regularly, it’s about time to update my deployment process.
After every deploy I have to :

  • Login to the host
  • Navigate to app/current directory
  • Run bundle
  • Run rake assets:precompile
  • Restart application server

Fuck this! Let’s update.

  • Add capistrano gems to Gemfile
group :development do
      gem 'capistrano','3.2.1'
      gem 'capistrano-rvm', github: 'capistrano/rvm'
      gem 'capistrano-rails'
      gem 'capistrano-bundler'
    end
  • Require specific files in Capfile
# Load DSL and Setup Up Stages
    require 'capistrano/setup'

    # Includes default deployment tasks
    require 'capistrano/rvm'
    require 'capistrano/deploy'
    require 'capistrano/rails'
    require 'capistrano/rails/migrations'

    # Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
    Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
  • Update deploy.rb
# config valid only for Capistrano 3.1
    lock '3.2.1'

    set :application, 'shops'
    set :repo_url, 'git@dev.suwappu.net:suwappu/shops.git'

    set :deploy_to, '/nfs/apps/shops_production'

    set :ssh_options, {
      forward_agent: true
    }

    set :pty, true
    set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle
      public/system}

    # Default value for default_env is {}
    # set :default_env, { path: "/opt/rbenv/shims:$PATH" }

    set :rvm_type, :user                     # Defaults to: :auto
    set :rvm_ruby_version, 'rbx-2.2.10'      # Defaults to: 'default'
    set :rvm_custom_path, '/usr/local/rvm'  # only needed if not detected

    stage = "production"
    shared_path = "/nfs/apps/shops_production/shared"
    puma_sock    = "unix://#{shared_path}/sockets/puma.sock"
    puma_control = "unix://#{shared_path}/sockets/pumactl.sock"
    puma_state   = "#{shared_path}/sockets/puma.state"
    puma_log     = "#{shared_path}/log/puma-#{stage}.log"

    namespace :deploy do
      desc 'Restart application'
      task :restart do
        on roles(:app), in: :sequence, wait: 5 do
          # Your restart mechanism here, for example:
          # execute :touch, release_path.join('tmp/restart.txt')
          execute 'sudo /etc/init.d/puma restart'
        end
      end

      desc 'Resetting DB & seeding'
      task :db_reset_and_seed do
        on roles(:app) do
          within "#{current_path}" do
            with rails_env: :production do
              execute :rake, "db:migrate:reset"
              execute :rake, "db:seed"
            end
          end
        end
      end

      after :publishing, :restart

      after :restart, :clear_cache do
        on roles(:web), in: :groups, limit: 3, wait: 10 do
        end
      end
    end

Application server is not restarted yet.
I’ll give it some time to fix, but if it takes to long I’ll just leave it open.

It was because of the very weak bootscript for the application server. Changed it to :

echo -n "Restarting Puma server for $APP..."
    su - $USR -c "kill -s SIGTERM `cat $PID`"
    rm /nfs/apps/shops_production/shared/tmp/pids/*
    su - $USR -c "cd $APP/current ; bundle exec thin start -p 8080 -e $ENV -P $PID -d"
    echo "[ Done ]"

After separating web and zmq-backend we’ll be using a different application server. Then I’ll look to upgrade the application bootscript.

Adding a VPN Client to Suwappu Network

To add an OpenVPN client to the Suwappu network, you need to do the following :

  • Login to openvpn.suwappu.net
  • cd /etc/openvpn/easy-rsa
  • source ./vars
  • /etc/openvpn/easy-rsa/suwappu_host_keys
  • Logout OpenVPN server
  • cp /var/lib/vz/private/1003/tmp/.tar.gz /vservers/containers/private/1012/home/tom/
  • knife bootstrap -r ‘suwappu::openvpn-client’

Add Custom Protocol Handler to Iceweasel

You may try to edit Firefox/Iceweasel configuration via about:config:

  • network.protocol-handler.expose.komodo: true (This protocol should be handled either by the browser or by an external application)
  • network.protocol-handler.external.komodo: true (This protocol should be handled by an external application)
  • network.protocol-handler.app.komodo: python /path/to/my/script.py (Path to a program to handle the request)

Install Proxmox on Hetzner Server

  • Boot in rescue mode
  • Set root passwd
  • Install image
installimage
  • Configure partitions

    Use LVM so that we can take snapshots and live dumps.

Filesystem                Size  Used Avail Use% Mounted on
udev                       10M     0   10M   0% /dev
tmpfs                     1.2G  340K  1.2G   1% /run
/dev/mapper/vg0-root       50G  3.0G   44G   7% /
tmpfs                     5.0M     0  5.0M   0% /run/lock
tmpfs                     3.6G  3.1M  3.6G   1% /run/shm
/dev/md0                  496M   40M  430M   9% /boot
/dev/mapper/vg0-tmp       5.0G   33M  5.0G   1% /tmp
/dev/mapper/vg0-home       20G   33M   20G   1% /home
/dev/mapper/vg0-backup     75G   33M   75G   1% /backup
/dev/mapper/vg0-vservers  500G  1.2G  499G   1% /vservers
  • Reboot
  • Install suwappu::base
knife bootstrap <hw-node> -r 'suwappu::base'
  • Add ssh-key to root and user
  • Install sudo and configure for user
  • Login to https://hw-node:8006
  • Add storage

    Datacenter -> Storage add /vservers

    • backup
    • disk image
    • container
  • Put in some containers

Install-appserver-internal

Howto install an application server @ Suwappu

  • Add container to data bag openvz-instances hw-node
knife data bag edit openvz-instances hw-node -e vim
  • Create specified container on openvz hardware node
knife bootstrap hw-node -r 'suwappu::openvz-instances'
  • Install base software that all containers need
knife bootstrap container -r 'suwappu::base'
  • Configure node node[‘app’][‘name’]
1 {
    2   "name": "ws1.suwappu.net",
    3   "chef_environment": "_default",
    4   "normal": {
    5     "tags": [
    6 
    7     ],
    8     "app": {
    9       "name": "sdn",
   10       "path": "/u/apps/sdn_production",
   11       "username": "sdn",
   12       "password": "YOURMOMMA"
   13     },
   14     "mysql": {
   15       "server_root_password": "YOURMOMMA"
   16     },
   17     "unicorn-ng": {
   18       "service": {
   19         "environment": "production",
   20         "user": "deploy"
   21       }
   22     },
   23     "nginx": {
   24       "user": "deploy"
   25     },
   26     "rvm": {
   27       "install_pkgs": [
   28         "sed",
   29         "grep",
   30         "tar",
   31         "gzip",
   32         "bzip2",
   33         "bash",
   34         "curl",
   35         "git-core"
   36       ]
   37     }
   38   },
   39   "run_list": [
   40     "recipe[suwappu::appserver]"
   41   ]
   42 }
  • Install appserver
knife bootstrap container -r 'suwappu::appserver'
  • Install correct ruby version
rvm install rbx-2.2.10
  • Capify application
  • Run bundle on server
  • Add SQL db to data bag sql-databases mysql-node
knife data bag edit sql-databases mysql-node -e vim
  • Create specified SQL DB
knife bootstrap mysql-node -r 'suwappu::sql-databases'
  • Add reverse proxy to data bag nginx-reverse-proxies nginx-node
knife data bag edit nginx-reverse-proxies nginx-node -e vim
  • Create specified Reverse Proxy
knife bootstrap nginx-node -r 'suwappu::nginx-reverse-proxies'

EDIT: Added node example data