How to solve tiller is unable to connect localhost:8080 in Helm

If you are facing issue when running helm ls, helm install (no resources found)…

Solution 1

when install helm (2.8.2)

kubectl create serviceaccount --namespace kube-system tiller

/* solve configmaps is forbidden: User "system:serviceaccount:kube-system:tiller" cannot list configmaps in the namespace "kube-system" */

kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller

helm init --service-account tiller

Solution 2

set the automountServiceAccountToken to true (It seems to be fixed in v2.9?)

kubectl -n kube-system patch deployment tiller-deploy -p '{"spec": {"template": {"spec": {"automountServiceAccountToken": true}}}}'



How to use Terraform with Nectar For Beginner

What is Nectar?

Nectar is a cloud platform built on top of OpenStack. Nectar is used to support Australian researchers.

What is Terraform?

Terraform is a tool of Infrastructure-As-Code (IAC). By using it, we write codes in HCL language to provision VMs in automation manner. Other tools of IAC are Ansible, Chef, Puppet, etc. It provides us great maintainability and reduces the security flaws if a same procedure has to be done again and again to build and configure VMs.

Terraform’s file extension is *.tf.  In this tutorial, we will create three files:

    • Variables such as account credentials, login url, etc, are all declared here.
    • Terraform is built on modules. We need to let it know which module we will use.
    • Configuration of VMs lies here.

Get Started

Install Terraform
brew install terraform
Account Credentials

Once log in Nectar, reset your password in order to access OpenStack in SSH. The credentials you log in Dashboard with is not the one for SSH.

Download the OpenStack RC file which is used to set environment variables on client-side.

Create your keypair

Now that credentials are obtained, we can start putting them into the file.

