Saturday, December 19, 2020

IBM Cloud VPC Network Load Balancer -- Node.js SDK Examples

 What is Network Load Balancer (NLB)?


Network Load Balancer works in Layer 4 and is best fit for business-critical and interactive workloads that require high throughput and low latency.

                -- from IBM Cloud blog

With traditional load balancer, all incoming and returning traffics would go through the load balancer itself. The big disadvantage is the high volume of traffics will increase the latency and affect the throughput.

NLB is using a technology called Direct Server Return (DSR). The information processed by the backend targets is sent directly back to the client, thus minimizing latency and optimizing throughput performance.

                  -- from IBM Cloud blog

Node.js SDK

This Node.js SDK is a new tool for developer to manage their IBM Cloud VPC resources. If you are new to Node.js and need to use the Node.js SDK to manage your ALB/NLB on IBM Cloud VPC, this doc can help you to get start. 

Import the VPC libaries:

const { IamAuthenticator } = require('ibm-vpc/auth');
const VpcV1 = require('ibm-vpc/vpc/v1');
view raw gistfile1.txt hosted with ❤ by GitHub

Create VPC service object and authenticate:

// Create an IAM authenticator.
const authenticator = new IamAuthenticator({
apikey: '<api-key>',
});
// Construct the service client.
const vpcService = new VpcV1({
authenticator, // required
serviceUrl: 'https://us-south.iaas.cloud.ibm.com/v1', // optional, change us-south base on the region you are using
});
view raw gistfile1.txt hosted with ❤ by GitHub

Define some variables and sleep function that will be used below:

const instanceId = "<instaince_id>";
const subnetId = "<subnet_id>";
const nlbName = "nodesdk-nlb-test-1";
const listenerPort = 234;
const memberPort = 234;
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
view raw gistfile1.txt hosted with ❤ by GitHub

Define an async checkLbActive function:

async function checkLbActive(lbId) {
const params = {id: lbId};
var lb;
do {
var lb = await vpcService.getLoadBalancer(params)
console.log("LB is in " + lb.result.provisioning_status + " state")
// const second = 1000
await sleep(30 * 1000);
} while(lb.result.provisioning_status != "active");
}
view raw gistfile1.txt hosted with ❤ by GitHub

List load balancers:

async function listLbs() {
console.log("\nListing all load balancers in us-south ...")
const params = {};
var lbs = await vpcService.listLoadBalancers(params);
lbs.result.load_balancers.forEach((item, _) => {
console.log(item)
})
}
view raw gistfile1.txt hosted with ❤ by GitHub

CREATE Load Balancer:

async function createNlb() {
console.log("\nCreating network load balancer ...")
// SubnetIdentityById
const subnetIdentityModel = {
id: subnetId,
};
// LoadBalancerPoolIdentityByName
const loadBalancerPoolIdentityByNameModel = {
name: 'my-load-balancer-pool',
};
// LoadBalancerListenerPrototypeLoadBalancerContext
const loadBalancerListenerPrototypeLoadBalancerContextModel = {
port: listenerPort,
protocol: 'tcp',
default_pool: loadBalancerPoolIdentityByNameModel,
};
// LoadBalancerPoolHealthMonitorPrototype
const loadBalancerPoolHealthMonitorPrototypeModel = {
delay: 5,
max_retries: 2,
port: 22,
timeout: 2,
type: 'http',
url_path: '/',
};
// LoadBalancerPoolMemberTargetPrototypeInstanceIdentityInstanceIdentityById
const loadBalancerPoolMemberTargetPrototypeModel = {
id: instanceId,
};
// LoadBalancerPoolMemberPrototype
const loadBalancerPoolMemberPrototypeModel = {
port: memberPort,
weight: 50,
target: loadBalancerPoolMemberTargetPrototypeModel,
};
// LoadBalancerPoolSessionPersistencePrototype
const loadBalancerPoolSessionPersistencePrototypeModel = {
type: 'source_ip',
};
// LoadBalancerPoolPrototype
const loadBalancerPoolPrototypeModel = {
name: 'my-load-balancer-pool',
algorithm: 'least_connections',
protocol: 'tcp',
health_monitor: loadBalancerPoolHealthMonitorPrototypeModel,
members: [loadBalancerPoolMemberPrototypeModel],
session_persistence: loadBalancerPoolSessionPersistencePrototypeModel,
};
// LoadBalancerProfileIdentityByName
const loadBalancerProfileIdentityModel = {
name: 'network-fixed',
};
const isPublic = true;
const subnets = [subnetIdentityModel];
const name = nlbName;
const listeners = [loadBalancerListenerPrototypeLoadBalancerContextModel];
const pools = [loadBalancerPoolPrototypeModel];
const profile = loadBalancerProfileIdentityModel;
const params = {
isPublic: isPublic,
subnets: subnets,
name: name,
listeners: listeners,
pools: pools,
profile: profile,
};
try {
var lb = await vpcService.createLoadBalancer(params)
console.log(lb)
} catch(e) {
console.log(e.message)
throw 500
};
return lb.result
}
view raw gistfile1.txt hosted with ❤ by GitHub

CREATE Load Balancer Listener:

async function createListener(lbId, poolId) {
console.log("\nCreating listener ...")
// LoadBalancerPoolIdentityById
const loadBalancerPoolIdentityModel = {
id: poolId,
};
const params = {
loadBalancerId: lbId,
port: listenerPort,
protocol: "tcp",
defaultPool: loadBalancerPoolIdentityModel,
}
try {
var listener = await vpcService.createLoadBalancerListener(params);
console.log(listener)
} catch(e) {
console.log(e.message)
throw 500
}
console.log("Create listener request sent.")
return listener.result.id
}
view raw gistfile1.txt hosted with ❤ by GitHub

