Tag Archives: beginners

How to make hello world program in wxPython

In this article we will look at creating a simple hello world program using wxPython. This program will create and display simple window with a big button on it. Up on clicking the button program will exit. Use the following code to create hello world program. You must already have wxPython library installed

Hello world program

import wx

class MainWindow(wx.Frame):
    def __init__(self,parent):
        wx.Frame.__init__(self,parent,title="Hello World")
        self.killButton = wx.Button(self,label="Kill Me")
        self.killButton.Bind(wx.EVT_BUTTON,self.kill)
        self.Show()

    def kill(self,event):
        self.Close()
        print("Bye Bye cruel world")
        
app = wx.App(False)
frame = MainWindow(None)
app.MainLoop()

Explanation

We will go line by line here and try to explain what’s going on in this program. Most of the lines of self explanatory. If you are just getting started in programming the following explanation will be helpful.

  1. Import wxpython library
  2. Inherit from wx.Frame class. This is useful style for most of the programs that you will build. You can create one base frame or window and put rest of GUI widgets on top of it like Text controls, buttons,images, tables etc.
  3. Instantiate the inherited frame the desired title. parent argument is usually None for main windows.
  4. Create a button with label “Kill Me”. The first argument is parent. In this case we use “self” which is the main window we have just created.
  5. Bind the button click event (EVT_BUTTON) of the killButton to kill method. Whenever, EVT_BUTTON event is fired aka the killButton is clicked, kill method will be called.
  6. This line will cause the window to get displayed on screen. It’s customary to call this method after being done with construction of GUI i.e. create main window, place widgets, bind event like we did here.
  7. Create wxPython application by call wx.App. Every wxPython program must have this application.
  8. Start the main loop. Which will hand over control to wxPython library. This post explains why main loop has to be called.

Output

This program will launch the following window. The button takes all the available space on the window since there are no other widgets. You need a few more lines of code to make the button look like what users are used to – small and horizontal. You can exit the program by clicking the button.

How to install wxpython

In this post we will go over the topic of easy way to install wxpython. The following command will install wxpython easily in python3.

pip install wxpython

Python 2

Older versions of wxpython can be installed by downloading binaries (for windows) from sourceforge . The binaries are available for both Windows and MacOS.

Linux

The pip install command should work on linux also. However, if you are stuck on old linux vesions. You can try installing wxpython using your distro’s package manager like apt-get or yum. You can search for exact version and package name available on your platform using the following commands for debian variants.

apt-cache search wxpython

┌──(kali㉿kali)-[~]
└─$ apt-cache search wxpython
gnumed-client - medical practice management - Client
psychopy - environment for creating psychology stimuli in Python
pyscanfcs - scientific tool for perpendicular line scanning FCS
python3-genx - differential evolution algorithm for fitting
python3-opengl - Python bindings to OpenGL (Python 3)
python3-pyface - traits-capable windowing framework
python3-squaremap - wxPython control to display hierarchic data as nested squares
python3-wxgtk-media4.0 - Python 3 interface to the wxWidgets Cross-platform C++ GUI toolkit (wx.media)
python3-wxgtk-webview4.0 - Python 3 interface to the wxWidgets Cross-platform C++ GUI toolkit (wx.html2)
python3-wxgtk4.0 - Python 3 interface to the wxWidgets Cross-platform C++ GUI toolkit
soundgrain - Graphical interface to control granular sound synthesis modules
wxglade - GUI designer written in Python with wxPython
wxpython-tools - Tools from the wxPython distribution

Successful installation

Use the following command to check if the installation is successful or not.