variable "openstack_user_name" {
 description = "The username for the Tenant."
 default = "your account name : email"

variable "openstack_tenant_id" {
 description = "The id of the Tenant."
 default = "your project id"

variable "openstack_tenant_name" {
 description = "The name of the Tenant."
 default = "your project name"

variable "openstack_password" {
 description = "The password for the Tenant."
 default = "your password"

variable "openstack_auth_url" {
 description = "The endpoint url to connect to OpenStack."
 default = ""

variable "openstack_keypair" {
 description = "The keypair to be used."
 default = "your-keypair"

variable "tenant_network" {
 description = "The network to be used."
 default = "Classic Provider"

We are using auth v3, therefore, Tenant name/ID is replaced by Project name/ID.
provider "openstack" {
 user_name = "${var.openstack_user_name}"
 tenant_id = "${var.openstack_tenant_id}"
 tenant_name = "${var.openstack_tenant_name}"
 password = "${var.openstack_password}"
 auth_url = "${var.openstack_auth_url}"

We provision 2 instances. In OpenStack, the type of machine is called flavor and its ID can be found in the dashboard, so can the image (Operation System).

variable "count" {
 default = 2

resource "openstack_compute_instance_v2" "web" {
 count = "${var.count}"
 name = "${format("web-%02d", count.index+1)}"
 image_id = "d87a2d42-6a90-4d7d-918c-988e9ab13b56"
 availability_zone = "melbourne"
 flavor_id = "639b8b2a-a5a6-4aa2-8592-ca765ee7af63"
 key_pair = "${var.openstack_keypair}"
 security_groups = ["default"]
 network {
 name = "${var.tenant_network}"
 user_data = "${file("")}"

yum install -y httpd
chkconfig --level 345 httpd on

cat <<EOF > /var/www/html/index.html
<p>hostname is: $(hostname)</p>
chown -R apache:apache /var/www/html
service httpd start

Now we can tell Terraform to deploy it.
Before actually deploying it, we can preview it.

terraform plan

then apply(deploy) it

terraform apply
Test the instances

The deploy script has a key called user_data. Each instance will invoke this user data where we set up a static web page.

Initialising instances may take some time. Let’s wait…

Once it is done, we navigate to our instance with port 80.

You should able to see “host name is XXXX”


Wonder what can Terraform do more for OpenStack?

Check Terraform official guide for OpenStack – link

OpenStack is not fully supported by Terraform yet. Some functions may not be working.

Background Location Update in iOS 11

In iOS 11, CoreLocation has some changes including the showsBackgroundLocationIndicator property, a new Info.plist key : NSLocationAlwaysAndWhenInUseUsageDescription.

To suppor iOS 11, there are two keys for location service.

  1. NSLocationWhenInUseUsageDescription
  2. NSLocationAlwaysAndWhenInUseUsageDescription
  3. NSLocationAlwaysUsageDescription (support iOS 10 device or below)

Apple encourages developers to use location service more in foreground than in background, and gives users a clearer understanding of when and how the location service is used.

The arrow indicator of location service

  • stays hollow when device is either monitoring geofences or using significant location service.
  • stays solid when device receives location updates

The mechanism of CL Location Manager has been changed. There are some reports showing that apps can no longer receive background updates. During my testing on iOS 11.2.2, I found out the following scenarios work.

  1. Significant location service work in both foreground, background, and even user kills the App, it will wake up.
  2. Standard location service doesn’t start when the App is in the background. However, if the App also registers significant location service, standard location service is able to start in the background, even the App has been killed manually by users and significant location service launches the App before starting standard location service. (This requires UIBackgroundMode is set with Location Update).
  3. Entering geofences will give the App 10 seconds of execution time. During that time, the App can launch standard location service.
// setting up location manager

locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation // accuracy enhanced by sensor data

locationManager.pausesLocationUpdatesAutomatically = false // or true depends on you

locationManager.distanceFilter = 5 // how you want to receive the updates, every 5 meters? In real situation, it may report less than 5 meters!

if #available(iOS 11.0, *) {
    locationManager.showsBackgroundLocationIndicator = true // show users when standard location service is activated, good for debugging.

locationManager.allowsBackgroundLocationUpdates = true //  necessary to make standard location service work in background

locationManager.requestAlwaysAuthorization() // request permission

locationManager.startMonitoringSignificantLocationChanges() // crucial to start standard location service in background

// start standard location service when user enters a geofence
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {


I’ve tested the code on iPhone X iOS 11.2.2.
If you want to share test results on other devices, please do so! Thanks!

How to write multiple language code snippets in MkDocs

MkDocs is using markdown to generate documents on static web pages.

Recently, I was working on writing documents for a iOS project. In iOS, I would need to document 2 programming languages: Objective-C & Swift. If I write them in two separate code snippets, that would be very unreadable. So to improve the readability, I decided to put them together by using HTML Tabs.

We will need to use custom configuration to let MkDocs generate those HTML syntax with the javascript and CSS.

In mkdocs.yaml, specify the js and CSS files used for the tabs.

    - styles/tab.css
    - custom/tab.js

Javascript: when clicks the tab, it will hide others tab contents.

function openCode(codeName, elmnt, color) {
// Hide all elements with class="tabcontent" by default */
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i &lt; tabcontent.length; i++) {
tabcontent[i].style.display = "none";

// Remove the background color of all tablinks/buttons
tablinks = document.getElementsByClassName("tablink");
for (i = 0; i &lt; tablinks.length; i++) {
tablinks[i].style.backgroundColor = "";
tablinks[i].style.color = "black";

// Show the specific tabs content
var elements = document.getElementsByClassName(codeName);
for (i = 0; i&lt; elements.length; i++) {
elements[i].style.display = "block";

// Add the specific color to the button used to open the tab content
elements = document.getElementsByClassName(elmnt.className);
for (i = 0; i&lt; elements.length; i++) {
elements[i].style.backgroundColor = color;
elements[i].style.color = "white";

// Get the element with id="defaultOpen" and click on it
if(document.getElementsByClassName("objbutton") !== null){
var elements = document.getElementsByClassName("objbutton");
for (i = 0; i&lt; elements.length; i++) {

CSS: for Tab styling

/* Style the tab buttons */
.tablink {
    color: black;
    float: left;
    border: none;
    outline: none;
    cursor: pointer;
    padding: 12px;
    font-size: 12px;
    width: 100px;

/* Change background color of buttons on hover */
.tablink:hover {
    background-color: #777;

/* Set default styles for tab content */
.tabcontent {
    color: black;
    display: none;

/* Style each tab content individually */ 
#Obj {background-color:white;}
#Swift {background-color:white;}

Then finally in markdown file, we can easily create a multi-language code snippet.

<button class="tablink objbutton" onclick="openCode('obj', this, '#03a9f4')" markdown="1">Objective-C</button> 
<button class="tablink swiftbutton" onclick="openCode('swift', this, '#03a9f4')" markdown="1">Swift</button> 


<div class="obj tabcontent"> 
Your objective-c code goes here.


<div class="swift tabcontent"> 
Your swift code goes here.


In HTML tags, the markdown="1" tells MkDocs do not parse its content so it will be generated as normal HTML syntax.

Here it is how it looks like.

How to create iOS fat dynamic framework

“Fat” means that this framework has many slices. Each slice (machine code) is built for certain architecture. The fat framework we are going to build contains i386 x86_64 armv7 armv7s arm64.

  • armv7 is for iPhone 4s
  • armv7s is for iPhone 5
  • arm64 is for iPhone 6

Firstly we need to create a target for dynamic framework: Cocoa Touch Framework

Secondly we create a new target: External Build System

Go to Build Phases -> Run script

Paste the below code snippet in there


# make sure the output directory exists
# Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Convenience step to copy the framework to desktop directory
ditto "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${HOME}/Desktop/${PROJECT_NAME}.framework"

Build it then your fat dynamic framework will be located on your desktop! Before submitting the App to AppStore, you must strip off the simulator slice (i386 x86_64) from the framework

lipo -remove i386 Name.framework/Name -output Path/name

lipo -remove x86_64 Name.framework/Name -output Path/name

Or you can refer to this solution:


Logitech G213 Prodigy Keyboard

My first mechanical keyboard was CM Storm QuickFire TK. I likes its CHERRY MX RED Switches. Unfortunately, it did not come along with me to Australia. I had to use MacBook’s keyboard for 9 months. Finally, G213 caught my eyes with its shiny LED lights, and very fair price.

G213 supports OS X, its multimedia buttons are functional, including playing iTunes music, lower/raise the volume.

Though, it is not a mechanical keyboard, its keys actually provides a similar feeling as using cherry red switches. Nonetheless, the sound of clicking is not so clear and sharp as cherry red switches.

Its RGB lights are bright, and the keyboard can support multiple colors in 4 zones at once.

For this fair price, 70AUD, it worths purchasing.