Oracle Functions is a fully managed, multi-tenant, highly scalable, functions-as-a-service platform. It’s built on enterprise-grade Oracle Cloud Infrastructure components and powered by the open source Fn Project serverless platform. Along with Oracle Events, Oracle Functions can deliver powerful capabilities for infrastructure and application automation. Together, they enable services to act automatically based on state changes in infrastructure resources, a common use case for enterprise IT environments.
This post walks through an example of a function that verifies whether a compute instance is tagged correctly when it’s provisioned. If the instance isn’t tagged properly, the function acts to stop the instance. This practice is common in infrastructure automation; it allows resources to be audited for compliance with internal governance policies as they are created, rather than after.
This function is triggered by the Instance - Launch End event, which the Compute service generates at the completion of instance provisioning, based on whether the instance succeeds or fails.
This example uses Oracle Cloud Infrastructure Search to search for Compute resources with a tag key of costcenter and tag value of 1234.
Set up the Fn CLI with Oracle Functions.
To use and retrieve information about other Oracle Cloud Infrastructure services, include the function in a dynamic group. The following example rule allows functions in a specific compartment to be included in a dynamic group:
ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..exampleuniqueID'}
For more information, see To create a dynamic group.
Create or update policies to grant dynamic group access to resources.
After your dynamic group is created, create a policy that allows the dynamic group to use the instances in the compartment. Your policy should look something like this:
Allow dynamic-group to use instances in compartment
For example:
Allow dynamic-group demo-func-dyn-group to use instances in compartment demo-func-compartment
For more information, see Policy Syntax.
Use the Oracle Cloud Infrastructure Console to create an application in Oracle Functions.
From the navigation menu, select Developer Services, and then select Functions.
Click Create Application and then enter values in the New Application dialog box. If you have previously created VCNs, they are listed, and you can select the appropriate subnet.
Open a terminal and create the Python function:
fn init --runtime python stop-untagged-instance
cd stop-untagged-instance
In the requirements.txt file, add the following entries:
fdk
oci
When the Compute service emits the Instance - Launch End event, the JSON looks as follows:
{
"eventType" : "com.oraclecloud.computeapi.launchinstance.end",
"cloudEventsVersion" : "0.1",
"eventTypeVersion" : "2.0",
"source" : "ComputeApi",
"eventTime" : "2020-03-04T21:24:16.151Z",
"contentType" : "application/json",
"data" : {
"compartmentId" : "ocid1.compartment.oc1..exampleuniqueID",
"compartmentName" : "sandbox",
"resourceName" : "instance-20200304-1322",
"resourceId" : "ocid1.instance.oc1.iad.exampleuniqueID",
"availabilityDomain" : "QGaa:US-ASHBURN-AD-1",
"additionalDetails" : {
"imageId" : "ocid1.image.oc1.iad.exampleuniqueID",
"shape" : "VM.Standard2.1",
"type" : "CustomerVmi"
}
},
"eventID" : "08a71051-cb5c-490d-8e47-2354cfe503b5",
"extensions" : {
"compartmentId" : "ocid1.compartment.oc1..exampleuniqueID"
}
}
The resourceId is the instance identifier (OCID).
Following are some snippets of code from the func.py file:
From the JSON body, get the instance ID:
body = json.loads(data.getvalue())
instanceId = body["data"]["resourceId"]
Use a signer to authenticate to Oracle Cloud Infrastructure services:
signer = oci.auth.signers.get_resource_principals_signer()
Use Oracle Cloud Infrastructure Search to verify whether the Compute instance is properly tagged:
search_client = oci.resource_search.ResourceSearchClient(config={}, signer=signer)
key="costcenter"
value="1234"
structured_search = oci.resource_search.models.StructuredSearchDetails(
query="query instance resources where ((freeformTags.key != '{}' && freeformTags.value != '{}') && (identifier='{}'))".format(key,value,instanceId),
type='Structured',
matching_context_type=oci.resource_search.models.SearchDetails.MATCHING_CONTEXT_TYPE_NONE)
results = search_client.search_resources(structured_search)
If the search finds that the instance was not tagged properly, then stop the instance:
compute_client = oci.core.ComputeClient(config={}, signer=signer)
try:
if compute_client.get_instance(instanceId).data.lifecycle_state in ('RUNNING'):
try:
resp = compute_client.instance_action(instanceId,'STOP')
except oci.exceptions.ServiceError as :
print('Action failed. {0}'.format(e), flush=True)
raise
else:
print('The instance {0} was in the incorrect state to stop'.format(instanceId),flush=True)
Deploy the function:
fn deploy --app control-instance-app
In the navigation menu of the Console, select Application Integration, and then select Events Service.
Click Create Rule and enter values in the Edit Rule dialog box.
In this example, the service name is Compute, the event type is Instance - Launch End, and the action to take is to call the stop-untagged-instance function in the control-instance-app function application.
Launch a Compute instance with no tags.
After a few minutes, you should see that the instance has stopped for you to take further action.
This post shows an example of how to implement IT compliance rules by using Cloud Events and Functions in Oracle Cloud Infrastructure.
Previous Post
Next Post