PS C:\Users\godson> python
Python 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:52:53) [MSC v.1927 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import wx
>>> wx.version()
'4.1.1 msw (phoenix) wxWidgets 3.1.5'
>>>

As shown above it should print current version of wxpython installed if the installation is successful.

A more extensive tutorial is available here

TabLayout Example using ViewPager and Fragments in Android

If you are using the latest android application then you have noticed that now days android is following a design pattern. This is material design and it came with Android Lollipop (5.0). Though we can still use this design pattern for the older versions (>4.0) by using the support libraries. One of the component of material design is TabLayout. So in this TablLayout Example we will see how we can implement it in our android application.

What is TabLayout ?

Android TabLayout provides horizontal layout to display tabs. We can display more screens in a single screen using tabs. User can swipe the tabs quickly as you can see in the image below.

Creating a new project and add necessary libraries

Open Android Studio and create a new project. I have created DemoTabLayout.

After create a new project, First of all we have to need include design libraries in the dependencies section of our build.gradle file so include this libraries in your build.gradle file by below line.

implementation 'com.android.support:design:28.0.0'

Remove action bar from style

Now since we will be using Android Toolbar and TabLayout classes to show tabs, lets remove the action bar from layout by using styles,

Go to style.xml file and change the parent of theme which you are using in your app.Change parent with “Theme.AppCompat.Light.NoActionBar”. So now your style file will look like below code

<resources>
  <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
     <item name="colorPrimary">#3F51B5</item>
     <item name="colorPrimaryDark">#303F9F</item>
     <item name="colorAccent">#FF4081</item>
  </style>

</resources>

Creating fragments

We are creating an application which will have three tabs, So let’s define three fragment and their layouts.

First Fragment

package com.vikas.demotablayout;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
class tab1 extends Fragment {
   @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup container,
               Bundle savedInstanceState) {
           return inflater.inflate(R.layout.fragment_tab1, container, false);
         }
   }

It’s layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
     
    <TextView
      android:id="@+id/textView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerInParent="true"
      android:text="Tab 1"
      android:textAppearance="?android:attr/textAppearanceLarge"/>

 </RelativeLayout>

 

Second Fragment

package com.vikas.demotablayout;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


public class Tab2 extends Fragment {
   
   @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup container,
               Bundle savedInstanceState) {
          return inflater.inflate(R.layout.fragment_tab2, container, false);
	}
   }

it’s layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
	<TextView
          android:id="@+id/textView"
	  android:layout_width="wrap_content"
 	  android:layout_height="wrap_content"
          android:layout_centerInParent="true"
	  android:text="Tab 2"
          android:textAppearance="?android:attr/textAppearanceLarge"/>
</RelativeLayout>

Third Fragment

package com.vikas.demotablayout;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class Tab2 extends Fragment {


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

	 return inflater.inflate(R.layout.fragment_tab3, container, false);
      }

}

its layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical">
     <TextView
        android:id="@+id/textView"
	android:layout_width="wrap_content"
        android:layout_height="wrap_content"
	android:layout_centerInParent="true"
        android:text="Tab 2"
	android:textAppearance="?android:attr/textAppearanceLarge"/>
</RelativeLayout>

Now we will define a view pager adapter to create tab swipe functionality.

package com.vikas.demotablayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;

public class PagerAdapter extends FragmentStatePagerAdapter {

    int mNumOfTabs;
    public PagerAdapter(FragmentManager fm, int NumOfTabs) {
     	super(fm);
	this.mNumOfTabs = NumOfTabs;
    }
    @Override
    public Fragment getItem(int position) {
       switch (position) {
	  case 0:
            tab1 tab1 = new tab1();
            return tab1;
          case 1:
            Tab2 tab2 = new Tab2();
            return tab2;
          case 2:
            Tab3 tab3 = new Tab3();
            return tab3;
          default:
            return null;
        }
    }
    @Override
    public int getCount() {
        return mNumOfTabs;
    }
}

Now we will create an Activity named MainActivity which will hold the tabs . This Activity will have two part first is code file and second is layout file. layout file code given below

<RelativeLayout
        android:id="@+id/main_layout"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
	xmlns:tools="http://schemas.android.com/tools"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	tools:context=".MainActivity">
	<android.support.v7.widget.Toolbar
	    android:id="@+id/toolbar"
	    android:layout_width="match_parent"
	    android:layout_height="wrap_content"
	    android:layout_alignParentTop="true"
	    android:background="?attr/colorPrimary"
	    android:elevation="6dp"
	    android:minHeight="?attr/actionBarSize"
	    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
	    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
	<android.support.design.widget.TabLayout
	    android:id="@+id/tab_layout"
	    android:layout_width="match_parent"
	    android:layout_height="wrap_content"
	    android:layout_below="@+id/toolbar"
	    android:background="?attr/colorPrimary"
	    android:elevation="6dp"
	    android:minHeight="?attr/actionBarSize"
	    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
	<android.support.v4.view.ViewPager
	    android:id="@+id/pager"
	    android:layout_width="match_parent"
	    android:layout_height="fill_parent"
	    android:layout_below="@id/tab_layout"/>
