Set up automatic resizing for virtual machines (VMs) that exceed memory by using Notifications, Functions, and Monitoring services.
This scenario involves writing a function to resize VMs and creating an alarm that sends a message to that function. When the alarm fires, the Notifications service sends the alarm message to the destination topic, which then fans out to the topic's subscriptions. In this scenario, the topic's subscriptions include the function as well as your email address and an SMS phone number. The function is invoked on receipt of the alarm message.
Note
The Notifications service has no information about a function after it's invoked. For details, see the troubleshooting information in Function Not Invoked or Run.
Required IAM Policy
To use Oracle Cloud Infrastructure, an administrator must be a member of a group granted security access in a policy by a tenancy administrator. This access is required whether you're using the Console or the REST API with an SDK, CLI, or other tool. If you get a message that you don't have permission or are unauthorized, verify with the tenancy administrator what type of access you have and which compartment your access works in.
If you're a member of the Administrators group, you already have the required access to execute this scenario. Otherwise, you need access to Monitoring, Notifications, and Functions. You must have FN_INVOCATION permission against the function to be able to add the function as a subscription to a topic. To resize VMs, the function must be authorized to update compute instances. To authorize your function for access to other Oracle Cloud Infrastructure resources, such as compute instances, include the function in a dynamic group and create a policy to grant the dynamic group access to those resources. For more information, see Accessing Other Oracle Cloud Infrastructure Resources from Running Functions.
Task 1: Create and Authorize Your Function 🔗
Once you create your function to resize VMs using your preferred SDK and authorize your function to access VMs (include the function in a dynamic group and grant that dynamic group access), all other scenario steps can be completed in the Console. Alternatively, you can use the Oracle Cloud Infrastructure CLI or API, which lets you execute the individual operations yourself.
For this code sample, we recommend handling idempotency via a database.
The following code sample is for a function to resize VMs. For instructions on creating and deploying functions, see Creating and Deploying Functions.
Copy
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.Standard2.1":
new_shape = "VM.Standard2.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"}
)
POST /20181201/topics
Host: notification.us-phoenix-1.oraclecloud.com
<authorization and other headers>
{
"name": "Alarm Topic",
"compartmentId": "<compartment_OCID>"
}
Task 3: Create the Subscriptions 🔗
Your function must be deployed before creating the function subscription.
Select the topic that you created earlier (example name was Alarm Topic): On the Topics list page, select the topic that you want to work with. If you need help finding the list page or the topic, see Listing Topics.
Create the function subscription.
Open the Create Subscription panel: In the detail page for the topic, select Create Subscription.
The Create Subscription panel opens.
For Protocol, select Function.
Fill in the remaining fields.
Field
Description
Function Compartment
Select the compartment containing the function.
Function Application
Select the application containing the function.
Function
Select the function.
Select Create.
No confirmation is needed for new function subscriptions.
Create the SMS subscription.
Open the Create Subscription panel: In the detail page for the topic, select Create Subscription.