Nikhil Verma

Sep 14, 20234 min

Leverage OCI Functions for Automation


 
Oracle Cloud Infrastructure (OCI) Functions is a serverless compute service that lets you create, run, and scale applications without managing any infrastructure. Functions are small but powerful blocks of code that generally do one simple thing. They are grouped into applications and stored as Docker images in a specified Docker registry. Functions can be invoked in response to a CLI command or signed HTTP request.

Here are some of the benefits of using OCI Functions:

  • Serverless: You don't have to provision or manage any infrastructure. OCI Functions takes care of all that for you.

  • Scalable: Functions can scale automatically to meet demand. You don't have to worry about provisioning enough capacity for your application.

  • Secure: OCI Functions is a secure service that is compliant with industry standards. Your code and data are protected.

  • Cost-effective: You only pay for the resources you use. There are no upfront costs or commitments.

I am going to showcase how to change VM shape when critical Memory alarm triggered using OCI functions.

Let's create function first :

Go to Developer services and Choose functions.

Let's create function :

Here i have set application name , shape and Network.

For Function deployment we can use either Cloud shell or Local.

Here i am using cloud shell

Login to Cloud Shell :

First we need to list Context and see you have right region context set :

fn list context

To set different region you can provide region name :

fn use context us-ashburn-1

Then we need to set Compartment where you have deployed this app

fn update context oracle.compartment-id ocid1.compartment

We need to create container registry to store Function container image . Here i am using Oracle Container registry

fn update context registry iad.ocir.io/tenancynamespace/prefix

To connect this container registry we need to Generate your Auth token

Login to OCI registry and Enter Auth token

docker login -u

Till here our context and Registry is ready , now we need to initialize function

Since i am going to use python script so i have initialized with runtime python.

fn init --runtime python compute

After initialize you will find three files : func.py,func.yaml & requirements.txt

Let's add our python script and renamed func.py to compute.py

In this example i am going to change VM shape with higher resources when function invoked by Memory alarm.

import io
 
import json
 
import oci
 

 
from fdk import response
 

 
def increase_compute_shape(instance_id, alarm_msg_shape):
 
signer = oci.auth.signers.get_resource_principals_signer()
 
compute_client = oci.core.ComputeClient(config={}, signer=signer)
 
current_shape = compute_client.get_instance(instance_id).data.shape
 
print("INFO: current shape for Instance {0}: {1}".format(instance_id,current_shape), flush=True)
 
if current_shape != alarm_msg_shape:
 
return "The shape of Instance {} differs from the Alarm message".format(instance_id)
 
# improve the logic below to handle more scenarios, make sure the shapes you select are available in the region and AD
 
if current_shape == "VM.Standard1.1":
 
new_shape = "VM.Standard2.1"
 
elif current_shape == "VM.Standard.E2.1":
 
new_shape = "VM.Standard.E2.2"
 
else:
 
return "Instance {0} cannot get a bigger shape than its current shape {1}".format(instance_id,current_shape)
 
print("INFO: new shape for Instance {0}: {1}".format(instance_id,new_shape), flush=True)
 
try:
 
update_instance_details = oci.core.models.UpdateInstanceDetails(shape=new_shape)
 
resp = compute_client.update_instance(instance_id=instance_id, update_instance_details=update_instance_details)
 
print(resp, flush=True)
 
except Exception as ex:
 
print('ERROR: cannot update instance {}'.format(instance_id), flush=True)
 
raise
 
return "The shape of Instance {} is updated, the instance is rebooting...".format(instance_id)
 

 
def handler(ctx, data: io.BytesIO=None):
 
alarm_msg = {}
 
message_id = func_response = ""
 
try:
 
headers = ctx.Headers()
 
message_id = headers["x-oci-ns-messageid"]
 
except Exception as ex:
 
print('ERROR: Missing Message ID in the header', ex, flush=True)
 
raise
 
print("INFO: Message ID = ", message_id, flush=True)
 
# the Message Id can be stored in a database and be used to check for duplicate messages
 
try:
 
alarm_msg = json.loads(data.getvalue())
 
print("INFO: Alarm message: ")
 
print(alarm_msg, flush=True)
 
except (Exception, ValueError) as ex:
 
print(str(ex), flush=True)
 

 
if alarm_msg["type"] == "OK_TO_FIRING":
 
if alarm_msg["alarmMetaData"][0]["dimensions"]:
 
alarm_metric_dimension = alarm_msg["alarmMetaData"][0]["dimensions"][0] #assuming the first dimension matches the instance to resize
 
print("INFO: Instance to resize: ", alarm_metric_dimension["resourceId"], flush=True)
 
func_response = increase_compute_shape(alarm_metric_dimension["resourceId"], alarm_metric_dimension["shape"])
 
print("INFO: ", func_response, flush=True)
 
else:
 
print('ERROR: There is no metric dimension in this alarm message', flush=True)
 
func_response = "There is no metric dimension in this alarm message"
 
else:
 
print('INFO: Nothing to do, alarm is not FIRING', flush=True)
 
func_response = "Nothing to do, alarm is not FIRING"
 

 
return response.Response(
 
ctx,
 
response_data=func_response,
 
headers={"Content-Type": "application/json"}
 
)

In this python script i am using OCI module so i have to update requirements with OCI.

Then i have updated func.yaml with my compute.py script name

Now all our function files ready ,let's deploy this function :

fn -v deploy --app computeapp

After Deployment in your computeapp you will find image and endpoint details.

To test this function i have deployed Test-linux VM with shape VM.standard.E2.1

To set alarm we need to create topic and subscription in Notifications.

I have created topic Name : Memory_alrm

Then i have created subscription where i have specified protocol Function and choose my compute function.

Now our subscription is ready.

Let's Create Alarm. In alarm i have choose Metric Namespace: oci_computeagent and Metric name : MemoryUtilization

In Metric Dimensions i have specified VM name: Test-linux

For Destination it will trigger Memory_alrm topic which will invoke function to change shape.

Let's generate Memory load using Stress-ng this will trigger this alarm which further invoke function to change this VM shape.

As you can see Alarm triggered as we have continuous 100% memory utlization for 1 min.

If you check function logs it is invoked and triggered VM shape change to VM.standard.E2.2

Now my instance going to stop to set this image shape change.

Finally my Instance shape change to VM.standard.E2.2

This is just one example , you can do lot more with OCI functions.

    830
    0