CREATE Load Balancer Pool:

async function createPool(lbId) {
console.log("\nCreating pool ...")
// LoadBalancerPoolHealthMonitorPrototype
const loadBalancerPoolHealthMonitorPrototypeModel = {
delay: 20,
max_retries: 3,
port: 6060,
timeout: 10,
type: 'tcp',
};
// LoadBalancerPoolPrototype
const params = {
loadBalancerId: lbId,
name: 'my-pool',
algorithm: 'round_robin',
protocol: 'tcp',
healthMonitor: loadBalancerPoolHealthMonitorPrototypeModel,
};
try {
var pool = await vpcService.createLoadBalancerPool(params);
console.log(pool)
} catch(e) {
console.log(e.message)
throw 500
}
console.log("Create pool request sent.")
return pool.result.id;
}
view raw gistfile1.txt hosted with ❤ by GitHub

CREATE Load Balancer Pool Member:

async function createMember(lbId, poolId) {
console.log("\nCreating member ...")
// LoadBalancerPoolMemberTargetPrototypeInstanceIdentityInstanceIdentityById
const loadBalancerPoolMemberTargetPrototypeModel = {
id: instanceId,
};
var params = {
loadBalancerId: lbId,
poolId: poolId,
port: memberPort,
weight: 50,
target: loadBalancerPoolMemberTargetPrototypeModel,
}
try {
var member = await vpcService.createLoadBalancerPoolMember(params);
console.log(member)
} catch(e) {
console.log(e.message)
throw 500
}
console.log("Create member request sent.")
return member.result.id
}
view raw gistfile1.txt hosted with ❤ by GitHub

UPDATE Load Balancer Listener:

async function updateListener(lbId, listenerId) {
console.log("\nUpdating listener ...")
const params = {
loadBalancerId: lbId,
id: listenerId,
port: 1010,
}
try {
var listener = await vpcService.updateLoadBalancerListener(params);
console.log(listener)
} catch(e) {
console.log(e.message)
throw 500
}
console.log("Update listener request sent.")
}
view raw gistfile1.txt hosted with ❤ by GitHub

UPDATE Load Balancer Pool:

async function updatePool(lbId, poolId) {
console.log("\nUpdating pool ...")
// LoadBalancerPoolHealthMonitorPrototype
const loadBalancerPoolHealthMonitorPrototypeModel = {
delay: 30,
max_retries: 2,
port: 7070,
timeout: 6,
type: 'http',
url_path: "/hello",
};
// LoadBalancerPoolPrototype
const params = {
loadBalancerId: lbId,
id: poolId,
name: 'my-pool-test',
algorithm: 'weighted_round_robin',
protocol: 'tcp',
healthMonitor: loadBalancerPoolHealthMonitorPrototypeModel,
};
try {
var pool = await vpcService.updateLoadBalancerPool(params);
console.log(pool)
} catch(e) {
console.log(e.message)
throw 500
}
console.log("Update pool request sent.")
}
view raw gistfile1.txt hosted with ❤ by GitHub

UPDATE Load Balancer Member:

async function updateMember(lbId, poolId, memberId) {
console.log("\nUpdating member ...")
var params = {
loadBalancerId: lbId,
poolId: poolId,
id: memberId,
port: 9090,
weight: 80
}
try {
var member = await vpcService.updateLoadBalancerPoolMember(params);
console.log(member)
} catch(e) {
console.log(e.message)
throw 500
}
console.log("Update member request sent.")
}
view raw gistfile1.txt hosted with ❤ by GitHub

DELETE Load Balancer:

async function deleteLb(lbId) {
console.log("Updating member ...")
var params = {
id: lbId
}
try {
var resp = await vpcService.deleteLoadBalancer(params);
console.log("status: " + resp.status.toString())
} catch(e) {
console.log(e.message)
throw 500
}
console.log("Delete NLB request sent.")
}
view raw gistfile1.txt hosted with ❤ by GitHub

DELETE Load Balancer Listener:

async function deleteListener(lbId, listenerId) {
console.log("\nDeleting listener " + listenerId + " ...");
var params = {
loadBalancerId: lbId,
id: listenerId
};
try {
var resp = await vpcService.deleteLoadBalancerListener(params);
console.log("status: " + resp.status.toString())
} catch(e) {
console.log(e.message)
throw 500
};
console.log("Delete listener request sent.")
}
view raw gistfile1.txt hosted with ❤ by GitHub

DELETE Load Balancer Pool:

async function deletePool(lbId, poolId) {
console.log("\nDeleting pool " + poolId + "...");
var params = {
loadBalancerId: lbId,
id: poolId
}
try {
var resp = await vpcService.deleteLoadBalancerPool(params);
console.log("status: " + resp.status.toString())
} catch(e) {
console.log(e.message)
throw 500
}
console.log("Delete pool request sent.")
}
view raw gistfile1.txt hosted with ❤ by GitHub

DELETE Load Balancer Pool Member:

async function deleteMember(lbId, poolId) {
var params = {
loadBalancerId: lbId,
id: poolId
}
var pools = await vpcService.getLoadBalancerPool(params)
var memberId = pools.result.members.pop().id
console.log("\nDeleting member " + memberId + " of pool " + poolId + "...");
var params = {
loadBalancerId: lbId,
poolId: poolId,
id: memberId
}
try {
var resp = vpcService.deleteLoadBalancerPoolMember(params);
console.log("status: " + (await resp).status.toString())
} catch(e) {
console.log(e.message)
throw 500
}
console.log("Delete member request sent.")
}
view raw gistfile1.txt hosted with ❤ by GitHub

