Wednesday, February 5, 2020

Build and run EMQX MQTT broker (edge) in Raspberry PI

In the previous post, I documented the steps to build emqx MQTT broker 'cloud' version.
In this post, we will build and run the 'edge' version which is more lightweight hence more suitable for Raspberry PI.

Build emqx-edge from source code.

Follow the instructions in README in emqx-rel project.
The exact commands I executed
$ git clone -b v4.0.0 https://github.com/emqx/emqx-rel.git emqx-rel
cd emqx-rel && make emqx-edge
Execute this command to test if the broker can start normally:
$./_build/emqx-edge/rel/emqx/bin/emqx console
Expected log:
EMQ X Edge 4.0.0 is running now!

Start it in systemd

Move rel to your favourite location.

$ sudo mv _build/emqx-edge/rel/emqx /opt/

Make a systemd unit file for emqx service

There is a system unit file in emqx-rel project. File path: deploy/packages/rpm/emqx.service
To make it simple, update the file to
  • Run systemd service with user pi
  • Replace /usr/bin/ with /opt/emqx/bin.
$ cat /opt/emqx/emqx.service
[Unit]
Description=emqx daemon
After=network.target

[Service]
User=pi
Group=pi
Type=forking
Environment=HOME=/opt/emqx
ExecStart=/bin/sh /opt/emqx/bin/emqx start
LimitNOFILE=1048576
ExecStop=/bin/sh /opt/emqx/bin/emqx stop

[Install]
WantedBy=multi-user.target
$ sudo ln -s /opt/emqx/emqx.service /etc/systemd/system/emqx.service

Start it

$ sudo systemctl start emqx

Check if it's running well

$ systemctl status emqx.service

We should be able to find the expected log line:
MQ X Edge v4.0.0 is started successfully!

Make it auto start

$ sudo systemctl enable emqx.service

Tuesday, February 4, 2020

Build and run EMQX MQTT broker in raspberry pi

Before start following the steps ...

You should probably know that there is official doc about how to install in variant systems. For example:
https://docs.emqx.io/broker/v3/en/install.html#debian
However I prefer to gain the sense of control over the install locations etc.

Install Erlang/OTP 21 or newer

There are many ways to do it. I'd recommend https://github.com/asdf-vm/asdf

Build emqx from source code.

Follow the instructions in README in emqx-rel project.
The exact commands I executed
$ git clone -b v4.0.0 https://github.com/emqx/emqx-rel.git emqx-rel
cd emqx-rel && make
Execute this command to test if the broker can start normally:
$./_build/emqx/rel/emqx/bin/emqx console
Expected log:
EMQ X Broker 4.0.0 is running now!

Start it in systemd

Move rel to your favourite location.

$ sudo mv _build/emqx/rel/emqx /opt/

Make a systemd unit file for emqx service

There is a system unit file in emqx-rel project. File path: deploy/packages/rpm/emqx.service
To make it simple, update the file to
  • Run systemd service with user pi
  • Replace /usr/bin/ with /opt/emqx/bin.
$ cat /opt/emqx/emqx.service
[Unit]
Description=emqx daemon
After=network.target

[Service]
User=pi
Group=pi
Type=forking
Environment=HOME=/opt/emqx
ExecStart=/bin/sh /opt/emqx/bin/emqx start
LimitNOFILE=1048576
ExecStop=/bin/sh /opt/emqx/bin/emqx stop

[Install]
WantedBy=multi-user.target
$ sudo ln -s /opt/emqx/emqx.service /etc/systemd/system/emqx.service

Start it

$ sudo systemctl start emqx

Check if it's running well

$ systemctl status emqx.service
....
Feb 04 20:37:46 raspberrypi sh[5945]: EMQ X Broker v4.0.0 is started successfully!
Feb 04 20:37:46 raspberrypi systemd[1]: Started emqx daemon.

Make it auto start

$ sudo systemctl enable emqx.service

Thursday, August 13, 2015

Ensure boolean literals in ansible j2 template

variables:

---
var_true: "true"
var_0: 0
var_false: False
var_no: no
playbook:
- hosts: all
  tasks:
    - name: test
      debug: msg="var_true={{ var_true |bool|lower}} var_false={{ var_false | bool|lower }} var_0={{ var_0 |bool|lower}} var_yes={{ var_yes | bool|lower}}"
output:
"msg": "var_true=true var_false=false var_0=false var_yes=true" 
| bool  to ensure ‘True’ or ‘False’
| lower to ensure lowercase boolean literals for e.g. configs in Java world

Thursday, January 29, 2015

platform_define in rebar.config

in rebar.config

{erl_opts, [
  ...
  {platform_define, "^R", otp_before_17}
]}.

in code:

-ifdef(otp_before_17).
-type myqueue() :: queue().
-type mydict()  :: dict().
-else.
-type myqueue() :: queue:queue().
-type mydict()  :: dict:dict().
-endif.

Written with StackEdit.

Friday, August 15, 2014

erlang init restart issue

Create file reltool.config:
{sys, [{erts, [{mod_cond, derived}, {app_file, strip}]},
   {app_file, strip},
   {rel, "test", "1", []},
   {boot_rel, "test"},
   {profile, embedded},
   {incl_cond, exclude},
   {app, kernel, [{incl_cond, include}]},
   {app, stdlib, [{incl_cond, include}]},
   {app, crypto, [{incl_cond, include}]}
  ]}.
Create an Erlang release named ‘test’ from ‘reltool.conig’ above:
BASH> erl -eval '{ok, [Config]} = file:consult("reltool.config"),{ok, Spec} = reltool:get_target_spec([Config]), _ = file:make_dir("test"), reltool:eval_target_spec(Spec, code:root_dir(), "test").' -s init stop -noshell
Now bring up the node and crash it:
BASH> export BINDIR=$(pwd)/test/erts-6.0.1/bin && $BINDIR/erlexec -boot test/releases/1/test -mode embedded
Erlang/OTP 17 [erts-6.0.1] [source-57e57ad] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V6.0.1  (abort with ^G)
1> init:restart().
ok
2> {"init terminating in do_boot",{'cannot load',crypto,get_files}}

Crash dump was written to: erl_crash.dump
init terminating in do_boot ()
Problematic code in init.erl
load_mod_code(Mod, BinCode, FullName) ->
    case erlang:module_loaded(Mod) of
        false ->
            case erlang:load_module(Mod, BinCode) of
                {module,Mod} -> {ok,FullName};
                {error,on_load} ->
                    ?ON_LOAD_HANDLER ! {loaded,Mod},
                    {ok,FullName};
                Other ->
                    exit({'cannot load',Mod,Other})
            end; 
        _ -> % Already loaded.
            {ok,FullName}
    end. 