</RelativeLayout>

We can see above that here we add a Toolbar, second is Tablayout and third thing is Viewpager. Toolbar is for showing application name and menu icon. TabLayout is for showing Tabs and viewpager is for holding fragments. Now we write code for attach this layout with fragments in MainActivity code file. Code is given below:

package com.vikas.demotablayout;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;

public class MainActivity extends AppCompatActivity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
	TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
	tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
        tabLayout.addTab(tabLayout.newTab().setText("Tab 2"));
        tabLayout.addTab(tabLayout.newTab().setText("Tab 3"));
        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
        final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
        final PagerAdapter adapter = new PagerAdapter
                (getSupportFragmentManager(), tabLayout.getTabCount());
        viewPager.setAdapter(adapter);
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

        tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
          @Override
          public void onTabSelected(TabLayout.Tab tab) {
	          viewPager.setCurrentItem(tab.getPosition());
	  }
          @Override
          public void onTabUnselected(TabLayout.Tab tab) {
	  }
          @Override
          public void onTabReselected(TabLayout.Tab tab) {
          }
        });
     }

     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
	    getMenuInflater().inflate(R.menu.menu_main, menu);
	    return true;
     }

}

That’s all, Now you can run your project.

Happy coding…

DatePicker Example in Android

In android, DatePicker is a control which will allow users to select the date by day, month and year in our application user interface.

The images of datePicker are given blow

Create DatePicker with xml

We can create DatePicker using <Datepicker> element in xml file, which is given below

<DatePicker android:id="@+id/datePicker1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

There are two types of view of DatePicker

1. Complete Calendar view

2. Spinner View

Complete Calendar view :- We can create complete calendar view with below code

<DatePicker
    android:id="@+id/datePicker1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:datePickerMode="calendar"/>

This is output

Spinner view :- We can create complete calendar view with below code

 <DatePicker
    android:id="@+id/datePicker1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:datePickerMode="spinner"
    android:calendarViewShown="false"
/>

This is output

Now we will create an example of datePicker in which we will set date picker on edit text and we will create date picker using java code also. In this example we will create a Textview and a button also. On button click we will show date in TextView.

Create a new android application using android studio and give name DatePickerDemo.

Now Open activity_main.xml file from \res\layout path and write code which is given below

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical" android:gravity="center">
    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="150dp"
        android:ems="10"
        android:hint="Enter Date" />
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="Get Date" />
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:textStyle="bold"
        android:textSize="18dp"/>
</LinearLayout>

Now open MainActivity.java file and write code which is given below

MainActivity.java

package com.vikas.datepickerdemo;

import android.app.DatePickerDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.InputType;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.TextView;

import java.util.Calendar;

public class MainActivity extends AppCompatActivity {

    DatePickerDialog datepicker;
    EditText eText;
    Button btn;
    TextView tvw;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvw=(TextView)findViewById(R.id.textView1);
        eText=(EditText) findViewById(R.id.editText1);
        eText.setInputType(InputType.TYPE_NULL);
        eText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final Calendar cldr = Calendar.getInstance();
                int day = cldr.get(Calendar.DAY_OF_MONTH);
                int month = cldr.get(Calendar.MONTH);
                int year = cldr.get(Calendar.YEAR);
                // date picker dialog
                datepicker = new DatePickerDialog(MainActivity.this,
                        new DatePickerDialog.OnDateSetListener() {
                            @Override
                            public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                                eText.setText(dayOfMonth + "/" + (monthOfYear + 1) + "/" + year);
                            }
                        }, year, month, day);
                datepicker.show();
            }
        });
        btn=(Button)findViewById(R.id.button1);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tvw.setText("Selected Date: "+ eText.getText());
            }
        });


    }
}

In java code you can see that we set an Onclicklistener on EditText, when we click on EditText then will see calendar dialog, From which we can select date.

Output of example