Putting all the functions together and run it:

async function test_node_sdk_lb() {
await listLbs();
var lb = await createNlb();
await checkLbActive(lb.id);
var listener = lb.listeners.pop()
await deleteListener(lb.id, listener.id);
await checkLbActive(lb.id);
var pool = lb.pools.pop()
await deleteMember(lb.id, pool.id);
await checkLbActive(lb.id);
await deletePool(lb.id, pool.id);
await checkLbActive(lb.id);
var poolId = await createPool(lb.id);
await checkLbActive(lb.id);
var memberId = await createMember(lb.id, poolId);
await checkLbActive(lb.id);
var listenerId = await createListener(lb.id, poolId)
await checkLbActive(lb.id);
await updateListener(lb.id, listenerId)
await checkLbActive(lb.id);
await updatePool(lb.id, poolId)
await checkLbActive(lb.id);
await updateMember(lb.id, poolId, memberId)
await checkLbActive(lb.id);
deleteLb(lb.id);
}

Github Repo that has all the code above: gugucode/ibm-vpc-nlb-nodejs-test


Some references:

Node.js SDK version: https://www.npmjs.com/package/ibm-vpc
Node.js SDK Github repo: https://github.com/IBM/vpc-node-sdk#using-the-sdk/


Monday, November 23, 2020

IBM Cloud VPC Network Load Balancer -- Java SDK Examples

 What is Network Load Balancer (NLB)?


Network Load Balancer works in Layer 4 and is best fit for business-critical and interactive workloads that require high throughput and low latency.

                -- from IBM Cloud blog

With traditional load balancer, all incoming and returning traffics would go through the load balancer itself. The big disadvantage is the high volume of traffics will increase the latency and affect the throughput.

NLB is using a technology called Direct Server Return (DSR). The information processed by the backend targets is sent directly back to the client, thus minimizing latency and optimizing throughput performance.

                  -- from IBM Cloud blog

Java SDK

This Java SDK is a new tool for developer to manage their IBM Cloud VPC resources. If you are new to Java and need to use the Java SDK to manage your NLB on IBM Cloud VPC, this doc can help you to get start. 

Import the VPC libaries:

import com.ibm.cloud.sdk.core.http.Response;
import com.ibm.cloud.sdk.core.http.ServiceCall;
import com.ibm.cloud.sdk.core.security.Authenticator;
import com.ibm.cloud.sdk.core.security.IamAuthenticator;
import com.ibm.cloud.is.vpc.v1.*;
import com.ibm.cloud.is.vpc.v1.model.*;
view raw gistfile1.txt hosted with ❤ by GitHub

Create VPC service object and authenticate:

// Define info.
String version = "2020-09-26";
// Create an IAM authenticator.
String apiKey = "<APIKEY>";
Authenticator authenticator = new IamAuthenticator(apiKey);
Vpc vpcService = new Vpc(version, Vpc.DEFAULT_SERVICE_NAME, authenticator);
vpcService.setServiceUrl(Vpc.DEFAULT_SERVICE_URL); // The DEFAULT_SERVICE_URL is https://us-south.iaas.cloud.ibm.com
view raw gistfile1.txt hosted with ❤ by GitHub

GET Profile:

// GET Profile (If you want to create Network Load Balancer, you need to sepcify the profile in your request. If not, an Application Load Balancer will be created. ) -----------------------------------------------------------------------------
public static void GetLoadBalancerProfile(Vpc vpcService, String name) throws Exception {
GetLoadBalancerProfileOptions getLbProfileOptions = new GetLoadBalancerProfileOptions.Builder(name).build();
Response<LoadBalancerProfile> lbProfile = vpcService.getLoadBalancerProfile(getLbProfileOptions).execute();
LoadBalancerProfile lbProfleObj = lbProfile.getResult();
String profleName = lbProfleObj.getName();
System.out.println(lbProfile.toString());
assertValueString(profleName, name);
}
view raw gistfile1.txt hosted with ❤ by GitHub

GET Load Balancer:

public static LoadBalancer GetLoadBalancer(Vpc vpcService, String lbId) throws Exception {
GetLoadBalancerOptions getLbOptions = new GetLoadBalancerOptions.Builder(lbId).build();
Response<LoadBalancer> lb = vpcService.getLoadBalancer(getLbOptions).execute();
LoadBalancer lbObj = lb.getResult();
String id = lbObj.getId();
assertValueString(id, lbId);
return lbObj;
}
view raw gistfile1.txt hosted with ❤ by GitHub

GET Load Balancer Listener:

public static void GetLoadBalancerListener(Vpc vpcService, String lbId, String id) throws Exception {
GetLoadBalancerListenerOptions getLbListenerOptions = new GetLoadBalancerListenerOptions.Builder()
.loadBalancerId(lbId)
.id(id)
.build();
Response<LoadBalancerListener> lbListener = vpcService.getLoadBalancerListener(getLbListenerOptions).execute();
LoadBalancerListener lbProfleObj = lbListener.getResult();
String listenerId = lbProfleObj.getId();
System.out.println(lbProfleObj.toString());
assertValueString(listenerId, id);
}
view raw gistfile1.txt hosted with ❤ by GitHub

GET Load Balancer Pool:

public static void GetLoadBalancerPool(Vpc vpcService, String lbId, String id) throws Exception {
GetLoadBalancerPoolOptions getLbPoolOptions = new GetLoadBalancerPoolOptions.Builder()
.loadBalancerId(lbId)
.id(id)
.build();
Response<LoadBalancerPool> lbPool = vpcService.getLoadBalancerPool(getLbPoolOptions).execute();
LoadBalancerPool lbPoolObj = lbPool.getResult();
String poolId = lbPoolObj.getId();
System.out.println(lbPoolObj.toString());
assertValueString(poolId, id);
}
view raw gistfile1.txt hosted with ❤ by GitHub