?ON_LOAD_HANDLER ! {loaded,Mod}, crashed with ‘badarg’ because ?ON_LOAD_HANDLER was not alive 
?ON_LOAD_HANDLER is not started for init:restart, bug ? 
If boot the node with -init_dbug flag, below log can be observed, but not during init:restart
{running_on_load_handler,crypto}
{on_load_handler_returned_ok,crypto}
In fact, if any of the -on_load(…) modules gets loaded when booting, init:restart won’t work!
bootstrap/lib/asn1/src/asn1rt_nif.erl:-on_load(load_nif/0).
lib/runtime_tools/src/dyntrace.erl:-on_load(on_load/0).
lib/crypto/src/crypto.erl:-on_load(on_load/0).
lib/asn1/src/asn1rt_nif.erl:-on_load(load_nif/0).
erts/example/matrix_nif.erl:-on_load(on_load/0).
Try asn1 for example:
BASH> export BINDIR=$(pwd)/asn1/erts-6.0.1/bin && $BINDIR/erlexec -boot asn1/releases/1/asn1 -mode embedded -init_debug
{progress,preloaded}
{progress,kernel_load_completed}
{progress,modules_loaded}
{start,heart}
{start,error_logger}
{start,application_controller}
{progress,init_kernel_started}
{apply,{application,load,[{application,stdlib,[{description,"ERTS  CXC 138 10"},{vsn,"2.0"},{id,[]},{modules,[array,base64,beam_lib,binary,c,calendar,dets,dets_server,dets_sup,dets_utils,dets_v8,dets_v9,dict,digraph,digraph_utils,edlin,edlin_expand,epp,eval_bits,erl_bits,erl_compile,erl_eval,erl_expand_records,erl_internal,erl_lint,erl_parse,erl_posix_msg,erl_pp,erl_scan,erl_tar,error_logger_file_h,error_logger_tty_h,escript,ets,file_sorter,filelib,filename,gb_trees,gb_sets,gen,gen_event,gen_fsm,gen_server,io,io_lib,io_lib_format,io_lib_fread,io_lib_pretty,lib,lists,log_mf_h,maps,math,ms_transform,orddict,ordsets,otp_internal,pg,pool,proc_lib,proplists,qlc,qlc_pt,queue,random,re,sets,shell,shell_default,slave,sofs,string,supervisor,supervisor_bridge,sys,timer,unicode,win32reg,zip]},{registered,[timer_server,rsh_starter,take_over_monitor,pool_master,dets]},{applications,[kernel]},{included_applications,[]},{env,[]},{maxT,infinity},{maxP,infinity}]}]}}
{apply,{application,load,[{application,asn1,[{description,"The Erlang ASN1 compiler version 3.0"},{vsn,"3.0"},{id,[]},{modules,[asn1rt,asn1rt_nif]},{registered,[asn1_ns,asn1db]},{applications,[kernel,stdlib]},{included_applications,[]},{env,[]},{maxT,infinity},{maxP,infinity}]}]}}
{progress,applications_loaded}
{apply,{application,start_boot,[kernel,permanent]}}
Erlang/OTP 17 [erts-6.0.1] [source-57e57ad] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

{running_on_load_handler,asn1rt_nif}
{on_load_handler_returned_ok,asn1rt_nif}
{apply,{application,start_boot,[stdlib,permanent]}}
{apply,{c,erlangrc,[]}}
{progress,started}
Eshell V6.0.1  (abort with ^G)
1> 
1> 
1> init:restart().
ok
2> {progress,preloaded}
{progress,kernel_load_completed}
{"init terminating in do_boot",{'cannot load',asn1rt_nif,get_files}}

Crash dump was written to: erl_crash.dump
init terminating in do_boot ()
Written with StackEdit.

Friday, July 18, 2014

Erlang unixODBC to Oracle