That’s all . This is the final output of example.

Happy Coding…

How to Setup Redis Cluster from Source

What is redis

Redis is an open source in-memory database. It stores data in key-value format. Because of residing in memory, redis is an excellent tool for caching. Redis provides a rich set of data types. This gives redis upper hand over Memcached. Apart from caching, redis can be used as distributed message broker.

Redis Cluster and Sentinels

To achieve high availability, redis can be deployed in cluster along with Sentinels. Sentinel is a feature of redis. Multiple sentinels are deployed across redis clusters for monitoring purpose. When redis master goes down, sentinels elect a new master from slaves. When old master comes up again, it is added as slave.

Another use case of clustering is a distribution of load. In high load environment, we can send write requests to master and read request to slaves.

This tutorial is specifically focused on Redis Cluster Master Slave model. We will not cover data sharding across cluster here. In data sharding, keys are distributed across multiple redis nodes.

Setup for tutorial

For this tutorial, we will use 3 (virtual) servers. On one server Redis master will reside while other two servers will be used for slaves. Standard redis port is 6379. To differentiate easily, we will run master on 6379 port and slaves on
6380 and 6381 ports. Same will be applied for sentinel services. Master sentinel will listen on 16379 port while slave sentinels will be on 16380 and 16381.

Lets put this easy way.

    Server 1 (Redis Master)
    Redis Service at host 192.168.0.1 and port tcp:6379
    Sentinel Service at host 192.168.0.1 and port tcp:16379
    Server 2 (Redis Slave 1)
    Redis Service at host 192.168.0.2 and port tcp:6380
    Sentinel at host 192.168.0.2 and port tcp:16380
    Server 3 (Redis Slave 2)
    Redis Service at host 192.168.0.3 and port tcp:6381
    Sentinel Service at host 192.168.0.3 and port tcp:16381

This tutorial is tested on CentOS 6.9. For CentOS 7.X, check below Notes Section.

Installation

We will follow same installation steps for setting up of all servers. Only difference will be in configurations.

  • Step 1: Grab redis source, make and install
  • Step 2: Setup required directories
  • Step 3: Configure redis master
  • Step 4: Configure redis master sentinel
  • Step 5: Add low privileged user to run redis
  • Step 6: Setup init scripts
  • Step 7: Start service

Server 1 (Redis Master)


Install Redis

    cd /opt
    wget download.redis.io/releases/redis-4.0.9.tar.gz
    tar -xf redis-4.0.9.tar.gz
    cd redis-4.0.9
    make
    make install

Setup required directories

    mkdir -p /etc/redis /var/run/redis /var/log/redis /var/redis/6379
    cp redis.conf redis.conf.bak
    cp redis.conf /etc/redis/6379.conf

Configure redis master

Edit config file `/etc/redis/6379.conf` in your favorite editor and change below options.

    bind 192.168.0.1
    port 6379
    daemonize yes
    pidfile "/var/run/redis/redis_6379.pid"
    logfile "/var/log/redis/redis_6379.log"
    dir "/var/redis/6379"

Configure redis master sentinel

Add config file for sentinel at `/etc/redis/sentinel_6379.conf`. Open a file and add below content

    bind 192.168.0.1
    port 16379
    sentinel monitor redis-cluster 192.167.0.1 6379 2
    sentinel down-after-milliseconds redis-cluster 5000
    sentinel parallel-syncs redis-cluster 1
    sentinel failover-timeout redis-cluster 10000
    daemonize yes
    pidfile "/var/run/redis/sentinel_6379.pid"
    dir "/var/redis/6379"

Add non-privileged user

    adduser redis -M -g daemon
    passwd -l redis
    chown -R redis:daemon /opt/redis-4.0.9
    chown -R redis:daemon /var/run/redis
    chown -R redis:daemon /var/log/redis
    chown -R redis:daemon /var/redis/

Setup init scripts

You can find sample init scripts in Notes section below.

    cp redis-6379-init-script /etc/init.d/redis_6379
    chmod 750 /etc/init.d/redis_6379
    chkconfig redis_6379 on
    cp sentinel-6379-init-script /etc/init.d/sentinel_6379
    chmod 750 /etc/init.d/sentinel_6379
    chkconfig sentinel_6379 on