GET Load Balancer Pool Member:

public static void GetLoadBalancerPoolMember(Vpc vpcService, String lbId, String poolId, String id) throws Exception {
GetLoadBalancerPoolMemberOptions getMemberOptions = new GetLoadBalancerPoolMemberOptions.Builder()
.loadBalancerId(lbId)
.poolId(poolId)
.id(id)
.build();
Response<LoadBalancerPoolMember> member = vpcService.getLoadBalancerPoolMember(getMemberOptions).execute();
LoadBalancerPoolMember memberObj = member.getResult();
String memberId = memberObj.getId();
System.out.println(memberObj.toString());
assert memberId == id;
assertValueString(memberId, id);
}
view raw gistfile1.txt hosted with ❤ by GitHub

GET Load Balancer Statistics:

public static void GetLoadBalancerStatistics(Vpc vpcService, String id) throws Exception {
GetLoadBalancerStatisticsOptions getLbProfileOptions = new GetLoadBalancerStatisticsOptions.Builder(id).build();
Response<LoadBalancerStatistics> stat = vpcService.getLoadBalancerStatistics(getLbProfileOptions).execute();
LoadBalancerStatistics statObj = stat.getResult();
long activeConnections = statObj.getActiveConnections();
Float connectionRate = statObj.getConnectionRate();
long dataProcessed = statObj.getDataProcessedThisMonth();
Float throughtput = statObj.getThroughput();
System.out.println(statObj.toString());
assertValueLong(activeConnections, 0);
assert connectionRate >= 0;
assertValueLong(dataProcessed, 0);
assert throughtput >= 0;
}
view raw gistfile1.txt hosted with ❤ by GitHub

GET Load Balancer Statistics:

public static void GetLoadBalancerStatistics(Vpc vpcService, String id) throws Exception {
GetLoadBalancerStatisticsOptions getLbProfileOptions = new GetLoadBalancerStatisticsOptions.Builder(id).build();
Response<LoadBalancerStatistics> stat = vpcService.getLoadBalancerStatistics(getLbProfileOptions).execute();
LoadBalancerStatistics statObj = stat.getResult();
long activeConnections = statObj.getActiveConnections();
Float connectionRate = statObj.getConnectionRate();
long dataProcessed = statObj.getDataProcessedThisMonth();
Float throughtput = statObj.getThroughput();
System.out.println(statObj.toString());
assertValueLong(activeConnections, 0);
assert connectionRate >= 0;
assertValueLong(dataProcessed, 0);
assert throughtput >= 0;
}
view raw gistfile1.txt hosted with ❤ by GitHub

CREATE Load Balancer:

public static String CreateLoadBalancer(Vpc vpcService, String subnetId) throws Exception {
LocalDateTime dateObj = LocalDateTime.now();
DateTimeFormatter formatObj = DateTimeFormatter.ofPattern("yyMMddHHMM");
String formattedDate = dateObj.format(formatObj);
String lbName = "javasdk-nlb-" + formattedDate;
LoadBalancerProfileIdentity profile = new LoadBalancerProfileIdentityByName.Builder("network-fixed").build();
SubnetIdentityById subnet = new SubnetIdentityById.Builder(subnetId).build();
List<SubnetIdentity> subnets = new ArrayList<SubnetIdentity>();
subnets.add(subnet);
CreateLoadBalancerOptions createLbOptions = new CreateLoadBalancerOptions.Builder()
.name(lbName)
.isPublic(true)
.profile(profile)
.subnets(subnets)
.build();
Response<LoadBalancer> lb = vpcService.createLoadBalancer(createLbOptions).execute();
LoadBalancer lbObj = lb.getResult();
String lbId = lbObj.getId();
LoadBalancerProfileReference lbProfile = lbObj.getProfile();
boolean isPublic = lbObj.isIsPublic();
List<SubnetReference> lbSubnets = lbObj.getSubnets();
System.out.println(lbObj.toString());
assertValueString(lbProfile.getName(), "network-fixed");
assert isPublic == true;
assertValueString(lbSubnets.get(0).getId(), subnetId);
return lbId;
}
view raw gistfile1.txt hosted with ❤ by GitHub

CREATE Load Balancer Listener:

public static String CreateLoadBalancerListener(Vpc vpcService, String lbId) throws Exception {
long port = 8080;
CreateLoadBalancerListenerOptions createLbListenerOptions = new CreateLoadBalancerListenerOptions.Builder(lbId, port, "tcp").build();
Response<LoadBalancerListener> listener = vpcService.createLoadBalancerListener(createLbListenerOptions).execute();
LoadBalancerListener listenerObj = listener.getResult();
long ListenerPort = listenerObj.getPort();
String ListenerProtocol = listenerObj.getProtocol();
System.out.println(listenerObj.toString());
assertValueLong(ListenerPort, port);
assertValueString(ListenerProtocol, "tcp");
return listenerObj.getId();
}
view raw gistfile1.txt hosted with ❤ by GitHub

CREATE Load Balancer Pool:

public static String CreateLoadBalancerPool(Vpc vpcService, String lbId) throws Exception {
String algorithm = "weighted_round_robin";
String protocol = "tcp";
long port = 9090;
long delay = 10;
long maxRetries = 6;
long timeout = 5;
String type = "http";
LoadBalancerPoolHealthMonitorPrototype healthPrototype = new LoadBalancerPoolHealthMonitorPrototype.Builder(delay, maxRetries, timeout, type)
.port(port)
.build();
CreateLoadBalancerPoolOptions createLbPoolOptions = new CreateLoadBalancerPoolOptions.Builder(lbId, algorithm, protocol, healthPrototype).build();
Response<LoadBalancerPool> pool = vpcService.createLoadBalancerPool(createLbPoolOptions).execute();
LoadBalancerPool poolObj = pool.getResult();
String poolAlgorithm = poolObj.getAlgorithm();
String poolProtocol = poolObj.getProtocol();
LoadBalancerPoolHealthMonitor poolHealthMonitor = poolObj.getHealthMonitor();
System.out.println(poolObj.toString());
assertValueString(poolAlgorithm, algorithm);
assertValueString(poolProtocol, protocol);
assertValueLong(poolHealthMonitor.getDelay(), delay);
assertValueLong(poolHealthMonitor.getMaxRetries(), maxRetries);
assertValueLong(poolHealthMonitor.getPort(), port);
assertValueLong(poolHealthMonitor.getTimeout(), timeout);
assertValueString(poolHealthMonitor.getType(), type);
assertValueString(poolHealthMonitor.getUrlPath(), "/");
return poolObj.getId();
}
view raw gistfile1.txt hosted with ❤ by GitHub

CREATE Load Balancer Pool Member:

public static String CreateLoadBalancerPoolMember(Vpc vpcService, String lbId, String poolId, String instanceId) throws Exception {
long port = 80;
long weight = 60;
LoadBalancerPoolMemberTargetPrototypeInstanceIdentityInstanceIdentityById target;
target = new LoadBalancerPoolMemberTargetPrototypeInstanceIdentityInstanceIdentityById.Builder(instanceId).build();
CreateLoadBalancerPoolMemberOptions createLbPoolMemberOptions = new CreateLoadBalancerPoolMemberOptions.Builder(lbId, poolId, port, target)
.weight(weight)
.build();
Response<LoadBalancerPoolMember> lbPoolMember = vpcService.createLoadBalancerPoolMember(createLbPoolMemberOptions).execute();
LoadBalancerPoolMember memberObj = lbPoolMember.getResult();
long memberPort = memberObj.getPort();
long memberWeight = memberObj.getWeight();
String memberInstanceId = memberObj.getTarget().getId();
System.out.println(memberObj.toString());
assertValueLong(memberPort, port);
assertValueLong(memberWeight, weight);
assertValueString(memberInstanceId, instanceId);
return memberObj.getId();
}
view raw gistfile1.txt hosted with ❤ by GitHub

CREATE Load Balancer Listener With Pool:

public static String CreateLoadBalancerListenerWithPool(Vpc vpcService, String lbId, String poolId) throws Exception {
long port = 5050;
String protocol = "tcp";
LoadBalancerPoolIdentityById poolIdentity = new LoadBalancerPoolIdentityById.Builder(poolId).build();
CreateLoadBalancerListenerOptions createLbListenerOptions = new CreateLoadBalancerListenerOptions.Builder(lbId, port, "tcp")
.loadBalancerId(lbId)
.port(port)
.protocol(protocol)
.defaultPool(poolIdentity)
.build();
Response<LoadBalancerListener> listener = vpcService.createLoadBalancerListener(createLbListenerOptions).execute();
LoadBalancerListener listenerObj = listener.getResult();
long ListenerPort = listenerObj.getPort();
String listenerProtocol = listenerObj.getProtocol();
LoadBalancerPoolReference listenerPool = listenerObj.getDefaultPool();
System.out.println(listenerObj.toString());
assertValueLong(ListenerPort, port);
assertValueString(listenerProtocol, "tcp");
assertValueString(listenerPool.getId(), poolId);
return listenerObj.getId();
}
view raw gistfile1.txt hosted with ❤ by GitHub

CREATE Load Balancer Pool With Member:

public static String CreateLoadBalancerPoolWithMember(Vpc vpcService, String lbId, String instanceId) throws Exception {
String algorithm = "round_robin";
String protocol = "tcp";
long port = 6060;
long delay = 15;
long maxRetries = 10;
long timeout = 10;
String type = "tcp";
LoadBalancerPoolHealthMonitorPrototype healthPrototype = new LoadBalancerPoolHealthMonitorPrototype.Builder(delay, maxRetries, timeout, type)
.port(port)
.build();
LoadBalancerPoolMemberTargetPrototypeInstanceIdentityInstanceIdentityById target;
target = new LoadBalancerPoolMemberTargetPrototypeInstanceIdentityInstanceIdentityById.Builder(instanceId).build();
LoadBalancerPoolMemberPrototype memeberPrototype = new LoadBalancerPoolMemberPrototype.Builder(port, target).build();
CreateLoadBalancerPoolOptions createLbPoolOptions = new CreateLoadBalancerPoolOptions.Builder()
.loadBalancerId(lbId)
.algorithm(algorithm)
.protocol(protocol)
.healthMonitor(healthPrototype)
.addMembers(memeberPrototype)
.build();
Response<LoadBalancerPool> pool = vpcService.createLoadBalancerPool(createLbPoolOptions).execute();
LoadBalancerPool poolObj = pool.getResult();
String poolAlgorithm = poolObj.getAlgorithm();
String poolProtocol = poolObj.getProtocol();
LoadBalancerPoolHealthMonitor poolHealthMonitor = poolObj.getHealthMonitor();
List<LoadBalancerPoolMemberReference> members = poolObj.getMembers();
System.out.println(poolObj.toString());
assertValueString(poolAlgorithm, algorithm);
assertValueString(poolProtocol, protocol);
assertValueLong(poolHealthMonitor.getDelay(), delay);
assertValueLong(poolHealthMonitor.getMaxRetries(), maxRetries);
assertValueLong(poolHealthMonitor.getPort(), port);
assertValueLong(poolHealthMonitor.getTimeout(), timeout);
assertValueString(poolHealthMonitor.getType(), type);
if (members.get(0) == null) {
throw new Exception("Memeber not found");
}
return poolObj.getId();
}
view raw gistfile1.txt hosted with ❤ by GitHub