Tested in CentOS 6.5, OTP-R15B03, Oracle 11.2
NOTE examples below assume that:
Oracle server/client are both installed on localhost as instructions here:
http://zmstone.blogspot.se/2014/07/oracle-11g-serverclient-in-cetos-65.html
Test database, username and passwords are created as instructions here:
http://zmstone.blogspot.se/2014/07/create-test-database-and-roles-in-fresh.html
  1. Install some possibly missing clients/libraries [1]
    oracle-instantclient11.2-devel-11.2.0.4.0-1.x86_64.rpm
    oracle-instantclient11.2-odbc-11.2.0.4.0-1.x86_64.rpm
  2. Install unixODBC
    1. download unixODBC-2.3.2.tar.gz from http://www.unixodbc.org/
    2. build unixODBC:
      ./configure --prefix=/usr --sysconfdir=/etc --enable-gui=no --enable-drivers=no --enable-iconv --with-iconv-char-enc=UTF8 --with-iconv-ucode-enc=UTF16LE
      # enable iconv library to make it work with unicode.
      make
      # if everything goes fine
      sudo make install
  3. Edit unixODBC config files
    1. /etc/odbc.ini
      [TEST]
      Driver          = Oracle-11g
      ServerName      = //localhost:1521
      Database        = test
      
    2. append to /etc/odbcinst.ini
      [Oracle-11g]
      Description     = Oracle ODBC driver for Oracle 11g
      Driver          = /usr/lib/oracle/11.2/client64/lib/libsqora.so.11.1
      Driver64        = /usr/lib/oracle/11.2/client64/lib/libsqora.so.11.1
      Setup           = 
      Setup64         = 
      UsageCount      = 
      CPTimeout       = 
      CPReuse         = 
      FileUsage       = 1 
      Driver Logging  = 7
      
  4. Test unixODBC oracle using isql
    BASH> isql -v test tester1 SECRET
    [01000][unixODBC][Driver Manager]Can't open lib '/usr/lib/oracle/11.2/client64/lib/libsqora.so.11.1' : file not found
    [ISQL]ERROR: Could not SQLConnect
    This does not necessarily mean libsqora.so.11.1 is missing, as it's been investigated in [2], it's probably libodbcinst.so.1 missing.
    To fix it, LD_LIBRARY_PATH should be updated:
    export LD_LIBRARY_PATH=/usr/lib/oracle/11.2/client64/lib:/usr/lib64
    # and make a soft link like below, since it's unixODBC-2.3.2 we installed,
    # but libsqora.so is looking for libodbcinst.so.1
    sudo ln -s /usr/lib64/libodbcinst.so.2.0.0 /usr/lib64/libodbcinst.so.1
    
    Now it should work (tab0 in the example below is created here: http://zmstone.blogspot.se/2014/07/create-test-database-and-roles-in-fresh.html)
    BASH> isql -v test tester1 SECRET
    +---------------------------------------+
    | Connected!                            |
    |                                       |
    | sql-statement                         |
    | help [tablename]                      |
    | quit                                  |
    |                                       |
    +---------------------------------------+
    SQL> select * from tab0;
    +-------------+---------------------------------+
    | K           | V                               |
    +-------------+---------------------------------+
    | 1           | test value                      |
    +-------------+---------------------------------+
    SQLRowCount returns -1
    1 rows fetched
    
  5. Try connect to oracle from Erlang shell [3]
    NOTE: If Erlang OTP was built from source code, and lib/erlang/lib/odbc-* can not be found in OTP install directory, you'll have to install libodbc first, then redo configure and make install.
    BASH> erl
    Erlang R15B03 ......
    
    Eshell V5.9.3.1  (abort with ^G)
    1> odbc:start().
    ok
    2> {ok, Pid} = odbc:connect("DSN=test;UID=tester1;PWD=SECRET", [{scrollable_cursors, off}]).
    {ok,<0 data-blogger-escaped-.39.0="">}
    3> odbc:sql_query(Pid, "select * from tab0").    
    {selected,["K","V"],[{1.0,"test value"}]}
References
[1] https://community.oracle.com/thread/1115824
[2] http://en.it-usenet.org/thread/876/22511/
[3] http://www.databaseskill.com/331542/

create test database and roles in a fresh oracle install


See here to install oracle and sqlplus.

Connect to oracle as system or sysdba
BASH> rlwrap $ORACLE_HOME/bin/sqlplus -L system/INIT_PASSWORD@//localhost:1521/

Create a test database:
SQL> create bigfile tablespace test datafile 'test.dat' size 32m autoextend on nologging;

Tablespace created.

Create a test user:
SQL> create role tester; 

Role created.

SQL> grant connect, resource, dba to tester;

Grant succeeded.

SQL> create user tester1 identified by SECRET default tablespace test;

User created.

SQL> grant tester to tester1;

Grant succeeded.

SQL> alter user tester1 quota unlimited on test;

User altered.

SQL> quit

...

Now try to connect to oracle using the newly created user
BASH> rlwrap $ORACLE_HOME/bin/sqlplus -L tester1/SECRET@//localhost:1521

Create a test table and insert some random value
SQL> create table tab0(k number(10) not null, v varchar2(32) not null) tablespace test;

Table created

SQL> insert into tab0 (k,v) values (1, 'test value');
1 row created.

SQL> select * from tab0;
         K V
---------- --------------------------------
         1 test value