Start service

    service redis_6379 start
    service sentinel_6379 start

Server 2 (Redis Slave 1)


Install Redis

    cd /opt
    wget download.redis.io/releases/redis-4.0.9.tar.gz
    tar -xf redis-4.0.9.tar.gz
    cd redis-4.0.9
    make
    make install

Setup required directories

    mkdir -p /etc/redis /var/run/redis /var/log/redis /var/redis/6380
    cp redis.conf redis.conf.bak
    cp redis.conf /etc/redis/6380.conf

Configure redis slave 1

Edit config file `/etc/redis/6380.conf` in your favorite editor and change below options.

    bind 192.168.0.2
    port 6380
    daemonize yes
    pidfile "/var/run/redis/redis_6380.pid"
    logfile "/var/log/redis/redis_6380.log"
    dir "/var/redis/6380"
    slaveof 192.168.0.1 6379

Configure redis slave 1 sentinel

Add config file for sentinel at `/etc/redis/sentinel_6380.conf`. Open a file and add below content

    bind 192.168.0.2
    port 16380
    sentinel monitor redis-cluster 192.167.0.1 6379 2
    sentinel down-after-milliseconds redis-cluster 5000
    sentinel parallel-syncs redis-cluster 1
    sentinel failover-timeout redis-cluster 10000
    daemonize yes
    pidfile "/var/run/redis/sentinel_6380.pid"
    dir "/var/redis/6380"

Add non-privileged user

    adduser redis -M -g daemon
    passwd -l redis
    chown -R redis:daemon /opt/redis-4.0.9
    chown -R redis:daemon /var/run/redis
    chown -R redis:daemon /var/log/redis
    chown -R redis:daemon /var/redis/

Setup init scripts

You can find sample init scripts in Notes section below. Change `$HOST` and `$PORT` values accordingly

cp redis-6380-init-script /etc/init.d/redis_6380
    chmod 750 /etc/init.d/redis_6380
    chkconfig redis_6380 on
cp sentinel-6380-init-script /etc/init.d/sentinel_6380
    chmod 750 /etc/init.d/sentinel_6380
    chkconfig sentinel_6380 on

Start service

    service redis_6380 start
    service sentinel_6380 start

Server 3 (Redis Slave 2)


Install Redis

    cd /opt
    wget download.redis.io/releases/redis-4.0.9.tar.gz
    tar -xf redis-4.0.9.tar.gz
    cd redis-4.0.9
    make
    make install

Setup required directories

    mkdir -p /etc/redis /var/run/redis /var/log/redis /var/redis/6381
    cp redis.conf redis.conf.bak
    cp redis.conf /etc/redis/6381.conf

Configure redis slave 2

Edit config file `/etc/redis/6381.conf` in your favorite editor and change below options.

    bind 192.168.0.3
    port 6381
    daemonize yes
    pidfile "/var/run/redis/redis_6381.pid"
    logfile "/var/log/redis/redis_6381.log"
    dir "/var/redis/6381"
    slaveof 192.168.0.1 6379

Configure redis slave 2 sentinel

Add config file for sentinel at `/etc/redis/sentinel_6381.conf`. Open a file and add below content

    bind 192.168.0.3
    port 16381
    sentinel monitor redis-cluster 192.167.0.1 6379 2
    sentinel down-after-milliseconds redis-cluster 5000
    sentinel parallel-syncs redis-cluster 1
    sentinel failover-timeout redis-cluster 10000
    daemonize yes
    pidfile "/var/run/redis/sentinel_6381.pid"
    dir "/var/redis/6381"

Add non-privileged user

    adduser redis -M -g daemon
    passwd -l redis
    chown -R redis:daemon /opt/redis-4.0.9
    chown -R redis:daemon /var/run/redis
    chown -R redis:daemon /var/log/redis
    chown -R redis:daemon /var/redis/

Setup init scripts

You can find sample init scripts in Notes section below. Change `$HOST` and `$PORT` values accordingly

    cp redis-6381-init-script /etc/init.d/redis_6381
    chmod 750 /etc/init.d/redis_6381
    chkconfig redis_6381 on
    cp sentinel-6381-init-script /etc/init.d/sentinel_6381
    chmod 750 /etc/init.d/sentinel_6381
    chkconfig sentinel_6381 on