UPDATE Load Balancer:

public static void UpdateLoadBalancer(Vpc vpcService, String lbId) throws Exception {
LocalDateTime dateObj = LocalDateTime.now();
DateTimeFormatter formatObj = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
String formattedDate = dateObj.format(formatObj);
String newName = "javasdk-nlb-" + formattedDate;
UpdateLoadBalancerOptions updateLbOptions = new UpdateLoadBalancerOptions.Builder()
.id(lbId)
.name(newName)
.build();
Response<LoadBalancer> lb = vpcService.updateLoadBalancer(updateLbOptions).execute();
LoadBalancer lbObj = lb.getResult();
String lbName = lbObj.getName();
System.out.println(lbObj.toString());
assertValueString(lbName, newName);
}
view raw gistfile1.txt hosted with ❤ by GitHub

UPDATE Load Balancer Listener:

public static void UpdateLoadBalancerListener(Vpc vpcService, String lbId, String listenerId, String poolId) throws Exception {
long newPort = 8090;
LoadBalancerPoolIdentityById poolIdentitybyId = new LoadBalancerPoolIdentityById.Builder(poolId).build();
UpdateLoadBalancerListenerOptions updateLbListenerOptions = new UpdateLoadBalancerListenerOptions.Builder()
.loadBalancerId(lbId)
.id(listenerId)
.defaultPool(poolIdentitybyId)
.port(newPort)
.build();
Response<LoadBalancerListener> lbListener = vpcService.updateLoadBalancerListener(updateLbListenerOptions).execute();
LoadBalancerListener lbListenerObj = lbListener.getResult();
long listenerPort = lbListenerObj.getPort();
LoadBalancerPoolReference listenerPool = lbListenerObj.getDefaultPool();
System.out.println(lbListenerObj.toString());
assertValueLong(listenerPort, newPort);
assertValueString(listenerPool.getId(), poolId);
}
view raw gistfile1.txt hosted with ❤ by GitHub

UPDATE Load Balancer Pool:

public static void UpdateLoadBalancerPool(Vpc vpcService, String lbId, String poolId) throws Exception {
String newName = "new-pool";
String newAlgorithm = "least_connections";
long delay = 15;
long maxRetries = 6;
long timeout = 10;
String type = "tcp";
LoadBalancerPoolSessionPersistencePatch sessionPersistence = new LoadBalancerPoolSessionPersistencePatch.Builder("source_ip").build();
LoadBalancerPoolHealthMonitorPatch healthMonitor = new LoadBalancerPoolHealthMonitorPatch.Builder(delay, maxRetries, timeout, type).build();
UpdateLoadBalancerPoolOptions updateLbPoolOptions = new UpdateLoadBalancerPoolOptions.Builder()
.loadBalancerId(lbId)
.id(poolId)
.name(newName)
.sessionPersistence(sessionPersistence)
.algorithm(newAlgorithm)
.healthMonitor(healthMonitor)
.build();
Response<LoadBalancerPool> lbPool = vpcService.updateLoadBalancerPool(updateLbPoolOptions).execute();
LoadBalancerPool poolObj = lbPool.getResult();
String poolName = poolObj.getName();
String poolAlgorithm = poolObj.getAlgorithm();
LoadBalancerPoolHealthMonitor poolHealthMonitor = poolObj.getHealthMonitor();
System.out.println(poolObj.toString());
assertValueString(poolName, newName);
assertValueString(poolAlgorithm, newAlgorithm);
assertValueLong(poolHealthMonitor.getDelay(), delay);
assertValueLong(poolHealthMonitor.getMaxRetries(), maxRetries);
assertValueLong(poolHealthMonitor.getTimeout(), timeout);
assertValueString(poolHealthMonitor.getType(), type);
}
view raw gistfile1.txt hosted with ❤ by GitHub

UPDATE Load Balancer Member:

public static void UpdateLoadBalancerMember(Vpc vpcService, String lbId, String poolId, String memberId, String instanceId) throws Exception {
long newPort = 7070;
long newWeight = 90;
LoadBalancerPoolMemberTargetPrototypeInstanceIdentityInstanceIdentityById target;
target = new LoadBalancerPoolMemberTargetPrototypeInstanceIdentityInstanceIdentityById.Builder(instanceId).build();
UpdateLoadBalancerPoolMemberOptions updateLbPoolMemberOptions;
updateLbPoolMemberOptions = new UpdateLoadBalancerPoolMemberOptions.Builder()
.id(memberId)
.poolId(poolId)
.loadBalancerId(lbId)
.port(newPort)
.weight(newWeight)
.target(target)
.build();
Response<LoadBalancerPoolMember> lbMember = vpcService.updateLoadBalancerPoolMember(updateLbPoolMemberOptions).execute();
LoadBalancerPoolMember memberObj = lbMember.getResult();
long memberPort = memberObj.getPort();
long memberWeight = memberObj.getWeight();
String memberInstanceId = memberObj.getTarget().getId();
System.out.println(memberObj.toString());
assertValueLong(memberPort, newPort);
assertValueLong(memberWeight, newWeight);
assertValueString(memberInstanceId, instanceId);
}
view raw gistfile1.txt hosted with ❤ by GitHub