Start service

    service redis_6381 start
    service sentinel_6381 start

Sentinel Testing

    # Connect to any redis sentinel
    /usr/local/bin/redis-cli -h 192.168.0.3 -p 16381

    # To see current masters
    192.168.0.3:16381> SENTINEL masters

    # To see slaves for given cluster
    192.168.0.3:16381> SENTINEL slaves redis-cluster

Redis Fail-over Testing

For fail-over testing, we can take down redis-master either using init script or below command.

    # Connect to redis master and execute below command
    /usr/local/bin/redis-cli -h 192.168.0.1 -p 6379
    192.168.0.1:6379> DEBUG SEGFAULT

Also we can force sentinel to run fail over using below command

    # Forced failure
    192.168.0.1:6379> SENTINEL failover redis-cluster
    # Check after few seconds. You should get new master
    192.168.0.1:6379> SENTINEL masters

Sample init scripts

Redis Init Script

#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
#
# chkconfig: 345 85 15
# description:  Redis is persistent key-value database
# processname: redis_6379

# Source function library
. /etc/init.d/functions

REDISHOST=192.168.0.1
REDISPORT=6379
EXEC=/usr/local/bin/redis-server
USER=redis
CLIEXEC=/usr/local/bin/redis-cli
PIDFILE=/var/run/redis/redis_${REDISPORT}.pid
CONF="/etc/redis/${REDISPORT}.conf"

case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis server..."
                daemon --user $USER $EXEC $CONF
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
                echo "$PIDFILE does not exist, process is not running"
        else
                PID=$(cat $PIDFILE)
                echo "Stopping ..."
                daemon --user $USER $CLIEXEC -h $REDISHOST -p $REDISPORT shutdown
                while [ -x /proc/${PID} ]
                do
                    echo "Waiting for Redis to shutdown ..."
                    sleep 1
                done
                echo "Redis stopped"
        fi
        ;;
    restart)
        stop
        sleep 3
        start
        ;;
    *)
        echo "Usage: $PROG_NAME {start|stop|restart}"
		exit 1
		;;
esac

Sentinel Init Script

#!/bin/sh
#
# Simple Redis Sentinel init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
#
# chkconfig: 345 86 15
# description:  Redis Sentinel to monitor redis cluster
# processname: sentinel_6379

# Source function library
. /etc/init.d/functions

REDIS_PORT=6379
SENTINEL_PORT=16379
EXEC=/usr/local/bin/redis-server
CLIEXEC=/usr/local/bin/redis-cli
USER=redis

PIDFILE=/var/run/redis/sentinel_${REDIS_PORT}.pid
CONF="/etc/redis/sentinel_${REDIS_PORT}.conf"

case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis Sentinel server..."
                daemon --user $USER $EXEC $CONF --sentinel
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
                echo "$PIDFILE does not exist, process is not running"
        else
                PID=$(cat $PIDFILE)
                echo "Stopping ..."
                kill -9 $PID
                rm $PIDFILE
                while [ -x /proc/${PID} ]
                do
                    echo "Waiting for Redis Sentinel to shutdown ..."
                    sleep 1
                done
                echo "Redis Sentinel stopped"
        fi
        ;;
    restart)
        stop
        sleep 3
        start
        ;;
    *)
        echo "Usage: $PROG_NAME {start|stop|restart}"
		exit 1
		;;
esac

Notes

Security

  • NEVER EVER run redis on public interface
  • If redis is deployed in cloud environment like AWS, set up security groups/firewalls carefully. Most of times, cloud providers use ephemeral ips. Because of ephermal ips, even redis is bound to private ip, it can be accessed over public interface.
  • For more security, dangerous commands can be disabled(renamed). But be careful with them in cluster environment.
  • Redis also provides simple authentication mechanism. It is not covered here because of scope.

Sentinel management

  • During redis fail-over, config files are rewritten by sentinel program. So when restarting redis-cluster, be careful.

Sources

  • https://redis.io/topics/cluster-tutorial
  • https://redis.io/topics/security
  • https://redis.io/commands/debug-segfault