PUT Application LoadBalancer Member:

public static void PutApplicationLoadBalancerMember(Vpc vpcService, String lbId, String poolId, String instanceIp1, String instanceIp2) throws Exception {
long port1 = 2020;
LoadBalancerPoolMemberTargetPrototypeIP target1;
target1 = new LoadBalancerPoolMemberTargetPrototypeIP.Builder(instanceIp1).build();
LoadBalancerPoolMemberPrototype memeberPrototype1 = new LoadBalancerPoolMemberPrototype.Builder(port1, target1).build();
long port2 = 2020;
LoadBalancerPoolMemberTargetPrototypeIP target2;
target2 = new LoadBalancerPoolMemberTargetPrototypeIP.Builder(instanceIp2).build();
LoadBalancerPoolMemberPrototype memeberPrototype2 = new LoadBalancerPoolMemberPrototype.Builder(port2, target2).build();
List<LoadBalancerPoolMemberPrototype> members = new ArrayList();
members.add(memeberPrototype1);
members.add(memeberPrototype2);
ReplaceLoadBalancerPoolMembersOptions putLbMemberOptions = new ReplaceLoadBalancerPoolMembersOptions.Builder()
.loadBalancerId(lbId)
.poolId(poolId)
.members(members)
.build();
Response<LoadBalancerPoolMemberCollection> response = vpcService.replaceLoadBalancerPoolMembers(putLbMemberOptions).execute();
System.out.println(response.toString());
System.out.print(response.getStatusCode());
}
view raw gistfile1.txt hosted with ❤ by GitHub

DELETE Load Balancer:

public static void DeleteLoadBalancer(Vpc vpcService, String lbId) throws Exception {
DeleteLoadBalancerOptions deleteLbOptions = new DeleteLoadBalancerOptions.Builder(lbId).build();
Response<Void> response = vpcService.deleteLoadBalancer(deleteLbOptions).execute();
if (response.getStatusCode() != 204) {
throw new Exception();
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

DELETE Load Balancer Listener:

public static void DeleteLoadBalancerListener(Vpc vpcService, String lbId, String listenerId) throws Exception {
DeleteLoadBalancerListenerOptions deleteLbListenerOptions = new DeleteLoadBalancerListenerOptions.Builder(lbId, listenerId).build();
Response<Void> response = vpcService.deleteLoadBalancerListener(deleteLbListenerOptions).execute();
if (response.getStatusCode() != 204) {
throw new Exception();
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

DELETE Load Balancer Pool:

public static void DeleteLoadBalancerPool(Vpc vpcService, String lbId, String poolId) throws Exception {
DeleteLoadBalancerPoolOptions deleteLbPoolOptions = new DeleteLoadBalancerPoolOptions.Builder(lbId, poolId).build();
Response<Void> response = vpcService.deleteLoadBalancerPool(deleteLbPoolOptions).execute();
if (response.getStatusCode() != 204) {
throw new Exception();
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

DELETE Load Balancer Pool Member:

public static void DeleteLoadBalancerPoolMember(Vpc vpcService, String lbId, String poolId, String memberId) throws Exception {
DeleteLoadBalancerPoolMemberOptions deleteLbPoolMemberOptions = new DeleteLoadBalancerPoolMemberOptions.Builder(lbId, poolId, memberId).build();
Response<Void> response = vpcService.deleteLoadBalancerPoolMember(deleteLbPoolMemberOptions).execute();
if (response.getStatusCode() != 204) {
throw new Exception();
}
}
view raw gistfile1.txt hosted with ❤ by GitHub


Some references:

Java SDK version: https://mvnrepository.com/artifact/com.ibm.cloud/vpc
Doc: https://ibm.github.io/vpc-java-sdk/docs/latest/
Source: https://github.com/IBM/vpc-java-sdk


Saturday, October 3, 2020

Create a Rock Paper Scissors Game with Firebase Realtime Database and Hosting service

What is Firebase Realtime Databases?

Firebase is Google's mobile platform that helps you quickly develop high-quality apps and grow your business. Firebase Realtime Database is a cloud NoSQL database that is using data synchronization to update all connected client devices in real time. It has very friendly IOS, Android and JavaScript SDK and REST API for client-side developers to use.


RPS-Multiplayer

In this blogger, we build a Rock Paper Scissors game. Our program will pair up two players and tell the player who is available if his/her opponent is offline and someone is waiting at the same time. Players can send message to each other, but all previous messages will be remove if player has new opponent.

Step 1:

In the Firebase console, click Add project, then follow the on-screen instructions to create a Firebase project called "RPS-game".

After you create the project, select your project on the console and "Realtime Database" on the right panel. Click on the "Create Database" and follow the on-screen instructions to create your database. Select "Test mode" for your database.


Step 2:

Create a folder has this structure:

├── README.md
├── assets
│   ├── css
│   │   └── style.css
│   ├── images
│   └── javascript
│       └── game.js
└── index.html

Step 3:

Import Firebase JavaScript SDK with CDN in index.html:

<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
 
<script src="https://www.gstatic.com/firebasejs/7.22.0/firebase-app.js"></script>

Step 4:

Obtain your config info from this your project's console:




If you have difficulty to find the config info, follow Firebase Help page: https://support.google.com/firebase/answer/7015592

Initialize Firebase in assets/javascript/game.js:

 // Set the configuration for your app
 
// TODO: Replace with your project's config object
 
var config = {
    apiKey
: "apiKey",
    authDomain
: "projectId.firebaseapp.com",
    databaseURL
: "https://databaseName.firebaseio.com",
    storageBucket
: "bucket.appspot.com"
 
};
  firebase
.initializeApp(config);

 
// Get a reference to the database service
 
var database = firebase.database();

Step 5:

The main logic of the game is in the assets/javascript/game.js. Let's focus on some of the main functions to achieve functionalities of the game.

 // find player who waits for the longest
player_ref.orderByChild("waitTime").limitToLast(1).once("value",function(snapshot){                       
    // check if anyone is waiting to play game
    checkIfSomeoneWaiting(snapshot.val());

    // save player1's info into database
    savePlayer1Info();

    // check if we have update in enemy property
    checkIfHaveEnemy();
                        
    // check database and render player1's choice and score
    initPlayer1Game();

    // check if player1 makes a choice
    database.ref("players/"+my_key+"/choice").on("value",function(snapshot){
        my_choice = snapshot.val();
        if(my_choice !== "" && enemy_choice !== ""){ // if player2 has made a choice
            checkWhoWin();
        };
    })

    // handle player1 offline event
    handlePlayer1Offline();

     // clear the start input
     $("#player_name").val("");
}) 

checkIfSomeoneWaiting(snapshot.val()) has the player that wait for the longest time as argument. If this player hasn't started playing with anyone, pair this player up with the current player.

 function checkIfSomeoneWaiting(data){
    if(data !== null){ // if there is someone waiting to play game
        var key = Object.keys(data)[0];
        if(data[key].enemy === ""){  // if the returned player isn't playing with someone
            my_enemy_key = key;
            enemy = data[my_enemy_key].name;
            wait_time = Number.MAX_VALUE;

            // set myself as the enemy of the returned player and waitTime to min integer 
            database.ref("players/"+my_enemy_key).update({enemy: my_name, waitTime: wait_time});                                 
        }
    } 
}

savePlayer1Info() save current player's info into the database.

function savePlayer1Info(){
    var player1_info = { 
        name: my_name,
        enemy: enemy,
        waitTime: wait_time,
        choice: "",
        online: true,
        message: ""
    }
    database.ref("players/"+my_key).update(player1_info);
}

checkIfHaveEnemy() fires a listener on current player's "enemy" data field. On this field has update, the realtime database with use the callback function "function(snapshot)" here to perform a serial of actions and fire more listeners to listening on the enemy's input, determine who is the winner, incoming new message, and terminate the game if the enemy is offline.

function checkIfHaveEnemy(){
    database.ref("players/"+my_key+"/enemy").on("value",function(snapshot){
        var data = snapshot.val();
        if(data !== ""){
            player_ref.orderByChild("name").equalTo(data).once("value",function(snap){
                my_enemy_key = Object.keys(snap.val())[0];
                var enemy_data = snap.val()[my_enemy_key];
                
                if(enemy_data !== null && (enemy_data.enemy === "" || enemy_data.enemy === my_name)){
                    wait_time = Number.MAX_VALUE;
                    database.ref("players/"+my_enemy_key).update({enemy: my_name, waitTime: wait_time});

                    // render player2's choice and score
                    enemy = enemy_data.name;
                    $("#player2_name").text(enemy);
                    printChoice("#player2_choice");
                    printScore("#player2_result",my_lose,my_win,my_tie);
                    $("#dialogue").empty();

                    // check if there is a new message from player2
                    checkNewMessage();

                    database.ref("players/"+my_enemy_key+"/choice").on("value",function(snapshot){
                        enemy_choice = snapshot.val();
                        if(enemy_choice !== "" && my_choice !== ""){
                            checkWhoWin();
                        }
                    })

                    // handle enemy offline event
                    enemyOfflineHandle();
                }else{
                    $("#player2_choice").append("<p>Sorry,"+data+" is not available!")
                }
            })
        }       
    })
}

initPlayer1Game() fires a listener on current player's value change in DB, then print the choice and score of the game on UI.

function initPlayer1Game(){
    database.ref("players/"+my_key).on("value",function(snapshot){
        var data = snapshot.val()
        if(data !== null){
            if(!in_game){
                $("#player1_name").text(data.name);
                printChoice("#player1_choice");
                printScore("#player1_result",my_win,my_lose,my_tie);
            }
            in_game = true;
        }
    })
}

handlePlayer1Offline() is used to remove current player's data from database, and this could help to automatically clean up the database.

function handlePlayer1Offline(){
    database.ref("players/"+my_key+"/online").on('value', function(snapshot) {
        if (snapshot.val()) { database.ref("players/"+my_key).onDisconnect().remove(); }               
    });
}

You can find the source code here:

https://github.com/gugucode/RPS-Multiplayer

Learn more about the Firebase database JavaScript SDK:

https://firebase.google.com/docs/reference/js/firebase.database

Step 6:

Use Firebase Hosting service to host your RPS-game, follow below steps:

// Install the firebase CLI
npm install -g firebase-tools

// Make a folder named rpg-project
mkdir rpg-project
cd rpg-project

// Login to your google account
firebase login


// Initialize your project and select the Firebase Hosting service with arrow keys to // go up/down and empty bar to select your service
firebase init

// Remove the default files inside public folder
rm -r public/*

// Clone your github repo to public folder
git clone <git_clone_your_project_path> public

// Run this command to deploy your application
firebase deploy

More detail can be found here:
https://firebase.google.com/docs/hosting/quickstart

Here is the URL to the game that has been deployed on Firebase Hosting:
https://rps-multiplayer-2c7aa.firebaseapp.com/

Happy coding ~~~~~~~~~`









IBM Cloud VPC Network Load Balancer -- Node.js SDK Examples

 What is Network Load Balancer (NLB)? Network Load Balancer works in Layer 4 and is best fit for business-critical and intera...